rx 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +22 -0
  3. data/.gitignore +173 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +4 -0
  6. data/Rakefile +11 -0
  7. data/examples/aggregate.rb +39 -0
  8. data/examples/amb.rb +25 -0
  9. data/examples/ambproto.rb +24 -0
  10. data/examples/and.rb +26 -0
  11. data/examples/as_observable.rb +25 -0
  12. data/examples/average.rb +43 -0
  13. data/examples/buffer_with_count.rb +44 -0
  14. data/examples/buffer_with_time.rb +51 -0
  15. data/examples/case.rb +29 -0
  16. data/examples/catch.rb +20 -0
  17. data/examples/catchproto.rb +39 -0
  18. data/examples/combine_latest.rb +35 -0
  19. data/examples/combine_latestproto.rb +33 -0
  20. data/examples/concat.rb +22 -0
  21. data/examples/concat_all.rb +27 -0
  22. data/examples/concat_map.rb +61 -0
  23. data/examples/concat_map_observer.rb +29 -0
  24. data/examples/concatproto.rb +25 -0
  25. data/examples/connect.rb +41 -0
  26. data/examples/contains.rb +37 -0
  27. data/examples/count.rb +36 -0
  28. data/examples/create.rb +55 -0
  29. data/examples/debounce.rb +35 -0
  30. data/examples/default_if_empty.rb +35 -0
  31. data/examples/defer.rb +20 -0
  32. data/examples/delay.rb +49 -0
  33. data/examples/delay_with_selector.rb +63 -0
  34. data/examples/dematerialize.rb +22 -0
  35. data/examples/disposable.rb +12 -0
  36. data/examples/distinct.rb +43 -0
  37. data/examples/distinct_until_changed.rb +43 -0
  38. data/examples/do.rb +59 -0
  39. data/examples/empty.rb +16 -0
  40. data/examples/for.rb +26 -0
  41. data/examples/fork_join.rb +23 -0
  42. data/examples/from.rb +106 -0
  43. data/examples/from_array.rb +21 -0
  44. data/examples/from_callback.rb +21 -0
  45. data/examples/generate.rb +24 -0
  46. data/examples/group_join.rb +39 -0
  47. data/examples/if.rb +46 -0
  48. data/examples/intervals.rb +26 -0
  49. data/examples/merge.rb +36 -0
  50. data/examples/merge_all.rb +27 -0
  51. data/examples/multicast.rb +32 -0
  52. data/examples/never.rb +15 -0
  53. data/examples/of.rb +19 -0
  54. data/examples/on_error_resume_next.rb +21 -0
  55. data/examples/pairs.rb +26 -0
  56. data/examples/publish.rb +79 -0
  57. data/examples/range.rb +19 -0
  58. data/examples/reduce.rb +18 -0
  59. data/examples/repeat.rb +19 -0
  60. data/examples/return.rb +17 -0
  61. data/examples/scan.rb +41 -0
  62. data/examples/start.rb +29 -0
  63. data/examples/throw.rb +17 -0
  64. data/examples/time_intervals.rb +28 -0
  65. data/examples/timer.rb +26 -0
  66. data/examples/timestamp.rb +28 -0
  67. data/examples/to_a.rb +23 -0
  68. data/examples/to_async.rb +26 -0
  69. data/examples/using.rb +52 -0
  70. data/examples/when.rb +26 -0
  71. data/examples/while.rb +25 -0
  72. data/examples/window_with_time.rb +78 -0
  73. data/examples/zip.rb +27 -0
  74. data/examples/zip_array.rb +25 -0
  75. data/lib/core_ext/enumerable.rb +22 -0
  76. data/lib/rx_ruby.rb +27 -0
  77. data/lib/rx_ruby/concurrency/async_lock.rb +57 -0
  78. data/lib/rx_ruby/concurrency/current_thread_scheduler.rb +75 -0
  79. data/lib/rx_ruby/concurrency/default_scheduler.rb +51 -0
  80. data/lib/rx_ruby/concurrency/historical_scheduler.rb +16 -0
  81. data/lib/rx_ruby/concurrency/immediate_scheduler.rb +68 -0
  82. data/lib/rx_ruby/concurrency/local_scheduler.rb +39 -0
  83. data/lib/rx_ruby/concurrency/periodic_scheduler.rb +74 -0
  84. data/lib/rx_ruby/concurrency/scheduled_item.rb +42 -0
  85. data/lib/rx_ruby/concurrency/scheduler.rb +150 -0
  86. data/lib/rx_ruby/concurrency/virtual_time_scheduler.rb +170 -0
  87. data/lib/rx_ruby/core/async_lock_observer.rb +46 -0
  88. data/lib/rx_ruby/core/auto_detach_observer.rb +59 -0
  89. data/lib/rx_ruby/core/checked_observer.rb +66 -0
  90. data/lib/rx_ruby/core/notification.rb +161 -0
  91. data/lib/rx_ruby/core/observable.rb +104 -0
  92. data/lib/rx_ruby/core/observe_on_observer.rb +50 -0
  93. data/lib/rx_ruby/core/observer.rb +119 -0
  94. data/lib/rx_ruby/core/scheduled_observer.rb +83 -0
  95. data/lib/rx_ruby/core/synchronized_observer.rb +47 -0
  96. data/lib/rx_ruby/core/time_interval.rb +17 -0
  97. data/lib/rx_ruby/internal/priority_queue.rb +122 -0
  98. data/lib/rx_ruby/internal/util.rb +9 -0
  99. data/lib/rx_ruby/joins/active_plan.rb +45 -0
  100. data/lib/rx_ruby/joins/join_observer.rb +51 -0
  101. data/lib/rx_ruby/joins/pattern.rb +14 -0
  102. data/lib/rx_ruby/joins/plan.rb +44 -0
  103. data/lib/rx_ruby/linq/connectable_observable.rb +34 -0
  104. data/lib/rx_ruby/linq/observable/_observable_timer_date_and_period.rb +22 -0
  105. data/lib/rx_ruby/linq/observable/_observable_timer_time_span.rb +14 -0
  106. data/lib/rx_ruby/linq/observable/_observable_timer_time_span_and_period.rb +20 -0
  107. data/lib/rx_ruby/linq/observable/aggregate.rb +7 -0
  108. data/lib/rx_ruby/linq/observable/and.rb +7 -0
  109. data/lib/rx_ruby/linq/observable/case.rb +15 -0
  110. data/lib/rx_ruby/linq/observable/concat_all.rb +7 -0
  111. data/lib/rx_ruby/linq/observable/concat_map.rb +35 -0
  112. data/lib/rx_ruby/linq/observable/concat_map_observer.rb +43 -0
  113. data/lib/rx_ruby/linq/observable/contains.rb +28 -0
  114. data/lib/rx_ruby/linq/observable/debounce.rb +41 -0
  115. data/lib/rx_ruby/linq/observable/delay.rb +81 -0
  116. data/lib/rx_ruby/linq/observable/delay_with_selector.rb +64 -0
  117. data/lib/rx_ruby/linq/observable/do.rb +42 -0
  118. data/lib/rx_ruby/linq/observable/for.rb +13 -0
  119. data/lib/rx_ruby/linq/observable/fork_join.rb +55 -0
  120. data/lib/rx_ruby/linq/observable/from.rb +34 -0
  121. data/lib/rx_ruby/linq/observable/group_join.rb +108 -0
  122. data/lib/rx_ruby/linq/observable/if.rb +17 -0
  123. data/lib/rx_ruby/linq/observable/interval.rb +5 -0
  124. data/lib/rx_ruby/linq/observable/multicast.rb +14 -0
  125. data/lib/rx_ruby/linq/observable/of.rb +11 -0
  126. data/lib/rx_ruby/linq/observable/pairs.rb +7 -0
  127. data/lib/rx_ruby/linq/observable/pluck.rb +7 -0
  128. data/lib/rx_ruby/linq/observable/publish.rb +11 -0
  129. data/lib/rx_ruby/linq/observable/start.rb +7 -0
  130. data/lib/rx_ruby/linq/observable/time_interval.rb +15 -0
  131. data/lib/rx_ruby/linq/observable/timer.rb +26 -0
  132. data/lib/rx_ruby/linq/observable/timestamp.rb +9 -0
  133. data/lib/rx_ruby/linq/observable/to_async.rb +40 -0
  134. data/lib/rx_ruby/linq/observable/when.rb +36 -0
  135. data/lib/rx_ruby/linq/observable/while.rb +41 -0
  136. data/lib/rx_ruby/operators/aggregates.rb +611 -0
  137. data/lib/rx_ruby/operators/creation.rb +220 -0
  138. data/lib/rx_ruby/operators/multiple.rb +735 -0
  139. data/lib/rx_ruby/operators/single.rb +399 -0
  140. data/lib/rx_ruby/operators/standard_query_operators.rb +279 -0
  141. data/lib/rx_ruby/operators/synchronization.rb +47 -0
  142. data/lib/rx_ruby/operators/time.rb +120 -0
  143. data/lib/rx_ruby/subjects/async_subject.rb +161 -0
  144. data/lib/rx_ruby/subjects/behavior_subject.rb +149 -0
  145. data/lib/rx_ruby/subjects/replay_subject.rb +39 -0
  146. data/lib/rx_ruby/subjects/subject.rb +131 -0
  147. data/lib/rx_ruby/subjects/subject_extensions.rb +45 -0
  148. data/lib/rx_ruby/subscriptions/composite_subscription.rb +91 -0
  149. data/lib/rx_ruby/subscriptions/ref_count_subscription.rb +88 -0
  150. data/lib/rx_ruby/subscriptions/scheduled_subscription.rb +32 -0
  151. data/lib/rx_ruby/subscriptions/serial_subscription.rb +60 -0
  152. data/lib/rx_ruby/subscriptions/single_assignment_subscription.rb +64 -0
  153. data/lib/rx_ruby/subscriptions/subscription.rb +56 -0
  154. data/lib/rx_ruby/testing/cold_observable.rb +45 -0
  155. data/lib/rx_ruby/testing/hot_observable.rb +47 -0
  156. data/lib/rx_ruby/testing/mock_observer.rb +33 -0
  157. data/lib/rx_ruby/testing/reactive_test.rb +94 -0
  158. data/lib/rx_ruby/testing/recorded.rb +17 -0
  159. data/lib/rx_ruby/testing/test_scheduler.rb +96 -0
  160. data/lib/rx_ruby/testing/test_subscription.rb +22 -0
  161. data/lib/rx_ruby/version.rb +3 -0
  162. data/license.txt +13 -0
  163. data/readme.md +152 -0
  164. data/rx_ruby.gemspec +22 -0
  165. data/test/rx_ruby/concurrency/helpers/historical_virtual_scheduler_helper.rb +135 -0
  166. data/test/rx_ruby/concurrency/helpers/immediate_local_scheduler_helper.rb +51 -0
  167. data/test/rx_ruby/concurrency/test_async_lock.rb +56 -0
  168. data/test/rx_ruby/concurrency/test_current_thread_scheduler.rb +44 -0
  169. data/test/rx_ruby/concurrency/test_default_scheduler.rb +44 -0
  170. data/test/rx_ruby/concurrency/test_historical_scheduler.rb +18 -0
  171. data/test/rx_ruby/concurrency/test_immediate_scheduler.rb +53 -0
  172. data/test/rx_ruby/concurrency/test_local_scheduler.rb +12 -0
  173. data/test/rx_ruby/concurrency/test_periodic_scheduler.rb +53 -0
  174. data/test/rx_ruby/concurrency/test_scheduled_item.rb +50 -0
  175. data/test/rx_ruby/concurrency/test_scheduler.rb +128 -0
  176. data/test/rx_ruby/concurrency/test_virtual_time_scheduler.rb +14 -0
  177. data/test/rx_ruby/core/test_notification.rb +129 -0
  178. data/test/rx_ruby/core/test_observable_creation.rb +483 -0
  179. data/test/rx_ruby/core/test_observer.rb +634 -0
  180. data/test/rx_ruby/internal/test_priority_queue.rb +71 -0
  181. data/test/rx_ruby/subscriptions/test_composite_subscription.rb +116 -0
  182. data/test/rx_ruby/subscriptions/test_serial_subscription.rb +62 -0
  183. data/test/rx_ruby/subscriptions/test_singleassignment_subscription.rb +61 -0
  184. data/test/rx_ruby/subscriptions/test_subscription.rb +27 -0
  185. data/test/test_helper.rb +11 -0
  186. metadata +291 -0
