rspec-sequencing 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +39 -65
- data/lib/rspec/sequencing.rb +28 -19
- data/lib/rspec_sequencing.rb +2 -0
- data/rspec-sequencing.gemspec +2 -1
- metadata +16 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9ff6bcb858f98c3a60578bb99c9b7c5944ed85fe174d97f4d2b1d808b3cf3568
|
4
|
+
data.tar.gz: 19db7c75c1c8ae858070a430a2c9c3983abc4dd4ba02b4ea0aa82e616343fa0c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2446014dd4416e4e774adcddf6d1fdbffe6cd546a90f2a6f5a45fd7039bb97c2a6eefd68e2518522e29bf3744cdf3fd94a9681c3c8fd1e9b8bd9ff3ef7e3ffaf
|
7
|
+
data.tar.gz: 0aa4c7910af0457c715fc5b7b9e2a161c0ae8a1c708821fee8d1241326b9365a191f76c0fa5c242e17df9ea6a9c19fc37719ad443ff9451f9a0370ab3c05497e
|
data/README.md
CHANGED
@@ -101,71 +101,36 @@ You might be tempted to think, I can just do:
|
|
101
101
|
```
|
102
102
|
and you would be correct, for this contrived example.
|
103
103
|
|
104
|
-
Here is a real example from the
|
104
|
+
Here is a real example from the Logstash file input plugin tests. Here we use Sequencing to let files age and other elapsed time mechanisms.
|
105
105
|
```ruby
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
let(:subscribe_proc) do
|
125
|
-
lambda do
|
126
|
-
formatted_puts("subscribing")
|
127
|
-
# subject subscribe does not return until subject.quit is called
|
128
|
-
subject.subscribe(stat_interval, discover_interval) do |event, watched_file|
|
129
|
-
results.push([event, watched_file.path])
|
106
|
+
context "when ignore_older is less than close_older and all files are not expired" do
|
107
|
+
let(:opts) { super.merge(:ignore_older => 1, :close_older => 1.1) }
|
108
|
+
let(:suffix) { "N" }
|
109
|
+
let(:actions) do
|
110
|
+
RSpec::Sequencing
|
111
|
+
.run_after(0.1, "file created") do
|
112
|
+
File.open(file_path, "wb") { |file| file.write("line1\nline2\n") }
|
113
|
+
end
|
114
|
+
.then("start watching before file age reaches ignore_older") do
|
115
|
+
tailing.watch_this(watch_dir)
|
116
|
+
end
|
117
|
+
.then("wait for lines") do
|
118
|
+
wait(1.2).for{listener1.calls}.to eq([:open, :accept, :accept, :timed_out])
|
119
|
+
end
|
120
|
+
.then("quit after allowing time to close the file") do
|
121
|
+
tailing.quit
|
122
|
+
end
|
130
123
|
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
subject { FileWatch::Watch.new(:logger => loggr) }
|
135
|
-
|
136
|
-
before do
|
137
|
-
allow(loggr).to receive(:debug)
|
138
|
-
end
|
139
|
-
after do
|
140
|
-
FileUtils.rm_rf(directory)
|
141
|
-
end
|
142
124
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
.
|
150
|
-
|
151
|
-
end
|
152
|
-
.then_after(3.1, "start watching after the file ages more than two seconds") do
|
153
|
-
subject.watch(watch_dir)
|
154
|
-
end
|
155
|
-
.then("append more lines to file when its 'ignored'") do
|
156
|
-
File.open(file_path, "ab") { |file| file.write("line3\nline4\n") }
|
157
|
-
end
|
158
|
-
.then_after(3.1, "quit after allowing time for the close mechanism (timeout)") do
|
159
|
-
subject.quit #<--- this unblocks the subscribe loop
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
it "yields unignore, modify then timeout file events" do
|
164
|
-
subscribe_proc.call #<--- the rspec thread is in a forever loop until quit is called in another thread
|
165
|
-
expect(results).to eq([[:unignore, file_path], [:modify, file_path], [:timeout, file_path]])
|
125
|
+
it "reads lines normally" do
|
126
|
+
actions.activate
|
127
|
+
# subscribe is a blocking operation until tailing.quit is called on the sequence threads
|
128
|
+
# and that last step is dependent on the wait(1.2).for rspec expectation to succeed.
|
129
|
+
tailing.subscribe(observer)
|
130
|
+
actions.assert_no_errors # if the rspec `wait` call times out then this raises the RSpec failed assertion exception.
|
131
|
+
expect(listener1.lines).to eq(["line1", "line2"])
|
132
|
+
end
|
166
133
|
end
|
167
|
-
end
|
168
|
-
end
|
169
134
|
```
|
170
135
|
|
171
136
|
### API
|
@@ -180,13 +145,22 @@ and some instance methods:
|
|
180
145
|
```ruby
|
181
146
|
then(description = '', &block) # when the previous action completed the block runs without delay
|
182
147
|
then_after(delay, description = '', &block) # when the previous action completed the block runs after delay seconds
|
148
|
+
|
149
|
+
# use `activate` or `activate_quietly`, when defining a sequence in a `let` block,
|
150
|
+
# to get RSpec to instantiate the sequence.
|
151
|
+
activate # this will print 'sequence activated' to the RSpec output_stream
|
152
|
+
activate_quietly # this will print nothing to the RSpec output_stream
|
153
|
+
value # this will block until the value from the last step is available
|
183
154
|
```
|
184
|
-
Note
|
155
|
+
#### Note:
|
156
|
+
The description is optional, however by adding a description you document
|
157
|
+
the action in the code and the spec output. The description is printed after the delay and before the block is executed - use present tense, e.g. "Creating file"
|
185
158
|
|
186
|
-
This library is multithreaded and uses the `concurrent-ruby` Dataflow
|
187
|
-
|
159
|
+
This library is multithreaded and uses the `concurrent-ruby` Dataflow feature.
|
160
|
+
Dataflow will absorb any exceptions and cause the dataflow to be rejected with the `reason` set to the Exception.
|
161
|
+
In this case, use the `assert_no_errors` method - this will re-raise the first exception it finds.
|
188
162
|
|
189
|
-
|
163
|
+
#### Note:
|
190
164
|
- The sequence executes in different threads from the main RSpec thread. You will need to wait for the sequence value (see this library's specs) otherwise the test will end before the sequence ends and any expectations based on side effects of the sequence will not be met. However, if you are testing scenarios where the main RSpec thread is blocked in some way, e.g. a subscribe loop, then one, usually the last, task should act to unblock the RSpec main thread. In this case you should not wait on the sequence value.
|
191
165
|
- The system that you are testing needs to be thread safe.
|
192
166
|
|
data/lib/rspec/sequencing.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'concurrent'
|
2
4
|
|
3
5
|
module RSpec
|
@@ -10,42 +12,49 @@ module RSpec
|
|
10
12
|
new.then_after(delay, description, &block)
|
11
13
|
end
|
12
14
|
|
15
|
+
attr_reader :flows
|
16
|
+
|
13
17
|
def initialize
|
14
|
-
@
|
18
|
+
@flows = []
|
15
19
|
end
|
16
20
|
|
17
21
|
def then_after(delay, description = '', &block)
|
18
|
-
@
|
22
|
+
@flows << Concurrent.dataflow(*@flows) do
|
23
|
+
sleep delay
|
24
|
+
formatted_puts(description) unless description.empty?
|
25
|
+
block.call
|
26
|
+
end
|
19
27
|
self
|
20
28
|
end
|
21
29
|
|
22
|
-
def then(description, &block)
|
30
|
+
def then(description = '', &block)
|
23
31
|
then_after(0, description, &block)
|
24
32
|
end
|
25
33
|
|
26
|
-
def
|
27
|
-
|
28
|
-
task(delay, &block).execute.value.tap do
|
29
|
-
formatted_puts(description)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def task(delay, &block)
|
35
|
-
Concurrent::ScheduledTask.new(delay) do
|
36
|
-
block.call
|
37
|
-
true
|
38
|
-
end
|
34
|
+
def activate_quietly
|
35
|
+
# use this method if you define the sequencing in a let block so RSpec instantiates it
|
39
36
|
end
|
40
37
|
|
41
38
|
def activate
|
42
|
-
# use this method if you define the sequencing in a let block
|
43
|
-
# so RSpec runs it
|
39
|
+
# use this method if you define the sequencing in a let block so RSpec instantiates it
|
44
40
|
formatted_puts "sequence activated"
|
45
41
|
end
|
46
42
|
|
43
|
+
def assert_no_errors
|
44
|
+
# if you think you might get exceptions raised in any step the use this to get rspec to see them
|
45
|
+
# the raised error gets set as the dataflow `reason`.
|
46
|
+
value
|
47
|
+
@flows.map do |flow|
|
48
|
+
if flow.rejected?
|
49
|
+
raise flow.reason
|
50
|
+
end
|
51
|
+
flow.value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
47
55
|
def value
|
48
|
-
|
56
|
+
# this is a blocking operation
|
57
|
+
@flows.last.value
|
49
58
|
end
|
50
59
|
|
51
60
|
private
|
data/lib/rspec_sequencing.rb
CHANGED
data/rspec-sequencing.gemspec
CHANGED
@@ -4,7 +4,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "rspec-sequencing"
|
7
|
-
spec.version = "0.1.
|
7
|
+
spec.version = "0.1.1"
|
8
|
+
spec.licenses = ['Apache-2.0']
|
8
9
|
spec.authors = ["Elastic"]
|
9
10
|
spec.email = ["info@elastic.co"]
|
10
11
|
|
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-sequencing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- -
|
16
|
+
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: 3.0.0
|
19
19
|
name: rspec
|
@@ -21,13 +21,13 @@ dependencies:
|
|
21
21
|
type: :runtime
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- -
|
30
|
+
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '0'
|
33
33
|
name: concurrent-ruby
|
@@ -35,13 +35,13 @@ dependencies:
|
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - ~>
|
44
|
+
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '1.10'
|
47
47
|
name: bundler
|
@@ -49,13 +49,13 @@ dependencies:
|
|
49
49
|
type: :development
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.10'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- - ~>
|
58
|
+
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '10.0'
|
61
61
|
name: rake
|
@@ -63,7 +63,7 @@ dependencies:
|
|
63
63
|
type: :development
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
69
|
description:
|
@@ -73,7 +73,7 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
-
- .gitignore
|
76
|
+
- ".gitignore"
|
77
77
|
- Gemfile
|
78
78
|
- LICENSE
|
79
79
|
- README.md
|
@@ -82,7 +82,8 @@ files:
|
|
82
82
|
- lib/rspec_sequencing.rb
|
83
83
|
- rspec-sequencing.gemspec
|
84
84
|
homepage: https://github.com/elastic/rspec-sequencing
|
85
|
-
licenses:
|
85
|
+
licenses:
|
86
|
+
- Apache-2.0
|
86
87
|
metadata: {}
|
87
88
|
post_install_message:
|
88
89
|
rdoc_options: []
|
@@ -90,17 +91,17 @@ require_paths:
|
|
90
91
|
- lib
|
91
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|
92
93
|
requirements:
|
93
|
-
- -
|
94
|
+
- - ">="
|
94
95
|
- !ruby/object:Gem::Version
|
95
96
|
version: '0'
|
96
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
98
|
requirements:
|
98
|
-
- -
|
99
|
+
- - ">="
|
99
100
|
- !ruby/object:Gem::Version
|
100
101
|
version: '0'
|
101
102
|
requirements: []
|
102
103
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
104
|
+
rubygems_version: 2.6.13
|
104
105
|
signing_key:
|
105
106
|
specification_version: 4
|
106
107
|
summary: Define sequenced actions that simulate real-world scenarios
|