meepo 1.5.2
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/.coveralls.yml +1 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +10 -0
- data/Dockerfile +7 -0
- data/Gemfile +13 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +15 -0
- data/TODO +5 -0
- data/bin/invoker +7 -0
- data/contrib/completion/invoker-completion.bash +70 -0
- data/contrib/completion/invoker-completion.zsh +62 -0
- data/examples/hello_sinatra.rb +26 -0
- data/examples/sample.ini +3 -0
- data/invoker.gemspec +43 -0
- data/lib/invoker.rb +152 -0
- data/lib/invoker/cli.rb +159 -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/command_worker.rb +60 -0
- data/lib/invoker/commander.rb +95 -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.rb +45 -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.rb +170 -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/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/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 +131 -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/pf_migrate.rb +64 -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.rb +90 -0
- data/lib/invoker/power/setup/distro/arch.rb +15 -0
- data/lib/invoker/power/setup/distro/base.rb +57 -0
- data/lib/invoker/power/setup/distro/debian.rb +11 -0
- data/lib/invoker/power/setup/distro/mint.rb +10 -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 +10 -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 +105 -0
- data/lib/invoker/power/setup/osx_setup.rb +137 -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 +198 -0
- data/lib/invoker/process_printer.rb +43 -0
- data/lib/invoker/reactor.rb +37 -0
- data/lib/invoker/reactor/reader.rb +54 -0
- data/lib/invoker/version.rb +47 -0
- data/readme.md +25 -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 +22 -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/pf_migrate_spec.rb +87 -0
- data/spec/invoker/power/port_finder_spec.rb +16 -0
- data/spec/invoker/power/setup/linux_setup_spec.rb +103 -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 +70 -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 +389 -0
|
@@ -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,103 @@
|
|
|
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
|
+
end
|
|
20
|
+
|
|
21
|
+
describe Invoker::Power::LinuxSetup, fakefs: true do
|
|
22
|
+
before do
|
|
23
|
+
FileUtils.mkdir_p(inv_conf_dir)
|
|
24
|
+
FileUtils.mkdir_p(Invoker::Power::Distro::Base::RESOLVER_DIR)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
let(:invoker_setup) { Invoker::Power::LinuxSetup.new('dev') }
|
|
28
|
+
let(:distro_installer) { Invoker::Power::Distro::Ubuntu.new('dev') }
|
|
29
|
+
|
|
30
|
+
describe "should only proceed after user confirmation" do
|
|
31
|
+
before { invoker_setup.distro_installer = distro_installer }
|
|
32
|
+
|
|
33
|
+
it "should create config file with port" do
|
|
34
|
+
invoker_setup.expects(:initialize_distro_installer).returns(true)
|
|
35
|
+
invoker_setup.expects(:get_user_confirmation?).returns(true)
|
|
36
|
+
invoker_setup.expects(:install_resolver).returns(true)
|
|
37
|
+
invoker_setup.expects(:install_port_forwarder).returns(true)
|
|
38
|
+
invoker_setup.expects(:drop_to_normal_user).returns(true)
|
|
39
|
+
|
|
40
|
+
distro_installer.expects(:install_required_software)
|
|
41
|
+
distro_installer.expects(:restart_services)
|
|
42
|
+
|
|
43
|
+
invoker_setup.setup_invoker
|
|
44
|
+
|
|
45
|
+
config = Invoker::Power::Config.load_config
|
|
46
|
+
expect(config.http_port).not_to be_nil
|
|
47
|
+
expect(config.dns_port).to be_nil
|
|
48
|
+
expect(config.https_port).not_to be_nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "configuring dnsmasq and socat" do
|
|
53
|
+
before(:all) do
|
|
54
|
+
@original_invoker_config = Invoker.config
|
|
55
|
+
Invoker.config = mock
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
after(:all) do
|
|
59
|
+
Invoker.config = @original_invoker_config
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
before(:each) do
|
|
63
|
+
invoker_setup.distro_installer = distro_installer
|
|
64
|
+
mock_socat_scripts
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should create proper config file" do
|
|
68
|
+
invoker_setup.expects(:initialize_distro_installer).returns(true)
|
|
69
|
+
invoker_setup.expects(:get_user_confirmation?).returns(true)
|
|
70
|
+
invoker_setup.expects(:drop_to_normal_user).returns(true)
|
|
71
|
+
|
|
72
|
+
distro_installer.expects(:install_required_software)
|
|
73
|
+
distro_installer.expects(:restart_services)
|
|
74
|
+
|
|
75
|
+
invoker_setup.setup_invoker
|
|
76
|
+
|
|
77
|
+
config = Invoker::Power::Config.load_config
|
|
78
|
+
|
|
79
|
+
dnsmasq_content = File.read(distro_installer.resolver_file)
|
|
80
|
+
expect(dnsmasq_content.strip).to_not be_empty
|
|
81
|
+
expect(dnsmasq_content).to match(/dev/)
|
|
82
|
+
|
|
83
|
+
socat_content = File.read(Invoker::Power::Distro::Base::SOCAT_SHELLSCRIPT)
|
|
84
|
+
expect(socat_content.strip).to_not be_empty
|
|
85
|
+
expect(socat_content.strip).to match(/#{config.https_port}/)
|
|
86
|
+
expect(socat_content.strip).to match(/#{config.http_port}/)
|
|
87
|
+
|
|
88
|
+
service_file = File.read(Invoker::Power::Distro::Base::SOCAT_SYSTEMD)
|
|
89
|
+
expect(service_file.strip).to_not be_empty
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe 'resolver file' do
|
|
94
|
+
context 'user sets up a custom top level domain' do
|
|
95
|
+
it 'should create the correct resolver file' do
|
|
96
|
+
linux_setup = Invoker::Power::LinuxSetup.new('local')
|
|
97
|
+
suse_installer = Invoker::Power::Distro::Opensuse.new('local')
|
|
98
|
+
linux_setup.distro_installer = suse_installer
|
|
99
|
+
expect(linux_setup.resolver_file).to eq('/etc/dnsmasq.d/local-tld')
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Invoker::Power::OsxSetup, fakefs: true do
|
|
4
|
+
before do
|
|
5
|
+
FileUtils.mkdir_p(inv_conf_dir)
|
|
6
|
+
FileUtils.mkdir_p(Invoker::Power::OsxSetup::RESOLVER_DIR)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe "when no setup exists" do
|
|
10
|
+
it "should create a config file with port etc" do
|
|
11
|
+
setup = Invoker::Power::OsxSetup.new('dev')
|
|
12
|
+
setup.expects(:install_resolver).returns(true)
|
|
13
|
+
setup.expects(:drop_to_normal_user).returns(true)
|
|
14
|
+
setup.expects(:install_firewall).once
|
|
15
|
+
|
|
16
|
+
setup.setup_invoker
|
|
17
|
+
|
|
18
|
+
config = Invoker::Power::Config.load_config
|
|
19
|
+
expect(config.http_port).not_to be_nil
|
|
20
|
+
expect(config.dns_port).not_to be_nil
|
|
21
|
+
expect(config.https_port).not_to be_nil
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "when a setup file exists" do
|
|
26
|
+
it "should throw error about existing file" do
|
|
27
|
+
File.open(Invoker::Power::Config.config_file, "w") {|fl|
|
|
28
|
+
fl.write("foo test")
|
|
29
|
+
}
|
|
30
|
+
Invoker::Power::Setup.any_instance.expects(:setup_invoker).never
|
|
31
|
+
Invoker::Power::Setup.install('dev')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe "when pow like setup exists" do
|
|
36
|
+
before {
|
|
37
|
+
File.open(File.join(Invoker::Power::OsxSetup::RESOLVER_DIR, "dev"), "w") { |fl|
|
|
38
|
+
fl.write("hello")
|
|
39
|
+
}
|
|
40
|
+
@setup = Invoker::Power::OsxSetup.new('dev')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe "when user selects to overwrite it" do
|
|
44
|
+
it "should run setup normally" do
|
|
45
|
+
@setup.expects(:setup_resolver_file).returns(true)
|
|
46
|
+
@setup.expects(:drop_to_normal_user).returns(true)
|
|
47
|
+
@setup.expects(:install_resolver).returns(true)
|
|
48
|
+
@setup.expects(:install_firewall).once()
|
|
49
|
+
|
|
50
|
+
@setup.setup_invoker
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "when user chose not to overwrite it" do
|
|
55
|
+
it "should abort the setup process" do
|
|
56
|
+
@setup.expects(:setup_resolver_file).returns(false)
|
|
57
|
+
|
|
58
|
+
@setup.expects(:install_resolver).never
|
|
59
|
+
@setup.expects(:install_firewall).never
|
|
60
|
+
|
|
61
|
+
@setup.setup_invoker
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "uninstalling firewall rules" do
|
|
67
|
+
it "should uninstall firewall rules and remove all files created by setup" do
|
|
68
|
+
setup = Invoker::Power::OsxSetup.new('dev')
|
|
69
|
+
|
|
70
|
+
Invoker::CLI::Question.expects(:agree).returns(true)
|
|
71
|
+
setup.expects(:remove_resolver_file).once
|
|
72
|
+
setup.expects(:unload_firewall_rule).with(true).once
|
|
73
|
+
Invoker::Power::Config.expects(:delete).once
|
|
74
|
+
|
|
75
|
+
setup.uninstall_invoker
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe "setup on fresh osx install" do
|
|
80
|
+
context "when resolver directory does not exist" do
|
|
81
|
+
before do
|
|
82
|
+
@setup = Invoker::Power::OsxSetup.new('dev')
|
|
83
|
+
FileUtils.rm_rf(Invoker::Power::OsxSetup::RESOLVER_DIR)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "should create the directory and install" do
|
|
87
|
+
@setup.expects(:setup_resolver_file).returns(true)
|
|
88
|
+
@setup.expects(:drop_to_normal_user).returns(true)
|
|
89
|
+
@setup.expects(:install_firewall).once()
|
|
90
|
+
|
|
91
|
+
@setup.setup_invoker
|
|
92
|
+
expect(Dir.exist?(Invoker::Power::OsxSetup::RESOLVER_DIR)).to be_truthy
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '.resolver_file' do
|
|
98
|
+
context 'user sets up a custom top level domain' do
|
|
99
|
+
it 'should create the correct resolver file' do
|
|
100
|
+
setup = Invoker::Power::OsxSetup.new('local')
|
|
101
|
+
expect(setup.resolver_file).to eq('/etc/resolver/local')
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Invoker::Power::UrlRewriter do
|
|
4
|
+
let(:rewriter) { Invoker::Power::UrlRewriter.new }
|
|
5
|
+
|
|
6
|
+
context "matching domain part of incoming request" do
|
|
7
|
+
before(:all) do
|
|
8
|
+
@original_invoker_config = Invoker.config
|
|
9
|
+
|
|
10
|
+
Invoker.config = mock
|
|
11
|
+
Invoker.config.stubs(:tld).returns("dev")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
after(:all) do
|
|
15
|
+
Invoker.config = @original_invoker_config
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should match foo.dev" do
|
|
19
|
+
match = rewriter.extract_host_from_domain("foo.dev")
|
|
20
|
+
expect(match).to_not be_empty
|
|
21
|
+
|
|
22
|
+
matching_string = match[0]
|
|
23
|
+
expect(matching_string).to eq("foo")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should match foo.dev:1080" do
|
|
27
|
+
match = rewriter.extract_host_from_domain("foo.dev:1080")
|
|
28
|
+
expect(match).to_not be_empty
|
|
29
|
+
|
|
30
|
+
matching_string = match[0]
|
|
31
|
+
expect(matching_string).to eq("foo")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should match emacs.bar.dev" do
|
|
35
|
+
match = rewriter.extract_host_from_domain("emacs.bar.dev")
|
|
36
|
+
expect(match).to_not be_empty
|
|
37
|
+
|
|
38
|
+
expect(match[0]).to eq("emacs.bar")
|
|
39
|
+
expect(match[1]).to eq("bar")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should match hello-world.dev" do
|
|
43
|
+
match = rewriter.extract_host_from_domain("hello-world.dev")
|
|
44
|
+
expect(match).to_not be_nil
|
|
45
|
+
|
|
46
|
+
expect(match[0]).to eq("hello-world")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'user sets up a custom top level domain' do
|
|
50
|
+
before(:all) do
|
|
51
|
+
@original_invoker_config = Invoker.config
|
|
52
|
+
|
|
53
|
+
Invoker.config = mock
|
|
54
|
+
Invoker.config.stubs(:tld).returns("local")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'should match domain part of incoming request correctly' do
|
|
58
|
+
match = rewriter.extract_host_from_domain("foo.local")
|
|
59
|
+
expect(match).to_not be_empty
|
|
60
|
+
|
|
61
|
+
matching_string = match[0]
|
|
62
|
+
expect(matching_string).to eq("foo")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
after(:all) do
|
|
66
|
+
Invoker.config = @original_invoker_config
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Full integration test. Start a server, and client. Let client interact with
|
|
4
|
+
# server do a ping-pong. Client checks whether ping pong is successful or not.
|
|
5
|
+
# Also, mock rewriter so that it returns valid port for request proxying.
|
|
6
|
+
# - Server will run on port 28080.
|
|
7
|
+
# - Balancer will run on port 28081 proxying to 28080
|
|
8
|
+
# - Client will connect to 28081 performing ping-pong
|
|
9
|
+
|
|
10
|
+
def websocket_server
|
|
11
|
+
require 'websocket-eventmachine-server'
|
|
12
|
+
|
|
13
|
+
EM.run do
|
|
14
|
+
WebSocket::EventMachine::Server.start(host: "0.0.0.0", port: 28080) do |ws|
|
|
15
|
+
ws.onerror { |e| p e }
|
|
16
|
+
ws.onmessage { ws.send "pong" }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
EM.add_timer(2) { EM.stop }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def websocket_client
|
|
24
|
+
require 'websocket-eventmachine-client'
|
|
25
|
+
|
|
26
|
+
@message = ""
|
|
27
|
+
|
|
28
|
+
EM.run do
|
|
29
|
+
ws = WebSocket::EventMachine::Client.connect(uri: 'ws://0.0.0.0:28081')
|
|
30
|
+
ws.onerror { |e| p e }
|
|
31
|
+
ws.onopen { ws.send("ping") }
|
|
32
|
+
ws.onmessage { |m, _| @message = m }
|
|
33
|
+
|
|
34
|
+
EM.add_timer(2) do
|
|
35
|
+
expect(@message).to eq "pong"
|
|
36
|
+
EM.stop
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
describe 'Web sockets support' do
|
|
43
|
+
it 'can ping pong via balancer' do
|
|
44
|
+
dns_response = Struct.new(:port, :ip).new(28080, "0.0.0.0")
|
|
45
|
+
Invoker::Power::UrlRewriter.any_instance
|
|
46
|
+
.stubs(:select_backend_config)
|
|
47
|
+
.returns(dns_response)
|
|
48
|
+
|
|
49
|
+
EM.run do
|
|
50
|
+
EM.start_server("0.0.0.0", 28081, EM::ProxyServer::Connection, {}) do |conn|
|
|
51
|
+
Invoker::Power::Balancer.new(conn, "http").install_callbacks
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
fork { websocket_server }
|
|
55
|
+
fork { websocket_client }
|
|
56
|
+
EM.add_timer(3) { EM.stop }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
Process.waitall
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Invoker::ProcessManager do
|
|
4
|
+
let(:process_manager) { Invoker::ProcessManager.new }
|
|
5
|
+
|
|
6
|
+
describe "#start_process_by_name" do
|
|
7
|
+
it "should find command by label and start it, if found" do
|
|
8
|
+
@original_invoker_config = Invoker.config
|
|
9
|
+
Invoker.config = mock
|
|
10
|
+
|
|
11
|
+
Invoker.config.stubs(:processes).returns([OpenStruct.new(:label => "resque", :cmd => "foo", :dir => "bar")])
|
|
12
|
+
Invoker.config.expects(:process).returns(OpenStruct.new(:label => "resque", :cmd => "foo", :dir => "bar"))
|
|
13
|
+
process_manager.expects(:start_process).returns(true)
|
|
14
|
+
|
|
15
|
+
process_manager.start_process_by_name("resque")
|
|
16
|
+
|
|
17
|
+
Invoker.config = @original_invoker_config
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should not start already running process" do
|
|
21
|
+
process_manager.workers.expects(:[]).returns(OpenStruct.new(:pid => "bogus"))
|
|
22
|
+
expect(process_manager.start_process_by_name("resque")).to be_falsey
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#stop_process" do
|
|
27
|
+
let(:message) { MM::Remove.new(options) }
|
|
28
|
+
describe "when a worker is found" do
|
|
29
|
+
before do
|
|
30
|
+
process_manager.workers.expects(:[]).returns(OpenStruct.new(:pid => "bogus"))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "if a signal is specified" do
|
|
34
|
+
let(:options) { { process_name: 'bogus', signal: 'HUP' } }
|
|
35
|
+
it "should use that signal to kill the worker" do
|
|
36
|
+
process_manager.expects(:process_kill).with("bogus", "HUP").returns(true)
|
|
37
|
+
expect(process_manager.stop_process(message)).to be_truthy
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "if no signal is specified" do
|
|
42
|
+
let(:options) { { process_name: 'bogus' } }
|
|
43
|
+
it "should use INT signal" do
|
|
44
|
+
process_manager.expects(:process_kill).with("bogus", "INT").returns(true)
|
|
45
|
+
expect(process_manager.stop_process(message)).to be_truthy
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "when no worker is found" do
|
|
51
|
+
let(:options) { { process_name: 'bogus', signal: 'HUP' } }
|
|
52
|
+
before do
|
|
53
|
+
process_manager.workers.expects(:[]).returns(nil)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should not kill anything" do
|
|
57
|
+
process_manager.expects(:process_kill).never
|
|
58
|
+
process_manager.stop_process(message)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe "#load_env" do
|
|
64
|
+
it "should load .env file from the specified directory" do
|
|
65
|
+
dir = "/tmp"
|
|
66
|
+
begin
|
|
67
|
+
env_file = File.new("#{dir}/.env", "w")
|
|
68
|
+
env_data =<<-EOD
|
|
69
|
+
FOO=foo
|
|
70
|
+
BAR=bar
|
|
71
|
+
EOD
|
|
72
|
+
env_file.write(env_data)
|
|
73
|
+
env_file.close
|
|
74
|
+
env_options = process_manager.load_env(dir)
|
|
75
|
+
expect(env_options).to include("FOO" => "foo", "BAR" => "bar")
|
|
76
|
+
ensure
|
|
77
|
+
File.delete(env_file.path)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "should default to current directory if no directory is specified" do
|
|
82
|
+
dir = ENV["HOME"]
|
|
83
|
+
ENV.stubs(:[]).with("PWD").returns(dir)
|
|
84
|
+
begin
|
|
85
|
+
env_file = File.new("#{dir}/.env", "w")
|
|
86
|
+
env_data =<<-EOD
|
|
87
|
+
FOO=bar
|
|
88
|
+
BAR=foo
|
|
89
|
+
EOD
|
|
90
|
+
env_file.write(env_data)
|
|
91
|
+
env_file.close
|
|
92
|
+
env_options = process_manager.load_env
|
|
93
|
+
expect(env_options).to include("FOO" => "bar", "BAR" => "foo")
|
|
94
|
+
ensure
|
|
95
|
+
File.delete(env_file.path)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should return empty hash if there is no .env file" do
|
|
100
|
+
dir = "/tmp"
|
|
101
|
+
expect(process_manager.load_env(dir)).to eq({})
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should load .local.env file if it exists" do
|
|
105
|
+
dir = "/tmp"
|
|
106
|
+
begin
|
|
107
|
+
env_file = File.new("#{dir}/.env", "w")
|
|
108
|
+
env_data =<<-EOD
|
|
109
|
+
FOO=foo
|
|
110
|
+
BAR=bar
|
|
111
|
+
EOD
|
|
112
|
+
env_file.write(env_data)
|
|
113
|
+
env_file.close
|
|
114
|
+
|
|
115
|
+
local_env_file = File.new("#{dir}/.env.local", "w")
|
|
116
|
+
local_env_data =<<-EOD
|
|
117
|
+
FOO=emacs
|
|
118
|
+
EOD
|
|
119
|
+
local_env_file.write(local_env_data)
|
|
120
|
+
local_env_file.close
|
|
121
|
+
|
|
122
|
+
env_options = process_manager.load_env(dir)
|
|
123
|
+
expect(env_options).to include("FOO" => "emacs", "BAR" => "bar")
|
|
124
|
+
ensure
|
|
125
|
+
File.delete(env_file.path)
|
|
126
|
+
File.delete(local_env_file.path)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|