invoker_ruby34 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/bin/invoker +7 -0
  3. data/lib/invoker/cli/pinger.rb +23 -0
  4. data/lib/invoker/cli/question.rb +15 -0
  5. data/lib/invoker/cli/tail.rb +34 -0
  6. data/lib/invoker/cli/tail_watcher.rb +34 -0
  7. data/lib/invoker/cli.rb +197 -0
  8. data/lib/invoker/command_worker.rb +64 -0
  9. data/lib/invoker/commander.rb +101 -0
  10. data/lib/invoker/daemon.rb +126 -0
  11. data/lib/invoker/dns_cache.rb +23 -0
  12. data/lib/invoker/errors.rb +17 -0
  13. data/lib/invoker/event/manager.rb +79 -0
  14. data/lib/invoker/ipc/add_command.rb +12 -0
  15. data/lib/invoker/ipc/add_http_command.rb +10 -0
  16. data/lib/invoker/ipc/base_command.rb +24 -0
  17. data/lib/invoker/ipc/client_handler.rb +26 -0
  18. data/lib/invoker/ipc/dns_check_command.rb +17 -0
  19. data/lib/invoker/ipc/list_command.rb +11 -0
  20. data/lib/invoker/ipc/message/list_response.rb +35 -0
  21. data/lib/invoker/ipc/message/tail_response.rb +10 -0
  22. data/lib/invoker/ipc/message.rb +170 -0
  23. data/lib/invoker/ipc/ping_command.rb +10 -0
  24. data/lib/invoker/ipc/reload_command.rb +12 -0
  25. data/lib/invoker/ipc/remove_command.rb +12 -0
  26. data/lib/invoker/ipc/server.rb +26 -0
  27. data/lib/invoker/ipc/tail_command.rb +11 -0
  28. data/lib/invoker/ipc/unix_client.rb +60 -0
  29. data/lib/invoker/ipc.rb +45 -0
  30. data/lib/invoker/logger.rb +13 -0
  31. data/lib/invoker/parsers/config.rb +184 -0
  32. data/lib/invoker/parsers/procfile.rb +86 -0
  33. data/lib/invoker/power/balancer.rb +133 -0
  34. data/lib/invoker/power/config.rb +77 -0
  35. data/lib/invoker/power/dns.rb +38 -0
  36. data/lib/invoker/power/http_parser.rb +68 -0
  37. data/lib/invoker/power/http_response.rb +81 -0
  38. data/lib/invoker/power/port_finder.rb +49 -0
  39. data/lib/invoker/power/power.rb +3 -0
  40. data/lib/invoker/power/powerup.rb +29 -0
  41. data/lib/invoker/power/setup/distro/arch.rb +15 -0
  42. data/lib/invoker/power/setup/distro/base.rb +80 -0
  43. data/lib/invoker/power/setup/distro/debian.rb +11 -0
  44. data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
  45. data/lib/invoker/power/setup/distro/redhat.rb +11 -0
  46. data/lib/invoker/power/setup/distro/ubuntu.rb +46 -0
  47. data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
  48. data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
  49. data/lib/invoker/power/setup/linux_setup.rb +97 -0
  50. data/lib/invoker/power/setup/osx_setup.rb +137 -0
  51. data/lib/invoker/power/setup.rb +93 -0
  52. data/lib/invoker/power/templates/400.html +40 -0
  53. data/lib/invoker/power/templates/404.html +40 -0
  54. data/lib/invoker/power/templates/503.html +40 -0
  55. data/lib/invoker/power/url_rewriter.rb +40 -0
  56. data/lib/invoker/process_manager.rb +201 -0
  57. data/lib/invoker/process_printer.rb +59 -0
  58. data/lib/invoker/reactor/reader.rb +65 -0
  59. data/lib/invoker/reactor.rb +37 -0
  60. data/lib/invoker/version.rb +47 -0
  61. data/lib/invoker.rb +151 -0
  62. data/spec/invoker/cli/pinger_spec.rb +22 -0
  63. data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
  64. data/spec/invoker/cli_spec.rb +27 -0
  65. data/spec/invoker/command_worker_spec.rb +45 -0
  66. data/spec/invoker/commander_spec.rb +152 -0
  67. data/spec/invoker/config_spec.rb +361 -0
  68. data/spec/invoker/daemon_spec.rb +34 -0
  69. data/spec/invoker/event/manager_spec.rb +67 -0
  70. data/spec/invoker/invoker_spec.rb +71 -0
  71. data/spec/invoker/ipc/client_handler_spec.rb +54 -0
  72. data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
  73. data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
  74. data/spec/invoker/ipc/message_spec.rb +49 -0
  75. data/spec/invoker/ipc/unix_client_spec.rb +29 -0
  76. data/spec/invoker/power/balancer_spec.rb +53 -0
  77. data/spec/invoker/power/config_spec.rb +18 -0
  78. data/spec/invoker/power/http_parser_spec.rb +32 -0
  79. data/spec/invoker/power/http_response_spec.rb +34 -0
  80. data/spec/invoker/power/port_finder_spec.rb +16 -0
  81. data/spec/invoker/power/setup/linux_setup_spec.rb +166 -0
  82. data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
  83. data/spec/invoker/power/setup_spec.rb +4 -0
  84. data/spec/invoker/power/url_rewriter_spec.rb +69 -0
  85. data/spec/invoker/power/web_sockets_spec.rb +61 -0
  86. data/spec/invoker/process_manager_spec.rb +130 -0
  87. data/spec/invoker/reactor_spec.rb +6 -0
  88. data/spec/spec_helper.rb +43 -0
  89. metadata +374 -0
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::Event::Manager do
4
+ describe "Run scheduled events" do
5
+ before do
6
+ @event_manager = Invoker::Event::Manager.new()
7
+ end
8
+
9
+ it "should run matched events" do
10
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
11
+ @event_manager.trigger("foo", :exit)
12
+
13
+ @event_manager.run_scheduled_events do |event|
14
+ expect(event.block.call).to eq("exit foo")
15
+ end
16
+
17
+ expect(@event_manager.scheduled_events).to be_empty
18
+ expect(@event_manager.triggered_events).to be_empty
19
+ end
20
+
21
+ it "should remove triggrered and scheduld events on run" do
22
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
23
+ @event_manager.schedule_event("bar", :entry) { "entry bar"}
24
+ @event_manager.trigger("foo", :exit)
25
+ @event_manager.trigger("baz", :exit)
26
+
27
+ @event_manager.run_scheduled_events do |event|
28
+ expect(event.block.call).to eq("exit foo")
29
+ end
30
+
31
+ expect(@event_manager.scheduled_events).not_to be_empty
32
+ expect(@event_manager.triggered_events).not_to be_empty
33
+
34
+ baz_containing_event = @event_manager.triggered_events.map(&:command_label)
35
+ expect(baz_containing_event).to include("baz")
36
+
37
+ bar_containing_scheduled_event = @event_manager.scheduled_events.keys
38
+ expect(bar_containing_scheduled_event).to include("bar")
39
+ end
40
+
41
+ it "should handle multiple events for same command" do
42
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
43
+ @event_manager.schedule_event("foo", :entry) { "entry bar"}
44
+ @event_manager.trigger("foo", :exit)
45
+
46
+ @event_manager.run_scheduled_events { |event| }
47
+
48
+
49
+ @event_manager.schedule_event("foo", :exit) { 'exit foo' }
50
+ @event_manager.trigger("foo", :exit)
51
+
52
+ expect(@event_manager.scheduled_events).not_to be_empty
53
+ expect(@event_manager.triggered_events).not_to be_empty
54
+ end
55
+
56
+ it "should not run unmatched events" do
57
+ @event_manager.schedule_event("bar", :entry) { "entry bar"}
58
+ @event_manager.trigger("foo", :exit)
59
+
60
+ events_ran = false
61
+ @event_manager.run_scheduled_events do |event|
62
+ events_ran = true
63
+ end
64
+ expect(events_ran).to eql false
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+ describe "Invoker" do
4
+ describe "#darwin?" do
5
+ it "should return true on osx" do
6
+ Invoker.expects(:ruby_platform).returns("x86_64-darwin12.4.0")
7
+ expect(Invoker.darwin?).to be_truthy
8
+ end
9
+
10
+ it "should return false on linux" do
11
+ Invoker.expects(:ruby_platform).returns("i686-linux")
12
+ expect(Invoker.darwin?).to be_falsey
13
+ end
14
+ end
15
+
16
+ describe "#can_run_balancer?", fakefs: true do
17
+ before { FileUtils.mkdir_p(Invoker::Power::Config.config_dir) }
18
+ it "should return false if setup command was not run" do
19
+ expect(Invoker.can_run_balancer?).to be_falsey
20
+ end
21
+
22
+ it "should return true if setup was run properly" do
23
+ File.open(Invoker::Power::Config.config_file, "w") {|fl|
24
+ fl.write("hello")
25
+ }
26
+ expect(Invoker.can_run_balancer?).to be_truthy
27
+ end
28
+
29
+ it "should not print warning if setup is not run when flag is false" do
30
+ Invoker::Logger.expects(:puts).never()
31
+ Invoker.can_run_balancer?(false)
32
+ end
33
+ end
34
+
35
+ describe "#setup_config_location" do
36
+ before do
37
+ Dir.stubs(:home).returns('/tmp')
38
+ @config_location = File.join('/tmp', '.invoker')
39
+ FileUtils.rm_rf(@config_location)
40
+ end
41
+
42
+ context "when the old config file does not exist" do
43
+ it "creates the new config directory" do
44
+ Invoker.setup_config_location
45
+ expect(Dir.exist?(@config_location)).to be_truthy
46
+ end
47
+ end
48
+
49
+ context "when the old config file exists" do
50
+ before do
51
+ File.open(@config_location, 'w') do |file|
52
+ file.write('invoker config')
53
+ end
54
+ end
55
+
56
+ it "moves the file to the new directory" do
57
+ Invoker.setup_config_location
58
+ expect(Dir.exist?(@config_location)).to be_truthy
59
+ new_config_file = File.join(@config_location, 'config')
60
+ expect(File.exist?(new_config_file)).to be_truthy
61
+ expect(File.read(new_config_file)).to match('invoker config')
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#home" do
67
+ it "should return home directory using etc module" do
68
+ expect(Invoker.home).to eql ENV['HOME']
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::IPC::ClientHandler do
4
+ let(:client_socket) { StringIO.new }
5
+ let(:client) { Invoker::IPC::ClientHandler.new(client_socket) }
6
+
7
+ describe "add command" do
8
+ let(:message_object) { MM::Add.new(process_name: 'foo') }
9
+ it "should run if read from socket" do
10
+ invoker_commander.expects(:on_next_tick).with("foo")
11
+ client_socket.string = message_object.encoded_message
12
+
13
+ client.read_and_execute
14
+ end
15
+ end
16
+
17
+ describe "remove command" do
18
+ it "with specific signal" do
19
+ message_object = MM::Remove.new(process_name: 'foo', signal: 'INT')
20
+ invoker_commander.expects(:on_next_tick)
21
+ client_socket.string = message_object.encoded_message
22
+
23
+ client.read_and_execute
24
+ end
25
+
26
+ it "with default signal" do
27
+ message_object = MM::Remove.new(process_name: 'foo')
28
+ invoker_commander.expects(:on_next_tick)
29
+ client_socket.string = message_object.encoded_message
30
+
31
+ client.read_and_execute
32
+ end
33
+ end
34
+
35
+ describe "add_http command" do
36
+ let(:message_object) { MM::AddHttp.new(process_name: 'foo', port: 9000)}
37
+ it "adds the process name and port to dns cache" do
38
+ invoker_dns_cache.expects(:add).with('foo', 9000, nil)
39
+ client_socket.string = message_object.encoded_message
40
+
41
+ client.read_and_execute
42
+ end
43
+ end
44
+
45
+ describe "add_http command with optional ip" do
46
+ let(:message_object) { MM::AddHttp.new(process_name: 'foo', port: 9000, ip: '192.168.0.1')}
47
+ it "adds the process name, port and host ip to dns cache" do
48
+ invoker_dns_cache.expects(:add).with('foo', 9000, '192.168.0.1')
49
+ client_socket.string = message_object.encoded_message
50
+
51
+ client.read_and_execute
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Invoker::IPC::DnsCheckCommand do
4
+ let(:client_socket) { StringIO.new }
5
+ let(:client) { Invoker::IPC::ClientHandler.new(client_socket) }
6
+
7
+ describe "dns check for valid process" do
8
+ let(:message_object) { MM::DnsCheck.new(process_name: 'lolbro') }
9
+ it "should response with dns check response" do
10
+ invoker_dns_cache.expects(:[]).returns('port' => 9000)
11
+ client_socket.string = message_object.encoded_message
12
+
13
+ client.read_and_execute
14
+
15
+ dns_check_response = client_socket.string
16
+ expect(dns_check_response).to match(/9000/)
17
+ end
18
+ end
19
+
20
+ describe "dns check for invalid process" do
21
+ let(:message_object) { MM::DnsCheck.new(process_name: 'foo') }
22
+ it "should response with dns check response" do
23
+ invoker_dns_cache.expects(:[]).returns('port' => nil)
24
+ client_socket.string = message_object.encoded_message
25
+
26
+ client.read_and_execute
27
+
28
+ dns_check_response = client_socket.string
29
+ expect(dns_check_response).to match(/null/)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe MM::ListResponse do
4
+ context "serializing a response" do
5
+ let(:process_array) do
6
+ [
7
+ { shell_command: 'foo', process_name: 'foo', dir: '/tmp', pid: 100,
8
+ port: 9000 },
9
+ { shell_command: 'bar', process_name: 'bar', dir: '/tmp', pid: 200,
10
+ port: 9001 }
11
+ ]
12
+ end
13
+
14
+ let(:message) { MM::ListResponse.new(processes: process_array) }
15
+
16
+ it "should prepare proper json" do
17
+ json_hash = message.as_json
18
+ expect(json_hash[:type]).to eql "list_response"
19
+ expect(json_hash[:processes].length).to eql 2
20
+ expect(json_hash[:processes][0]).to be_a(Hash)
21
+ expect(json_hash[:processes][1]).to be_a(Hash)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::IPC::Message do
4
+ describe "test equality of objects" do
5
+ context "for simple messages" do
6
+ let(:message) { MM::Add.new(process_name: 'foo') }
7
+
8
+ it "object should be reported same if same value" do
9
+ m2 = MM::Add.new(process_name: 'foo')
10
+ expect(message).to eql m2
11
+ end
12
+
13
+ it "should report objects to be not eql if differnt value" do
14
+ m2 = MM::Add.new(process_name: 'bar')
15
+ expect(message).to_not eql m2
16
+ end
17
+ end
18
+
19
+ context "for nested messages" do
20
+ let(:process_array) do
21
+ [
22
+ { shell_command: 'foo', process_name: 'foo', dir: '/tmp', pid: 100,
23
+ port: 9000 },
24
+ { shell_command: 'bar', process_name: 'bar', dir: '/tmp', pid: 200,
25
+ port: 9001 }
26
+ ]
27
+ end
28
+
29
+ let(:message) { MM::ListResponse.new(processes: process_array) }
30
+
31
+ it "should report eql for eql objects" do
32
+ m2 = MM::ListResponse.new(processes: process_array)
33
+ expect(message).to eql m2
34
+ end
35
+
36
+ it "should report not equal for different objects" do
37
+ another_process_array = [
38
+ { shell_command: 'baz', process_name: 'foo', dir: '/tmp', pid: 100,
39
+ port: 9000 },
40
+ { shell_command: 'bar', process_name: 'bar', dir: '/tmp', pid: 200,
41
+ port: 9001 }
42
+ ]
43
+
44
+ m2 = MM::ListResponse.new(processes: another_process_array)
45
+ expect(message).to_not eql m2
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::IPC::UnixClient do
4
+ let(:unix_client) { described_class.new }
5
+ let(:socket) { StringIO.new }
6
+
7
+ describe "serializing a " do
8
+ it "list request should work" do
9
+ unix_client.expects(:open_client_socket).yields(socket)
10
+ unix_client.send_command("list")
11
+
12
+ expect(socket.string).to match(/list/)
13
+ end
14
+
15
+ it "add request should work" do
16
+ unix_client.expects(:open_client_socket).yields(socket)
17
+ unix_client.send_command("add", process_name: "hello")
18
+
19
+ expect(socket.string).to match(/hello/)
20
+ end
21
+ end
22
+
23
+ describe ".send_command" do
24
+ it "calls the send_command instance method" do
25
+ Invoker::IPC::UnixClient.any_instance.expects(:send_command).once
26
+ Invoker::IPC::UnixClient.send_command("list")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Invoker::Power::Balancer do
4
+ before do
5
+ @http_connection = mock("connection")
6
+ @balancer = Invoker::Power::Balancer.new(@http_connection, "http")
7
+ end
8
+
9
+ context "when Host field is not capitalized" do
10
+ before(:all) do
11
+ @original_invoker_config = Invoker.config
12
+ end
13
+
14
+ def mock_invoker_tld_as(domain)
15
+ Invoker.config = mock
16
+ Invoker.config.stubs(:tld).returns(domain)
17
+ end
18
+
19
+ after(:all) do
20
+ Invoker.config = @original_invoker_config
21
+ end
22
+
23
+ it "should not return 400 when host is lowercase" do
24
+ headers = { 'host' => 'somehost.com' }
25
+ mock_invoker_tld_as('test')
26
+ @http_connection.expects(:send_data).with() { |value| value =~ /404 Not Found/i }
27
+ @http_connection.expects(:close_connection_after_writing)
28
+ @balancer.headers_received(headers)
29
+ end
30
+
31
+ it "should not return 400 when host is written as HoSt" do
32
+ headers = { 'HoSt' => 'somehost.com' }
33
+ mock_invoker_tld_as('test')
34
+ @http_connection.expects(:send_data).with() { |value| value =~ /404 Not Found/i }
35
+ @http_connection.expects(:close_connection_after_writing)
36
+ @balancer.headers_received(headers)
37
+ end
38
+ end
39
+
40
+ context "when Host field is missing in the request" do
41
+ it "should return 400 as response when Host is missing" do
42
+ headers = {}
43
+ @http_connection.expects(:send_data).with() { |value| value =~ /400 Bad Request/i }
44
+ @balancer.headers_received(headers)
45
+ end
46
+
47
+ it "should return 400 as response when Host is empty" do
48
+ headers = { 'Host' => '' }
49
+ @http_connection.expects(:send_data).with() { |value| value =~ /400 Bad Request/i }
50
+ @balancer.headers_received(headers)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ describe "Invoker Power configuration", fakefs: true do
4
+ describe "#create" do
5
+ it "should create a config file given a hash" do
6
+ FileUtils.mkdir_p(inv_conf_dir)
7
+ config = Invoker::Power::Config.create(
8
+ dns_port: 1200, http_port: 1201, ipfw_rule_number: 010
9
+ )
10
+ expect(File.exist?(Invoker::Power::Config.config_file)).to be_truthy
11
+
12
+ config = Invoker::Power::Config.load_config()
13
+ expect(config.dns_port).to eq(1200)
14
+ expect(config.http_port).to eq(1201)
15
+ expect(config.ipfw_rule_number).to eq(010)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::Power::HttpParser do
4
+ let(:parser) { Invoker::Power::HttpParser.new('https') }
5
+
6
+ describe "complete message received" do
7
+ before { parser.reset }
8
+ it "should call header received with full header" do
9
+ @header = nil
10
+ parser.on_headers_complete { |header| @header = header }
11
+ parser << "HTTP/1.1 200 OK\r\n"
12
+ parser << "Content-Type: text/plain;charset=utf-8\r\n"
13
+ parser << "Content-Length: 5\r\n"
14
+ parser << "Connection: close\r\n\r\n"
15
+ parser << "hello"
16
+
17
+ expect(@header['Content-Type']).to eql "text/plain;charset=utf-8"
18
+ end
19
+
20
+ it "should return complete message with x_forwarded added" do
21
+ complete_message = nil
22
+ parser.on_message_complete { |message| complete_message = message }
23
+ parser.on_headers_complete { |header| @header = header }
24
+ parser << "HTTP/1.1 200 OK\r\n"
25
+ parser << "Content-Type: text/plain;charset=utf-8\r\n"
26
+ parser << "Content-Length: 5\r\n"
27
+ parser << "Connection: close\r\n\r\n"
28
+ parser << "hello"
29
+ expect(complete_message).to match(/X_FORWARDED_PROTO:/i)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+ require "tempfile"
3
+
4
+ describe Invoker::Power::HttpResponse do
5
+ before do
6
+ @http_response = Invoker::Power::HttpResponse.new()
7
+ end
8
+
9
+ it "should allow user to send a file" do
10
+ begin
11
+ file = Tempfile.new("error.html")
12
+ file_content = "Error message"
13
+ file.write(file_content)
14
+ file.close
15
+
16
+ @http_response.use_file_as_body(file.path)
17
+ expect(@http_response.body).to eq(file_content)
18
+ expect(@http_response.http_string).to include(file_content)
19
+ ensure
20
+ file.unlink
21
+ end
22
+ end
23
+
24
+ it "should allow user to set headers" do
25
+ @http_response["Content-Type"] = "text/html"
26
+ expect(@http_response.header["Content-Type"]).to eq("text/html")
27
+ expect(@http_response.http_string).to include("Content-Type")
28
+ end
29
+
30
+ it "should allow user to set status" do
31
+ @http_response.status = 503
32
+ expect(@http_response.http_string).to include(Invoker::Power::HttpResponse::STATUS_MAPS[503])
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ describe "PortFinder" do
4
+ before do
5
+ @port_finder = Invoker::Power::PortFinder.new()
6
+ @port_finder.find_ports
7
+ end
8
+
9
+ it "should find a http port" do
10
+ expect(@port_finder.http_port).not_to be_nil
11
+ end
12
+
13
+ it "should find a dns port" do
14
+ expect(@port_finder.dns_port).not_to be_nil
15
+ end
16
+ end
@@ -0,0 +1,166 @@
1
+ require "spec_helper"
2
+ require "invoker/power/setup/distro/ubuntu"
3
+ require "invoker/power/setup/distro/opensuse"
4
+
5
+ def mock_socat_scripts
6
+ FakeFS.deactivate!
7
+ socat_content = File.read(invoker_setup.forwarder_script)
8
+ socat_systemd = File.read(invoker_setup.socat_unit)
9
+ FakeFS.activate!
10
+ FileUtils.mkdir_p(File.dirname(invoker_setup.forwarder_script))
11
+ FileUtils.mkdir_p(File.dirname(invoker_setup.socat_unit))
12
+ File.open(invoker_setup.socat_unit, "w") do |fl|
13
+ fl.write(socat_systemd)
14
+ end
15
+ File.open(invoker_setup.forwarder_script, "w") do |fl|
16
+ fl.write(socat_content)
17
+ end
18
+ FileUtils.mkdir_p("/usr/bin")
19
+ FileUtils.mkdir_p("/etc/systemd/system")
20
+ end
21
+
22
+ describe Invoker::Power::LinuxSetup, fakefs: true do
23
+ before do
24
+ FileUtils.mkdir_p(inv_conf_dir)
25
+ FileUtils.mkdir_p(Invoker::Power::Distro::Base::RESOLVER_DIR)
26
+ Invoker.config = mock
27
+ end
28
+
29
+ let(:invoker_setup) { Invoker::Power::LinuxSetup.new('test') }
30
+ let(:distro_installer) { Invoker::Power::Distro::Ubuntu.new('test') }
31
+
32
+ before do
33
+ invoker_setup.distro_installer = distro_installer
34
+ end
35
+
36
+ it "should only proceed after user confirmation" do
37
+ distro_installer.expects(:get_user_confirmation?).returns(false)
38
+
39
+ invoker_setup.setup_invoker
40
+
41
+ expect { Invoker::Power::Config.load_config }.to raise_error(Errno::ENOENT)
42
+ end
43
+
44
+ it "should create config file with http(s) ports" do
45
+ invoker_setup.expects(:initialize_distro_installer).returns(true)
46
+ invoker_setup.expects(:install_resolver).returns(true)
47
+ invoker_setup.expects(:install_port_forwarder).returns(true)
48
+ invoker_setup.expects(:drop_to_normal_user).returns(true)
49
+
50
+ distro_installer.expects(:get_user_confirmation?).returns(true)
51
+ distro_installer.expects(:install_required_software)
52
+ distro_installer.expects(:restart_services)
53
+
54
+ invoker_setup.setup_invoker
55
+
56
+ config = Invoker::Power::Config.load_config
57
+ expect(config.tld).to eq('test')
58
+ expect(config.http_port).not_to be_nil
59
+ expect(config.dns_port).to be_nil
60
+ expect(config.https_port).not_to be_nil
61
+ end
62
+
63
+ describe "configuring services" do
64
+ let(:config) { Invoker::Power::Config.load_config }
65
+
66
+ before(:all) do
67
+ @original_invoker_config = Invoker.config
68
+ end
69
+
70
+ after(:all) do
71
+ Invoker.config = @original_invoker_config
72
+ end
73
+
74
+ before(:each) do
75
+ mock_socat_scripts
76
+ end
77
+
78
+ def run_setup
79
+ invoker_setup.expects(:initialize_distro_installer).returns(true)
80
+ invoker_setup.expects(:drop_to_normal_user).returns(true)
81
+
82
+ distro_installer.expects(:get_user_confirmation?).returns(true)
83
+ distro_installer.expects(:install_required_software)
84
+ distro_installer.expects(:restart_services)
85
+
86
+ invoker_setup.setup_invoker
87
+ end
88
+
89
+ def test_socat_config
90
+ socat_content = File.read(Invoker::Power::Distro::Base::SOCAT_SHELLSCRIPT)
91
+ expect(socat_content.strip).to_not be_empty
92
+ expect(socat_content.strip).to match(/#{config.https_port}/)
93
+ expect(socat_content.strip).to match(/#{config.http_port}/)
94
+
95
+ service_file = File.read(Invoker::Power::Distro::Base::SOCAT_SYSTEMD)
96
+ expect(service_file.strip).to_not be_empty
97
+ end
98
+
99
+ context 'on ubuntu with systemd-resolved' do
100
+ it "should create socat config & set tld to localhost" do
101
+ distro_installer.expects(:using_systemd_resolved?).at_least_once.returns(true)
102
+ run_setup
103
+ expect(distro_installer.resolver_file).to be_nil
104
+ test_socat_config
105
+ expect(config.tld).to eq('localhost')
106
+ end
107
+ end
108
+
109
+ context 'on non-systemd-resolved distro' do
110
+ it "should create dnsmasq & socat configs" do
111
+ run_setup
112
+ dnsmasq_content = File.read(distro_installer.resolver_file)
113
+ expect(dnsmasq_content.strip).to_not be_empty
114
+ expect(dnsmasq_content).to match(/test/)
115
+
116
+ test_socat_config
117
+ end
118
+ end
119
+ end
120
+
121
+ describe 'resolver file' do
122
+ context 'user sets up a custom top level domain' do
123
+ let(:tld) { 'local' }
124
+ let(:linux_setup) { Invoker::Power::LinuxSetup.new(tld) }
125
+
126
+ context 'on ubuntu with systemd-resolved' do
127
+ it 'should not create a resolver file' do
128
+ ubuntu_installer = Invoker::Power::Distro::Ubuntu.new(tld)
129
+ linux_setup.distro_installer = ubuntu_installer
130
+ ubuntu_installer.expects(:using_systemd_resolved?).at_least_once.returns(true)
131
+ expect(linux_setup.resolver_file).to eq(nil)
132
+ end
133
+ end
134
+
135
+ context 'on non-systemd-resolved distro' do
136
+ it 'should create the correct resolver file' do
137
+ suse_installer = Invoker::Power::Distro::Opensuse.new(tld)
138
+ linux_setup.distro_installer = suse_installer
139
+ expect(linux_setup.resolver_file).to eq("/etc/dnsmasq.d/#{tld}-tld")
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ describe Invoker::Power::Distro::Base, docker: true do
147
+ describe '.distro_installer' do
148
+ it 'correctly recognizes the current distro' do
149
+ case ENV['DISTRO']
150
+ when 'archlinux', 'manjarolinux/base'
151
+ expect(described_class.distro_installer('')).to be_a Invoker::Power::Distro::Arch
152
+ when 'debian'
153
+ expect(described_class.distro_installer('')).to be_a Invoker::Power::Distro::Debian
154
+ when 'fedora'
155
+ expect(described_class.distro_installer('')).to be_a Invoker::Power::Distro::Redhat
156
+ when 'linuxmintd/mint20-amd64', 'ubuntu'
157
+ expect(described_class.distro_installer('')).to be_a Invoker::Power::Distro::Ubuntu
158
+ when 'opensuse/leap', 'opensuse/tumbleweed'
159
+ expect(described_class.distro_installer('')).to be_a Invoker::Power::Distro::Opensuse
160
+ when nil
161
+ else
162
+ raise 'Unrecognized Linux distro. Please add the appropriate docker image to the travis build matrix, update the described method, and add a case here.'
163
+ end
164
+ end
165
+ end
166
+ end