object-stream 0.1

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.
@@ -0,0 +1,176 @@
1
+ require 'object-stream'
2
+ require 'stringio'
3
+
4
+ require 'minitest/autorun'
5
+
6
+ module TestBasic
7
+ attr_reader :sio, :stream
8
+
9
+ # supported by all types
10
+ BASIC_OBJECTS = [
11
+ nil,
12
+ true,
13
+ false,
14
+ "The quick brown fox jumped over the lazy dog's back.",
15
+ [-5, "foo", [4]],
16
+ {"a" => 1, "b" => 2}
17
+ ]
18
+
19
+ ADVANCED_OBJECTS = [
20
+ 12,
21
+ 2**40 + 123,
22
+ 3.45,
23
+ { 1 => 2 },
24
+ { ["a"] => 3 },
25
+ { {"b" => 5} => 6 }
26
+ ]
27
+
28
+ class Custom
29
+ attr_reader :x, :y
30
+ def initialize x, y
31
+ @x, @y = x, y
32
+ end
33
+ def ==(other)
34
+ @x == other.x
35
+ @y == other.y # just enough to make test pass
36
+ end
37
+ end
38
+
39
+ RUBY_OBJECTS = [
40
+ :foo,
41
+ {:foo => :bar},
42
+ String,
43
+ File,
44
+ Custom.new(1,2)
45
+ ]
46
+
47
+ def type; self.class::TYPE; end
48
+ def objects; BASIC_OBJECTS + self.class::OBJECTS; end
49
+
50
+ def setup
51
+ @sio = StringIO.new
52
+ @stream = ObjectStream.new sio, type: type
53
+ end
54
+
55
+ def test_write_read
56
+ objects.each do |obj|
57
+ sio.rewind # do not need to clear stream's buffer (if any)
58
+ sio.truncate 0
59
+ stream.write obj
60
+
61
+ sio.rewind
62
+ dump = sio.read
63
+ sio.rewind
64
+
65
+ stream.read do |obj2|
66
+ assert_equal(obj, obj2, "dump is #{dump.inspect}")
67
+ end
68
+ end
69
+ end
70
+
71
+ def test_batch_write
72
+ a = ["a", "b", "c"]
73
+ stream.write *a
74
+ sio.rewind
75
+ dump = sio.read
76
+ sio.rewind
77
+ assert_equal(a, stream.to_a, "dump is #{dump.inspect}")
78
+ end
79
+
80
+ def test_each
81
+ objects.each do |obj|
82
+ stream.write obj
83
+ end
84
+
85
+ sio.rewind
86
+ dump = sio.read
87
+ sio.rewind
88
+
89
+ assert_equal(objects, stream.to_a, # <-- #each called by #to_a
90
+ "dump is #{dump.inspect}")
91
+ end
92
+
93
+ def test_break
94
+ a = (1..10).to_a
95
+ a.each do |i|
96
+ stream.write [i]
97
+ end
98
+
99
+ sio.rewind
100
+
101
+ a2 = []
102
+ stream.each do |object|
103
+ i = object[0]
104
+ a2 << i
105
+ break if i == 5
106
+ end
107
+
108
+ stream.each do |object|
109
+ i = object[0]
110
+ a2 << i
111
+ end
112
+
113
+ case type
114
+ when ObjectStream::MARSHAL_TYPE
115
+ assert_equal(a, a2)
116
+ else
117
+ assert_equal(a[0..4], a2) # fixable?
118
+ end
119
+ end
120
+
121
+ def test_enum
122
+ objects.each do |obj|
123
+ stream.write obj
124
+ end
125
+
126
+ sio.rewind
127
+
128
+ enum = stream.each
129
+ assert_equal(objects, enum.to_a)
130
+ end
131
+
132
+ def test_read_without_block
133
+ n = 100
134
+ n.times do |i|
135
+ stream << [i]
136
+ end
137
+
138
+ stream.io.rewind
139
+
140
+ count = 0
141
+ until stream.eof?
142
+ obj = stream.read
143
+ assert_equal [count], obj
144
+ count += 1
145
+ end
146
+ assert_equal n, count
147
+ end
148
+ end
149
+
150
+ class TestBasicMarshal < Minitest::Test
151
+ include TestBasic
152
+
153
+ TYPE = ObjectStream::MARSHAL_TYPE
154
+ OBJECTS = ADVANCED_OBJECTS + RUBY_OBJECTS
155
+ end
156
+
157
+ class TestBasicYaml < Minitest::Test
158
+ include TestBasic
159
+
160
+ TYPE = ObjectStream::YAML_TYPE
161
+ OBJECTS = ADVANCED_OBJECTS + RUBY_OBJECTS
162
+ end
163
+
164
+ class TestBasicJson < Minitest::Test
165
+ include TestBasic
166
+
167
+ TYPE = ObjectStream::JSON_TYPE
168
+ OBJECTS = [] # poor json!
169
+ end
170
+
171
+ class TestBasicMsgpack < Minitest::Test
172
+ include TestBasic
173
+
174
+ TYPE = ObjectStream::MSGPACK_TYPE
175
+ OBJECTS = ADVANCED_OBJECTS
176
+ end
@@ -0,0 +1,51 @@
1
+ require 'object-stream-wrapper'
2
+ require 'stringio'
3
+
4
+ require 'minitest/autorun'
5
+
6
+ class TestConsume < Minitest::Test
7
+ attr_reader :sio
8
+
9
+ def setup
10
+ @sio = StringIO.new
11
+ end
12
+
13
+ ObjectStream::TYPES.each do |type|
14
+ define_method "test_consume_#{type}" do
15
+ do_test_consume_for type: type
16
+ end
17
+ end
18
+
19
+ def do_test_consume_for(type: type)
20
+ n_total = 10
21
+ n_consumed = 5
22
+
23
+ objects = (0...n_total).map {|i| [i]}
24
+
25
+ stream = ObjectStreamWrapper.new(sio, type: type)
26
+ objects.each do |object|
27
+ stream << object
28
+ end
29
+
30
+ sio.rewind
31
+ stream = ObjectStreamWrapper.new(sio, type: type)
32
+
33
+ count = 0
34
+
35
+ n_consumed.times do |i|
36
+ stream.consume do |a|
37
+ assert_equal(i, a[0])
38
+ count += 1
39
+ end
40
+ end
41
+
42
+ assert_equal(0, sio.pos)
43
+
44
+ stream.each_with_index do |a, i|
45
+ assert_equal i + n_consumed, a[0]
46
+ count += 1
47
+ end
48
+
49
+ assert_equal(n_total, count)
50
+ end
51
+ end
@@ -0,0 +1,80 @@
1
+ require 'object-stream-wrapper'
2
+ require 'stringio'
3
+
4
+ require 'minitest/autorun'
5
+
6
+ class TestExpect < Minitest::Test
7
+ attr_reader :sio
8
+
9
+ class A
10
+ def initialize x, y
11
+ @x, @y = x, y
12
+ end
13
+
14
+ def to_msgpack pk = nil
15
+ case pk
16
+ when MessagePack::Packer
17
+ pk.write_array_header(2)
18
+ pk.write @x
19
+ pk.write @y
20
+ return pk
21
+
22
+ else # nil or IO
23
+ MessagePack.pack(self, pk)
24
+ end
25
+ end
26
+
27
+ def to_a
28
+ [@x, @y]
29
+ end
30
+
31
+ def to_json
32
+ to_a.to_json
33
+ end
34
+
35
+ def self.from_serialized ary
36
+ new *ary
37
+ end
38
+
39
+ def == other
40
+ self.class == other.class and
41
+ to_a == other.to_a
42
+ end
43
+ end
44
+
45
+ class B < A
46
+ end
47
+
48
+ def setup
49
+ @sio = StringIO.new
50
+ end
51
+
52
+ def test_expect
53
+ objects = []
54
+ 20.times do |i|
55
+ if rand < 0.5
56
+ objects << "A" << A.new(i, i.to_s)
57
+ else
58
+ objects << "B" << B.new(i, i.to_s)
59
+ end
60
+ end
61
+
62
+ stream = ObjectStreamWrapper.new(sio, type: ObjectStream::MSGPACK_TYPE)
63
+ objects.each do |object|
64
+ stream << object
65
+ end
66
+
67
+ sio.rewind
68
+ stream = ObjectStreamWrapper.new(sio, type: ObjectStream::MSGPACK_TYPE)
69
+ objects2 = []
70
+ stream.read do |object|
71
+ case object
72
+ when "A"; stream.expect A
73
+ when "B"; stream.expect B
74
+ else stream.unexpect
75
+ end
76
+ objects2 << object
77
+ end
78
+ assert_equal objects, objects2
79
+ end
80
+ end
@@ -0,0 +1,65 @@
1
+ require 'object-stream'
2
+ require 'socket'
3
+
4
+ require 'minitest/autorun'
5
+
6
+ class TestInbox < Minitest::Test
7
+ attr_reader :s, :t
8
+
9
+ def setup
10
+ @s, @t = UNIXSocket.pair
11
+ end
12
+
13
+ def test_marshal
14
+ do_test(ObjectStream::MARSHAL_TYPE)
15
+ end
16
+
17
+ def test_yaml
18
+ do_test(ObjectStream::YAML_TYPE)
19
+ end
20
+
21
+ def test_json
22
+ do_test(ObjectStream::JSON_TYPE)
23
+ end
24
+
25
+ def test_msgpack
26
+ do_test(ObjectStream::MSGPACK_TYPE)
27
+ end
28
+
29
+ def do_test type
30
+ n = 200
31
+ th = Thread.new do
32
+ src = ObjectStream.new(s, type: type)
33
+ n.times do |i|
34
+ src << [i]
35
+ end
36
+ src.close
37
+ end
38
+
39
+ dst = ObjectStream.new(t, type: type)
40
+ i = 0
41
+
42
+ begin
43
+ rand(5).times do
44
+ assert_equal(i, dst.read[0])
45
+ i+=1
46
+ end
47
+ rescue EOFError
48
+ end
49
+
50
+ begin
51
+ dst.read do |obj|
52
+ assert_equal(i, obj[0])
53
+ i+=1
54
+ end
55
+ rescue EOFError
56
+ end
57
+
58
+ dst.each do |obj|
59
+ assert_equal(i, obj[0])
60
+ i+=1
61
+ end
62
+
63
+ assert_equal n, i
64
+ end
65
+ end
@@ -0,0 +1,22 @@
1
+ require 'object-stream'
2
+ require 'stringio'
3
+
4
+ require 'minitest/autorun'
5
+
6
+ class TestMaxbuf < Minitest::Test
7
+ attr_reader :sio, :stream
8
+
9
+ def setup
10
+ @sio = StringIO.new
11
+ end
12
+
13
+ def test_maxbuf
14
+ stream = ObjectStream.new(sio, type: ObjectStream::MSGPACK_TYPE)
15
+ stream << "a"*20
16
+ sio.rewind
17
+ stream = ObjectStream.new(sio, type: ObjectStream::MSGPACK_TYPE, maxbuf: 20)
18
+ assert_raises(ObjectStream::OverflowError) do
19
+ stream.to_a
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ require 'object-stream'
2
+ require 'stringio'
3
+
4
+ require 'minitest/autorun'
5
+
6
+ class TestOutbox < Minitest::Test
7
+ attr_reader :sio
8
+
9
+ def setup
10
+ @sio = StringIO.new
11
+ end
12
+
13
+ def test_outbox_is_lazy
14
+ stream = ObjectStream.new(sio, type: ObjectStream::MSGPACK_TYPE)
15
+ stream.write_to_outbox "foo"
16
+ sio.rewind
17
+ assert_empty sio.read
18
+ end
19
+
20
+ def test_outbox_precedes
21
+ stream = ObjectStream.new(sio, type: ObjectStream::MSGPACK_TYPE)
22
+ n_foo = stream.max_outbox+10
23
+
24
+ n_foo.times do |i|
25
+ stream.write_to_outbox "foo#{i}"
26
+ end
27
+ stream.write "bar"
28
+ sio.rewind
29
+
30
+ stream = ObjectStream.new(sio, type: ObjectStream::MSGPACK_TYPE)
31
+ items = stream.to_a
32
+ assert_equal n_foo + 1, items.size
33
+ assert_equal "bar", items.last
34
+ end
35
+ end
@@ -0,0 +1,79 @@
1
+ require 'object-stream'
2
+ require 'socket'
3
+ require 'stringio'
4
+
5
+ require 'minitest/autorun'
6
+
7
+ class TestSlowSender < Minitest::Test
8
+ attr_reader :s, :t
9
+
10
+ def setup
11
+ @s, @t = UNIXSocket.pair
12
+ end
13
+
14
+ def test_marshal
15
+ assert_equal(:block, get_test_result(ObjectStream::MARSHAL_TYPE))
16
+ end
17
+
18
+ def test_yaml
19
+ assert_equal(:block, get_test_result(ObjectStream::YAML_TYPE))
20
+ end
21
+
22
+ def test_json
23
+ assert_equal(:noblock, get_test_result(ObjectStream::JSON_TYPE))
24
+ end
25
+
26
+ def test_msgpack
27
+ assert_equal(:noblock, get_test_result(ObjectStream::MSGPACK_TYPE))
28
+ end
29
+
30
+ def get_test_result type
31
+ pid = fork do
32
+ sio = StringIO.new
33
+ stream = ObjectStream.new(sio, type: type)
34
+ 10.times do |i|
35
+ stream << "foo bar #{i}"
36
+ end
37
+
38
+ sio.rewind
39
+ data = sio.read
40
+ pos = data.index "bar 5"
41
+ raise unless pos < data.size - 10 # assume strings not munged
42
+ s.write data[0...pos]
43
+ sleep 0.1
44
+ s.write data[pos...pos+1]
45
+ sleep 0.1
46
+ s.write data[pos+1...pos+2]
47
+ sleep 0.1
48
+ s.write data[pos+2..-1]
49
+ end
50
+
51
+ s.close
52
+ stream = ObjectStream.new(t, type: type)
53
+
54
+ select_count = 0
55
+ empty_read_count = 0
56
+ until stream.eof?
57
+ select_count += 1
58
+ select([stream])
59
+
60
+ obj_count = 0
61
+ stream.read do |obj|
62
+ obj_count += 1
63
+ end
64
+ if obj_count == 0
65
+ empty_read_count += 1
66
+ end
67
+ end
68
+
69
+ stream.close
70
+ if select_count > 1 and empty_read_count > 0
71
+ :noblock
72
+ else
73
+ :block
74
+ end
75
+
76
+ ensure
77
+ Process.wait pid if pid
78
+ end
79
+ end