fiber_scheduler_spec 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75aebdfe9a1849f812c214b78eaa70a1d5ea759317e75ff1a895ae54eb9c6826
4
- data.tar.gz: 5a1f24342b3191c79b0e09b346d46b046009475b795b3842c16bd613e96535ff
3
+ metadata.gz: c1e20ced7c55e6f9566d1a0e802f217e0981be4ab4d2ccbd5c27ac9604e43f7b
4
+ data.tar.gz: 5b2234c2a5dee08864e7cbbd27105c9e1b70e610c379afbd74b6c86ab38e2d88
5
5
  SHA512:
6
- metadata.gz: 37f63683f1abc6822db5748059badef9a6799b18bac7a2e0eb1a35a12c295b1eca23f623eea81edca6246c731bcae6b12384ed01abd6a30ff526298edc06c863
7
- data.tar.gz: 36b1726dcf43159c40c5fd311382442653a772b132956e6bdc9f70e797e0b28b60fa13787b3204b399cc6e701c573af3e4c22de1d190316c02e887bb8126a390
6
+ metadata.gz: a7baa25d93db508fb5dde06e91979c30df901b817e5dc878369873c9932af07a0c2be2e4587be3160c1c43e0672e0872470032dc600135585cf6fe9b97200405
7
+ data.tar.gz: 20471ba20badf88e691affb068309e7734a67d1f73e9d8d272d6de460040795b1b8e305fb09221908cdcdf9a281d6d066309d56d7f733c4cd126499669c33928
@@ -0,0 +1,47 @@
1
+ require "rspec"
2
+ require "socket"
3
+ require_relative "context"
4
+
5
+ module FiberSchedulerSpec
6
+ module AddressResolve
7
+ end
8
+ end
9
+
10
+ RSpec.shared_examples FiberSchedulerSpec::AddressResolve do
11
+ include_context FiberSchedulerSpec::Context
12
+
13
+ context "Addrinfo.getaddrinfo" do
14
+ let(:order) { [] }
15
+
16
+ def operations
17
+ Fiber.schedule do
18
+ order << 1
19
+ Addrinfo.getaddrinfo("example.com", 80, :AF_INET, :STREAM)
20
+ order << 5
21
+ end
22
+
23
+ order << 2
24
+
25
+ Fiber.schedule do
26
+ order << 3
27
+ Addrinfo.getaddrinfo("example.com", 80, :AF_INET, :STREAM)
28
+ order << 6
29
+ end
30
+ order << 4
31
+ end
32
+
33
+ it "calls #address_resolve" do
34
+ expect_any_instance_of(scheduler_class)
35
+ .to receive(:address_resolve).exactly(2).times
36
+ .and_call_original
37
+
38
+ setup
39
+ end
40
+
41
+ it "behaves async" do
42
+ setup
43
+
44
+ expect(order).to eq (1..6).to_a
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "context"
2
+
3
+ module FiberSchedulerSpec
4
+ module BlockUnblock
5
+ end
6
+ end
7
+
8
+ RSpec.shared_examples FiberSchedulerSpec::BlockUnblock do
9
+ include_context FiberSchedulerSpec::Context
10
+
11
+ context "Addrinfo.getaddrinfo" do
12
+ let(:order) { [] }
13
+ let(:queue) { Thread::Queue.new }
14
+ let(:item) { "item" }
15
+ let(:popped_items) { [] }
16
+
17
+ def operations
18
+ Fiber.schedule do
19
+ order << 1
20
+ popped_items << queue.pop
21
+ order << 6
22
+ end
23
+
24
+ order << 2
25
+
26
+ Fiber.schedule do
27
+ order << 3
28
+ queue.push(item)
29
+ order << 4
30
+ end
31
+
32
+ order << 5
33
+ end
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
48
+
49
+ expect(popped_items).to contain_exactly(item)
50
+ expect(order).to eq (1..6).to_a
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,83 @@
1
+ require "rspec"
2
+ require_relative "context"
3
+
4
+ module FiberSchedulerSpec
5
+ module Close
6
+ end
7
+ end
8
+
9
+ RSpec.shared_examples FiberSchedulerSpec::Close do
10
+ include_context FiberSchedulerSpec::Context
11
+
12
+ # TODO: should closing a scheduler also set Fiber.scheduler to nil?
13
+ context "without #run" do
14
+ let(:order) { [] }
15
+
16
+ def operations
17
+ Fiber.schedule do
18
+ order << 2
19
+ end
20
+ order << 1
21
+ end
22
+
23
+ # NOTE: this example does not use 'setup', #run should not be invoked
24
+ if method_defined?(:default_setup)
25
+ # skipping if user overrode setup
26
+ it "calls #close" do
27
+ expect(scheduler)
28
+ .to receive(:close).once
29
+ .and_call_original
30
+
31
+ Thread.new do
32
+ Fiber.set_scheduler(scheduler)
33
+
34
+ operations
35
+ end.join
36
+ end
37
+ end
38
+
39
+ it "behaves async" do
40
+ setup
41
+
42
+ expect(order).to contain_exactly(1, 2)
43
+ end
44
+ end
45
+
46
+ context "with #run" do
47
+ let(:order) { [] }
48
+
49
+ def operations
50
+ Fiber.schedule do
51
+ order << 2
52
+ 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
+ end
82
+ end
83
+ end
@@ -0,0 +1,30 @@
1
+ require "rspec"
2
+
3
+ module FiberSchedulerSpec
4
+ module Context
5
+ end
6
+ end
7
+
8
+ RSpec.shared_context FiberSchedulerSpec::Context do
9
+ unless method_defined?(:scheduler_class)
10
+ let(:scheduler_class) { described_class }
11
+ end
12
+ unless method_defined?(:scheduler)
13
+ subject(:scheduler) { scheduler_class.new }
14
+ end
15
+ def setup
16
+ ::Fiber.set_scheduler(scheduler)
17
+
18
+ operations
19
+
20
+ scheduler.run
21
+ end
22
+
23
+ around do |example|
24
+ result = Thread.new do
25
+ example.run
26
+ end.join(1)
27
+
28
+ expect(result).to be_a Thread # failure means spec timed out
29
+ end
30
+ end
@@ -0,0 +1,48 @@
1
+ require_relative "context"
2
+
3
+ module FiberSchedulerSpec
4
+ module Fiber
5
+ end
6
+ end
7
+
8
+ RSpec.shared_examples FiberSchedulerSpec::Fiber do
9
+ include_context FiberSchedulerSpec::Context
10
+
11
+ context "Fiber.schedule" do
12
+ let(:fibers) { [] }
13
+ let(:fiber) { fibers.first }
14
+
15
+ def operations
16
+ fibers << Fiber.schedule {}
17
+ end
18
+
19
+ it "calls #fiber" do
20
+ expect_any_instance_of(scheduler_class)
21
+ .to receive(:fiber).once
22
+ .and_call_original
23
+
24
+ setup
25
+ end
26
+
27
+ it "creates a fiber" do
28
+ # Prevent GC running inbetween two ObjectSpace calls.
29
+ GC.disable
30
+
31
+ before = ObjectSpace.each_object(Fiber).count
32
+ setup
33
+ after = ObjectSpace.each_object(Fiber).count
34
+
35
+ # The after - before is > 1 with the built-in selector.
36
+ expect(after - before).to be >= 1
37
+ ensure
38
+ GC.enable
39
+ end
40
+
41
+ it "creates a non-blocking fiber" do
42
+ setup
43
+
44
+ expect(fiber).to be_a Fiber
45
+ expect(fiber).not_to be_blocking
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,82 @@
1
+ require_relative "context"
2
+
3
+ module FiberSchedulerSpec
4
+ module IOWait
5
+ end
6
+ end
7
+
8
+ RSpec.shared_examples FiberSchedulerSpec::IOWait do
9
+ include_context FiberSchedulerSpec::Context
10
+
11
+ context "UNIXSocket#wait_readable" do
12
+ context "without a timeout" do
13
+ let(:order) { [] }
14
+ let(:pair) { UNIXSocket.pair }
15
+ let(:reader) { pair.first }
16
+ let(:writer) { pair.last }
17
+
18
+ def operations
19
+ Fiber.schedule do
20
+ order << 1
21
+ reader.wait_readable
22
+ reader.close
23
+ order << 6
24
+ end
25
+
26
+ order << 2
27
+
28
+ Fiber.schedule do
29
+ order << 3
30
+ writer.write(".")
31
+ writer.close
32
+ order << 4
33
+ end
34
+ order << 5
35
+ end
36
+
37
+ it "behaves async" do
38
+ setup
39
+
40
+ expect(order).to eq (1..6).to_a
41
+ end
42
+
43
+ it "calls #io_wait" do
44
+ expect_any_instance_of(scheduler_class)
45
+ .to receive(:io_wait).once
46
+ .and_call_original
47
+
48
+ setup
49
+ end
50
+ end
51
+
52
+ context "with a timeout" do
53
+ let(:order) { [] }
54
+ let(:pair) { UNIXSocket.pair }
55
+ let(:reader) { pair.first }
56
+ let(:writer) { pair.last }
57
+
58
+ def operations
59
+ Fiber.schedule do
60
+ order << 1
61
+ reader.wait_readable(0.001)
62
+ order << 3
63
+ end
64
+ order << 2
65
+ end
66
+
67
+ it "behaves async" do
68
+ setup
69
+
70
+ expect(order).to eq (1..3).to_a
71
+ end
72
+
73
+ it "calls #io_wait" do
74
+ expect_any_instance_of(scheduler_class)
75
+ .to receive(:io_wait).once
76
+ .and_call_original
77
+
78
+ setup
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,97 @@
1
+ require_relative "context"
2
+
3
+ module FiberSchedulerSpec
4
+ module KernelSleep
5
+ end
6
+ end
7
+
8
+ RSpec.shared_examples FiberSchedulerSpec::KernelSleep do
9
+ include_context FiberSchedulerSpec::Context
10
+
11
+ context "Kernel.sleep" do
12
+ let(:order) { [] }
13
+ let(:times) { [] }
14
+ let(:duration) { times[1] - times[0] }
15
+
16
+ context "multiple sleep operations" do
17
+ let(:interval) { 0.1 }
18
+
19
+ def operations
20
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
21
+
22
+ Fiber.schedule do
23
+ order << 1
24
+ sleep interval
25
+ order << 5
26
+ end
27
+
28
+ order << 2
29
+
30
+ Fiber.schedule do
31
+ order << 3
32
+ sleep interval
33
+ order << 6
34
+ end
35
+
36
+ order << 4
37
+ end
38
+
39
+ it "calls #kernel_sleep" do
40
+ expect_any_instance_of(scheduler_class)
41
+ .to receive(:kernel_sleep).exactly(2).times
42
+ .and_call_original
43
+
44
+ setup
45
+ end
46
+
47
+ it "behaves async" do
48
+ setup
49
+
50
+ expect(order).to eq (1..6).to_a
51
+ end
52
+
53
+ it "runs operations in parallel" do
54
+ setup
55
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
56
+
57
+ expect(duration).to be >= interval
58
+ expect(duration).to be < (interval * 1.2)
59
+ end
60
+ end
61
+
62
+ context "sleep 0" do
63
+ def operations
64
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
65
+
66
+ Fiber.schedule do
67
+ order << 1
68
+ sleep 0
69
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
70
+ order << 3
71
+ end
72
+ order << 2
73
+ end
74
+
75
+ it "calls #kernel_sleep" do
76
+ expect_any_instance_of(scheduler_class)
77
+ .to receive(:kernel_sleep).once
78
+ .and_call_original
79
+
80
+ setup
81
+ end
82
+
83
+ it "behaves async" do
84
+ setup
85
+
86
+ expect(order).to eq (1..3).to_a
87
+ end
88
+
89
+ it "runs the operation in no time" do
90
+ setup
91
+
92
+ # No sleeping was performed at all.
93
+ expect(duration).to be < 0.0005
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,61 @@
1
+ require_relative "context"
2
+
3
+ module FiberSchedulerSpec
4
+ module ProcessWait
5
+ end
6
+ end
7
+
8
+ RSpec.shared_examples FiberSchedulerSpec::ProcessWait do
9
+ include_context FiberSchedulerSpec::Context
10
+
11
+ context "Process.wait" do
12
+ let(:interval_short) { 0.09 }
13
+ let(:interval) { 0.1 }
14
+ let(:order) { [] }
15
+ let(:times) { [] }
16
+ let(:duration) { times[1] - times[0] }
17
+ def operations
18
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
19
+
20
+ Fiber.schedule do
21
+ order << 1
22
+ # This interval is shorter so we're certain it will finish before the
23
+ # other fiber.
24
+ Process.wait(spawn("sleep #{interval_short}"))
25
+ order << 5
26
+ end
27
+
28
+ order << 2
29
+
30
+ Fiber.schedule do
31
+ order << 3
32
+ Process.wait(spawn("sleep #{interval}"))
33
+ order << 6
34
+ end
35
+
36
+ order << 4
37
+ end
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
46
+
47
+ it "behaves async" do
48
+ setup
49
+
50
+ expect(order).to eq (1..6).to_a
51
+ end
52
+
53
+ it "runs operations in parallel" do
54
+ setup
55
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
56
+
57
+ expect(duration).to be >= interval
58
+ expect(duration).to be < (interval * 1.5)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,62 @@
1
+ require_relative "context"
2
+
3
+ module FiberSchedulerSpec
4
+ module SocketIO
5
+ end
6
+ end
7
+
8
+ RSpec.shared_examples FiberSchedulerSpec::SocketIO do
9
+ include_context FiberSchedulerSpec::Context
10
+
11
+ context "UNIXSocket.pair" do
12
+ let(:order) { [] }
13
+ let(:pair) { UNIXSocket.pair }
14
+ let(:reader) { pair.first }
15
+ let(:writer) { pair.last }
16
+ let(:messages) { [] }
17
+ let(:sent) { "ruby" }
18
+ let(:received) { messages.first }
19
+
20
+ def operations
21
+ Fiber.schedule do
22
+ order << 1
23
+ messages << reader.read(sent.size)
24
+ reader.close
25
+ order << 6
26
+ end
27
+
28
+ order << 2
29
+
30
+ Fiber.schedule do
31
+ order << 3
32
+ writer.write(sent)
33
+ writer.close
34
+ order << 4
35
+ end
36
+ order << 5
37
+ end
38
+
39
+ it "calls #io_read and #io_write" do
40
+ expect_any_instance_of(scheduler_class)
41
+ .to receive(:io_read).once
42
+ .and_call_original
43
+ expect_any_instance_of(scheduler_class)
44
+ .to receive(:io_write).once
45
+ .and_call_original
46
+
47
+ setup
48
+ end
49
+
50
+ it "writes and reads a message" do
51
+ setup
52
+
53
+ expect(received).to eq sent
54
+ end
55
+
56
+ it "behaves async" do
57
+ setup
58
+
59
+ expect(order).to eq (1..6).to_a
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,87 @@
1
+ require "timeout"
2
+ require_relative "context"
3
+
4
+ module FiberSchedulerSpec
5
+ module TimeoutAfter
6
+ end
7
+ end
8
+
9
+ RSpec.shared_examples FiberSchedulerSpec::TimeoutAfter do
10
+ include_context FiberSchedulerSpec::Context
11
+
12
+ context "Timeout.timeout" do
13
+ let(:order) { [] }
14
+ let(:times) { [] }
15
+ let(:duration) { times[1] - times[0] }
16
+ let(:sleep_duration) { 0.01 }
17
+
18
+ def operations
19
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
20
+ Fiber.schedule do
21
+ begin
22
+ order << 1
23
+ Timeout.timeout(timeout) do
24
+ order << 2
25
+ sleep sleep_duration
26
+ order << 4
27
+ end
28
+ order << 5
29
+ rescue Timeout::Error
30
+ order << 6
31
+ end
32
+ times << Process.clock_gettime(Process::CLOCK_MONOTONIC)
33
+ end
34
+ order << 3
35
+ end
36
+
37
+ context "when the operation times out" do
38
+ let(:timeout) { 0.001 }
39
+
40
+ it "calls #timeout_after" do
41
+ expect_any_instance_of(scheduler_class)
42
+ .to receive(:timeout_after)
43
+ .and_call_original
44
+
45
+ setup
46
+ end
47
+
48
+ it "behaves async" do
49
+ setup
50
+
51
+ expect(order).to eq [1, 2, 3, 6]
52
+ end
53
+
54
+ it "times out early" do
55
+ setup
56
+
57
+ expect(duration).to be >= timeout
58
+ expect(duration).to be < (timeout * 10)
59
+ end
60
+ end
61
+
62
+ context "when the operation doesn't time out" do
63
+ let(:timeout) { 0.1 }
64
+
65
+ it "calls #timeout_after" do
66
+ expect_any_instance_of(scheduler_class)
67
+ .to receive(:timeout_after)
68
+ .and_call_original
69
+
70
+ setup
71
+ end
72
+
73
+ it "behaves async" do
74
+ setup
75
+
76
+ expect(order).to eq (1..5).to_a
77
+ end
78
+
79
+ it "finishes the operation" do
80
+ setup
81
+
82
+ expect(duration).to be >= sleep_duration
83
+ expect(duration).to be < (sleep_duration * 1.5)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,3 +1,3 @@
1
1
  module FiberSchedulerSpec
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,2 +1,21 @@
1
- module FiberSchedulerSpec
1
+ require_relative "fiber_scheduler_spec/address_resolve"
2
+ require_relative "fiber_scheduler_spec/block_unblock"
3
+ require_relative "fiber_scheduler_spec/close"
4
+ require_relative "fiber_scheduler_spec/fiber"
5
+ require_relative "fiber_scheduler_spec/io_wait"
6
+ require_relative "fiber_scheduler_spec/kernel_sleep"
7
+ require_relative "fiber_scheduler_spec/process_wait"
8
+ require_relative "fiber_scheduler_spec/socket_io"
9
+ require_relative "fiber_scheduler_spec/timeout_after"
10
+
11
+ RSpec.shared_examples FiberSchedulerSpec do
12
+ include_examples FiberSchedulerSpec::AddressResolve
13
+ include_examples FiberSchedulerSpec::BlockUnblock
14
+ include_examples FiberSchedulerSpec::Close
15
+ include_examples FiberSchedulerSpec::Fiber
16
+ include_examples FiberSchedulerSpec::IOWait
17
+ include_examples FiberSchedulerSpec::KernelSleep
18
+ include_examples FiberSchedulerSpec::ProcessWait
19
+ include_examples FiberSchedulerSpec::SocketIO
20
+ include_examples FiberSchedulerSpec::TimeoutAfter
2
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiber_scheduler_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Sutic
@@ -17,7 +17,7 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3.11'
20
- type: :development
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
@@ -45,6 +45,16 @@ extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
47
  - lib/fiber_scheduler_spec.rb
48
+ - lib/fiber_scheduler_spec/address_resolve.rb
49
+ - lib/fiber_scheduler_spec/block_unblock.rb
50
+ - lib/fiber_scheduler_spec/close.rb
51
+ - lib/fiber_scheduler_spec/context.rb
52
+ - lib/fiber_scheduler_spec/fiber.rb
53
+ - lib/fiber_scheduler_spec/io_wait.rb
54
+ - lib/fiber_scheduler_spec/kernel_sleep.rb
55
+ - lib/fiber_scheduler_spec/process_wait.rb
56
+ - lib/fiber_scheduler_spec/socket_io.rb
57
+ - lib/fiber_scheduler_spec/timeout_after.rb
48
58
  - lib/fiber_scheduler_spec/version.rb
49
59
  homepage: https://github.com/bruno-/fiber_scheduler_spec
50
60
  licenses: