fiber_scheduler_spec 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fiber_scheduler_spec/address_resolve.rb +30 -28
- data/lib/fiber_scheduler_spec/block_unblock.rb +38 -36
- data/lib/fiber_scheduler_spec/close.rb +55 -53
- data/lib/fiber_scheduler_spec/fiber.rb +43 -41
- data/lib/fiber_scheduler_spec/io_wait.rb +59 -57
- data/lib/fiber_scheduler_spec/kernel_sleep.rb +64 -62
- data/lib/fiber_scheduler_spec/nested_fiber_schedule.rb +59 -0
- data/lib/fiber_scheduler_spec/process_wait.rb +44 -42
- data/lib/fiber_scheduler_spec/socket_io.rb +44 -42
- data/lib/fiber_scheduler_spec/timeout_after.rb +58 -56
- data/lib/fiber_scheduler_spec/version.rb +1 -1
- data/lib/fiber_scheduler_spec.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebf711718c86a2f4372dec616ab5e44b3c9c4bb6af812de8fec46b24ee640f11
|
4
|
+
data.tar.gz: 544329b6f114df44a59b6b385dec14a6e3d4ccf5f431027dcee14ada4d7a6357
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b59f23041b1032595604310bd50689b16587d45c6710bb42639c2c2ffadab68dbf3222116732d4a0d995c651560213df2fc99c23d1d0aceec3e138546864f04
|
7
|
+
data.tar.gz: 5e58e1e3b7417d9a95b4b31f84a2cde308238dab9d9e28613e332fd5911501c1c9daaaa3cb1ec82dd25db78ef077d2b1d6d29ba753242566a2b8bae8d451972e
|
@@ -8,40 +8,42 @@ module FiberSchedulerSpec
|
|
8
8
|
end
|
9
9
|
|
10
10
|
RSpec.shared_examples FiberSchedulerSpec::AddressResolve do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
describe "#address_resolve" do
|
12
|
+
include_context FiberSchedulerSpec::Context
|
13
|
+
|
14
|
+
context "Addrinfo.getaddrinfo" do
|
15
|
+
let(:order) { [] }
|
16
|
+
|
17
|
+
def operations
|
18
|
+
Fiber.schedule do
|
19
|
+
order << 1
|
20
|
+
Addrinfo.getaddrinfo("example.com", 80, :AF_INET, :STREAM)
|
21
|
+
order << 5
|
22
|
+
end
|
23
|
+
|
24
|
+
order << 2
|
25
|
+
|
26
|
+
Fiber.schedule do
|
27
|
+
order << 3
|
28
|
+
Addrinfo.getaddrinfo("example.com", 80, :AF_INET, :STREAM)
|
29
|
+
order << 5
|
30
|
+
end
|
31
|
+
order << 4
|
21
32
|
end
|
22
33
|
|
23
|
-
|
34
|
+
it "calls #address_resolve" do
|
35
|
+
expect_any_instance_of(scheduler_class)
|
36
|
+
.to receive(:address_resolve).exactly(2).times
|
37
|
+
.and_call_original
|
24
38
|
|
25
|
-
|
26
|
-
order << 3
|
27
|
-
Addrinfo.getaddrinfo("example.com", 80, :AF_INET, :STREAM)
|
28
|
-
order << 5
|
39
|
+
setup
|
29
40
|
end
|
30
|
-
order << 4
|
31
|
-
end
|
32
41
|
|
33
|
-
|
34
|
-
|
35
|
-
.to receive(:address_resolve).exactly(2).times
|
36
|
-
.and_call_original
|
42
|
+
it "behaves async" do
|
43
|
+
setup
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
it "behaves async" do
|
42
|
-
setup
|
43
|
-
|
44
|
-
expect(order).to eq [1, 2, 3, 4, 5, 5]
|
45
|
+
expect(order).to eq [1, 2, 3, 4, 5, 5]
|
46
|
+
end
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
@@ -6,48 +6,50 @@ module FiberSchedulerSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.shared_examples FiberSchedulerSpec::BlockUnblock do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
describe "#block #unblock" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
11
|
+
|
12
|
+
context "Addrinfo.getaddrinfo" do
|
13
|
+
let(:order) { [] }
|
14
|
+
let(:queue) { Thread::Queue.new }
|
15
|
+
let(:item) { "item" }
|
16
|
+
let(:popped_items) { [] }
|
17
|
+
|
18
|
+
def operations
|
19
|
+
Fiber.schedule do
|
20
|
+
order << 1
|
21
|
+
popped_items << queue.pop
|
22
|
+
order << 6
|
23
|
+
end
|
24
|
+
|
25
|
+
order << 2
|
26
|
+
|
27
|
+
Fiber.schedule do
|
28
|
+
order << 3
|
29
|
+
queue.push(item)
|
30
|
+
order << 4
|
31
|
+
end
|
32
|
+
|
33
|
+
order << 5
|
22
34
|
end
|
23
35
|
|
24
|
-
|
36
|
+
it "calls #block and #unblock" do
|
37
|
+
expect_any_instance_of(scheduler_class)
|
38
|
+
.to receive(:block).once
|
39
|
+
.and_call_original
|
40
|
+
expect_any_instance_of(scheduler_class)
|
41
|
+
.to receive(:unblock).once
|
42
|
+
.and_call_original
|
25
43
|
|
26
|
-
|
27
|
-
order << 3
|
28
|
-
queue.push(item)
|
29
|
-
order << 4
|
44
|
+
setup
|
30
45
|
end
|
31
46
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
it "calls #block and #unblock" do
|
36
|
-
expect_any_instance_of(scheduler_class)
|
37
|
-
.to receive(:block).once
|
38
|
-
.and_call_original
|
39
|
-
expect_any_instance_of(scheduler_class)
|
40
|
-
.to receive(:unblock).once
|
41
|
-
.and_call_original
|
42
|
-
|
43
|
-
setup
|
44
|
-
end
|
45
|
-
|
46
|
-
it "behaves async" do
|
47
|
-
setup
|
47
|
+
it "behaves async" do
|
48
|
+
setup
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
expect(popped_items).to contain_exactly(item)
|
51
|
+
expect(order).to eq (1..6).to_a
|
52
|
+
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
@@ -7,22 +7,62 @@ module FiberSchedulerSpec
|
|
7
7
|
end
|
8
8
|
|
9
9
|
RSpec.shared_examples FiberSchedulerSpec::Close do
|
10
|
-
|
10
|
+
describe "#close" do
|
11
|
+
include_context FiberSchedulerSpec::Context
|
12
|
+
|
13
|
+
# TODO: should closing a scheduler also set Fiber.scheduler to nil?
|
14
|
+
context "without #run" do
|
15
|
+
let(:order) { [] }
|
16
|
+
|
17
|
+
def operations
|
18
|
+
Fiber.schedule do
|
19
|
+
order << 2
|
20
|
+
end
|
21
|
+
order << 1
|
22
|
+
end
|
23
|
+
|
24
|
+
# NOTE: this example does not use 'setup', #run should not be invoked
|
25
|
+
if method_defined?(:default_setup)
|
26
|
+
# skipping if user overrode setup
|
27
|
+
it "calls #close" do
|
28
|
+
expect(scheduler)
|
29
|
+
.to receive(:close).once
|
30
|
+
.and_call_original
|
11
31
|
|
12
|
-
|
13
|
-
|
14
|
-
let(:order) { [] }
|
32
|
+
Thread.new do
|
33
|
+
Fiber.set_scheduler(scheduler)
|
15
34
|
|
16
|
-
|
17
|
-
|
18
|
-
|
35
|
+
operations
|
36
|
+
end.join
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "behaves async" do
|
41
|
+
setup
|
42
|
+
|
43
|
+
expect(order).to contain_exactly(1, 2)
|
19
44
|
end
|
20
|
-
order << 1
|
21
45
|
end
|
22
46
|
|
23
|
-
|
24
|
-
|
25
|
-
|
47
|
+
context "with #run" do
|
48
|
+
let(:order) { [] }
|
49
|
+
|
50
|
+
def operations
|
51
|
+
Fiber.schedule do
|
52
|
+
order << 2
|
53
|
+
end
|
54
|
+
|
55
|
+
order << 1
|
56
|
+
Fiber.scheduler.run
|
57
|
+
order << 3
|
58
|
+
|
59
|
+
Fiber.schedule do
|
60
|
+
order << 4
|
61
|
+
end
|
62
|
+
|
63
|
+
order << 5
|
64
|
+
end
|
65
|
+
|
26
66
|
it "calls #close" do
|
27
67
|
expect(scheduler)
|
28
68
|
.to receive(:close).once
|
@@ -30,54 +70,16 @@ RSpec.shared_examples FiberSchedulerSpec::Close do
|
|
30
70
|
|
31
71
|
Thread.new do
|
32
72
|
Fiber.set_scheduler(scheduler)
|
33
|
-
|
34
73
|
operations
|
74
|
+
scheduler.run
|
35
75
|
end.join
|
36
76
|
end
|
37
|
-
end
|
38
77
|
|
39
|
-
|
40
|
-
|
78
|
+
it "behaves async" do
|
79
|
+
setup
|
41
80
|
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "with #run" do
|
47
|
-
let(:order) { [] }
|
48
|
-
|
49
|
-
def operations
|
50
|
-
Fiber.schedule do
|
51
|
-
order << 2
|
81
|
+
expect(order).to contain_exactly(1, 2, 3, 4, 5)
|
52
82
|
end
|
53
|
-
|
54
|
-
order << 1
|
55
|
-
Fiber.scheduler.run
|
56
|
-
order << 3
|
57
|
-
|
58
|
-
Fiber.schedule do
|
59
|
-
order << 4
|
60
|
-
end
|
61
|
-
|
62
|
-
order << 5
|
63
|
-
end
|
64
|
-
|
65
|
-
it "calls #close" do
|
66
|
-
expect(scheduler)
|
67
|
-
.to receive(:close).once
|
68
|
-
.and_call_original
|
69
|
-
|
70
|
-
Thread.new do
|
71
|
-
Fiber.set_scheduler(scheduler)
|
72
|
-
operations
|
73
|
-
scheduler.run
|
74
|
-
end.join
|
75
|
-
end
|
76
|
-
|
77
|
-
it "behaves async" do
|
78
|
-
setup
|
79
|
-
|
80
|
-
expect(order).to contain_exactly(1, 2, 3, 4, 5)
|
81
83
|
end
|
82
84
|
end
|
83
85
|
end
|
@@ -6,63 +6,65 @@ module FiberSchedulerSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.shared_examples FiberSchedulerSpec::Fiber do
|
9
|
-
|
9
|
+
describe "#fiber" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
shared_examples :examples do
|
13
|
+
let(:fibers) { [] }
|
14
|
+
let(:fiber) { fibers.first }
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
it "calls #fiber" do
|
17
|
+
expect_any_instance_of(scheduler_class)
|
18
|
+
.to receive(:fiber).once
|
19
|
+
.and_call_original
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
setup
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
it "creates a fiber" do
|
25
|
+
# Prevent GC running inbetween two ObjectSpace calls.
|
26
|
+
GC.disable
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
before = ObjectSpace.each_object(Fiber).count
|
29
|
+
setup
|
30
|
+
after = ObjectSpace.each_object(Fiber).count
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
# The 'after - before' is > 1 with some selectors.
|
33
|
+
expect(after - before).to be >= 1
|
34
|
+
ensure
|
35
|
+
GC.enable
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
it "creates a non-blocking fiber" do
|
39
|
+
setup
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
expect(fiber).to be_a Fiber
|
42
|
+
expect(fiber).not_to be_blocking
|
43
|
+
end
|
42
44
|
end
|
43
|
-
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
context "Fiber.schedule with an empty block" do
|
47
|
+
def operations
|
48
|
+
fibers << Fiber.schedule {}
|
49
|
+
end
|
50
|
+
|
51
|
+
include_examples :examples
|
48
52
|
end
|
49
53
|
|
50
|
-
|
51
|
-
|
54
|
+
context "Fiber.schedule with a non-blocking operation" do
|
55
|
+
def operations
|
56
|
+
fibers << Fiber.schedule { sleep 0 }
|
57
|
+
end
|
52
58
|
|
53
|
-
|
54
|
-
def operations
|
55
|
-
fibers << Fiber.schedule { sleep 0 }
|
59
|
+
include_examples :examples
|
56
60
|
end
|
57
61
|
|
58
|
-
|
59
|
-
|
62
|
+
context "Fiber.schedule with a blocking operation" do
|
63
|
+
def operations
|
64
|
+
fibers << Fiber.schedule { "." }
|
65
|
+
end
|
60
66
|
|
61
|
-
|
62
|
-
def operations
|
63
|
-
fibers << Fiber.schedule { "." }
|
67
|
+
include_examples :examples
|
64
68
|
end
|
65
|
-
|
66
|
-
include_examples :examples
|
67
69
|
end
|
68
70
|
end
|
@@ -6,76 +6,78 @@ module FiberSchedulerSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.shared_examples FiberSchedulerSpec::IOWait do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
context "
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
9
|
+
describe "#io_wait" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
11
|
+
|
12
|
+
context "UNIXSocket#wait_readable" do
|
13
|
+
context "without a timeout" do
|
14
|
+
let(:order) { [] }
|
15
|
+
let(:pair) { UNIXSocket.pair }
|
16
|
+
let(:reader) { pair.first }
|
17
|
+
let(:writer) { pair.last }
|
18
|
+
|
19
|
+
def operations
|
20
|
+
Fiber.schedule do
|
21
|
+
order << 1
|
22
|
+
reader.wait_readable
|
23
|
+
reader.close
|
24
|
+
order << 6
|
25
|
+
end
|
26
|
+
|
27
|
+
order << 2
|
28
|
+
|
29
|
+
Fiber.schedule do
|
30
|
+
order << 3
|
31
|
+
writer.write(".")
|
32
|
+
writer.close
|
33
|
+
order << 4
|
34
|
+
end
|
35
|
+
order << 5
|
24
36
|
end
|
25
37
|
|
26
|
-
|
38
|
+
it "behaves async" do
|
39
|
+
setup
|
27
40
|
|
28
|
-
|
29
|
-
order << 3
|
30
|
-
writer.write(".")
|
31
|
-
writer.close
|
32
|
-
order << 4
|
41
|
+
expect(order).to eq (1..6).to_a
|
33
42
|
end
|
34
|
-
order << 5
|
35
|
-
end
|
36
|
-
|
37
|
-
it "behaves async" do
|
38
|
-
setup
|
39
43
|
|
40
|
-
|
41
|
-
|
44
|
+
it "calls #io_wait" do
|
45
|
+
expect_any_instance_of(scheduler_class)
|
46
|
+
.to receive(:io_wait).once
|
47
|
+
.and_call_original
|
42
48
|
|
43
|
-
|
44
|
-
|
45
|
-
.to receive(:io_wait).once
|
46
|
-
.and_call_original
|
47
|
-
|
48
|
-
setup
|
49
|
+
setup
|
50
|
+
end
|
49
51
|
end
|
50
|
-
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
53
|
+
context "with a timeout" do
|
54
|
+
let(:order) { [] }
|
55
|
+
let(:pair) { UNIXSocket.pair }
|
56
|
+
let(:reader) { pair.first }
|
57
|
+
let(:writer) { pair.last }
|
58
|
+
|
59
|
+
def operations
|
60
|
+
Fiber.schedule do
|
61
|
+
order << 1
|
62
|
+
reader.wait_readable(0.001)
|
63
|
+
order << 3
|
64
|
+
end
|
65
|
+
order << 2
|
63
66
|
end
|
64
|
-
order << 2
|
65
|
-
end
|
66
67
|
|
67
|
-
|
68
|
-
|
68
|
+
it "behaves async" do
|
69
|
+
setup
|
69
70
|
|
70
|
-
|
71
|
-
|
71
|
+
expect(order).to eq (1..3).to_a
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
it "calls #io_wait" do
|
75
|
+
expect_any_instance_of(scheduler_class)
|
76
|
+
.to receive(:io_wait).once
|
77
|
+
.and_call_original
|
77
78
|
|
78
|
-
|
79
|
+
setup
|
80
|
+
end
|
79
81
|
end
|
80
82
|
end
|
81
83
|
end
|
@@ -6,91 +6,93 @@ module FiberSchedulerSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.shared_examples FiberSchedulerSpec::KernelSleep do
|
9
|
-
|
9
|
+
describe "#kernel_sleep" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
context "Kernel.sleep" do
|
13
|
+
let(:order) { [] }
|
14
|
+
let(:times) { [] }
|
15
|
+
let(:duration) { times[1] - times[0] }
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
context "multiple sleep operations" do
|
18
|
+
let(:interval) { 0.1 }
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
def operations
|
21
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
Fiber.schedule do
|
24
|
+
order << 1
|
25
|
+
sleep interval
|
26
|
+
order << 5
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
+
order << 2
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
Fiber.schedule do
|
32
|
+
order << 3
|
33
|
+
sleep interval
|
34
|
+
order << 6
|
35
|
+
end
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
order << 4
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
it "calls #kernel_sleep" do
|
41
|
+
expect_any_instance_of(scheduler_class)
|
42
|
+
.to receive(:kernel_sleep).exactly(2).times
|
43
|
+
.and_call_original
|
43
44
|
|
44
|
-
|
45
|
-
|
45
|
+
setup
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
48
|
+
it "behaves async" do
|
49
|
+
setup
|
49
50
|
|
50
|
-
|
51
|
-
|
51
|
+
expect(order).to eq (1..6).to_a
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
it "runs operations in parallel" do
|
55
|
+
setup
|
56
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
expect(duration).to be >= interval
|
59
|
+
expect(duration).to be < (interval * 1.2)
|
60
|
+
end
|
59
61
|
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context "sleep 0" do
|
63
|
-
def operations
|
64
|
-
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
65
62
|
|
66
|
-
|
67
|
-
|
68
|
-
sleep 0
|
63
|
+
context "sleep 0" do
|
64
|
+
def operations
|
69
65
|
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
70
|
-
|
66
|
+
|
67
|
+
Fiber.schedule do
|
68
|
+
order << 1
|
69
|
+
sleep 0
|
70
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
71
|
+
order << 3
|
72
|
+
end
|
73
|
+
order << 2
|
71
74
|
end
|
72
|
-
order << 2
|
73
|
-
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
it "calls #kernel_sleep" do
|
77
|
+
expect_any_instance_of(scheduler_class)
|
78
|
+
.to receive(:kernel_sleep).once
|
79
|
+
.and_call_original
|
79
80
|
|
80
|
-
|
81
|
-
|
81
|
+
setup
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
84
|
+
it "behaves async" do
|
85
|
+
setup
|
85
86
|
|
86
|
-
|
87
|
-
|
87
|
+
expect(order).to eq (1..3).to_a
|
88
|
+
end
|
88
89
|
|
89
|
-
|
90
|
-
|
90
|
+
it "runs the operation in no time" do
|
91
|
+
setup
|
91
92
|
|
92
|
-
|
93
|
-
|
93
|
+
# No sleeping was performed at all.
|
94
|
+
expect(duration).to be < 0.0005
|
95
|
+
end
|
94
96
|
end
|
95
97
|
end
|
96
98
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative "context"
|
2
|
+
|
3
|
+
module FiberSchedulerSpec
|
4
|
+
module NestedFiberSchedule
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec.shared_examples FiberSchedulerSpec::NestedFiberSchedule do
|
9
|
+
describe "nested Fiber.schedule" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
11
|
+
|
12
|
+
let(:order) { [] }
|
13
|
+
|
14
|
+
context "with blocking operations" do
|
15
|
+
context "Kernel.sleep" do
|
16
|
+
def operations
|
17
|
+
Fiber.schedule do
|
18
|
+
order << 1
|
19
|
+
sleep 0
|
20
|
+
order << 3
|
21
|
+
|
22
|
+
Fiber.schedule do
|
23
|
+
order << 4
|
24
|
+
sleep 0
|
25
|
+
order << 6
|
26
|
+
end
|
27
|
+
order << 5
|
28
|
+
end
|
29
|
+
|
30
|
+
order << 2
|
31
|
+
end
|
32
|
+
|
33
|
+
it "completes all scheduled fibers" do
|
34
|
+
setup
|
35
|
+
|
36
|
+
expect(order).to eq (1..6).to_a
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "without blocking operations" do
|
42
|
+
def operations
|
43
|
+
Fiber.schedule do
|
44
|
+
order << 1
|
45
|
+
Fiber.schedule do
|
46
|
+
order << 2
|
47
|
+
end
|
48
|
+
order << 3
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "completes all scheduled fibers" do
|
53
|
+
setup
|
54
|
+
|
55
|
+
expect(order).to eq (1..3).to_a
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -6,56 +6,58 @@ module FiberSchedulerSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.shared_examples FiberSchedulerSpec::ProcessWait do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
9
|
+
describe "#process_wait" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
11
|
+
|
12
|
+
context "Process.wait" do
|
13
|
+
let(:interval_short) { 0.09 }
|
14
|
+
let(:interval) { 0.1 }
|
15
|
+
let(:order) { [] }
|
16
|
+
let(:times) { [] }
|
17
|
+
let(:duration) { times[1] - times[0] }
|
18
|
+
def operations
|
19
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
20
|
+
|
21
|
+
Fiber.schedule do
|
22
|
+
order << 1
|
23
|
+
# This interval is shorter so we're certain it will finish before the
|
24
|
+
# other fiber.
|
25
|
+
Process.wait(spawn("sleep #{interval_short}"))
|
26
|
+
order << 5
|
27
|
+
end
|
28
|
+
|
29
|
+
order << 2
|
30
|
+
|
31
|
+
Fiber.schedule do
|
32
|
+
order << 3
|
33
|
+
Process.wait(spawn("sleep #{interval}"))
|
34
|
+
order << 6
|
35
|
+
end
|
36
|
+
|
37
|
+
order << 4
|
26
38
|
end
|
27
39
|
|
28
|
-
|
40
|
+
it "calls #process_wait" do
|
41
|
+
expect_any_instance_of(scheduler_class)
|
42
|
+
.to receive(:process_wait).exactly(2).times
|
43
|
+
.and_call_original
|
29
44
|
|
30
|
-
|
31
|
-
order << 3
|
32
|
-
Process.wait(spawn("sleep #{interval}"))
|
33
|
-
order << 6
|
45
|
+
setup
|
34
46
|
end
|
35
47
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
it "calls #process_wait" do
|
40
|
-
expect_any_instance_of(scheduler_class)
|
41
|
-
.to receive(:process_wait).exactly(2).times
|
42
|
-
.and_call_original
|
43
|
-
|
44
|
-
setup
|
45
|
-
end
|
48
|
+
it "behaves async" do
|
49
|
+
setup
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
expect(order).to eq (1..6).to_a
|
51
|
-
end
|
51
|
+
expect(order).to eq (1..6).to_a
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
it "runs operations in parallel" do
|
55
|
+
setup
|
56
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
expect(duration).to be >= interval
|
59
|
+
expect(duration).to be < (interval * 1.5)
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
@@ -6,57 +6,59 @@ module FiberSchedulerSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
RSpec.shared_examples FiberSchedulerSpec::SocketIO do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
9
|
+
describe "socket #io_read #io_write" do
|
10
|
+
include_context FiberSchedulerSpec::Context
|
11
|
+
|
12
|
+
context "UNIXSocket.pair" do
|
13
|
+
let(:order) { [] }
|
14
|
+
let(:pair) { UNIXSocket.pair }
|
15
|
+
let(:reader) { pair.first }
|
16
|
+
let(:writer) { pair.last }
|
17
|
+
let(:messages) { [] }
|
18
|
+
let(:sent) { "ruby" }
|
19
|
+
let(:received) { messages.first }
|
20
|
+
|
21
|
+
def operations
|
22
|
+
Fiber.schedule do
|
23
|
+
order << 1
|
24
|
+
messages << reader.read(sent.size)
|
25
|
+
reader.close
|
26
|
+
order << 6
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
+
order << 2
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
Fiber.schedule do
|
32
|
+
order << 3
|
33
|
+
writer.write(sent)
|
34
|
+
writer.close
|
35
|
+
order << 4
|
36
|
+
end
|
37
|
+
order << 5
|
35
38
|
end
|
36
|
-
order << 5
|
37
|
-
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
it "calls #io_read and #io_write" do
|
41
|
+
expect_any_instance_of(scheduler_class)
|
42
|
+
.to receive(:io_read).once
|
43
|
+
.and_call_original
|
44
|
+
expect_any_instance_of(scheduler_class)
|
45
|
+
.to receive(:io_write).once
|
46
|
+
.and_call_original
|
46
47
|
|
47
|
-
|
48
|
-
|
48
|
+
setup
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
51
|
+
it "writes and reads a message" do
|
52
|
+
setup
|
52
53
|
|
53
|
-
|
54
|
-
|
54
|
+
expect(received).to eq sent
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
57
|
+
it "behaves async" do
|
58
|
+
setup
|
58
59
|
|
59
|
-
|
60
|
+
expect(order).to eq (1..6).to_a
|
61
|
+
end
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
@@ -7,80 +7,82 @@ module FiberSchedulerSpec
|
|
7
7
|
end
|
8
8
|
|
9
9
|
RSpec.shared_examples FiberSchedulerSpec::TimeoutAfter do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
10
|
+
describe "#timeout_after" do
|
11
|
+
include_context FiberSchedulerSpec::Context
|
12
|
+
|
13
|
+
context "Timeout.timeout" do
|
14
|
+
let(:order) { [] }
|
15
|
+
let(:times) { [] }
|
16
|
+
let(:duration) { times[1] - times[0] }
|
17
|
+
let(:sleep_duration) { 0.01 }
|
18
|
+
|
19
|
+
def operations
|
20
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
21
|
+
Fiber.schedule do
|
22
|
+
begin
|
23
|
+
order << 1
|
24
|
+
Timeout.timeout(timeout) do
|
25
|
+
order << 2
|
26
|
+
sleep sleep_duration
|
27
|
+
order << 4
|
28
|
+
end
|
29
|
+
order << 5
|
30
|
+
rescue Timeout::Error
|
31
|
+
order << 6
|
27
32
|
end
|
28
|
-
|
29
|
-
rescue Timeout::Error
|
30
|
-
order << 6
|
33
|
+
times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
31
34
|
end
|
32
|
-
|
35
|
+
order << 3
|
33
36
|
end
|
34
|
-
order << 3
|
35
|
-
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
context "when the operation times out" do
|
39
|
+
let(:timeout) { 0.001 }
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
it "calls #timeout_after" do
|
42
|
+
expect_any_instance_of(scheduler_class)
|
43
|
+
.to receive(:timeout_after)
|
44
|
+
.and_call_original
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
setup
|
47
|
+
end
|
47
48
|
|
48
|
-
|
49
|
-
|
49
|
+
it "behaves async" do
|
50
|
+
setup
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
expect(order).to eq [1, 2, 3, 6]
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
55
|
+
it "times out early" do
|
56
|
+
setup
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
expect(duration).to be >= timeout
|
59
|
+
expect(duration).to be < (timeout * 10)
|
60
|
+
end
|
59
61
|
end
|
60
|
-
end
|
61
62
|
|
62
|
-
|
63
|
-
|
63
|
+
context "when the operation doesn't time out" do
|
64
|
+
let(:timeout) { 0.1 }
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
it "calls #timeout_after" do
|
67
|
+
expect_any_instance_of(scheduler_class)
|
68
|
+
.to receive(:timeout_after)
|
69
|
+
.and_call_original
|
69
70
|
|
70
|
-
|
71
|
-
|
71
|
+
setup
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
-
|
74
|
+
it "behaves async" do
|
75
|
+
setup
|
75
76
|
|
76
|
-
|
77
|
-
|
77
|
+
expect(order).to eq (1..5).to_a
|
78
|
+
end
|
78
79
|
|
79
|
-
|
80
|
-
|
80
|
+
it "finishes the operation" do
|
81
|
+
setup
|
81
82
|
|
82
|
-
|
83
|
-
|
83
|
+
expect(duration).to be >= sleep_duration
|
84
|
+
expect(duration).to be < (sleep_duration * 1.5)
|
85
|
+
end
|
84
86
|
end
|
85
87
|
end
|
86
88
|
end
|
data/lib/fiber_scheduler_spec.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative "fiber_scheduler_spec/close"
|
|
4
4
|
require_relative "fiber_scheduler_spec/fiber"
|
5
5
|
require_relative "fiber_scheduler_spec/io_wait"
|
6
6
|
require_relative "fiber_scheduler_spec/kernel_sleep"
|
7
|
+
require_relative "fiber_scheduler_spec/nested_fiber_schedule"
|
7
8
|
require_relative "fiber_scheduler_spec/process_wait"
|
8
9
|
require_relative "fiber_scheduler_spec/socket_io"
|
9
10
|
require_relative "fiber_scheduler_spec/timeout_after"
|
@@ -15,6 +16,7 @@ RSpec.shared_examples FiberSchedulerSpec do
|
|
15
16
|
include_examples FiberSchedulerSpec::Fiber
|
16
17
|
include_examples FiberSchedulerSpec::IOWait
|
17
18
|
include_examples FiberSchedulerSpec::KernelSleep
|
19
|
+
include_examples FiberSchedulerSpec::NestedFiberSchedule
|
18
20
|
include_examples FiberSchedulerSpec::ProcessWait
|
19
21
|
include_examples FiberSchedulerSpec::SocketIO
|
20
22
|
include_examples FiberSchedulerSpec::TimeoutAfter
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fiber_scheduler_spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno Sutic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- lib/fiber_scheduler_spec/fiber.rb
|
67
67
|
- lib/fiber_scheduler_spec/io_wait.rb
|
68
68
|
- lib/fiber_scheduler_spec/kernel_sleep.rb
|
69
|
+
- lib/fiber_scheduler_spec/nested_fiber_schedule.rb
|
69
70
|
- lib/fiber_scheduler_spec/process_wait.rb
|
70
71
|
- lib/fiber_scheduler_spec/socket_io.rb
|
71
72
|
- lib/fiber_scheduler_spec/timeout_after.rb
|