pants 0.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.
- data/.gemtest +1 -0
- data/.gitignore +23 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +42 -0
- data/History.rdoc +6 -0
- data/README.rdoc +339 -0
- data/Rakefile +23 -0
- data/bin/pants +59 -0
- data/lib/pants.rb +84 -0
- data/lib/pants/core.rb +216 -0
- data/lib/pants/error.rb +5 -0
- data/lib/pants/logger.rb +8 -0
- data/lib/pants/network_helpers.rb +25 -0
- data/lib/pants/readers/base_reader.rb +302 -0
- data/lib/pants/readers/file_reader.rb +81 -0
- data/lib/pants/readers/udp_reader.rb +80 -0
- data/lib/pants/seam.rb +120 -0
- data/lib/pants/version.rb +3 -0
- data/lib/pants/writers/base_writer.rb +73 -0
- data/lib/pants/writers/file_writer.rb +59 -0
- data/lib/pants/writers/udp_writer.rb +125 -0
- data/pants.gemspec +31 -0
- data/spec/acceptance/file_reads_spec.rb +24 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/matchers/file_same_size_as.rb +20 -0
- data/spec/support/pants.wav +0 -0
- data/spec/unit/pants/core_spec.rb +105 -0
- data/spec/unit/pants/readers/base_reader_spec.rb +340 -0
- data/spec/unit/pants/readers/file_reader_spec.rb +94 -0
- data/spec/unit/pants/version_spec.rb +7 -0
- data/spec/unit/pants/writers/base_writer_spec.rb +35 -0
- data/spec/unit/pants/writers/file_writer_spec.rb +71 -0
- data/spec/unit/pants/writers/udp_writer_spec.rb +146 -0
- data/spec/unit/pants_spec.rb +6 -0
- data/tasks/pantsmark.thor +66 -0
- data/test_readers.rb +43 -0
- data/test_seams.rb +107 -0
- metadata +215 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pants/readers/file_reader'
|
3
|
+
|
4
|
+
|
5
|
+
describe Pants::Readers::FileReader do
|
6
|
+
let(:core_stopper_callback) do
|
7
|
+
double "EventMachine.Callback", call: true
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:tick_loop) do
|
11
|
+
tl = double "EventMachine::TickLoop"
|
12
|
+
tl.stub(:on_stop)
|
13
|
+
|
14
|
+
tl
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
EventMachine.stub(:tick_loop).and_return(tick_loop)
|
19
|
+
EventMachine::Iterator.stub_chain(:new, :each)
|
20
|
+
end
|
21
|
+
|
22
|
+
subject do
|
23
|
+
Pants::Readers::FileReader.new('some file', core_stopper_callback)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#start" do
|
27
|
+
let(:file) { double "File" }
|
28
|
+
let(:starter) { double "EventMachine::Callback starter" }
|
29
|
+
let(:stopper) { double "EventMachine::Callback stopper" }
|
30
|
+
|
31
|
+
before do
|
32
|
+
File.should_receive(:open).and_return(file)
|
33
|
+
subject.should_receive(:starter).and_return(starter)
|
34
|
+
subject.should_receive(:stopper).and_return(stopper)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "defines an EventMachine Callback" do
|
38
|
+
EventMachine.should_receive(:Callback).times.and_yield.and_call_original
|
39
|
+
|
40
|
+
EventMachine.should_receive(:attach) do |arg1, arg2, arg3, arg4, arg5|
|
41
|
+
arg1.should == file
|
42
|
+
arg2.should == Pants::Readers::FileReaderConnection
|
43
|
+
arg3.should be_a EventMachine::Channel
|
44
|
+
arg4.should == starter
|
45
|
+
arg5.should == stopper
|
46
|
+
end
|
47
|
+
|
48
|
+
subject.start
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe Pants::Readers::FileReaderConnection do
|
54
|
+
let(:channel) { double "EventMachine::Channel" }
|
55
|
+
let(:starter) { double "EventMachine::Callback starter" }
|
56
|
+
let(:stopper) { double "EventMachine::Callback stopper" }
|
57
|
+
|
58
|
+
subject do
|
59
|
+
Pants::Readers::FileReaderConnection.new(1, channel, starter, stopper)
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#post_init" do
|
63
|
+
let(:starter) { double "EventMachine::Callback" }
|
64
|
+
|
65
|
+
it "tells the starter that it's started" do
|
66
|
+
starter.should_receive(:call)
|
67
|
+
subject
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#receive_data" do
|
72
|
+
let(:data) { "some data" }
|
73
|
+
|
74
|
+
before do
|
75
|
+
Pants::Readers::FileReaderConnection.any_instance.stub(:post_init)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "directly writes it to the channel" do
|
79
|
+
channel.should_receive(:<<).with(data)
|
80
|
+
subject.receive_data(data)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#unbind" do
|
85
|
+
before do
|
86
|
+
Pants::Readers::FileReaderConnection.any_instance.stub(:post_init)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "tells the stopper that it's stopped" do
|
90
|
+
stopper.should_receive(:call)
|
91
|
+
subject.unbind
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pants/writers/base_writer'
|
3
|
+
|
4
|
+
|
5
|
+
describe Pants::Writers::BaseWriter do
|
6
|
+
let(:channel) { double "EventMachine::Channel" }
|
7
|
+
|
8
|
+
subject do
|
9
|
+
Pants::Writers::BaseWriter.new(channel)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#starter" do
|
13
|
+
context "@starter not yet defined" do
|
14
|
+
it "creates a new deferrable that sets @running to true" do
|
15
|
+
subject.should_not be_running
|
16
|
+
subject.starter.call
|
17
|
+
subject.should be_running
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#stopper" do
|
23
|
+
context "@stopper not yet defined and @running is true" do
|
24
|
+
before do
|
25
|
+
subject.instance_variable_set(:@running, true)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "creates a new deferrable that sets @running to false" do
|
29
|
+
subject.should be_running
|
30
|
+
subject.stopper.call
|
31
|
+
subject.should_not be_running
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pants/writers/file_writer'
|
3
|
+
|
4
|
+
|
5
|
+
describe Pants::Writers::FileWriter do
|
6
|
+
let(:channel) { EventMachine::Channel.new }
|
7
|
+
|
8
|
+
subject do
|
9
|
+
Pants::Writers::FileWriter.new(file, channel)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#stop" do
|
13
|
+
let(:file) do
|
14
|
+
c = double "File"
|
15
|
+
c.should_receive(:closed?).and_return(false)
|
16
|
+
c.should_receive(:close)
|
17
|
+
|
18
|
+
c
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:stopper) do
|
22
|
+
s = double "EventMachine::Callback"
|
23
|
+
s.should_receive(:call)
|
24
|
+
|
25
|
+
s
|
26
|
+
end
|
27
|
+
|
28
|
+
before do
|
29
|
+
File.stub(:open)
|
30
|
+
subject.instance_variable_set(:@file, file)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "closes the file and calls succeed on the stopper" do
|
34
|
+
subject.should_receive(:stopper).and_return(stopper)
|
35
|
+
subject.stop
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#start" do
|
40
|
+
let(:data) do
|
41
|
+
'0' * 100
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:file) do
|
45
|
+
f = double "File"
|
46
|
+
f.should_receive(:write_nonblock).once.with(data).and_return(data.size)
|
47
|
+
f.should_receive(:closed?).and_return(true)
|
48
|
+
|
49
|
+
f
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:tick_loop) do
|
53
|
+
t = double "EventMachine::TickLoop"
|
54
|
+
t.should_receive(:on_stop).and_yield
|
55
|
+
|
56
|
+
t
|
57
|
+
end
|
58
|
+
|
59
|
+
before do
|
60
|
+
File.should_receive(:open).and_return(file)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "subscribes to the channel and writes data as it comes in" do
|
64
|
+
EM.should_receive(:defer).and_yield
|
65
|
+
channel.should_receive(:subscribe).and_yield(data).and_call_original
|
66
|
+
EventMachine.should_receive(:tick_loop).and_yield.and_return(tick_loop)
|
67
|
+
|
68
|
+
subject.start
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pants/writers/udp_writer'
|
3
|
+
|
4
|
+
|
5
|
+
describe Pants::Writers::UDPWriter do
|
6
|
+
let(:channel) { double "EventMachine::Channel" }
|
7
|
+
let(:ip) { '127.0.0.1' }
|
8
|
+
let(:port) { 1234 }
|
9
|
+
before { subject.stub(:log) }
|
10
|
+
|
11
|
+
subject do
|
12
|
+
Pants::Writers::UDPWriter.new(ip, port, channel)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#start" do
|
16
|
+
let(:starter) do
|
17
|
+
s = double "EventMachine::Callback"
|
18
|
+
s.should_receive(:call)
|
19
|
+
|
20
|
+
s
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:tick_loop) do
|
24
|
+
t = double "EventMachine::TickLoop"
|
25
|
+
t.should_receive(:on_stop).and_yield
|
26
|
+
|
27
|
+
t
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
subject.stub(:starter).and_return(starter)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "opens a datagram socket on 0.0.0.0 then calls succeed on the starter" do
|
35
|
+
EventMachine.should_receive(:defer).and_yield
|
36
|
+
EventMachine.should_receive(:open_datagram_socket).with(
|
37
|
+
'0.0.0.0', 0, Pants::Writers::UDPWriterConnection, channel, ip, port
|
38
|
+
).and_return(true)
|
39
|
+
EventMachine.should_receive(:tick_loop).and_yield.and_return(tick_loop)
|
40
|
+
|
41
|
+
subject.start
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#stop" do
|
46
|
+
let(:connection) do
|
47
|
+
c = double "EventMachine::Connection"
|
48
|
+
c.should_receive(:close_connection_after_writing)
|
49
|
+
|
50
|
+
c
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:stopper) do
|
54
|
+
s = double "EventMachine::Callback"
|
55
|
+
s.should_receive(:call)
|
56
|
+
|
57
|
+
s
|
58
|
+
end
|
59
|
+
|
60
|
+
before do
|
61
|
+
subject.instance_variable_set(:@connection, connection)
|
62
|
+
subject.stub(:stopper).and_return(stopper)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "closes the socket and calls succeed on the stopper" do
|
66
|
+
subject.stop
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Pants::Writers::UDPWriterConnection do
|
72
|
+
let(:channel) { EventMachine::Channel.new }
|
73
|
+
let(:port) { 1234 }
|
74
|
+
let(:ip) { '127.0.0.1' }
|
75
|
+
|
76
|
+
subject do
|
77
|
+
Pants::Writers::UDPWriterConnection.new(1, channel, ip, port)
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#initialize" do
|
81
|
+
before do
|
82
|
+
Pants::Writers::UDPWriterConnection.any_instance.stub(:post_init)
|
83
|
+
end
|
84
|
+
|
85
|
+
context "multicast IP address" do
|
86
|
+
let(:ip) { '224.0.0.1' }
|
87
|
+
|
88
|
+
it "sets up the socket to do multicast" do
|
89
|
+
Pants::Writers::UDPWriterConnection.any_instance.
|
90
|
+
should_receive(:setup_multicast_socket).with(ip)
|
91
|
+
|
92
|
+
Pants::Writers::UDPWriterConnection.new(0, channel, ip, port)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "unicast IP address" do
|
97
|
+
let(:ip) { '223.0.0.1' }
|
98
|
+
|
99
|
+
it "does not set up the socket to do multicast" do
|
100
|
+
Pants::Writers::UDPWriterConnection.any_instance.
|
101
|
+
should_not_receive(:setup_multicast_socket)
|
102
|
+
|
103
|
+
Pants::Writers::UDPWriterConnection.new(0, channel, ip, port)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#post_init" do
|
109
|
+
around(:each) do |example|
|
110
|
+
EM.run do
|
111
|
+
example.run
|
112
|
+
EM.stop
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
before do
|
117
|
+
channel.should_receive(:subscribe).and_yield(data).and_call_original
|
118
|
+
end
|
119
|
+
|
120
|
+
context "data is bigger than PACKET_SPLIT_THRESHOLD" do
|
121
|
+
let(:data) do
|
122
|
+
"0" * Pants::Writers::UDPWriterConnection::PACKET_SPLIT_THRESHOLD * split_count
|
123
|
+
end
|
124
|
+
|
125
|
+
let(:split_count) { 3 }
|
126
|
+
|
127
|
+
it "splits the data by PACKET_SPLIT_SIZE and sends each chunk" do
|
128
|
+
subject.should_receive(:send_datagram).exactly(split_count + 1).times
|
129
|
+
channel << data
|
130
|
+
subject
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "data is smaller than PACKET_SPLIT_THRESHOLD" do
|
135
|
+
let(:data) do
|
136
|
+
"0" * 100
|
137
|
+
end
|
138
|
+
|
139
|
+
it "sends the data as it is" do
|
140
|
+
subject.should_receive(:send_datagram).once.with(data, ip, port)
|
141
|
+
channel << data
|
142
|
+
subject
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'benchmark'
|
5
|
+
require './lib/pants'
|
6
|
+
require 'bundler/setup'
|
7
|
+
|
8
|
+
|
9
|
+
class Pantsmark < Thor
|
10
|
+
desc "file_copy [FILE]", "Copies [FILE] --times number of times and benchmarks it"
|
11
|
+
method_option :times, type: :numeric, :default => 100
|
12
|
+
def file_copy(file_path)
|
13
|
+
Benchmark.bm do |x|
|
14
|
+
Pants.log = false
|
15
|
+
|
16
|
+
x.report("\tpants:") do
|
17
|
+
Pants.read(file_path) do |tee|
|
18
|
+
options[:times].times do |i|
|
19
|
+
tee.write_to("pants_test#{i}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
options[:times].times do |i|
|
25
|
+
result = %x[diff "#{file_path}" pants_test#{i}]
|
26
|
+
puts "Diff result: #{result}" unless result.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
x.report(" FileUtils.cp:") do
|
30
|
+
threads = []
|
31
|
+
|
32
|
+
options[:times].times do |i|
|
33
|
+
threads << Thread.new do
|
34
|
+
FileUtils.cp('pants_test1', "fu_cp_test#{i}")
|
35
|
+
end
|
36
|
+
|
37
|
+
threads.last.join
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
x.report(" cp:") do
|
42
|
+
threads = []
|
43
|
+
|
44
|
+
options[:times].times do |i|
|
45
|
+
threads << Thread.new do
|
46
|
+
`cp pants_test1 cp_test#{i}`
|
47
|
+
end
|
48
|
+
|
49
|
+
threads.last.join
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
rescue
|
54
|
+
FileUtils.rm_rf(Dir["./pants_test*"])
|
55
|
+
FileUtils.rm_rf(Dir["./fu_cp_test*"])
|
56
|
+
FileUtils.rm_rf(Dir["./cp_test*"])
|
57
|
+
|
58
|
+
raise
|
59
|
+
ensure
|
60
|
+
FileUtils.rm_rf(Dir["./pants_test*"])
|
61
|
+
FileUtils.rm_rf(Dir["./fu_cp_test*"])
|
62
|
+
FileUtils.rm_rf(Dir["./cp_test*"])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Pantsmark.start
|
data/test_readers.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative './lib/pants'
|
2
|
+
|
3
|
+
|
4
|
+
Pants.log = true
|
5
|
+
|
6
|
+
#EM.threadpool_size = 200
|
7
|
+
#EM.kqueue
|
8
|
+
#EM.epoll
|
9
|
+
|
10
|
+
orig_file = 'spec/support/pants.wav'
|
11
|
+
dest_file = 'dest_test_file'
|
12
|
+
#Pants.read('udp://127.0.0.1:1234') do |reader|
|
13
|
+
Pants.read(orig_file) do |reader|
|
14
|
+
10.times do |i|
|
15
|
+
reader.add_writer(dest_file)
|
16
|
+
reader.add_writer("udp://127.0.0.1:#{1235 + i}")
|
17
|
+
end
|
18
|
+
reader.add_writer('udp://10.221.222.90:9000')
|
19
|
+
end
|
20
|
+
|
21
|
+
if defined? orig_file
|
22
|
+
pants_file_size = File.stat(dest_file).size
|
23
|
+
orig_file_size = File.stat(orig_file).size
|
24
|
+
puts "Pants file size: #{pants_file_size}"
|
25
|
+
puts "Original file size: #{orig_file_size}"
|
26
|
+
puts "Difference: #{orig_file_size - pants_file_size}"
|
27
|
+
end
|
28
|
+
|
29
|
+
#==============
|
30
|
+
core = Pants::Core.new
|
31
|
+
udp_reader = core.read 'udp://127.0.0.1:1234'
|
32
|
+
udp_reader.write_to 'udp://127.0.0.1:1235'
|
33
|
+
|
34
|
+
udp_reader2 = core.add_reader(Pants::Readers::UDPReader, '127.0.0.1', 1234)
|
35
|
+
udp_reader2.add_writer(Pants::Writers::UDPWriter, '127.0.0.1', 1235)
|
36
|
+
|
37
|
+
udp_reader3 = Pants::Readers::UDPReader.new('127.0.0.1', 1234, core.callback)
|
38
|
+
udp_writer3 = Pants::Writers::UDPWriter.new('127.0.0.1', 1235, udp_reader3.write_to_channel)
|
39
|
+
core.add_reader(udp_reader3)
|
40
|
+
udp_reader3.add_writer(udp_writer3)
|
41
|
+
|
42
|
+
seam = udp_reader.add_seam(Pants::SimpleSeam)
|
43
|
+
seam.write_to 'my_file'
|