mt-libuv 4.1.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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +24 -0
  8. data/README.md +195 -0
  9. data/Rakefile +31 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +28 -0
  12. data/lib/mt-libuv/async.rb +51 -0
  13. data/lib/mt-libuv/check.rb +59 -0
  14. data/lib/mt-libuv/coroutines.rb +79 -0
  15. data/lib/mt-libuv/dns.rb +98 -0
  16. data/lib/mt-libuv/error.rb +88 -0
  17. data/lib/mt-libuv/ext/ext.rb +322 -0
  18. data/lib/mt-libuv/ext/platform/darwin_x64.rb +61 -0
  19. data/lib/mt-libuv/ext/platform/unix.rb +69 -0
  20. data/lib/mt-libuv/ext/platform/windows.rb +83 -0
  21. data/lib/mt-libuv/ext/tasks/mac.rb +24 -0
  22. data/lib/mt-libuv/ext/tasks/unix.rb +42 -0
  23. data/lib/mt-libuv/ext/tasks/win.rb +29 -0
  24. data/lib/mt-libuv/ext/tasks.rb +27 -0
  25. data/lib/mt-libuv/ext/types.rb +253 -0
  26. data/lib/mt-libuv/fiber_pool.rb +83 -0
  27. data/lib/mt-libuv/file.rb +309 -0
  28. data/lib/mt-libuv/filesystem.rb +263 -0
  29. data/lib/mt-libuv/fs_event.rb +37 -0
  30. data/lib/mt-libuv/handle.rb +108 -0
  31. data/lib/mt-libuv/idle.rb +59 -0
  32. data/lib/mt-libuv/mixins/accessors.rb +41 -0
  33. data/lib/mt-libuv/mixins/assertions.rb +25 -0
  34. data/lib/mt-libuv/mixins/fs_checks.rb +96 -0
  35. data/lib/mt-libuv/mixins/listener.rb +69 -0
  36. data/lib/mt-libuv/mixins/net.rb +42 -0
  37. data/lib/mt-libuv/mixins/resource.rb +30 -0
  38. data/lib/mt-libuv/mixins/stream.rb +276 -0
  39. data/lib/mt-libuv/pipe.rb +217 -0
  40. data/lib/mt-libuv/prepare.rb +59 -0
  41. data/lib/mt-libuv/q.rb +475 -0
  42. data/lib/mt-libuv/reactor.rb +567 -0
  43. data/lib/mt-libuv/signal.rb +62 -0
  44. data/lib/mt-libuv/spawn.rb +113 -0
  45. data/lib/mt-libuv/tcp.rb +465 -0
  46. data/lib/mt-libuv/timer.rb +107 -0
  47. data/lib/mt-libuv/tty.rb +42 -0
  48. data/lib/mt-libuv/udp.rb +302 -0
  49. data/lib/mt-libuv/version.rb +5 -0
  50. data/lib/mt-libuv/work.rb +86 -0
  51. data/lib/mt-libuv.rb +80 -0
  52. data/mt-libuv.gemspec +62 -0
  53. data/spec/async_spec.rb +67 -0
  54. data/spec/coroutines_spec.rb +121 -0
  55. data/spec/cpu_spec.rb +10 -0
  56. data/spec/defer_spec.rb +906 -0
  57. data/spec/dns_spec.rb +110 -0
  58. data/spec/dsl_spec.rb +43 -0
  59. data/spec/filesystem_spec.rb +270 -0
  60. data/spec/idle_spec.rb +44 -0
  61. data/spec/pipe_spec.rb +151 -0
  62. data/spec/spawn_spec.rb +119 -0
  63. data/spec/tcp_spec.rb +272 -0
  64. data/spec/test.sh +4 -0
  65. data/spec/test_fail.sh +3 -0
  66. data/spec/test_read.sh +3 -0
  67. data/spec/timer_spec.rb +14 -0
  68. data/spec/udp_spec.rb +73 -0
  69. data/spec/zen_spec.rb +34 -0
  70. metadata +196 -0
