pantry 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +19 -0
  5. data/Gemfile +15 -0
  6. data/Guardfile +16 -0
  7. data/LICENSE +20 -0
  8. data/README.md +53 -0
  9. data/Rakefile +18 -0
  10. data/Vagrantfile +86 -0
  11. data/bin/pantry +11 -0
  12. data/bin/pantry-client +38 -0
  13. data/bin/pantry-server +33 -0
  14. data/dist/client.yml +79 -0
  15. data/dist/server.yml +56 -0
  16. data/dist/upstart/pantry-client.conf +12 -0
  17. data/dist/upstart/pantry-server.conf +12 -0
  18. data/doc/message_packet.dot +19 -0
  19. data/doc/message_packet.dot.png +0 -0
  20. data/doc/network_topology.dot +42 -0
  21. data/doc/network_topology.dot.png +0 -0
  22. data/lib/celluloid_zmq_patches.rb +16 -0
  23. data/lib/opt_parse_plus.rb +184 -0
  24. data/lib/pantry.rb +197 -0
  25. data/lib/pantry/cli.rb +154 -0
  26. data/lib/pantry/client.rb +131 -0
  27. data/lib/pantry/client_info.rb +34 -0
  28. data/lib/pantry/client_registry.rb +104 -0
  29. data/lib/pantry/command.rb +194 -0
  30. data/lib/pantry/command_handler.rb +53 -0
  31. data/lib/pantry/command_line.rb +115 -0
  32. data/lib/pantry/commands/create_client.rb +30 -0
  33. data/lib/pantry/commands/download_directory.rb +35 -0
  34. data/lib/pantry/commands/echo.rb +32 -0
  35. data/lib/pantry/commands/edit_application.rb +60 -0
  36. data/lib/pantry/commands/register_client.rb +38 -0
  37. data/lib/pantry/commands/status.rb +78 -0
  38. data/lib/pantry/commands/sync_directory.rb +50 -0
  39. data/lib/pantry/commands/update_application.rb +45 -0
  40. data/lib/pantry/commands/upload_file.rb +68 -0
  41. data/lib/pantry/communication.rb +20 -0
  42. data/lib/pantry/communication/client.rb +75 -0
  43. data/lib/pantry/communication/client_filter.rb +117 -0
  44. data/lib/pantry/communication/file_service.rb +125 -0
  45. data/lib/pantry/communication/file_service/file_progress.rb +164 -0
  46. data/lib/pantry/communication/file_service/receive_file.rb +97 -0
  47. data/lib/pantry/communication/file_service/send_file.rb +74 -0
  48. data/lib/pantry/communication/publish_socket.rb +20 -0
  49. data/lib/pantry/communication/reading_socket.rb +89 -0
  50. data/lib/pantry/communication/receive_socket.rb +23 -0
  51. data/lib/pantry/communication/security.rb +44 -0
  52. data/lib/pantry/communication/security/authentication.rb +98 -0
  53. data/lib/pantry/communication/security/curve_key_store.rb +120 -0
  54. data/lib/pantry/communication/security/curve_security.rb +70 -0
  55. data/lib/pantry/communication/security/null_security.rb +32 -0
  56. data/lib/pantry/communication/send_socket.rb +19 -0
  57. data/lib/pantry/communication/serialize_message.rb +84 -0
  58. data/lib/pantry/communication/server.rb +97 -0
  59. data/lib/pantry/communication/subscribe_socket.rb +33 -0
  60. data/lib/pantry/communication/wait_list.rb +45 -0
  61. data/lib/pantry/communication/writing_socket.rb +46 -0
  62. data/lib/pantry/config.rb +182 -0
  63. data/lib/pantry/file_editor.rb +67 -0
  64. data/lib/pantry/logger.rb +78 -0
  65. data/lib/pantry/message.rb +134 -0
  66. data/lib/pantry/multi_command.rb +36 -0
  67. data/lib/pantry/server.rb +132 -0
  68. data/lib/pantry/test/acceptance.rb +83 -0
  69. data/lib/pantry/test/support/fake_fs.rb +31 -0
  70. data/lib/pantry/test/support/matchers.rb +13 -0
  71. data/lib/pantry/test/support/minitest.rb +13 -0
  72. data/lib/pantry/test/support/mock_ui.rb +23 -0
  73. data/lib/pantry/test/unit.rb +13 -0
  74. data/lib/pantry/ui.rb +68 -0
  75. data/lib/pantry/version.rb +3 -0
  76. data/pantry.gemspec +40 -0
  77. data/test/acceptance/cli/error_handling_test.rb +7 -0
  78. data/test/acceptance/cli/execute_command_on_clients_test.rb +32 -0
  79. data/test/acceptance/cli/request_info_from_server_test.rb +44 -0
  80. data/test/acceptance/communication/client_requests_info_from_server_test.rb +28 -0
  81. data/test/acceptance/communication/heartbeat_test.rb +19 -0
  82. data/test/acceptance/communication/pub_sub_communication_test.rb +53 -0
  83. data/test/acceptance/communication/security_test.rb +117 -0
  84. data/test/acceptance/communication/server_requests_info_from_client_test.rb +41 -0
  85. data/test/acceptance/test_helper.rb +25 -0
  86. data/test/fixtures/config.yml +22 -0
  87. data/test/fixtures/empty.yml +2 -0
  88. data/test/fixtures/file_to_upload +3 -0
  89. data/test/root_dir/.gitkeep +0 -0
  90. data/test/unit/cli_test.rb +173 -0
  91. data/test/unit/client_registry_test.rb +61 -0
  92. data/test/unit/client_test.rb +128 -0
  93. data/test/unit/command_handler_test.rb +79 -0
  94. data/test/unit/command_line_test.rb +5 -0
  95. data/test/unit/command_test.rb +206 -0
  96. data/test/unit/commands/create_client_test.rb +25 -0
  97. data/test/unit/commands/download_directory_test.rb +58 -0
  98. data/test/unit/commands/echo_test.rb +22 -0
  99. data/test/unit/commands/edit_application_test.rb +84 -0
  100. data/test/unit/commands/register_client_test.rb +41 -0
  101. data/test/unit/commands/status_test.rb +81 -0
  102. data/test/unit/commands/sync_directory_test.rb +75 -0
  103. data/test/unit/commands/update_application_test.rb +35 -0
  104. data/test/unit/commands/upload_file_test.rb +51 -0
  105. data/test/unit/communication/client_filter_test.rb +262 -0
  106. data/test/unit/communication/client_test.rb +99 -0
  107. data/test/unit/communication/file_service/receive_file_test.rb +214 -0
  108. data/test/unit/communication/file_service/send_file_test.rb +110 -0
  109. data/test/unit/communication/file_service_test.rb +56 -0
  110. data/test/unit/communication/publish_socket_test.rb +19 -0
  111. data/test/unit/communication/reading_socket_test.rb +110 -0
  112. data/test/unit/communication/receive_socket_test.rb +20 -0
  113. data/test/unit/communication/security/authentication_test.rb +97 -0
  114. data/test/unit/communication/security/curve_key_store_test.rb +110 -0
  115. data/test/unit/communication/security/curve_security_test.rb +44 -0
  116. data/test/unit/communication/security/null_security_test.rb +15 -0
  117. data/test/unit/communication/security_test.rb +49 -0
  118. data/test/unit/communication/send_socket_test.rb +19 -0
  119. data/test/unit/communication/serialize_message_test.rb +128 -0
  120. data/test/unit/communication/server_test.rb +106 -0
  121. data/test/unit/communication/subscribe_socket_test.rb +46 -0
  122. data/test/unit/communication/wait_list_test.rb +60 -0
  123. data/test/unit/communication/writing_socket_test.rb +46 -0
  124. data/test/unit/config_test.rb +150 -0
  125. data/test/unit/logger_test.rb +79 -0
  126. data/test/unit/message_test.rb +179 -0
  127. data/test/unit/multi_command_test.rb +45 -0
  128. data/test/unit/opt_parse_plus_test.rb +218 -0
  129. data/test/unit/pantry_test.rb +82 -0
  130. data/test/unit/server_test.rb +166 -0
  131. data/test/unit/test_helper.rb +25 -0
  132. data/test/unit/ui_test.rb +58 -0
  133. metadata +389 -13
