pantry 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,78 @@
|
|
1
|
+
module Pantry
|
2
|
+
|
3
|
+
# Access Pantry's logger.
|
4
|
+
def self.logger
|
5
|
+
@@logger ||= Pantry::Logger.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.logger=(logger)
|
9
|
+
@@logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
# Wrapper around the Celluloid's logging system. Depending on the passed in
|
13
|
+
# config, will send to STDOUT, Syslog, or a given file.
|
14
|
+
# See Celluloid::Logger for API (should be the same as Ruby's Logger API)
|
15
|
+
class Logger
|
16
|
+
|
17
|
+
def initialize(config = Pantry.config)
|
18
|
+
logger =
|
19
|
+
if config.log_to.nil? || config.log_to == "stdout"
|
20
|
+
::Logger.new(STDOUT)
|
21
|
+
elsif config.log_to == "syslog"
|
22
|
+
::Syslog::Logger.new(config.syslog_program_name)
|
23
|
+
else
|
24
|
+
::Logger.new(config.log_to)
|
25
|
+
end
|
26
|
+
|
27
|
+
logger.level = log_level(config.log_level)
|
28
|
+
Celluloid.logger = logger
|
29
|
+
end
|
30
|
+
|
31
|
+
# Turn off all logging entirely
|
32
|
+
def disable!
|
33
|
+
Celluloid.logger = NullLogger.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# Forward all methods on to the internal Celluloid Logger.
|
37
|
+
def method_missing(*args)
|
38
|
+
Celluloid.logger.send(*args) if Celluloid.logger
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def log_level(log_level_string)
|
44
|
+
case log_level_string.to_s
|
45
|
+
when "debug"
|
46
|
+
::Logger::DEBUG
|
47
|
+
when "info"
|
48
|
+
::Logger::INFO
|
49
|
+
when "warn"
|
50
|
+
::Logger::WARN
|
51
|
+
when "error"
|
52
|
+
::Logger::ERROR
|
53
|
+
when "fatal"
|
54
|
+
::Logger::FATAL
|
55
|
+
else
|
56
|
+
raise "Unknown log level given: #{log_level_string}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
# Because Celluloid tries to log things on shut-down that throw
|
63
|
+
# tons of exceptions if the logger is nil
|
64
|
+
class NullLogger
|
65
|
+
def debug(*args)
|
66
|
+
end
|
67
|
+
|
68
|
+
def info(*args)
|
69
|
+
end
|
70
|
+
|
71
|
+
def warn(*args)
|
72
|
+
end
|
73
|
+
|
74
|
+
def error(*args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Pantry
|
2
|
+
|
3
|
+
# A Message is the container for all network communication between Clients and Servers.
|
4
|
+
# Messages know what stream they've been sent down, have a type to differentiate them
|
5
|
+
# from each other, and an arbitrarily large body.
|
6
|
+
#
|
7
|
+
# Every message has three sections, the stream, metadata, and body. The stream defines
|
8
|
+
# where the message needs to go. The metadata defines information about the message, its
|
9
|
+
# type, if it needs a response, and anything else that doesn't go in the body.
|
10
|
+
# The body is the request message itself and can be one or many parts.
|
11
|
+
class Message
|
12
|
+
|
13
|
+
# Unique identifier for this Message. Automatically generated
|
14
|
+
attr_reader :uuid
|
15
|
+
|
16
|
+
# Where or who is this message intended for (Can be an identity or a stream)
|
17
|
+
# Defaults to the catch-all stream `""`
|
18
|
+
attr_accessor :to
|
19
|
+
|
20
|
+
# Who is this message coming from (Should be an identity)
|
21
|
+
attr_accessor :from
|
22
|
+
|
23
|
+
# What type of message are we?
|
24
|
+
attr_accessor :type
|
25
|
+
|
26
|
+
# The full, raw body of the message.
|
27
|
+
attr_accessor :body
|
28
|
+
|
29
|
+
attr_accessor :custom_metadata
|
30
|
+
|
31
|
+
attr_writer :requires_response
|
32
|
+
|
33
|
+
def initialize(message_type = nil)
|
34
|
+
@type = message_type
|
35
|
+
@body = []
|
36
|
+
@to = ""
|
37
|
+
|
38
|
+
@requires_response = false
|
39
|
+
@forwarded = false
|
40
|
+
|
41
|
+
@custom_metadata = {}
|
42
|
+
|
43
|
+
@uuid = SecureRandom.uuid
|
44
|
+
end
|
45
|
+
|
46
|
+
# Set the source of this message either by an object that responds to #identity
|
47
|
+
# or a string.
|
48
|
+
def from=(source)
|
49
|
+
if source.respond_to?(:identity)
|
50
|
+
@from = source.identity
|
51
|
+
else
|
52
|
+
@from = source
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def from_server?
|
57
|
+
@from == Pantry::SERVER_IDENTITY
|
58
|
+
end
|
59
|
+
|
60
|
+
# Flag this message as requiring a response
|
61
|
+
def requires_response!
|
62
|
+
@requires_response = true
|
63
|
+
end
|
64
|
+
|
65
|
+
# Does this message require a response message?
|
66
|
+
def requires_response?
|
67
|
+
@requires_response
|
68
|
+
end
|
69
|
+
|
70
|
+
# Has this message been forwarded through the Server?
|
71
|
+
# This flag is checked when the message comes back through the Server,
|
72
|
+
# which lets it know if the message needs to continue back to another Client.
|
73
|
+
def forwarded!
|
74
|
+
@forwarded = true
|
75
|
+
end
|
76
|
+
|
77
|
+
def forwarded?
|
78
|
+
@forwarded
|
79
|
+
end
|
80
|
+
|
81
|
+
# Set custom metadata on this message.
|
82
|
+
def []=(key, val)
|
83
|
+
@custom_metadata[key] = val
|
84
|
+
end
|
85
|
+
|
86
|
+
# Access value from the custom metadata
|
87
|
+
def [](key)
|
88
|
+
@custom_metadata[key]
|
89
|
+
end
|
90
|
+
|
91
|
+
# Build a copy of this message to use when responding
|
92
|
+
# to the message
|
93
|
+
def build_response
|
94
|
+
response = self.clone
|
95
|
+
response.body = []
|
96
|
+
response.to = self.from
|
97
|
+
response.from = self.to
|
98
|
+
response.requires_response = false
|
99
|
+
response.custom_metadata = self.custom_metadata.clone
|
100
|
+
response
|
101
|
+
end
|
102
|
+
|
103
|
+
# Add a message part to this Message's body
|
104
|
+
def <<(part)
|
105
|
+
@body << part
|
106
|
+
end
|
107
|
+
|
108
|
+
# Return all of this message's metadata as a hash
|
109
|
+
def metadata
|
110
|
+
{
|
111
|
+
:uuid => self.uuid,
|
112
|
+
:type => self.type,
|
113
|
+
:from => self.from,
|
114
|
+
:to => self.to || "",
|
115
|
+
:requires_response => self.requires_response?,
|
116
|
+
:forwarded => self.forwarded?,
|
117
|
+
:custom => @custom_metadata
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
# Given a hash, pull out the parts into local variables
|
122
|
+
def metadata=(hash)
|
123
|
+
@uuid = hash[:uuid]
|
124
|
+
@type = hash[:type]
|
125
|
+
@from = hash[:from]
|
126
|
+
@to = hash[:to] || ""
|
127
|
+
@requires_response = hash[:requires_response]
|
128
|
+
@forwarded = hash[:forwarded]
|
129
|
+
@custom_metadata = hash[:custom]
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Pantry
|
2
|
+
|
3
|
+
# A MultiCommand allows specifying multiple Commands to be run in succession.
|
4
|
+
# Each command class given in .performs will have it's #perform executed and
|
5
|
+
# the return values will be grouped together in a single return Message.
|
6
|
+
#
|
7
|
+
# It's currently expected that each Command executed is done when it's #perform
|
8
|
+
# returns.
|
9
|
+
class MultiCommand < Command
|
10
|
+
|
11
|
+
# MultiCommand.performs takes a list of Command class constants.
|
12
|
+
def self.performs(command_classes = [])
|
13
|
+
@command_classes = command_classes
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.command_classes
|
17
|
+
@command_classes
|
18
|
+
end
|
19
|
+
|
20
|
+
# Iterate through each Command class and run that Command with the
|
21
|
+
# given message. The results of each Command will be combined into a single
|
22
|
+
# array return value and thus a single response Message back to the requester.
|
23
|
+
def perform(message)
|
24
|
+
Pantry.logger.debug("[#{client.identity}] Running MultiCommands")
|
25
|
+
|
26
|
+
self.class.command_classes.map do |command_class|
|
27
|
+
Pantry.logger.debug("[#{client.identity}] Running #{command_class}")
|
28
|
+
command = command_class.new
|
29
|
+
command.server_or_client = server_or_client
|
30
|
+
command.perform(message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Pantry
|
2
|
+
|
3
|
+
# The Pantry Server.
|
4
|
+
class Server
|
5
|
+
include Celluloid
|
6
|
+
finalizer :shutdown
|
7
|
+
|
8
|
+
attr_accessor :identity
|
9
|
+
|
10
|
+
attr_reader :client_registry
|
11
|
+
|
12
|
+
def initialize(network_stack_class = Communication::Server)
|
13
|
+
@commands = CommandHandler.new(self, Pantry.server_commands)
|
14
|
+
@identity = current_hostname
|
15
|
+
@clients = []
|
16
|
+
|
17
|
+
@client_registry = ClientRegistry.new
|
18
|
+
|
19
|
+
@networking = network_stack_class.new_link(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Start up the networking stack and start the server
|
23
|
+
def run
|
24
|
+
Pantry.set_proc_title("pantry server #{Pantry::VERSION}")
|
25
|
+
@networking.run
|
26
|
+
Pantry.logger.info("[#{@identity}] Server running")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Close down networking and clean up resources
|
30
|
+
def shutdown
|
31
|
+
Pantry.logger.info("[#{@identity}] Server Shutting Down")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Mark an authenticated client as checked-in
|
35
|
+
def register_client(client)
|
36
|
+
Pantry.logger.info("[#{@identity}] Received client registration :: #{client.identity}")
|
37
|
+
@client_registry.check_in(client)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Generate new authentication credentials for a client.
|
41
|
+
# Returns a Hash containing the credentials required for the client to
|
42
|
+
# connect and authenticate with this Server
|
43
|
+
def create_client
|
44
|
+
@networking.create_client
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return ClientInfo on which Client sent the given Message
|
48
|
+
def client_who_sent(message)
|
49
|
+
@client_registry.find(message.from)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Broadcast a +message+ to all clients who match the given +filter+.
|
53
|
+
# By default all clients will be notified.
|
54
|
+
def publish_message(message, filter = Communication::ClientFilter.new)
|
55
|
+
Pantry.logger.debug("[#{@identity}] Publishing #{message.inspect} to #{filter.stream.inspect}")
|
56
|
+
message.to = filter.stream
|
57
|
+
@networking.publish_message(message)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Callback from the network when a message is received unsolicited from a client.
|
61
|
+
# If the message received is unhandleable by this Server, the message is forwarded
|
62
|
+
# on down to the clients who match the message's +to+.
|
63
|
+
def receive_message(message)
|
64
|
+
Pantry.logger.debug("[#{@identity}] Received message #{message.inspect}")
|
65
|
+
if @commands.can_handle?(message)
|
66
|
+
results = @commands.process(message)
|
67
|
+
|
68
|
+
if message.requires_response?
|
69
|
+
Pantry.logger.debug("[#{@identity}] Returning results #{results.inspect}")
|
70
|
+
send_results_back_to_requester(message, results)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
matched_clients = @client_registry.all_matching(message.to).map(&:identity)
|
74
|
+
|
75
|
+
Pantry.logger.debug("[#{@identity}] Forwarding message on. Expect response from #{matched_clients.inspect}")
|
76
|
+
send_results_back_to_requester(message, matched_clients, true)
|
77
|
+
forward_message(message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Send a Pantry::Message but mark it as requiring a response.
|
82
|
+
# This will set up and return a Celluloid::Future that will contain the
|
83
|
+
# response once it is available.
|
84
|
+
def send_request(client, message)
|
85
|
+
message.requires_response!
|
86
|
+
message.to = client.identity
|
87
|
+
|
88
|
+
Pantry.logger.debug("[#{@identity}] Sending request #{message.inspect}")
|
89
|
+
|
90
|
+
@networking.send_request(message)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Start a FileService::SendFile worker to upload the contents of the
|
94
|
+
# file at +file_path+ to the equivalent ReceiveFile at +receiver_uuid+.
|
95
|
+
# Using this method requires asking the receiving end (Server or Client) to receive
|
96
|
+
# a file first, which will return the +receiver_uuid+ and +file_uuid+ to use here.
|
97
|
+
def send_file(file_path, receiver_uuid, file_uuid)
|
98
|
+
@networking.send_file(file_path, receiver_uuid, file_uuid)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Set up a FileService::ReceiveFile worker to begin receiving a file with
|
102
|
+
# the given size and checksum. This returns an informational object with
|
103
|
+
# the new receiver's identity and the file UUID so a SendFile worker knows who
|
104
|
+
# to send the file contents to.
|
105
|
+
def receive_file(file_size, file_checksum)
|
106
|
+
@networking.receive_file(file_size, file_checksum)
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
def current_hostname
|
112
|
+
Socket.gethostname
|
113
|
+
end
|
114
|
+
|
115
|
+
def send_results_back_to_requester(message, results, client_response_list = false)
|
116
|
+
response_message = message.build_response
|
117
|
+
response_message.from = Pantry::SERVER_IDENTITY
|
118
|
+
response_message[:client_response_list] = client_response_list
|
119
|
+
|
120
|
+
[results].flatten(1).each do |entry|
|
121
|
+
response_message << entry
|
122
|
+
end
|
123
|
+
|
124
|
+
@networking.publish_message(response_message)
|
125
|
+
end
|
126
|
+
|
127
|
+
def forward_message(message)
|
128
|
+
@networking.forward_message(message)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#
|
2
|
+
# Require this file to grab the Pantry acceptance test environment.
|
3
|
+
# Acceptance tests run a full network of server and multiple clients,
|
4
|
+
# and are normally run via a CLI.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'pantry'
|
8
|
+
require 'celluloid/test'
|
9
|
+
require 'pantry/test/support/minitest'
|
10
|
+
require 'pantry/test/support/matchers'
|
11
|
+
require 'pantry/test/support/mock_ui'
|
12
|
+
require 'pantry/test/support/fake_fs'
|
13
|
+
|
14
|
+
# Catch and show all exceptions thrown during a test run
|
15
|
+
$all_exceptions = []
|
16
|
+
Celluloid.exception_handler do |exception|
|
17
|
+
$all_exceptions << exception
|
18
|
+
end
|
19
|
+
|
20
|
+
Minitest.after_run do
|
21
|
+
$all_exceptions.each do |exception|
|
22
|
+
puts exception
|
23
|
+
puts exception.backtrace.join("\n")
|
24
|
+
puts ""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Set up a Server-only echo command so we can differentiate between
|
29
|
+
# Client requests and Server requests in the acceptance tests.
|
30
|
+
class ServerEchoCommand < Pantry::Commands::Echo
|
31
|
+
end
|
32
|
+
|
33
|
+
module PantryAcceptanceHelpers
|
34
|
+
def configure_pantry(ports_start_at: 10101, heartbeat: 300, security: nil)
|
35
|
+
Pantry.config.server_host = "127.0.0.1"
|
36
|
+
Pantry.config.pub_sub_port = ports_start_at
|
37
|
+
Pantry.config.receive_port = ports_start_at + 1
|
38
|
+
Pantry.config.file_service_port = ports_start_at + 2
|
39
|
+
Pantry.config.client_heartbeat_interval = heartbeat
|
40
|
+
Pantry.config.response_timeout = 5
|
41
|
+
Pantry.config.security = security
|
42
|
+
|
43
|
+
begin
|
44
|
+
Pantry.add_server_command(ServerEchoCommand)
|
45
|
+
rescue Pantry::DuplicateCommandError
|
46
|
+
# Already registered
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Set up a fully functional Server + 2 Client environment on the given ports
|
51
|
+
# Make sure that the ports given are different for each test or port-conflict
|
52
|
+
# errors will happen. Tests should also have a wide enough range between their ports,
|
53
|
+
# to ensure there's room for the current setup and any later expansion (10 is a good number).
|
54
|
+
#
|
55
|
+
# This helper exposes @server, @client1, and @client2 for use in tests
|
56
|
+
def set_up_environment(ports_start_at: 10101, heartbeat: 300, security: nil)
|
57
|
+
Celluloid.boot
|
58
|
+
|
59
|
+
configure_pantry(ports_start_at: ports_start_at, heartbeat: heartbeat, security: security)
|
60
|
+
|
61
|
+
@server = Pantry::Server.new
|
62
|
+
@server.identity = "Test Server"
|
63
|
+
@server.run
|
64
|
+
|
65
|
+
@client1 = Pantry::Client.new identity: "client1", application: "pantry", environment: "test", roles: ["app1"]
|
66
|
+
@client1.run
|
67
|
+
|
68
|
+
@client2 = Pantry::Client.new identity: "client2", application: "pantry", environment: "test", roles: ["app2"]
|
69
|
+
@client2.run
|
70
|
+
end
|
71
|
+
|
72
|
+
def after_teardown
|
73
|
+
@client1.shutdown if @client1
|
74
|
+
@client2.shutdown if @client2
|
75
|
+
@server.shutdown if @server
|
76
|
+
|
77
|
+
Celluloid.shutdown rescue nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Minitest::Test
|
82
|
+
include PantryAcceptanceHelpers
|
83
|
+
end
|