pantry 0.0.0 → 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.
- checksums.yaml +4 -4
- data/.gitignore +9 -0
- data/.ruby-version +1 -0
- data/.travis.yml +19 -0
- data/Gemfile +15 -0
- data/Guardfile +16 -0
- data/LICENSE +20 -0
- data/README.md +53 -0
- data/Rakefile +18 -0
- data/Vagrantfile +86 -0
- data/bin/pantry +11 -0
- data/bin/pantry-client +38 -0
- data/bin/pantry-server +33 -0
- data/dist/client.yml +79 -0
- data/dist/server.yml +56 -0
- data/dist/upstart/pantry-client.conf +12 -0
- data/dist/upstart/pantry-server.conf +12 -0
- data/doc/message_packet.dot +19 -0
- data/doc/message_packet.dot.png +0 -0
- data/doc/network_topology.dot +42 -0
- data/doc/network_topology.dot.png +0 -0
- data/lib/celluloid_zmq_patches.rb +16 -0
- data/lib/opt_parse_plus.rb +184 -0
- data/lib/pantry.rb +197 -0
- data/lib/pantry/cli.rb +154 -0
- data/lib/pantry/client.rb +131 -0
- data/lib/pantry/client_info.rb +34 -0
- data/lib/pantry/client_registry.rb +104 -0
- data/lib/pantry/command.rb +194 -0
- data/lib/pantry/command_handler.rb +53 -0
- data/lib/pantry/command_line.rb +115 -0
- data/lib/pantry/commands/create_client.rb +30 -0
- data/lib/pantry/commands/download_directory.rb +35 -0
- data/lib/pantry/commands/echo.rb +32 -0
- data/lib/pantry/commands/edit_application.rb +60 -0
- data/lib/pantry/commands/register_client.rb +38 -0
- data/lib/pantry/commands/status.rb +78 -0
- data/lib/pantry/commands/sync_directory.rb +50 -0
- data/lib/pantry/commands/update_application.rb +45 -0
- data/lib/pantry/commands/upload_file.rb +68 -0
- data/lib/pantry/communication.rb +20 -0
- data/lib/pantry/communication/client.rb +75 -0
- data/lib/pantry/communication/client_filter.rb +117 -0
- data/lib/pantry/communication/file_service.rb +125 -0
- data/lib/pantry/communication/file_service/file_progress.rb +164 -0
- data/lib/pantry/communication/file_service/receive_file.rb +97 -0
- data/lib/pantry/communication/file_service/send_file.rb +74 -0
- data/lib/pantry/communication/publish_socket.rb +20 -0
- data/lib/pantry/communication/reading_socket.rb +89 -0
- data/lib/pantry/communication/receive_socket.rb +23 -0
- data/lib/pantry/communication/security.rb +44 -0
- data/lib/pantry/communication/security/authentication.rb +98 -0
- data/lib/pantry/communication/security/curve_key_store.rb +120 -0
- data/lib/pantry/communication/security/curve_security.rb +70 -0
- data/lib/pantry/communication/security/null_security.rb +32 -0
- data/lib/pantry/communication/send_socket.rb +19 -0
- data/lib/pantry/communication/serialize_message.rb +84 -0
- data/lib/pantry/communication/server.rb +97 -0
- data/lib/pantry/communication/subscribe_socket.rb +33 -0
- data/lib/pantry/communication/wait_list.rb +45 -0
- data/lib/pantry/communication/writing_socket.rb +46 -0
- data/lib/pantry/config.rb +182 -0
- data/lib/pantry/file_editor.rb +67 -0
- data/lib/pantry/logger.rb +78 -0
- data/lib/pantry/message.rb +134 -0
- data/lib/pantry/multi_command.rb +36 -0
- data/lib/pantry/server.rb +132 -0
- data/lib/pantry/test/acceptance.rb +83 -0
- data/lib/pantry/test/support/fake_fs.rb +31 -0
- data/lib/pantry/test/support/matchers.rb +13 -0
- data/lib/pantry/test/support/minitest.rb +13 -0
- data/lib/pantry/test/support/mock_ui.rb +23 -0
- data/lib/pantry/test/unit.rb +13 -0
- data/lib/pantry/ui.rb +68 -0
- data/lib/pantry/version.rb +3 -0
- data/pantry.gemspec +40 -0
- data/test/acceptance/cli/error_handling_test.rb +7 -0
- data/test/acceptance/cli/execute_command_on_clients_test.rb +32 -0
- data/test/acceptance/cli/request_info_from_server_test.rb +44 -0
- data/test/acceptance/communication/client_requests_info_from_server_test.rb +28 -0
- data/test/acceptance/communication/heartbeat_test.rb +19 -0
- data/test/acceptance/communication/pub_sub_communication_test.rb +53 -0
- data/test/acceptance/communication/security_test.rb +117 -0
- data/test/acceptance/communication/server_requests_info_from_client_test.rb +41 -0
- data/test/acceptance/test_helper.rb +25 -0
- data/test/fixtures/config.yml +22 -0
- data/test/fixtures/empty.yml +2 -0
- data/test/fixtures/file_to_upload +3 -0
- data/test/root_dir/.gitkeep +0 -0
- data/test/unit/cli_test.rb +173 -0
- data/test/unit/client_registry_test.rb +61 -0
- data/test/unit/client_test.rb +128 -0
- data/test/unit/command_handler_test.rb +79 -0
- data/test/unit/command_line_test.rb +5 -0
- data/test/unit/command_test.rb +206 -0
- data/test/unit/commands/create_client_test.rb +25 -0
- data/test/unit/commands/download_directory_test.rb +58 -0
- data/test/unit/commands/echo_test.rb +22 -0
- data/test/unit/commands/edit_application_test.rb +84 -0
- data/test/unit/commands/register_client_test.rb +41 -0
- data/test/unit/commands/status_test.rb +81 -0
- data/test/unit/commands/sync_directory_test.rb +75 -0
- data/test/unit/commands/update_application_test.rb +35 -0
- data/test/unit/commands/upload_file_test.rb +51 -0
- data/test/unit/communication/client_filter_test.rb +262 -0
- data/test/unit/communication/client_test.rb +99 -0
- data/test/unit/communication/file_service/receive_file_test.rb +214 -0
- data/test/unit/communication/file_service/send_file_test.rb +110 -0
- data/test/unit/communication/file_service_test.rb +56 -0
- data/test/unit/communication/publish_socket_test.rb +19 -0
- data/test/unit/communication/reading_socket_test.rb +110 -0
- data/test/unit/communication/receive_socket_test.rb +20 -0
- data/test/unit/communication/security/authentication_test.rb +97 -0
- data/test/unit/communication/security/curve_key_store_test.rb +110 -0
- data/test/unit/communication/security/curve_security_test.rb +44 -0
- data/test/unit/communication/security/null_security_test.rb +15 -0
- data/test/unit/communication/security_test.rb +49 -0
- data/test/unit/communication/send_socket_test.rb +19 -0
- data/test/unit/communication/serialize_message_test.rb +128 -0
- data/test/unit/communication/server_test.rb +106 -0
- data/test/unit/communication/subscribe_socket_test.rb +46 -0
- data/test/unit/communication/wait_list_test.rb +60 -0
- data/test/unit/communication/writing_socket_test.rb +46 -0
- data/test/unit/config_test.rb +150 -0
- data/test/unit/logger_test.rb +79 -0
- data/test/unit/message_test.rb +179 -0
- data/test/unit/multi_command_test.rb +45 -0
- data/test/unit/opt_parse_plus_test.rb +218 -0
- data/test/unit/pantry_test.rb +82 -0
- data/test/unit/server_test.rb +166 -0
- data/test/unit/test_helper.rb +25 -0
- data/test/unit/ui_test.rb +58 -0
- metadata +389 -13
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
require 'unit/test_helper'
|
|
2
|
+
|
|
3
|
+
describe Pantry::Communication::Client do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
Pantry::Communication::SubscribeSocket.any_instance.stubs(:open)
|
|
7
|
+
Pantry::Communication::SendSocket.any_instance.stubs(:open)
|
|
8
|
+
|
|
9
|
+
Pantry::Communication::FileService.any_instance.stubs(:start_client)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "sets up a subscribe socket for communication" do
|
|
13
|
+
pantry_client = Pantry::Client.new
|
|
14
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
15
|
+
|
|
16
|
+
Pantry::Communication::SubscribeSocket.any_instance.expects(:add_listener).with(client)
|
|
17
|
+
Pantry::Communication::SubscribeSocket.any_instance.expects(:open)
|
|
18
|
+
|
|
19
|
+
client.run
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "configures filtering if the client has been given a scope" do
|
|
23
|
+
pantry_client = Pantry::Client.new(
|
|
24
|
+
application: "pantry", environment: "test",
|
|
25
|
+
roles: %w(application database), identity: "client2"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
29
|
+
|
|
30
|
+
Pantry::Communication::SubscribeSocket.any_instance.stubs(:add_listener)
|
|
31
|
+
Pantry::Communication::SubscribeSocket.any_instance.stubs(:open)
|
|
32
|
+
|
|
33
|
+
Pantry::Communication::SubscribeSocket.any_instance.expects(:filter_on).with(
|
|
34
|
+
Pantry::Communication::ClientFilter.new(
|
|
35
|
+
application: "pantry", environment: "test", roles: %w(application database),
|
|
36
|
+
identity: "client2"
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
client.run
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "sets up a Send socket for communication" do
|
|
44
|
+
pantry_client = Pantry::Client.new
|
|
45
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
46
|
+
|
|
47
|
+
Pantry::Communication::SendSocket.any_instance.expects(:open)
|
|
48
|
+
|
|
49
|
+
client.run
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "starts up a local file service" do
|
|
53
|
+
pantry_client = Pantry::Client.new
|
|
54
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
55
|
+
|
|
56
|
+
Pantry::Communication::FileService.any_instance.expects(:start_client)
|
|
57
|
+
|
|
58
|
+
client.run
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "sends messages through the Send socket back to the server" do
|
|
62
|
+
pantry_client = Pantry::Client.new
|
|
63
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
64
|
+
message = Pantry::Message.new("message")
|
|
65
|
+
|
|
66
|
+
Pantry::Communication::SendSocket.any_instance.expects(:send_message).with(message)
|
|
67
|
+
|
|
68
|
+
client.run
|
|
69
|
+
client.send_message(message)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "sets the source of the message to the current listener" do
|
|
73
|
+
pantry_client = Pantry::Client.new
|
|
74
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
75
|
+
message = Pantry::Message.new("message")
|
|
76
|
+
|
|
77
|
+
Pantry::Communication::SendSocket.any_instance.expects(:send_message).with do |message|
|
|
78
|
+
message.from == pantry_client.identity
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
client.run
|
|
82
|
+
client.send_message(message)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "sends a request to the server, returning a future" do
|
|
86
|
+
pantry_client = Pantry::Client.new
|
|
87
|
+
client = Pantry::Communication::Client.new(pantry_client)
|
|
88
|
+
client.run
|
|
89
|
+
|
|
90
|
+
message = Pantry::Message.new("message")
|
|
91
|
+
Pantry::Communication::SendSocket.any_instance.expects(:send_message).with(message)
|
|
92
|
+
|
|
93
|
+
future = client.send_request(message)
|
|
94
|
+
|
|
95
|
+
assert_not_nil future
|
|
96
|
+
assert_false future.ready?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
require 'unit/test_helper'
|
|
2
|
+
|
|
3
|
+
describe Pantry::Communication::FileService::ReceiveFile do
|
|
4
|
+
|
|
5
|
+
class FakeReceiveService
|
|
6
|
+
attr_accessor :sent
|
|
7
|
+
def initialize
|
|
8
|
+
@sent = []
|
|
9
|
+
end
|
|
10
|
+
def send_message(identity, message)
|
|
11
|
+
@sent << {identity: identity, message: message}
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
let(:service) { FakeReceiveService.new }
|
|
16
|
+
let(:file_path) { fixture_path("file_to_upload") }
|
|
17
|
+
let(:receiver) { Pantry::Communication::FileService::ReceiveFile.new(service) }
|
|
18
|
+
|
|
19
|
+
def start_message(file_uuid)
|
|
20
|
+
Pantry::Message.new.tap do |msg|
|
|
21
|
+
msg.to = file_uuid
|
|
22
|
+
msg << "START"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def chunk(file_uuid, data = "binary data", offset: 0, size: 1_000)
|
|
27
|
+
Pantry::Message.new.tap do |msg|
|
|
28
|
+
msg.to = file_uuid
|
|
29
|
+
msg[:chunk_offset] = offset
|
|
30
|
+
msg[:chunk_size] = size
|
|
31
|
+
msg << "CHUNK"
|
|
32
|
+
msg << data
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "#receive_file" do
|
|
37
|
+
it "builds and returns file upload info when asked to receive a new file" do
|
|
38
|
+
info = receiver.receive_file(12_000, "abc123")
|
|
39
|
+
|
|
40
|
+
assert_not_nil info, "No info returned for the file info"
|
|
41
|
+
assert_equal 36, info.file_uuid.length
|
|
42
|
+
assert_equal 12_000, info.file_size
|
|
43
|
+
assert_equal "abc123", info.checksum
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "creates and returns a tempfile path where the upload will go" do
|
|
47
|
+
info = receiver.receive_file(12_000, "abc123")
|
|
48
|
+
|
|
49
|
+
assert_not_nil info.uploaded_path, "Did not give a file path where upload will live"
|
|
50
|
+
assert File.exists?(info.uploaded_path), "Did not create a tempfile for the upload"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "waits for a start message from the sender then sends initial chunk requests" do
|
|
55
|
+
info = receiver.receive_file(5_000_000, "checksum")
|
|
56
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
57
|
+
|
|
58
|
+
pipeline_size = receiver.pipeline_size
|
|
59
|
+
chunk_size = receiver.chunk_size
|
|
60
|
+
|
|
61
|
+
assert_equal pipeline_size, service.sent.length
|
|
62
|
+
|
|
63
|
+
service.sent.each_with_index do |msg, i|
|
|
64
|
+
assert_equal info.file_uuid, msg[:message].to, "Message #{i} did not set the to field properly"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
assert_equal "sender_ident", info.sender_uuid
|
|
68
|
+
|
|
69
|
+
assert_equal "sender_ident", service.sent[0][:identity]
|
|
70
|
+
assert_equal "sender_ident", service.sent[1][:identity]
|
|
71
|
+
assert_equal "sender_ident", service.sent[2][:identity]
|
|
72
|
+
|
|
73
|
+
assert_equal ["FETCH", 0, chunk_size], service.sent[0][:message].body
|
|
74
|
+
assert_equal ["FETCH", chunk_size, chunk_size], service.sent[1][:message].body
|
|
75
|
+
assert_equal ["FETCH", chunk_size * 2, chunk_size], service.sent[2][:message].body
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "writes out received chunks to the given save file path" do
|
|
79
|
+
info = receiver.receive_file(
|
|
80
|
+
File.size(file_path),
|
|
81
|
+
"9cb63cb779e8c571db3199b783a36cc43cd9e7c076beeb496c39e9cc06196dc5"
|
|
82
|
+
)
|
|
83
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
84
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
85
|
+
|
|
86
|
+
assert_equal "binary data", File.read(info.uploaded_path)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "keeps a certain number of chunk requests in the pipeline" do
|
|
90
|
+
info = receiver.receive_file(5_000_000, "checksum")
|
|
91
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
92
|
+
service.sent = []
|
|
93
|
+
|
|
94
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
95
|
+
|
|
96
|
+
# We've already requested 10 chunks. Having received one chunk we request the 11th (0-based)
|
|
97
|
+
assert_equal 1, service.sent.length
|
|
98
|
+
assert_equal ["FETCH", receiver.chunk_size * 10, receiver.chunk_size], service.sent[0][:message].body
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "doesn't add to the pipeline when the last chunk has been requested" do
|
|
102
|
+
info = receiver.receive_file(500_000, "checksum")
|
|
103
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
104
|
+
service.sent = []
|
|
105
|
+
|
|
106
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
107
|
+
assert_equal 0, service.sent.length
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "sends the finished message to the client when the file upload is successful" do
|
|
111
|
+
info = receiver.receive_file(
|
|
112
|
+
File.size(file_path),
|
|
113
|
+
"9cb63cb779e8c571db3199b783a36cc43cd9e7c076beeb496c39e9cc06196dc5"
|
|
114
|
+
)
|
|
115
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
116
|
+
service.sent = []
|
|
117
|
+
|
|
118
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
119
|
+
|
|
120
|
+
assert_equal 1, service.sent.length
|
|
121
|
+
assert_equal info.file_uuid, service.sent[0][:message].to
|
|
122
|
+
assert_equal ["FINISH"], service.sent[0][:message].body
|
|
123
|
+
|
|
124
|
+
assert info.finished?, "Did not mark info object as finished"
|
|
125
|
+
assert_not_nil info.wait_for_finish(1)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "triggers a completion block when the file has been fully uploaded" do
|
|
129
|
+
info = receiver.receive_file(
|
|
130
|
+
File.size(file_path),
|
|
131
|
+
"9cb63cb779e8c571db3199b783a36cc43cd9e7c076beeb496c39e9cc06196dc5"
|
|
132
|
+
)
|
|
133
|
+
completion_called = false
|
|
134
|
+
info.on_complete do
|
|
135
|
+
completion_called = true
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Finish the file
|
|
139
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
140
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
141
|
+
|
|
142
|
+
info.wait_for_finish(1)
|
|
143
|
+
|
|
144
|
+
assert completion_called, "The completion block was not called"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "does not trigger completion block on a failed upload" do
|
|
148
|
+
info = receiver.receive_file(File.size(file_path), "bad-checksum")
|
|
149
|
+
completion_called = false
|
|
150
|
+
info.on_complete do
|
|
151
|
+
completion_called = true
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Finish the file
|
|
155
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
156
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
157
|
+
|
|
158
|
+
info.wait_for_finish(1)
|
|
159
|
+
|
|
160
|
+
assert_false completion_called, "The completion block was called when it shouldn't have"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "does not fall over if the completion block throws an error" do
|
|
164
|
+
info = receiver.receive_file(
|
|
165
|
+
File.size(file_path),
|
|
166
|
+
"9cb63cb779e8c571db3199b783a36cc43cd9e7c076beeb496c39e9cc06196dc5"
|
|
167
|
+
)
|
|
168
|
+
info.on_complete do
|
|
169
|
+
raise "This is an error zomg"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Finish the file
|
|
173
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
174
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
175
|
+
|
|
176
|
+
info.wait_for_finish(1)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "fails and deletes the file if the checksum does not match after upload complete" do
|
|
180
|
+
info = receiver.receive_file(File.size(file_path), "invalid")
|
|
181
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
182
|
+
service.sent = []
|
|
183
|
+
|
|
184
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid))
|
|
185
|
+
|
|
186
|
+
assert_false File.exists?(info.uploaded_path)
|
|
187
|
+
|
|
188
|
+
error_message = service.sent[0][:message]
|
|
189
|
+
assert_not_nil error_message
|
|
190
|
+
assert_equal info.file_uuid, error_message.to
|
|
191
|
+
assert_equal "ERROR", error_message.body[0]
|
|
192
|
+
assert_equal "Checksum did not match the uploaded file", error_message.body[1]
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "supports receiving file data chunks out-of-order" do
|
|
196
|
+
receiver.chunk_size = 5
|
|
197
|
+
info = receiver.receive_file(
|
|
198
|
+
13, "c30facc0146cfaf7e64fea5399ccb2707a060c2d739218a1f3b20b15b8d6e89d"
|
|
199
|
+
)
|
|
200
|
+
receiver.receive_message("sender_ident", start_message(info.file_uuid))
|
|
201
|
+
service.sent = []
|
|
202
|
+
|
|
203
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid, "ry!", offset: 10, size: 3))
|
|
204
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid, "Hello", offset: 0, size: 5))
|
|
205
|
+
receiver.receive_message("sender_ident", chunk(info.file_uuid, " Pant", offset: 5, size: 5))
|
|
206
|
+
|
|
207
|
+
success_message = service.sent[0][:message]
|
|
208
|
+
assert_equal "FINISH", success_message.body[0]
|
|
209
|
+
|
|
210
|
+
assert File.exists?(info.uploaded_path), "File was baleted?!"
|
|
211
|
+
assert_equal "Hello Pantry!", File.read(info.uploaded_path)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'unit/test_helper'
|
|
2
|
+
|
|
3
|
+
describe Pantry::Communication::FileService::SendFile do
|
|
4
|
+
|
|
5
|
+
mock_ui!
|
|
6
|
+
|
|
7
|
+
class FakeSendService
|
|
8
|
+
attr_accessor :sent
|
|
9
|
+
def initialize
|
|
10
|
+
@sent = []
|
|
11
|
+
end
|
|
12
|
+
def send_message(identity, message)
|
|
13
|
+
@sent << {identity: identity, message: message}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
let(:service) { FakeSendService.new }
|
|
18
|
+
let(:file_path) { fixture_path("file_to_upload") }
|
|
19
|
+
let(:sender) { Pantry::Communication::FileService::SendFile.new(service) }
|
|
20
|
+
|
|
21
|
+
def fetch(uuid, seek, size)
|
|
22
|
+
chunk = Pantry::Message.new
|
|
23
|
+
chunk.to = uuid
|
|
24
|
+
chunk << "FETCH"
|
|
25
|
+
chunk << seek.to_s
|
|
26
|
+
chunk << size.to_s
|
|
27
|
+
chunk
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "#send_file" do
|
|
31
|
+
it "opens the file and sends the receiver the START command" do
|
|
32
|
+
sender.send_file(file_path, "receiver_ident", "file_uuid")
|
|
33
|
+
|
|
34
|
+
assert_equal 1, service.sent.length
|
|
35
|
+
|
|
36
|
+
start_message = service.sent[0]
|
|
37
|
+
assert_equal "receiver_ident", start_message[:identity]
|
|
38
|
+
assert_equal "file_uuid", start_message[:message].to
|
|
39
|
+
assert_equal "START", start_message[:message].body[0]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "returns a sending info object for callers to use" do
|
|
43
|
+
info = sender.send_file(file_path, "receiver_ident", "file_uuid")
|
|
44
|
+
|
|
45
|
+
assert_not_nil info
|
|
46
|
+
assert_equal file_path, info.path
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "reads the requested chunk of file and sends it along to the receiver" do
|
|
51
|
+
sender.send_file(file_path, "receiver", "file_uuid")
|
|
52
|
+
service.sent = []
|
|
53
|
+
|
|
54
|
+
sender.receive_message("receiver", fetch("file_uuid", 0, 5))
|
|
55
|
+
|
|
56
|
+
assert_equal 1, service.sent.length
|
|
57
|
+
|
|
58
|
+
chunk_data = service.sent[0][:message]
|
|
59
|
+
|
|
60
|
+
assert_equal "file_uuid", chunk_data.to
|
|
61
|
+
assert_equal "CHUNK", chunk_data.body[0]
|
|
62
|
+
assert_equal "Hello", chunk_data.body[1]
|
|
63
|
+
assert_equal 0, chunk_data[:chunk_offset]
|
|
64
|
+
assert_equal 5, chunk_data[:chunk_size]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "supports sending multiple files at a time (keyed by UUID)" do
|
|
68
|
+
sender.send_file(file_path, "receiver", "uuid1")
|
|
69
|
+
sender.send_file(file_path, "receiver", "uuid2")
|
|
70
|
+
sender.send_file(file_path, "receiver", "uuid3")
|
|
71
|
+
service.sent = []
|
|
72
|
+
|
|
73
|
+
sender.receive_message("receiver", fetch("uuid1", 0, 1))
|
|
74
|
+
sender.receive_message("receiver", fetch("uuid2", 1, 1))
|
|
75
|
+
sender.receive_message("receiver", fetch("uuid3", 2, 1))
|
|
76
|
+
|
|
77
|
+
assert_equal "uuid1", service.sent[0][:message].to
|
|
78
|
+
assert_equal "H", service.sent[0][:message].body[1]
|
|
79
|
+
|
|
80
|
+
assert_equal "uuid2", service.sent[1][:message].to
|
|
81
|
+
assert_equal "e", service.sent[1][:message].body[1]
|
|
82
|
+
|
|
83
|
+
assert_equal "uuid3", service.sent[2][:message].to
|
|
84
|
+
assert_equal "l", service.sent[2][:message].body[1]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "ignores FETCH requests of an unknown uuid" do
|
|
88
|
+
sender.receive_message("receiver", fetch("uuid1", 0, 1))
|
|
89
|
+
assert_equal 0, service.sent.length
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "closes up the file associated with the UUID on FINISH and notifies info" do
|
|
93
|
+
info = sender.send_file(file_path, "receiver", "uuid")
|
|
94
|
+
|
|
95
|
+
finish = Pantry::Message.new
|
|
96
|
+
finish.to = "uuid"
|
|
97
|
+
finish << "FINISH"
|
|
98
|
+
|
|
99
|
+
sender.receive_message("receiver", finish)
|
|
100
|
+
|
|
101
|
+
# See that further requests to this UUID are dropped
|
|
102
|
+
service.sent = []
|
|
103
|
+
sender.receive_message("receiver", fetch("uuid", 0, 1))
|
|
104
|
+
assert_equal [], service.sent
|
|
105
|
+
|
|
106
|
+
assert info.finished?, "Info object was not finished"
|
|
107
|
+
assert_not_nil info.wait_for_finish(1)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'unit/test_helper'
|
|
2
|
+
|
|
3
|
+
describe Pantry::Communication::FileService do
|
|
4
|
+
|
|
5
|
+
let(:security) { Pantry::Communication::Security::NullSecurity.new }
|
|
6
|
+
let(:file_service) { Pantry::Communication::FileService.new("host", "port", security) }
|
|
7
|
+
|
|
8
|
+
describe "#start_server" do
|
|
9
|
+
it "binds to the host/port when starting on the server" do
|
|
10
|
+
Celluloid::ZMQ::RouterSocket.any_instance.expects(:bind).with("tcp://host:port")
|
|
11
|
+
|
|
12
|
+
file_service.start_server
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "has the current security handler configure sockets" do
|
|
16
|
+
Celluloid::ZMQ::RouterSocket.any_instance.stubs(:bind)
|
|
17
|
+
security.expects(:configure_socket)
|
|
18
|
+
|
|
19
|
+
file_service.start_server
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe "#start_client" do
|
|
24
|
+
it "connects to the known server when starting on the client" do
|
|
25
|
+
Celluloid::ZMQ::RouterSocket.any_instance.expects(:connect).with("tcp://host:port")
|
|
26
|
+
|
|
27
|
+
file_service.start_client
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "has the current security handler configure sockets" do
|
|
31
|
+
Celluloid::ZMQ::RouterSocket.any_instance.stubs(:connect)
|
|
32
|
+
security.expects(:configure_socket)
|
|
33
|
+
|
|
34
|
+
file_service.start_client
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "builds receive-file information, setting the current socket's identity" do
|
|
39
|
+
info = file_service.receive_file(100, "checksum")
|
|
40
|
+
|
|
41
|
+
assert_not_nil info
|
|
42
|
+
assert_equal file_service.identity, info.receiver_uuid
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "sends a message to a specific identity" do
|
|
46
|
+
message = Pantry::Message.new
|
|
47
|
+
identity = "123abc"
|
|
48
|
+
|
|
49
|
+
Celluloid::ZMQ::RouterSocket.any_instance.expects(:write).with do |message|
|
|
50
|
+
assert_equal message[0], "123abc"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
file_service.send_message(identity, message)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|