SchedulerSpec.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //
  2. // SchedulerSpec.swift
  3. // ReactiveCocoa
  4. //
  5. // Created by Justin Spahr-Summers on 2014-07-13.
  6. // Copyright (c) 2014 GitHub. All rights reserved.
  7. //
  8. import Foundation
  9. import Nimble
  10. import Quick
  11. @testable
  12. import ReactiveCocoa
  13. class SchedulerSpec: QuickSpec {
  14. override func spec() {
  15. describe("ImmediateScheduler") {
  16. it("should run enqueued actions immediately") {
  17. var didRun = false
  18. ImmediateScheduler().schedule {
  19. didRun = true
  20. }
  21. expect(didRun) == true
  22. }
  23. }
  24. describe("UIScheduler") {
  25. func dispatchSyncInBackground(action: () -> Void) {
  26. let group = dispatch_group_create()
  27. dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), action)
  28. dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
  29. }
  30. it("should run actions immediately when on the main thread") {
  31. let scheduler = UIScheduler()
  32. var values: [Int] = []
  33. expect(NSThread.isMainThread()) == true
  34. scheduler.schedule {
  35. values.append(0)
  36. }
  37. expect(values) == [ 0 ]
  38. scheduler.schedule {
  39. values.append(1)
  40. }
  41. scheduler.schedule {
  42. values.append(2)
  43. }
  44. expect(values) == [ 0, 1, 2 ]
  45. }
  46. it("should enqueue actions scheduled from the background") {
  47. let scheduler = UIScheduler()
  48. var values: [Int] = []
  49. dispatchSyncInBackground {
  50. scheduler.schedule {
  51. expect(NSThread.isMainThread()) == true
  52. values.append(0)
  53. }
  54. return
  55. }
  56. expect(values) == []
  57. expect(values).toEventually(equal([ 0 ]))
  58. dispatchSyncInBackground {
  59. scheduler.schedule {
  60. expect(NSThread.isMainThread()) == true
  61. values.append(1)
  62. }
  63. scheduler.schedule {
  64. expect(NSThread.isMainThread()) == true
  65. values.append(2)
  66. }
  67. return
  68. }
  69. expect(values) == [ 0 ]
  70. expect(values).toEventually(equal([ 0, 1, 2 ]))
  71. }
  72. it("should run actions enqueued from the main thread after those from the background") {
  73. let scheduler = UIScheduler()
  74. var values: [Int] = []
  75. dispatchSyncInBackground {
  76. scheduler.schedule {
  77. expect(NSThread.isMainThread()) == true
  78. values.append(0)
  79. }
  80. return
  81. }
  82. scheduler.schedule {
  83. expect(NSThread.isMainThread()) == true
  84. values.append(1)
  85. }
  86. scheduler.schedule {
  87. expect(NSThread.isMainThread()) == true
  88. values.append(2)
  89. }
  90. expect(values) == []
  91. expect(values).toEventually(equal([ 0, 1, 2 ]))
  92. }
  93. }
  94. describe("QueueScheduler") {
  95. it("should run enqueued actions on a global queue") {
  96. var didRun = false
  97. let scheduler: QueueScheduler
  98. if #available(OSX 10.10, *) {
  99. scheduler = QueueScheduler(qos: QOS_CLASS_DEFAULT)
  100. } else {
  101. scheduler = QueueScheduler(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
  102. }
  103. scheduler.schedule {
  104. didRun = true
  105. expect(NSThread.isMainThread()) == false
  106. }
  107. expect{didRun}.toEventually(beTruthy())
  108. }
  109. describe("on a given queue") {
  110. var scheduler: QueueScheduler!
  111. beforeEach {
  112. if #available(OSX 10.10, *) {
  113. scheduler = QueueScheduler(qos: QOS_CLASS_DEFAULT)
  114. } else {
  115. scheduler = QueueScheduler(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
  116. }
  117. dispatch_suspend(scheduler.queue)
  118. }
  119. it("should run enqueued actions serially on the given queue") {
  120. var value = 0
  121. for _ in 0..<5 {
  122. scheduler.schedule {
  123. expect(NSThread.isMainThread()) == false
  124. value += 1
  125. }
  126. }
  127. expect(value) == 0
  128. dispatch_resume(scheduler.queue)
  129. expect{value}.toEventually(equal(5))
  130. }
  131. it("should run enqueued actions after a given date") {
  132. var didRun = false
  133. scheduler.scheduleAfter(NSDate()) {
  134. didRun = true
  135. expect(NSThread.isMainThread()) == false
  136. }
  137. expect(didRun) == false
  138. dispatch_resume(scheduler.queue)
  139. expect{didRun}.toEventually(beTruthy())
  140. }
  141. it("should repeatedly run actions after a given date") {
  142. let disposable = SerialDisposable()
  143. var count = 0
  144. let timesToRun = 3
  145. disposable.innerDisposable = scheduler.scheduleAfter(NSDate(), repeatingEvery: 0.01, withLeeway: 0) {
  146. expect(NSThread.isMainThread()) == false
  147. count += 1
  148. if count == timesToRun {
  149. disposable.dispose()
  150. }
  151. }
  152. expect(count) == 0
  153. dispatch_resume(scheduler.queue)
  154. expect{count}.toEventually(equal(timesToRun))
  155. }
  156. }
  157. }
  158. describe("TestScheduler") {
  159. var scheduler: TestScheduler!
  160. var startDate: NSDate!
  161. // How much dates are allowed to differ when they should be "equal."
  162. let dateComparisonDelta = 0.00001
  163. beforeEach {
  164. startDate = NSDate()
  165. scheduler = TestScheduler(startDate: startDate)
  166. expect(scheduler.currentDate) == startDate
  167. }
  168. it("should run immediately enqueued actions upon advancement") {
  169. var string = ""
  170. scheduler.schedule {
  171. string += "foo"
  172. expect(NSThread.isMainThread()) == true
  173. }
  174. scheduler.schedule {
  175. string += "bar"
  176. expect(NSThread.isMainThread()) == true
  177. }
  178. expect(string) == ""
  179. scheduler.advance()
  180. expect(scheduler.currentDate).to(beCloseTo(startDate))
  181. expect(string) == "foobar"
  182. }
  183. it("should run actions when advanced past the target date") {
  184. var string = ""
  185. scheduler.scheduleAfter(15) { [weak scheduler] in
  186. string += "bar"
  187. expect(NSThread.isMainThread()) == true
  188. expect(scheduler?.currentDate).to(beCloseTo(startDate.dateByAddingTimeInterval(15), within: dateComparisonDelta))
  189. }
  190. scheduler.scheduleAfter(5) { [weak scheduler] in
  191. string += "foo"
  192. expect(NSThread.isMainThread()) == true
  193. expect(scheduler?.currentDate).to(beCloseTo(startDate.dateByAddingTimeInterval(5), within: dateComparisonDelta))
  194. }
  195. expect(string) == ""
  196. scheduler.advanceByInterval(10)
  197. expect(scheduler.currentDate).to(beCloseTo(startDate.dateByAddingTimeInterval(10), within: dateComparisonDelta))
  198. expect(string) == "foo"
  199. scheduler.advanceByInterval(10)
  200. expect(scheduler.currentDate).to(beCloseTo(startDate.dateByAddingTimeInterval(20), within: dateComparisonDelta))
  201. expect(string) == "foobar"
  202. }
  203. it("should run all remaining actions in order") {
  204. var string = ""
  205. scheduler.scheduleAfter(15) {
  206. string += "bar"
  207. expect(NSThread.isMainThread()) == true
  208. }
  209. scheduler.scheduleAfter(5) {
  210. string += "foo"
  211. expect(NSThread.isMainThread()) == true
  212. }
  213. scheduler.schedule {
  214. string += "fuzzbuzz"
  215. expect(NSThread.isMainThread()) == true
  216. }
  217. expect(string) == ""
  218. scheduler.run()
  219. expect(scheduler.currentDate) == NSDate.distantFuture()
  220. expect(string) == "fuzzbuzzfoobar"
  221. }
  222. }
  223. }
  224. }