@@ -0,0 +1,22 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ module RxRuby
4
+
5
+ # Records information about subscriptions to and unsubscriptions from observable sequences.
6
+ class TestSubscription < Struct.new(:subscribe, :unsubscribe)
7
+
8
+ FIXNUM_MAX = Float::MAX.to_i
9
+
10
+ def initialize(subscribe, unsubscribe = FIXNUM_MAX)
11
+ super
12
+ end
13
+
14
+ def infinite?
15
+ unsubscribe == FIXNUM_MAX
16
+ end
17
+
18
+ def to_s
19
+ "#{subscribe}, #{infinite? ? 'Infinite' : unsubscribe}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module RxRuby
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,13 @@
1
+ Copyright (c) Microsoft Open Technologies. All rights reserved.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License"); you
4
+ may not use this file except in compliance with the License. You may
5
+ obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ implied. See the License for the specific language governing permissions
13
+ and limitations under the License.
@@ -0,0 +1,152 @@
1
+ [![Build Status](https://travis-ci.org/ReactiveX/RxRuby.svg?branch=master)](https://travis-ci.org/ReactiveX/RxRuby)
2
+ [![GitHub version](http://img.shields.io/github/tag/ReactiveX/RxRuby.svg)](https://github.com/ReactiveX/RxRuby)
3
+ [![Downloads](http://img.shields.io/gem/dt/rx.svg)](https://npmjs.org/package/rx)
4
+ [![Code Climate](https://codeclimate.com/github/ReactiveX/RxRuby/badges/gpa.svg)](https://codeclimate.com/github/ReactiveX/RxRuby)
5
+
6
+ **[The Need to go Reactive](#the-need-to-go-reactive)** |
7
+ **[About the Reactive Extensions](#about-the-reactive-extensions)** |
8
+ **[Why RxRuby?](#why-rxruby)** |
9
+ **[Contributing](#contributing)** |
10
+ **[License](#license)**
11
+
12
+ # The Reactive Extensions for Ruby (RxRuby) <sup>0.1</sup>... #
13
+ *...is a set of libraries to compose asynchronous and event-based programs using observable collections and Enumerable module style composition in Ruby*
14
+
15
+ ## The Need to go Reactive ##
16
+
17
+ Reactive Programming is a hot topic as of late, especially with such things as the [Reactive Manifesto](http://www.reactivemanifesto.org/). Applications needs have changed over time with simple polling for data, to a full reactive system where data is pushed at you. Each time, we're adding more complexity, more data, and asynchronous behavior to our applications. How do we manage it all? How do we scale it? By moving towards "Reactive Architectures" which are event-driven, resilient and responsive. With the Reactive Extensions, you have all the tools you need to help build these systems.
18
+
19
+ ## About the Reactive Extensions ##
20
+
21
+ The Reactive Extensions for Ruby (RxRuby) is a set of libraries for composing asynchronous and event-based programs using observable sequences and fluent query operators that many of you already know by with the in Ruby. Using RxRuby, developers represent asynchronous data streams with Observables, query asynchronous data streams using our many operators, and parameterize the concurrency in the asynchronous data streams using Schedulers. Simply put, RxRuby = Observables + Operators + Schedulers.
22
+
23
+ When you're authoring applications with Ruby, there may be times when you want to deal with asynchronous programming and event-based programming, and synchronization is difficult and error prone.
24
+
25
+ Using RxRuby, you can represent multiple asynchronous data streams (that come from diverse sources, e.g., stock quote, tweets, computer events, web service requests, etc.), and subscribe to the event stream using the Observer module. The Observable notifies the subscribed Observer instance whenever an event occurs.
26
+
27
+ Because observable sequences are data streams, you can query them using standard query operators implemented by the Observable module. Thus you can filter, project, reduce, compose and perform time-based operations on multiple events easily by using these our many operators. In addition, there are a number of other reactive stream specific operators that allow powerful queries to be written. Cancellation, exceptions, and synchronization are also handled gracefully by using the methods on the Observable module.
28
+
29
+ But the best news of all is that you already know how to program like this. Take for example the following Ruby code, where we get some stock data and then manipulate and then iterate the results.
30
+
31
+ ```ruby
32
+ # Get evens and square each
33
+ someSource
34
+ .select {|x| x.even? }
35
+ .map {|x| x * x }
36
+ .each {|x| puts x.to_s }
37
+ ```
38
+
39
+ Using RxRuby, you can accomplish the same kind of thing with a push based collection with little to no change to your code at all, changing `each` to `subscribe`.
40
+
41
+ ```ruby
42
+ someSource
43
+ .select {|x| x.even? }
44
+ .map {|x| x * x }
45
+ .subscribe {|x| puts x.to_s }
46
+ ```
47
+
48
+ ## Why RxRuby? ##
49
+
50
+ The overall goal of [RxRuby](https://github.com/ReactiveX/RxRuby) is to have a push based version of the [Enumerable module](http://www.ruby-doc.org/core-2.1.0/Enumerable.html) with an added notion of time. Right now, the [Observable module](http://ruby-doc.org/stdlib-1.9.3/libdoc/observer/rdoc/Observable.html) is not quite what we want because it does not allow for composition. That is no more than a simple implementation of the Subject/Observer pattern from the Gang of Four book, such as the following.
51
+
52
+ ```ruby
53
+ require 'observer'
54
+
55
+ class ArrayObservable
56
+ include Observable
57
+
58
+ def initialize(array)
59
+ @array = array
60
+ end
61
+
62
+ def run
63
+ index = 0
64
+
65
+ while index < @array.length
66
+ change #notify of change
67
+ notify_observers @array[index] # send the current value
68
+ index += 1
69
+ sleep 1
70
+ end
71
+ end
72
+ end
73
+
74
+ class ArrayObserver
75
+ def initialize(observable)
76
+ observable.add_observer(self)
77
+ end
78
+
79
+ def update(item)
80
+ puts item.to_s
81
+ end
82
+ end
83
+
84
+ observable = ArrayObservable [1,2]
85
+ observer = ArrayObserver.new(observable)
86
+ # 1
87
+ # 2
88
+ ```
89
+
90
+ But, how do you enable better composition so that you can compose together Observable instances? In this current model, this can't happen. That's why we need the Reactive Extensions for Ruby. Not only that, but we can at any point in the computation, change the concurrency model to be immediate, on a new thread, or on another machine.
91
+
92
+ There are many implementations of the Reactive Extensions such as [RxJS](https://github.com/Reactive-Extensions/RxJS), [Rx.NET](https://github.com/reactive-extensions/rx.net), [Java/JVM/Clojure/Scala/JRuby/Groovy](https://github.com/Netflix/RxJava) and [ObjC/ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa). Our goal is to have one operate like the JRuby one, but be available to all users of Ruby regardless of VM.
93
+
94
+ We'd like it to be much like our JavaScript version, [RxJS](https://github.com/Reactive-Extensions/RxJS) but be able to handle multi-threading, parallelism, and in addition, go across the network.
95
+
96
+ Instead, our goal is to make the Observable module look exactly like the Enumerable module in that you can write any query method over it to produce a value, but have it push based. This could become yet another competitor to [EventMachine](http://rubyeventmachine.com/) in which we have rich composition over events, whether locally or across the network.
97
+
98
+ So, take an example, zipping two Arrays.
99
+
100
+ ```ruby
101
+ a = [ 4, 5, 6 ]
102
+ b = [ 7, 8, 9 ]
103
+
104
+ [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
105
+ [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
106
+ a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
107
+ ```
108
+
109
+ Now, we could do something similar in [RxRuby](https://github.com/ReactiveX/RxRuby) with two observable sequences:
110
+
111
+ ```ruby
112
+ require 'rx_ruby'
113
+
114
+ a = RxRuby::Observable.from_array [ 4, 5, 6 ]
115
+ b = RxRuby::Observable.from_array [ 7, 8, 9 ]
116
+
117
+ sub = a.zip(b).subscribe {|arr| puts arr.to_s }
118
+ # => "[4, 7]"
119
+ # => "[5, 8]"
120
+ # => "[6, 9]"
121
+
122
+ # unsubscribes from the sequence and cleans up anything
123
+ sub.unsubscribe
124
+ ```
125
+
126
+ The difference here is that `zip` returns an `RxRuby::Observable` instead of an `Enumerable`. And once you call `subscribe` it's much like `each` but takes an observer, or perhaps just some blocks, lambdas, etc. The subscription handed back contains the cancellation logic. For example, if you are listening to events and you no longer want to listen, then you can call `unsubscribe` on the `sub` variable above.
127
+
128
+ What's the end goal? The first part is where we want to support the main `Enumerable` module methods in the `Observable` module and have them react the same way, but push instead of pull based. Then from there, we can explore such things as multi-threading, and calls across the network.
129
+
130
+ If you want to find out more, please check out the JavaScript version, [RxJS](https://github.com/Reactive-Extensions/RxJS), which has more details on the overall goals.
131
+
132
+ Our overall goal is to make this one of the best Rx libraries out there, better than RxJS, RxPy, ReactiveCocoa, RxJava, etc, all while maintaining the "Ruby Way".
133
+
134
+ ## Contributing ##
135
+
136
+ You can contribute by reviewing and sending feedback on code checkins, suggesting and trying out new features as they are implemented, submit bugs and help us verify fixes as they are checked in, as well as submit code fixes or code contributions of your own. Note that all code submissions will be rigorously reviewed and tested by the Rx Team, and only those that meet an extremely high bar for both quality and design/roadmap appropriateness will be merged into the source.
137
+
138
+ ## License ##
139
+
140
+ Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
141
+
142
+ Licensed under the Apache License, Version 2.0 (the "License"); you
143
+ may not use this file except in compliance with the License. You may
144
+ obtain a copy of the License at
145
+
146
+ http://www.apache.org/licenses/LICENSE-2.0
147
+
148
+ Unless required by applicable law or agreed to in writing, software
149
+ distributed under the License is distributed on an "AS IS" BASIS,
150
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
151
+ implied. See the License for the specific language governing permissions
152
+ and limitations under the License.
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rx_ruby/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["Microsoft Open Technologies, Inc."]
8
+ gem.description = %q{Reactive Extensions for Ruby}
9
+ gem.summary = %q{This is an implementation of the Reactive Extensions for Ruby. Note that this is an early prototype, but contributions are welcome.}
10
+ gem.homepage = "https://github.com/ReactiveX/RxRuby"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "rx"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = RxRuby::VERSION
17
+ gem.license = 'Apache License, v2.0'
18
+
19
+ gem.add_development_dependency 'rake'
20
+ gem.add_development_dependency 'minitest'
21
+ gem.add_development_dependency 'simplecov'
22
+ end
@@ -0,0 +1,135 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ module HistoricalVirtualSchedulerTestHelper
4
+
5
+ # Scheduler state
6
+
7
+ def test_disabled_by_default
8
+ assert_equal(false, @scheduler.enabled?)
9
+ end
10
+
11
+ def test_disabled_once_out_of_tasks
12
+ @scheduler.start
13
+ assert_equal(false, @scheduler.enabled?)
14
+ end
15
+
16
+ def test_enabled_while_running
17
+ @scheduler.schedule ->() { assert_equal(true, @scheduler.enabled?) }
18
+ @scheduler.start
19
+ end
20
+
21
+ def test_stop
22
+ @scheduler.schedule ->() { @scheduler.stop }
23
+ @scheduler.schedule ->() { flunk "Should be stopped" }
24
+ @scheduler.start
25
+
26
+ assert_equal(false, @scheduler.enabled?)
27
+ end
28
+
29
+ def test_now
30
+ assert_equal(@start, @scheduler.now)
31
+ end
32
+
33
+ def test_clock
34
+ assert_equal @start, @scheduler.clock
35
+ end
36
+
37
+ # Relative Scheduling
38
+
39
+ def test_relative_with_state
40
+ state = []
41
+ task = ->(_, s) { s.push 1 }
42
+ @scheduler.schedule_at_relative_with_state(state, 2, task)
43
+ @scheduler.start
44
+
45
+ assert_equal([1], state)
46
+ assert_equal(@start + 2, @scheduler.now)
47
+ end
48
+
49
+ def test_relative
50
+ ran = false
51
+ task = ->() { ran = true }
52
+ @scheduler.schedule_at_relative(2, task)
53
+ @scheduler.start
54
+
55
+ assert_equal(true, ran)
56
+ assert_equal(@start + 2, @scheduler.now)
57
+ end
58
+
59
+ # Absolute Scheduling
60
+
61
+ def test_absolute_with_state
62
+ state = []
63
+ time = @start + 2
64
+ task = ->(_, s) { s.push 1 }
65
+ @scheduler.schedule_at_absolute_with_state(state, time, task)
66
+ @scheduler.start
67
+
68
+ assert_equal([1], state)
69
+ assert_equal(time, @scheduler.now)
70
+ end
71
+
72
+ def test_absolute
73
+ ran = false
74
+ time = @start + 2
75
+ task = ->() { ran = true }
76
+ @scheduler.schedule_at_absolute(time, task)
77
+ @scheduler.start
78
+
79
+ assert_equal(true, ran)
80
+ assert_equal(time, @scheduler.now)
81
+ end
82
+
83
+ # Time manipulation
84
+
85
+ def test_advance
86
+ ran = false
87
+ task = ->() { ran = true }
88
+ failure = ->() { flunk "Should never reach." }
89
+
90
+ @scheduler.schedule_at_absolute(@start + 10, task)
91
+ @scheduler.schedule_at_absolute(@start + 11, failure)
92
+ @scheduler.advance_to(@start + 10)
93
+
94
+ assert_equal(true, ran)
95
+ assert_equal(@start + 10, @scheduler.now)
96
+ end
97
+
98
+ def test_advance_raises_if_running
99
+ task = ->() do
100
+ assert_raises(RuntimeError) { @scheduler.advance_to(@start + 10) }
101
+ end
102
+
103
+ @scheduler.schedule task
104
+ @scheduler.start
105
+ end
106
+
107
+ def test_advance_by
108
+ ran = false
109
+ task = ->() { ran = true }
110
+ failure = ->() { flunk "Should never reach." }
111
+
112
+ @scheduler.schedule_at_relative(10, task)
113
+ @scheduler.schedule_at_relative(11, failure)
114
+ @scheduler.advance_by(10)
115
+
116
+ assert_equal(true, ran)
117
+ assert_equal(@start + 10, @scheduler.now)
118
+ end
119
+
120
+ def test_advance_raises_if_out_of_range
121
+ assert_raises(RuntimeError) { @scheduler.advance_by(-10) }
122
+ end
123
+
124
+ def test_sleep
125
+ failure = ->() { flunk "Should not run." }
126
+ @scheduler.schedule_at_relative(10, failure)
127
+ @scheduler.sleep(20)
128
+
129
+ assert_equal(@start + 20, @scheduler.now)
130
+ end
131
+
132
+ def test_sleep_raises_if_out_of_range
133
+ assert_raises(RuntimeError) { @scheduler.sleep(-10) }
134
+ end
135
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ require 'test_helper'
4
+
5
+ module ImmediateLocalSchedulerTestHelper
6
+ def test_now
7
+ assert_equal(Time.now.to_i, @scheduler.now.to_i)
8
+ end
9
+
10
+ def test_schedule_with_state
11
+ state = []
12
+ task = ->(_, s) { s << 1 }
13
+ @scheduler.schedule_with_state(state, task)
14
+
15
+ assert_equal([1], state)
16
+ end
17
+
18
+ def test_schedule_with_state_simple_absolute
19
+ state = []
20
+ task = ->(_, s) { s << 1 }
21
+ @scheduler.schedule_absolute_with_state(state, Time.now, task)
22
+
23
+ assert_equal([1], state)
24
+ end
25
+
26
+ def test_schedule_recursive_absolute_with_state_simple
27
+ state = []
28
+ inner = ->(_, s) { s << 1 }
29
+ outer = ->(s, x) { s.schedule_absolute_with_state(x, Time.now, inner) }
30
+ @scheduler.schedule_absolute_with_state(state, Time.now, outer)
31
+
32
+ assert_equal([1], state)
33
+ end
34
+
35
+ def test_schedule_with_state_simple_relative
36
+ state = []
37
+ task = ->(_, s) { s << 1 }
38
+ @scheduler.schedule_relative_with_state(state, 0, task)
39
+
40
+ assert_equal([1], state)
41
+ end
42
+
43
+ def test_schedule_recursive_relative_with_state_simple
44
+ state = []
45
+ inner = ->(_, s) { s << 1 }
46
+ outer = ->(sched, s) { sched.schedule_relative_with_state(s, 1, inner) }
47
+ @scheduler.schedule_relative_with_state(state, 1, outer)
48
+
49
+ assert_equal([1], state)
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ require 'test_helper'
4
+
5
+ class TestAsyncLock < Minitest::Test
6
+ def setup
7
+ @lock = RxRuby::AsyncLock.new
8
+ end
9
+
10
+ def test_simple_wait
11
+ called = false
12
+ @lock.wait { called = true }
13
+ assert_equal(true, called)
14
+ end
15
+
16
+ def test_parallel_wait
17
+ state = [false, false]
18
+ sync = [Queue.new, Queue.new]
19
+
20
+ thread1 = Thread.new do
21
+ sync[0].pop
22
+ @lock.wait do
23
+ sync[1].push 1
24
+ sync[0].pop
25
+ state[0] = true
26
+ end
27
+ state.each { |s| assert_equal(true, s) }
28
+ end
29
+
30
+ thread2 = Thread.new do
31
+ sync[1].pop
32
+ @lock.wait do
33
+ assert_equal(thread1, Thread.current)
34
+ state[1] = true
35
+ end
36
+ state.each { |s| assert_equal(false, s) }
37
+ sync[0].push 1
38
+ end
39
+
40
+ sync[0].push 1
41
+ [thread1, thread2].each(&:join)
42
+ end
43
+
44
+ def test_clear
45
+ @lock.clear
46
+ called = false
47
+ @lock.wait { called = true }
48
+ assert_equal(false, called)
49
+ end
50
+
51
+ def test_exceptions_bubble_up_and_fault
52
+ assert_raises(StandardError) { @lock.wait { raise StandardError } }
53
+ assert_equal(true, @lock.send(:instance_variable_get, :@has_faulted))
54
+ assert_equal([], @lock.send(:instance_variable_get, :@queue))
55
+ end
56
+ end