@@ -0,0 +1,119 @@
1
+ require 'mt-libuv'
2
+
3
+ describe MTLibuv::Spawn do
4
+ describe 'basic spawn of external process' do
5
+ it "should accept arguments and return an termination signal code" do
6
+ @reactor = MTLibuv::Reactor.new
7
+ @log = []
8
+ @reactor.run { |reactor|
9
+ begin
10
+ p = MTLibuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'])
11
+ p.stdout.progress do |data|
12
+ @log << data
13
+ end
14
+ p.stdout.start_read
15
+ @log << p.value
16
+ rescue => e
17
+ @log << e
18
+ @reactor.stop
19
+ end
20
+ }
21
+
22
+ term_signal = @log.pop
23
+ expect(term_signal).to be(0)
24
+
25
+ expect(@log[0]).to eq("123\narg1\narg2\n")
26
+ end
27
+
28
+ it "should return termination signal if exit code was 0" do
29
+ @reactor = MTLibuv::Reactor.new
30
+ @log = []
31
+ @reactor.run { |reactor|
32
+ begin
33
+ p = MTLibuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'])
34
+ p.kill
35
+ p.stdout.progress do |data|
36
+ @log << data
37
+ end
38
+ p.stdout.start_read
39
+ @log << p.value
40
+ rescue => e
41
+ @log << e
42
+ @reactor.stop
43
+ end
44
+ }
45
+
46
+ term_signal = @log.pop
47
+ expect(term_signal).to be(2)
48
+ expect(@log[0]).to be(nil)
49
+ end
50
+
51
+ it "should fail if exit code was not 0 and read output from stderr" do
52
+ @reactor = MTLibuv::Reactor.new
53
+ @log = []
54
+ @reactor.run { |reactor|
55
+ begin
56
+ p = MTLibuv::Spawn.new(reactor, './spec/test_fail.sh')
57
+ p.stderr.progress do |data|
58
+ @log << data
59
+ end
60
+ p.stderr.start_read
61
+ @log << p.value
62
+ rescue => e
63
+ @log << e
64
+ @reactor.stop
65
+ end
66
+ }
67
+
68
+ stderr = @log[0]
69
+ e = @log[1]
70
+ expect(e.class).to be(::MTLibuv::Error::ProcessExitCode)
71
+ expect(e.exit_status).to be(1)
72
+ expect(e.term_signal).to be(0)
73
+ expect(stderr.length).to be > 0
74
+ end
75
+
76
+ it "should be interactive" do
77
+ @reactor = MTLibuv::Reactor.new
78
+ @log = []
79
+ @reactor.run { |reactor|
80
+ begin
81
+ p = MTLibuv::Spawn.new(reactor, './spec/test_read.sh')
82
+ p.stdout.progress do |data|
83
+ @log << data
84
+ end
85
+ p.stdout.start_read
86
+ p.stdin.write("2017\n")
87
+ @log << p.value
88
+ rescue => e
89
+ @log << e
90
+ @reactor.stop
91
+ end
92
+ }
93
+
94
+ term_signal = @log.pop
95
+ expect(term_signal).to be(0)
96
+
97
+ expect(@log[0]).to eq("you entered 2017 - sweet\n")
98
+ end
99
+
100
+ it "should support inheriting parent processes streams" do
101
+ @reactor = MTLibuv::Reactor.new
102
+ @log = []
103
+ @reactor.run { |reactor|
104
+ begin
105
+ p = MTLibuv::Spawn.new(reactor, './spec/test.sh', args: ['arg1', 'arg2'], env: ['SOME_VAR=123'], mode: :inherit)
106
+ @log << p.stdout
107
+ @log << p.value
108
+ rescue => e
109
+ @log << e
110
+ @reactor.stop
111
+ end
112
+ }
113
+
114
+ term_signal = @log.pop
115
+ expect(term_signal).to be(0)
116
+ expect(@log[0]).to be(nil)
117
+ end
118
+ end
119
+ end
data/spec/tcp_spec.rb ADDED
@@ -0,0 +1,272 @@
1
+ require 'mt-libuv'
2
+ require 'thread'
3
+
4
+
5
+ describe MTLibuv::TCP do
6
+ before :each do
7
+ @log = []
8
+ @general_failure = []
9
+
10
+ @reactor = MTLibuv::Reactor.new
11
+ @server = @reactor.tcp
12
+ @client = @reactor.tcp
13
+ @timeout = @reactor.timer do
14
+ @reactor.stop
15
+ @reactor2.stop if @reactor2
16
+ @general_failure << "test timed out"
17
+ end
18
+ @timeout.start(5000)
19
+
20
+ @reactor.all(@server, @client, @timeout).catch do |reason|
21
+ @general_failure << reason.inspect
22
+ end
23
+
24
+
25
+ @pipefile = "/tmp/test-pipe.pipe"
26
+ @reactor.notifier do |error, context|
27
+ begin
28
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
29
+ rescue Exception => e
30
+ @general_failure << "error in logger #{e.inspect}"
31
+ end
32
+ end
33
+
34
+ begin
35
+ File.unlink(@pipefile)
36
+ rescue
37
+ end
38
+ end
39
+
40
+ describe 'basic client server' do
41
+ it "should send a ping and return a pong", :network => true do
42
+ @reactor.run { |reactor|
43
+ @server.bind('127.0.0.1', 34567) do |client|
44
+ client.progress do |data|
45
+ @log << data
46
+
47
+ client.write('pong')
48
+ end
49
+ client.start_read
50
+ end
51
+
52
+ # catch errors
53
+ @server.catch do |reason|
54
+ @general_failure << reason.inspect
55
+ end
56
+
57
+ # start listening
58
+ @server.listen(1024)
59
+
60
+
61
+
62
+ # connect client to server
63
+ @client.connect('127.0.0.1', 34567) do |client|
64
+ client.progress do |data|
65
+ @log << data
66
+
67
+ @client.shutdown
68
+ end
69
+
70
+ @client.start_read
71
+ @client.write('ping')
72
+ end
73
+
74
+ # catch errors
75
+ @client.catch do |reason|
76
+ @general_failure << reason.inspect
77
+ end
78
+
79
+ # close the handle
80
+ @client.finally do
81
+ @server.close
82
+ @reactor.stop
83
+ end
84
+ }
85
+
86
+ expect(@general_failure).to eq([])
87
+ expect(@log).to eq(['ping', 'pong'])
88
+ end
89
+
90
+ it "should work with coroutines", :network => true do
91
+ @reactor.run { |reactor|
92
+ @server.bind('127.0.0.1', 34567) do |client|
93
+ client.progress do |data|
94
+ @log << data
95
+
96
+ client.write('pong')
97
+ end
98
+ client.start_read
99
+ end
100
+
101
+ # catch errors
102
+ @server.catch do |reason|
103
+ @general_failure << reason.inspect
104
+ end
105
+
106
+ # start listening
107
+ @server.listen(1024)
108
+
109
+ # connect client to server
110
+ @client.progress do |data|
111
+ @log << data
112
+
113
+ addrinfo = @reactor.lookup('127.0.0.1')
114
+ @log << addrinfo[0][0]
115
+
116
+ @client.shutdown
117
+ end
118
+ # catch errors
119
+ @client.catch do |reason|
120
+ @general_failure << reason.inspect
121
+ end
122
+
123
+ # close the handle
124
+ @client.finally do
125
+ @server.close
126
+ @reactor.stop
127
+ end
128
+ @client.connect('127.0.0.1', 34567)
129
+ @client.start_read
130
+ @client.write('ping')
131
+ }
132
+
133
+ expect(@general_failure).to eq([])
134
+ expect(@log).to eq(['ping', 'pong', '127.0.0.1'])
135
+ end
136
+
137
+ it "should quack a bit like an IO object", :network => true do
138
+ @reactor.run { |reactor|
139
+ @server.bind('127.0.0.1', 34567) do |client|
140
+ @log << client.read(4)
141
+ client.write('pong')
142
+ end
143
+
144
+ # catch errors
145
+ @server.catch do |reason|
146
+ @general_failure << reason.inspect
147
+ end
148
+
149
+ # start listening
150
+ @server.listen(1024)
151
+
152
+ # catch errors
153
+ @client.catch do |reason|
154
+ @general_failure << reason.inspect
155
+ end
156
+
157
+ # close the handle
158
+ @client.finally do
159
+ @server.close
160
+ @reactor.stop
161
+ end
162
+ @client.connect('127.0.0.1', 34567)
163
+ @client.write('ping')
164
+ @log << @client.read(4)
165
+ addrinfo = @reactor.lookup('127.0.0.1')
166
+ @log << addrinfo[0][0]
167
+ @client.shutdown
168
+ }
169
+
170
+ expect(@general_failure).to eq([])
171
+ expect(@log).to eq(['ping', 'pong', '127.0.0.1'])
172
+ end
173
+ end
174
+
175
+ it "should handle requests on different threads", :network => true do
176
+ @sync = Mutex.new
177
+
178
+ @reactor.run { |reactor|
179
+ @remote = nil
180
+ @server.bind('127.0.0.1', 45678) do |client|
181
+ @remote.write2(client)
182
+ end
183
+
184
+ # catch errors
185
+ @server.catch do |reason|
186
+ @general_failure << reason.inspect
187
+ end
188
+
189
+
190
+ @pipeserve = @reactor.pipe(true)
191
+ @pipeserve.bind(@pipefile) do |client|
192
+ @remote = client
193
+
194
+ # start listening on TCP server
195
+ @server.listen(1024)
196
+
197
+ # connect client to server
198
+ @client.connect('127.0.0.1', 45678) do |client|
199
+ client.progress do |data|
200
+ @sync.synchronize {
201
+ @log << data
202
+ }
203
+ @client.shutdown
204
+ end
205
+
206
+ @client.start_read
207
+ @client.write('ping')
208
+ end
209
+
210
+ @pipeserve.getsockname
211
+ end
212
+
213
+ # start listening
214
+ @pipeserve.listen(1024)
215
+
216
+
217
+
218
+ # catch errors
219
+ @client.catch do |reason|
220
+ @general_failure << reason.inspect
221
+ end
222
+
223
+ # close the handle
224
+ @client.finally do
225
+ @server.close
226
+ @pipeserve.close
227
+ end
228
+
229
+
230
+
231
+ Thread.new do
232
+ @reactor2 = MTLibuv::Reactor.new
233
+ @reactor2.notifier do |error, context|
234
+ begin
235
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
236
+ rescue Exception
237
+ @general_failure << "error in logger #{e.inspect}"
238
+ end
239
+ end
240
+ @pipeclient = @reactor2.pipe(true)
241
+
242
+
243
+ @reactor2.run do |reactor|
244
+ # connect client to server
245
+ @pipeclient.connect(@pipefile) do |client|
246
+ @pipeclient.progress do |data|
247
+ connection = @pipeclient.check_pending
248
+
249
+ connection.progress do |data|
250
+ @sync.synchronize {
251
+ @log << data
252
+ }
253
+ connection.write('pong')
254
+ end
255
+ connection.start_read
256
+ connection.finally do
257
+ @pipeclient.close
258
+ @reactor2.stop
259
+ @reactor.stop
260
+ end
261
+ end
262
+
263
+ @pipeclient.start_read
264
+ end
265
+ end
266
+ end
267
+ }
268
+
269
+ expect(@general_failure).to eq([])
270
+ expect(@log).to eq(['ping', 'pong'])
271
+ end
272
+ end
data/spec/test.sh ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ echo $SOME_VAR
3
+ echo $1
4
+ echo $2
data/spec/test_fail.sh ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ ech $SOME_VAR
3
+ exit 1
data/spec/test_read.sh ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ read year
3
+ echo "you entered $year - sweet"
@@ -0,0 +1,14 @@
1
+ require 'mt-libuv'
2
+
3
+ describe MTLibuv::Timer do
4
+ describe 'setting properties' do
5
+ it "should allow repeat to be set" do
6
+ @reactor = MTLibuv::Reactor.new
7
+ @reactor.run { |logger|
8
+ @timer = @reactor.timer
9
+ @timer.repeat = 5
10
+ expect(@timer.repeat).to eq(5)
11
+ }
12
+ end
13
+ end
14
+ end
data/spec/udp_spec.rb ADDED
@@ -0,0 +1,73 @@
1
+ require 'mt-libuv'
2
+ require 'thread'
3
+
4
+
5
+ describe MTLibuv::UDP do
6
+ before :each do
7
+ @log = []
8
+ @general_failure = []
9
+
10
+ @reactor = MTLibuv::Reactor.new
11
+ @server = @reactor.udp
12
+ @client = @reactor.udp
13
+ @timeout = @reactor.timer do
14
+ @reactor.stop
15
+ @general_failure << "test timed out"
16
+ end
17
+ @timeout.start(5000)
18
+
19
+ @reactor.notifier do |error, context|
20
+ begin
21
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
22
+ rescue Exception => e
23
+ @general_failure << "error in logger #{e.inspect}"
24
+ end
25
+ end
26
+
27
+ @reactor.all(@server, @client, @timeout).catch do |reason|
28
+ @general_failure << reason.inspect
29
+ end
30
+ end
31
+
32
+ describe 'basic client server' do
33
+ it "should send a ping and return a pong", :network => true do
34
+ @reactor.run { |reactor|
35
+ @server.bind('127.0.0.1', 34567)
36
+ @server.progress do |data, ip, port, server|
37
+ @log << data
38
+ server.send(ip, port, 'pong')
39
+ end
40
+ @server.start_read
41
+
42
+ # catch errors
43
+ @server.catch do |reason|
44
+ @general_failure << reason.inspect
45
+ end
46
+
47
+
48
+ # connect client to server
49
+ @client.bind('127.0.0.1', 34568)
50
+ @client.progress do |data, ip, port, client|
51
+ @log << data
52
+ client.close
53
+ end
54
+ @client.start_read
55
+ @client.send('127.0.0.1', 34567, 'ping')
56
+
57
+ # catch errors
58
+ @client.catch do |reason|
59
+ @general_failure << reason.inspect
60
+ end
61
+
62
+ # close the handle
63
+ @client.finally do
64
+ @server.close
65
+ @reactor.stop
66
+ end
67
+ }
68
+
69
+ expect(@log).to eq(['ping', 'pong'])
70
+ expect(@general_failure).to eq([])
71
+ end
72
+ end
73
+ end
data/spec/zen_spec.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'mt-libuv'
2
+
3
+
4
+ describe MTLibuv::Listener do
5
+ it "should ensure there are no remaining object references in callbacks", network: true do
6
+ require 'objspace'
7
+
8
+ checked = []
9
+
10
+ # These are created by loop objects and are never cleaned up
11
+ # This is OK as the loops are expected to execute for the life of the application
12
+ except = [::MTLibuv::Async, ::MTLibuv::Timer, ::MTLibuv::Prepare, ::MTLibuv::Signal]
13
+
14
+ ObjectSpace.each_object(Class) do |cls|
15
+ next unless cls.ancestors.include? ::MTLibuv::Handle
16
+ next if checked.include? cls
17
+ checked << cls
18
+
19
+ values = cls.callback_lookup.values
20
+ values.select! {|val| except.include?(val.class) ? false : val.class }
21
+
22
+ if values.length > 0
23
+ puts "\nMemory Leak in #{cls} with #{values.length} left over objects"
24
+ puts "Checked #{checked.length} classes, objects are:"
25
+ values.each do |val|
26
+ puts "\n#{val}\n"
27
+ end
28
+ raise 'Free the machines!'
29
+ end
30
+ end
31
+
32
+ expect(checked.length).to be > 3
33
+ end
34
+ end