itrg-invoker 1.6.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 +7 -0
- data/bin/invoker +7 -0
- data/lib/invoker/cli/pinger.rb +23 -0
- data/lib/invoker/cli/question.rb +15 -0
- data/lib/invoker/cli/tail.rb +34 -0
- data/lib/invoker/cli/tail_watcher.rb +34 -0
- data/lib/invoker/cli.rb +197 -0
- data/lib/invoker/command_worker.rb +64 -0
- data/lib/invoker/commander.rb +101 -0
- data/lib/invoker/daemon.rb +126 -0
- data/lib/invoker/dns_cache.rb +23 -0
- data/lib/invoker/errors.rb +17 -0
- data/lib/invoker/event/manager.rb +79 -0
- data/lib/invoker/ipc/add_command.rb +12 -0
- data/lib/invoker/ipc/add_http_command.rb +10 -0
- data/lib/invoker/ipc/base_command.rb +24 -0
- data/lib/invoker/ipc/client_handler.rb +26 -0
- data/lib/invoker/ipc/dns_check_command.rb +17 -0
- data/lib/invoker/ipc/list_command.rb +11 -0
- data/lib/invoker/ipc/message/list_response.rb +35 -0
- data/lib/invoker/ipc/message/tail_response.rb +10 -0
- data/lib/invoker/ipc/message.rb +170 -0
- data/lib/invoker/ipc/ping_command.rb +10 -0
- data/lib/invoker/ipc/reload_command.rb +12 -0
- data/lib/invoker/ipc/remove_command.rb +12 -0
- data/lib/invoker/ipc/server.rb +26 -0
- data/lib/invoker/ipc/tail_command.rb +11 -0
- data/lib/invoker/ipc/unix_client.rb +60 -0
- data/lib/invoker/ipc.rb +45 -0
- data/lib/invoker/logger.rb +13 -0
- data/lib/invoker/parsers/config.rb +184 -0
- data/lib/invoker/parsers/procfile.rb +86 -0
- data/lib/invoker/power/balancer.rb +133 -0
- data/lib/invoker/power/config.rb +77 -0
- data/lib/invoker/power/dns.rb +38 -0
- data/lib/invoker/power/http_parser.rb +68 -0
- data/lib/invoker/power/http_response.rb +81 -0
- data/lib/invoker/power/port_finder.rb +49 -0
- data/lib/invoker/power/power.rb +3 -0
- data/lib/invoker/power/powerup.rb +29 -0
- data/lib/invoker/power/setup/distro/arch.rb +15 -0
- data/lib/invoker/power/setup/distro/base.rb +80 -0
- data/lib/invoker/power/setup/distro/debian.rb +11 -0
- data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
- data/lib/invoker/power/setup/distro/redhat.rb +11 -0
- data/lib/invoker/power/setup/distro/ubuntu.rb +46 -0
- data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
- data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
- data/lib/invoker/power/setup/linux_setup.rb +97 -0
- data/lib/invoker/power/setup/osx_setup.rb +137 -0
- data/lib/invoker/power/setup.rb +93 -0
- data/lib/invoker/power/templates/400.html +40 -0
- data/lib/invoker/power/templates/404.html +40 -0
- data/lib/invoker/power/templates/503.html +40 -0
- data/lib/invoker/power/url_rewriter.rb +40 -0
- data/lib/invoker/process_manager.rb +201 -0
- data/lib/invoker/process_printer.rb +59 -0
- data/lib/invoker/reactor/reader.rb +65 -0
- data/lib/invoker/reactor.rb +37 -0
- data/lib/invoker/version.rb +47 -0
- data/lib/invoker.rb +151 -0
- data/spec/invoker/cli/pinger_spec.rb +22 -0
- data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
- data/spec/invoker/cli_spec.rb +27 -0
- data/spec/invoker/command_worker_spec.rb +45 -0
- data/spec/invoker/commander_spec.rb +152 -0
- data/spec/invoker/config_spec.rb +361 -0
- data/spec/invoker/daemon_spec.rb +34 -0
- data/spec/invoker/event/manager_spec.rb +67 -0
- data/spec/invoker/invoker_spec.rb +71 -0
- data/spec/invoker/ipc/client_handler_spec.rb +54 -0
- data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
- data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
- data/spec/invoker/ipc/message_spec.rb +49 -0
- data/spec/invoker/ipc/unix_client_spec.rb +29 -0
- data/spec/invoker/power/balancer_spec.rb +53 -0
- data/spec/invoker/power/config_spec.rb +18 -0
- data/spec/invoker/power/http_parser_spec.rb +32 -0
- data/spec/invoker/power/http_response_spec.rb +34 -0
- data/spec/invoker/power/port_finder_spec.rb +16 -0
- data/spec/invoker/power/setup/linux_setup_spec.rb +166 -0
- data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
- data/spec/invoker/power/setup_spec.rb +4 -0
- data/spec/invoker/power/url_rewriter_spec.rb +69 -0
- data/spec/invoker/power/web_sockets_spec.rb +61 -0
- data/spec/invoker/process_manager_spec.rb +130 -0
- data/spec/invoker/reactor_spec.rb +6 -0
- data/spec/spec_helper.rb +43 -0
- metadata +376 -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
|