invoker_ruby34 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +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
|