@@ -0,0 +1,31 @@
1
+ gem 'fakefs'
2
+ require 'fakefs/safe'
3
+
4
+ # Hook up FakeFS into Minitest
5
+ class MiniTest::Test
6
+ def self.fake_fs!
7
+ before do
8
+ FakeFS.activate!
9
+ end
10
+
11
+ after do
12
+ FakeFS.deactivate!
13
+ FakeFS::FileSystem.clear
14
+ end
15
+ end
16
+ end
17
+
18
+ # Minitest uses Tempfiles for figuring out more complicated diffs
19
+ # This causes FakeFS to explode, so make sure this is run without FakeFS
20
+ # enabled.
21
+ module Minitest
22
+ module Assertions
23
+ alias :actual_diff :diff
24
+
25
+ def diff exp, act
26
+ FakeFS.without do
27
+ actual_diff exp, act
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ # Some custom MiniTest matchers used throughout the system
2
+
3
+ module Minitest::Assertions
4
+
5
+ # I don't like the refute_ syntax, sorry =/
6
+
7
+ alias assert_not_nil refute_nil
8
+ alias assert_not refute
9
+ alias assert_false refute
10
+ alias assert_not_equal refute_equal
11
+ alias assert_no_match refute_match
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'minitest/autorun'
2
+
3
+ # Global helpers we're adding to Minitest
4
+ module PantryMinitestHelpers
5
+ def before_setup
6
+ Celluloid.init
7
+ Pantry.reset_config!
8
+ end
9
+ end
10
+
11
+ class Minitest::Test
12
+ include PantryMinitestHelpers
13
+ end
@@ -0,0 +1,23 @@
1
+ # For actions that print out or use the console via
2
+ # Pantry.ui, these helpers mock out stdout/stderr to make it easy
3
+ # to grab what's printed and to inject keypresses
4
+ class MiniTest::Test
5
+ def self.mock_ui!
6
+ before do
7
+ @mock_stdin = StringIO.new
8
+ @mock_stdout = StringIO.new
9
+ Pantry.reset_ui!
10
+ Pantry.ui(@mock_stdin, @mock_stdout)
11
+ end
12
+ end
13
+
14
+ # Return the strings added to stdout through the test
15
+ def stdout
16
+ @mock_stdout.string
17
+ end
18
+
19
+ # Get access to the mock of STDIN to add values
20
+ def stdin
21
+ @mock_stdin
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ #
2
+ # Require this file to grab the Pantry unit test environment.
3
+ # This environment includes setup helpers to ensure Celluloid is running,
4
+ # as well as a few mocks (ui and fakefs) as well as helpers to facilitate
5
+ # testing Pantry plugins.
6
+ #
7
+
8
+ require 'pantry'
9
+ require 'celluloid/test'
10
+ require 'pantry/test/support/minitest'
11
+ require 'pantry/test/support/matchers'
12
+ require 'pantry/test/support/mock_ui'
13
+ require 'pantry/test/support/fake_fs'
@@ -0,0 +1,68 @@
1
+ module Pantry
2
+
3
+ # Global access to Pantry's UI handler. This object offers up
4
+ # a set of methods used to interact with the User via the CLI.
5
+ def self.ui(input = $stdin, output = $stdout)
6
+ @@ui ||= Pantry::UI.new(input, output)
7
+ end
8
+
9
+ def self.reset_ui!
10
+ @@ui = nil
11
+ end
12
+
13
+ class UI
14
+
15
+ def initialize(input = $stdin, output = $stdout)
16
+ require 'highline'
17
+ @output = output
18
+ @input = input
19
+ @highline = HighLine.new(input, output)
20
+ end
21
+
22
+ # Send a message to STDOUT
23
+ def say(message)
24
+ @highline.say(message)
25
+ end
26
+
27
+ # Print out a list, attempting to make it look somewhat reasonable
28
+ def list(array)
29
+ say(array.join("\n") + "\n")
30
+ end
31
+
32
+ def color(string, color)
33
+ HighLine.color(string, color)
34
+ end
35
+
36
+ # Show the user a message and ask them to continue by hitting Enter,
37
+ # or they can cancel with "No"
38
+ def continue?(message)
39
+ @highline.agree(message) do |q|
40
+ q.default = "yes"
41
+ end
42
+ end
43
+
44
+ # Start a new progress meter with the given number of ticks
45
+ def progress_start(tick_count)
46
+ require 'ruby-progressbar'
47
+ @progress = ProgressBar.create(
48
+ total: tick_count, output: @output,
49
+ format: "Progress: %P%% |%B| %c/%C %e"
50
+ )
51
+ end
52
+
53
+ # Increment the running progress meter the given number of ticks
54
+ def progress_step(tick_count)
55
+ if @progress.progress + tick_count > @progress.total
56
+ tick_count = @progress.total - @progress.progress
57
+ end
58
+
59
+ @progress.progress += tick_count
60
+ end
61
+
62
+ # Complete and close down the current progress meter
63
+ def progress_finish
64
+ @progress.finish
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module Pantry
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,40 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "pantry/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "pantry"
6
+ s.version = Pantry::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Collective Idea", "Jason Roelofs"]
9
+ s.email = ["code@collectiveidea.com", "jasongroelofs@gmail.com"]
10
+ s.license = "MIT"
11
+ s.homepage = "http://pantryops.org"
12
+
13
+ s.summary = "Modern DevOps Automation"
14
+ s.description = <<-EOS
15
+ Pantry is a framework that provides answers to common questions encoutered when setting up a DevOps, server configuration, or server provisioning pipeline.
16
+ EOS
17
+
18
+ s.required_ruby_version = ">= 2.0.0"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- test/*`.split("\n")
22
+ s.require_path = "lib"
23
+ s.bindir = "bin"
24
+
25
+ s.executables = %w(pantry-client pantry-server pantry)
26
+
27
+ s.requirements << "zeromq 3.x or 4.x"
28
+ s.requirements << "libsodium for Curve security"
29
+
30
+ s.add_runtime_dependency "ffi-rzmq", "~> 2.0", ">= 2.0.0"
31
+ s.add_runtime_dependency "celluloid", "~> 0.15", ">= 0.15.0"
32
+ s.add_runtime_dependency "celluloid-zmq", "~> 0.15", ">= 0.15.0"
33
+ s.add_runtime_dependency "highline", "~> 1.6", ">= 1.6.21"
34
+ s.add_runtime_dependency "json", "~> 1.8", ">= 1.8.1"
35
+ s.add_runtime_dependency "ruby-progressbar", "~> 1.4", ">= 1.4.2"
36
+ s.add_runtime_dependency "safe_yaml", "~> 1.0", ">= 1.0.1"
37
+
38
+ s.add_development_dependency "mocha", "~> 1.0", ">= 1.0.0"
39
+ s.add_development_dependency "fakefs", "~> 0.5", ">= 0.5.1"
40
+ end
@@ -0,0 +1,7 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "CLI error handling" do
4
+
5
+ it "errors when the server is unavailable"
6
+
7
+ end
@@ -0,0 +1,32 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "CLI requests information from individual clients" do
4
+
5
+ mock_ui!
6
+
7
+ it "receives responses from each client asked" do
8
+ set_up_environment(ports_start_at: 10100)
9
+
10
+ Pantry::CLI.new(
11
+ ["-a", "pantry", "echo", "This is Neat"],
12
+ identity: "cli1"
13
+ ).run
14
+
15
+ assert_match %r|Expecting response from 2 clients|, stdout
16
+ assert_match %r|#{@client1.identity} echo's "This is Neat"|, stdout
17
+ assert_match %r|#{@client2.identity} echo's "This is Neat"|, stdout
18
+ end
19
+
20
+ it "can target specific clients for the commands sent" do
21
+ set_up_environment(ports_start_at: 10110)
22
+
23
+ Pantry::CLI.new(
24
+ ["-a", "pantry", "-e", "test", "-r", "app1", "echo", "This is Neat"],
25
+ identity: "cli1"
26
+ ).run
27
+
28
+ assert_match %r|Expecting response from 1 client|, stdout
29
+ assert_match %r|#{@client1.identity} echo's \"This is Neat\"|, stdout
30
+ end
31
+
32
+ end
@@ -0,0 +1,44 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "CLI can ask Server for information" do
4
+
5
+ mock_ui!
6
+
7
+ it "can ask for all known nodes" do
8
+ set_up_environment(ports_start_at: 10200)
9
+
10
+ Pantry::CLI.new(
11
+ ["status"],
12
+ identity: "test_client"
13
+ ).run
14
+
15
+ assert_match /#{@client1.identity}/, stdout, "Did not contain line for client1"
16
+ assert_match /#{@client2.identity}/, stdout, "Did not contain line for client2"
17
+ end
18
+
19
+ it "can limit the query to a subset of clients" do
20
+ set_up_environment(ports_start_at: 10210)
21
+
22
+ cli = Pantry::CLI.new(
23
+ ["-a", "chatbot", "status"],
24
+ identity: "test_client"
25
+ )
26
+
27
+ client3 = Pantry::Client.new(application: "chatbot", identity: "client3")
28
+ client3.run
29
+
30
+ client4 = Pantry::Client.new(application: "chatbot", identity: "client4")
31
+ client4.run
32
+
33
+ cli.run
34
+
35
+ assert_equal 2, stdout.split("\n").length
36
+
37
+ assert_match /client3/, stdout, "Did not contain line for client3"
38
+ assert_match /client4/, stdout, "Did not contain line for client4"
39
+
40
+ client3.shutdown
41
+ client4.shutdown
42
+ end
43
+
44
+ end
@@ -0,0 +1,28 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "Client requests information from the Server" do
4
+
5
+ it "asks the server for information and waits for a response" do
6
+ set_up_environment(ports_start_at: 10300)
7
+
8
+ message = ServerEchoCommand.new("Hello Server").to_message
9
+ response_future = @client1.send_request(message)
10
+
11
+ assert_equal ["Hello Server"], response_future.value(2).body
12
+ end
13
+
14
+ it "handles multiple requests in the proper order" do
15
+ set_up_environment(ports_start_at: 10310)
16
+
17
+ futures = []
18
+ 10.times do |i|
19
+ message = ServerEchoCommand.new("Hello Server #{i}").to_message
20
+ futures << @client1.send_request(message)
21
+ end
22
+
23
+ futures.each_with_index do |future, idx|
24
+ assert_equal ["Hello Server #{idx}"], future.value(1).body
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,19 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "Client / Server heartbeats" do
4
+
5
+ describe "Client" do
6
+ it "re-registers with the server every interval seconds" do
7
+ set_up_environment(ports_start_at: 10500, heartbeat: 1)
8
+
9
+ # Clean out the server registry then wait for clients to re-register themselves
10
+ @server.client_registry.clear!
11
+
12
+ sleep 2
13
+
14
+ assert @server.client_registry.include?(@client1), "Client1 did not check in again"
15
+ assert @server.client_registry.include?(@client2), "Client2 did not check in again"
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,53 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "Pub/Sub Communication" do
4
+
5
+ describe "Server" do
6
+ it "can publish a message to all connected clients" do
7
+ set_up_environment(ports_start_at: 10400)
8
+
9
+ @server.publish_message(
10
+ Pantry::Message.new("test_message"),
11
+ Pantry::Communication::ClientFilter.new(application: "pantry")
12
+ )
13
+
14
+ # Give communication time to happen
15
+ sleep 1
16
+
17
+ assert_equal "test_message", @client1.last_received_message.type
18
+ assert_equal "test_message", @client2.last_received_message.type
19
+ end
20
+
21
+ it "can publish a message to a subset of all connected clients" do
22
+ set_up_environment(ports_start_at: 10410)
23
+
24
+ client3 = Pantry::Client.new(roles: %w(database), identity: "client3")
25
+ client3.run
26
+
27
+ client4 = Pantry::Client.new(roles: %w(database task), identity: "client4")
28
+ client4.run
29
+
30
+ sleep 1
31
+
32
+ @server.publish_message(Pantry::Message.new("to_databases"),
33
+ Pantry::Communication::ClientFilter.new(roles: %w(database)))
34
+
35
+ # Give communication time to happen
36
+ sleep 1
37
+
38
+ assert_equal "to_databases", client3.last_received_message.type
39
+ assert_equal "to_databases", client4.last_received_message.type
40
+
41
+ @server.publish_message(Pantry::Message.new("to_tasks"),
42
+ Pantry::Communication::ClientFilter.new(roles: %w(task)))
43
+
44
+ # Give communication time to happen
45
+ sleep 1
46
+
47
+ assert_equal "to_tasks", client4.last_received_message.type
48
+
49
+ client3.shutdown
50
+ client4.shutdown
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,117 @@
1
+ require 'acceptance/test_helper'
2
+
3
+ describe "ZMQ4 CURVE security" do
4
+
5
+ break unless Pantry::Communication::Security.curve_supported?
6
+
7
+ def set_up_encrypted(ports_start_at, options = {})
8
+ Celluloid.boot
9
+ configure_pantry(ports_start_at: ports_start_at, security: "curve")
10
+
11
+ server_public, server_private = ZMQ::Util.curve_keypair
12
+ client_public, client_private = ZMQ::Util.curve_keypair
13
+
14
+ known_clients = options[:known_clients] || [client_public]
15
+
16
+ key_dir = Pantry.root.join("security", "curve")
17
+ FileUtils.mkdir_p(key_dir)
18
+
19
+ File.open(key_dir.join("server_keys.yml"), "w+") do |f|
20
+ f.write(YAML.dump({
21
+ "private_key" => server_private,
22
+ "public_key" => options[:server_public_key] || server_public,
23
+ "client_keys" => known_clients
24
+ }))
25
+ end
26
+
27
+ File.open(key_dir.join("client_keys.yml"), "w+") do |f|
28
+ f.write(YAML.dump({
29
+ "private_key" => client_private, "public_key" => client_public,
30
+ "server_public_key" => options[:server_public_key] || server_public
31
+ }))
32
+ end
33
+ end
34
+
35
+ describe "connectivity" do
36
+ def assert_message_timeout(client)
37
+ message = ServerEchoCommand.new("Hello Server").to_message
38
+ response_future = client.send_request(message)
39
+
40
+ assert_raises(Celluloid::TimeoutError) do
41
+ response_future.value(1).body
42
+ end
43
+ end
44
+
45
+ def assert_successful_message(client)
46
+ message = ServerEchoCommand.new("Hello Server").to_message
47
+ response_future = client.send_request(message)
48
+
49
+ assert_equal ["Hello Server"], response_future.value(2).body
50
+ end
51
+
52
+ it "configures CURVE security for encrypted server/client communication" do
53
+ set_up_encrypted(15000)
54
+
55
+ server = Pantry::Server.new
56
+ server.identity = "Encrypted Server"
57
+ server.run
58
+
59
+ client = Pantry::Client.new identity: "encrypted-client"
60
+ client.run
61
+
62
+ assert_successful_message(client)
63
+ end
64
+
65
+ it "rejects clients who connect with the wrong server key" do
66
+ set_up_encrypted(15010, server_public_key: "invalid security token1234567890")
67
+
68
+ server = Pantry::Server.new
69
+ server.identity = "Encrypted Server"
70
+ server.run
71
+
72
+ client = Pantry::Client.new identity: "encrypted-client"
73
+ client.run
74
+
75
+ assert_message_timeout(client)
76
+ end
77
+
78
+ it "rejects a client whos public key is not known by the server" do
79
+ set_up_encrypted(15020, known_clients: ["some other client here1234567890"])
80
+
81
+ server = Pantry::Server.new
82
+ server.identity = "Encrypted Server"
83
+ server.run
84
+
85
+ client = Pantry::Client.new identity: "encrypted-client"
86
+ client.run
87
+
88
+ assert_message_timeout(client)
89
+ end
90
+
91
+ end
92
+
93
+ describe "requesting new client keys" do
94
+
95
+ mock_ui!
96
+
97
+ it "returns a new set of client keys as requested" do
98
+ set_up_encrypted(15030)
99
+
100
+ server = Pantry::Server.new
101
+ server.identity = "Encrypted Server"
102
+ server.run
103
+
104
+ cli = Pantry::CLI.new(
105
+ ["client:create"],
106
+ identity: "encrypted-client"
107
+ )
108
+ cli.run
109
+
110
+ assert_match /server_public_key/, stdout
111
+ assert_match /public_key/, stdout
112
+ assert_match /private_key/, stdout
113
+ end
114
+
115
+ end
116
+
117
+ end