freud 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Freud
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,141 @@
1
+ require "spec_helper"
2
+ require "freud/config"
3
+
4
+ RSpec.describe Freud::Config do
5
+ let(:config) { Freud::Config.new }
6
+
7
+ describe "#snakify_string" do
8
+ def call(input)
9
+ config.snakify_string(input)
10
+ end
11
+
12
+ it { expect(call("")).to eq("") }
13
+
14
+ it { expect(call("hello")).to eq("hello") }
15
+
16
+ it { expect(call("helloWorld")).to eq("hello_world") }
17
+
18
+ it { expect(call("HelloWorld")).to eq("hello_world") }
19
+
20
+ it { expect(call("Helloworld")).to eq("helloworld") }
21
+
22
+ it { expect(call("ThinkABC")).to eq("think_abc") }
23
+ end
24
+
25
+ describe "#expand_path" do
26
+ def call(path, relative_to)
27
+ config.expand_path(path, relative_to)
28
+ end
29
+
30
+ it { expect(call(".", "/tmp")).to eq("/tmp") }
31
+
32
+ it { expect(call("../root", "/tmp")).to eq("/root") }
33
+
34
+ it { expect(call("/root", "/tmp")).to eq("/root") }
35
+
36
+ it { expect(call("foo", "/tmp")).to eq("/tmp/foo") }
37
+ end
38
+
39
+ it "#deep_merge" do
40
+ left = { a: { b: { c: 42 } } }
41
+ right = { a: { b: { d: 72 } } }
42
+ output = { a: { b: { c: 42, d: 72 } } }
43
+ expect(config.deep_merge(left, right)).to eq(output)
44
+ end
45
+
46
+ it "#snakify_keys" do
47
+ input = { "aKey" => "a" }
48
+ expect(config.snakify_keys(input)).to eq("a_key" => "a")
49
+ end
50
+
51
+ it "#snakify_keys not recursive" do
52
+ input = { "aKey" => { "bKey" => "b" } }
53
+ expect(config.snakify_keys(input)).to eq("a_key" => { "bKey" => "b" })
54
+ end
55
+
56
+ describe "#load" do
57
+ def mock_file(name, content = nil)
58
+ default = { stages: { back: {} } }
59
+ content ||= block_given? ? yield : default
60
+ content = JSON.dump(content) if content.is_a?(Hash)
61
+ double(read: content, path: name, close: true)
62
+ end
63
+
64
+ def call(file, stage = "development")
65
+ Freud::Config.new.load(file, stage)
66
+ end
67
+
68
+ let(:root) { File.expand_path("#{File.dirname(__FILE__)}/..") }
69
+
70
+ it "name from file with extension" do
71
+ config = call(mock_file("monkey.json"))
72
+ expect(config.fetch("name")).to eq("monkey")
73
+ end
74
+
75
+ it "name from file with extension" do
76
+ config = call(mock_file("monkey"))
77
+ expect(config.fetch("name")).to eq("monkey")
78
+ end
79
+
80
+ it "pidfile tmp/%name" do
81
+ config = call(mock_file("monkey"))
82
+ expect(config.fetch("pidfile")).to eq("#{root}/tmp/monkey.pid")
83
+ end
84
+
85
+ it "pidfile %HOME/tmp/%name" do
86
+ home = ENV["HOME"]
87
+ content = { pidfile: "%HOME/tmp/%name.pid" }
88
+ config = call(mock_file("monkey", content))
89
+ expect(config.fetch("pidfile")).to eq("#{home}/tmp/monkey.pid")
90
+ end
91
+
92
+ it "logfile" do
93
+ content = { logfile: "log/%name.log" }
94
+ config = call(mock_file("monkey", content))
95
+ expect(config.fetch("logfile")).to eq("#{root}/log/monkey.log")
96
+ end
97
+
98
+ it "env FREUD_STAGE" do
99
+ config = call(mock_file("monkey"), "back")
100
+ env = config.to_hash.fetch("env")
101
+ expect(env["FREUD_STAGE"]).to eq("back")
102
+ end
103
+
104
+ it "background" do
105
+ config = call(mock_file("monkey", background: true))
106
+ expect(config.fetch("background")).to be(true)
107
+ end
108
+
109
+ it "reset_env" do
110
+ config = call(mock_file("monkey", reset_env: true))
111
+ expect(config.fetch("reset_env")).to be(true)
112
+ end
113
+
114
+ it "create_pidfile" do
115
+ config = call(mock_file("monkey", create_pidfile: true))
116
+ expect(config.fetch("create_pidfile")).to be(true)
117
+ end
118
+
119
+ it "javascript comments" do
120
+ content = mock_file("monkey", <<-END)
121
+ {
122
+ // Comment one.
123
+ "reset_env": true,
124
+ /* Comment two */
125
+ "name": "quux"
126
+ }
127
+ END
128
+ config = call(content)
129
+ expect(config.fetch("reset_env")).to be(true)
130
+ expect(config.fetch("name")).to eq("quux")
131
+ end
132
+
133
+ it "interpolates fully-merged" do
134
+ vars = { vars: { "RUNAS_USER" => "bob" } }
135
+ content = mock_file("monkey", sudo_user: "%RUNAS_USER",
136
+ stages: { development: vars })
137
+ config = call(content)
138
+ expect(config.fetch("sudo_user")).to eq("bob")
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "root": "../..",
3
+ "pidfile": "tmp/true.pid",
4
+ "logfile": "tmp/true.log",
5
+ "commands": { "quux": "/bin/true" }
6
+ }
@@ -0,0 +1,114 @@
1
+ require "spec_helper"
2
+ require "fileutils"
3
+ require "stringio"
4
+ require "freud/logging"
5
+ require "freud/launcher"
6
+ require "freud/pidfile"
7
+
8
+ RSpec.describe Freud::Launcher do
9
+ let(:log) { StringIO.new }
10
+
11
+ before(:each) { Freud::Logging.log_to(log) }
12
+
13
+ it "#new" do
14
+ fields = %w(name root pidfile logfile background create_pidfile
15
+ reset_env env commands)
16
+ command = Freud::Launcher.new(Hash[fields.map { |k| [ k, 42 ] }])
17
+ fields.each { |f| expect(command.send(f)).to eq(42) }
18
+ end
19
+
20
+ describe "#run" do
21
+ let(:process) { double }
22
+
23
+ let(:pidfile) { double(Freud::Pidfile) }
24
+
25
+ after(:each) { FileUtils.rm_f("tmp/foo.json") }
26
+
27
+ def try(config, runnable, *args, &block)
28
+ command = Freud::Launcher.new(config)
29
+ trial = lambda { command.run(runnable, args) }
30
+ return(trial.call) unless block_given?
31
+ expect(trial).to raise_error(Freud::RunnerExit, &block)
32
+ end
33
+
34
+ describe "execute" do
35
+ it "bad external command" do
36
+ allow(pidfile).to receive(:read).and_return(35767)
37
+ config = { "process" => process, "pidfile" => pidfile,
38
+ "env" => {}, "commands" => {} }
39
+ try(config, "notacommand") { |e| expect(e.value).to eq(1) }
40
+ end
41
+
42
+ it "test: /bin/true" do
43
+ allow(pidfile).to receive(:read).and_return(35767)
44
+ config = { "process" => process, "pidfile" => pidfile,
45
+ "env" => {}, "commands" => { "test" => "/bin/true" } }
46
+ expect(process).to receive(:exec).with({}, "/bin/true",
47
+ { unsetenv_others: false, chdir: nil, close_others: true,
48
+ in: "/dev/null", out: :err })
49
+ try(config, "test")
50
+ end
51
+ end
52
+
53
+ describe "daemonize" do
54
+ it "bad external command" do
55
+ allow(pidfile).to receive(:read).and_return(35767)
56
+ config = { "process" => process, "pidfile" => pidfile,
57
+ "env" => {}, "commands" => {} }
58
+ try(config, "start") { |e| expect(e.value).to eq(1) }
59
+ end
60
+
61
+ it "background: false" do
62
+ allow(pidfile).to receive(:read).and_return(nil)
63
+ allow(pidfile).to receive(:running?).and_return(false)
64
+ allow(process).to receive(:pid).and_return(35767)
65
+ config = { "process" => process, "pidfile" => pidfile,
66
+ "env" => {}, "background" => false,
67
+ "commands" => { "start" => "/bin/true" } }
68
+ expect(process).to receive(:exec).with({}, "/bin/true",
69
+ { unsetenv_others: false, chdir: nil, close_others: true,
70
+ in: "/dev/null", out: :err })
71
+ try(config, "start")
72
+ end
73
+
74
+ it "background: true" do
75
+ allow(pidfile).to receive(:read).and_return(nil)
76
+ allow(pidfile).to receive(:running?).and_return(false)
77
+ config = { "process" => process, "pidfile" => pidfile,
78
+ "env" => {}, "background" => true,
79
+ "commands" => { "start" => "/bin/true" } }
80
+ expect(process).to receive(:spawn).with({}, "/bin/true",
81
+ { unsetenv_others: false, chdir: nil, close_others: true,
82
+ in: "/dev/null", out: :err, pgroup: true })
83
+ try(config, "start")
84
+ end
85
+
86
+ it "reset_env" do
87
+ allow(pidfile).to receive(:read).and_return(nil)
88
+ allow(pidfile).to receive(:running?).and_return(false)
89
+ allow(process).to receive(:pid).and_return(35767)
90
+ config = { "process" => process, "pidfile" => pidfile,
91
+ "env" => {}, "reset_env" => true,
92
+ "commands" => { "start" => "/bin/true" } }
93
+ expect(process).to receive(:exec).with({}, "/bin/true",
94
+ { unsetenv_others: true, chdir: nil, close_others: true,
95
+ in: "/dev/null", out: :err })
96
+ try(config, "start")
97
+ end
98
+
99
+ it "create_pidfile" do
100
+ allow(pidfile).to receive(:read).and_return(nil)
101
+ allow(pidfile).to receive(:running?).and_return(false)
102
+ allow(pidfile).to receive(:write).with(35767)
103
+ allow(process).to receive(:pid).and_return(35767)
104
+ config = { "process" => process, "pidfile" => pidfile,
105
+ "env" => {}, "create_pidfile" => true,
106
+ "commands" => { "start" => "/bin/true" } }
107
+ expect(process).to receive(:exec).with({}, "/bin/true",
108
+ { unsetenv_others: false, chdir: nil, close_others: true,
109
+ in: "/dev/null", out: :err })
110
+ try(config, "start")
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+ require "freud/pidfile"
3
+
4
+ RSpec.describe Freud::Pidfile do
5
+ PIDFILE = "tmp/freud.pid"
6
+
7
+ let(:pidfile) { Freud::Pidfile.new(PIDFILE) }
8
+
9
+ after(:each) { FileUtils.rm(PIDFILE) if File.exists?(PIDFILE) }
10
+
11
+ it "#write" do
12
+ pidfile.write(Process.pid)
13
+ expect(File.exists?(PIDFILE)).to be(true)
14
+ end
15
+
16
+ it "#read" do
17
+ expect(pidfile.read).to be_nil
18
+ pidfile.write(Process.pid)
19
+ expect(pidfile.read).to eq(Process.pid)
20
+ end
21
+
22
+ it "#running? true" do
23
+ pidfile.write(Process.pid)
24
+ expect(pidfile.running?).to be(true)
25
+ end
26
+
27
+ # NOTE: This will (obviously) fail if a process with that pid exists,
28
+ # but it's the maximum pid on a Linux system, and likely to be not used.
29
+ it "#running? false" do
30
+ pidfile.write(32768)
31
+ expect(pidfile.running?).to be(false)
32
+ end
33
+
34
+ it "#to_s returns path" do
35
+ expect(pidfile.to_s).to eq(PIDFILE)
36
+ end
37
+
38
+ it "== path" do
39
+ expect(pidfile).to eq(PIDFILE)
40
+ end
41
+ end
@@ -0,0 +1,133 @@
1
+ require "spec_helper"
2
+ require "freud/runner"
3
+ require "set"
4
+
5
+ RSpec.describe Freud::Runner do
6
+ def unused_pid
7
+ used = Set.new(`ps -A | awk '{print $1}'`.split(/\n/))
8
+ output = 35767.step(1, -1).find { |pid| not used.include?(pid.to_s) }
9
+ raise("Can't find an unused pid.") unless output
10
+ output
11
+ end
12
+
13
+ let(:root) { File.expand_path("#{File.dirname(__FILE__)}/..") }
14
+
15
+ let(:runner) { Freud::Runner.new }
16
+
17
+ let(:process) { double }
18
+
19
+ let(:pidfile) { double(Freud::Pidfile) }
20
+
21
+ let(:log) { StringIO.new }
22
+
23
+ before(:each) { Freud::Logging.log_to(log) }
24
+
25
+ after(:each) do
26
+ FileUtils.rm_f("tmp/generated.json")
27
+ FileUtils.rm_f("tmp/true.pid")
28
+ end
29
+
30
+ it ".run" do
31
+ expect { Freud::Runner.run([]) }.to raise_error(SystemExit)
32
+ end
33
+
34
+ describe "#run" do
35
+ def try(runnable, &block)
36
+ expect(runnable).to raise_error(Freud::RunnerExit, &block)
37
+ end
38
+
39
+ after(:each) do
40
+ ENV.delete("FREUD_CONFIG")
41
+ ENV.delete("FREUD_STAGE")
42
+ ENV.delete("FREUD_SERVICE_PATH")
43
+ end
44
+
45
+ it "@check (up)" do
46
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(Process.pid)
47
+ args = [ "@check", "spec/fixtures/true.json" ]
48
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
49
+ end
50
+
51
+ it "@check via FREUD_CONFIG" do
52
+ ENV["FREUD_CONFIG"] = "spec/fixtures/true.json"
53
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(Process.pid)
54
+ args = [ "@check" ]
55
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
56
+ log.rewind
57
+ expect(log.read).to match(/\bup\b/)
58
+ end
59
+
60
+ it "@check (down)" do
61
+ ENV["FREUD_CONFIG"] = "spec/fixtures/true.json"
62
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(unused_pid)
63
+ args = [ "@check", "spec/fixtures/true.json" ]
64
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
65
+ log.rewind
66
+ expect(log.read).to match(/\bdown\b/)
67
+ end
68
+
69
+ it "@wait-up (up)" do
70
+ ENV["FREUD_CONFIG"] = "spec/fixtures/true.json"
71
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(Process.pid)
72
+ args = [ "@wait-up", "-t", "1" ]
73
+ started_at = Time.now.to_i
74
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
75
+ expect(Time.now.to_i - started_at).to be < 2
76
+ end
77
+
78
+ it "@wait-up (down)" do
79
+ ENV["FREUD_CONFIG"] = "spec/fixtures/true.json"
80
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(unused_pid)
81
+ args = [ "@wait-up", "-t", "1" ]
82
+ started_at = Time.now.to_i
83
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(1) }
84
+ expect(Time.now.to_i - started_at).to be < 2
85
+ end
86
+
87
+ it "@wait-down (down)" do
88
+ ENV["FREUD_CONFIG"] = "spec/fixtures/true.json"
89
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(unused_pid)
90
+ args = [ "@wait-down", "-t", "1" ]
91
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
92
+ end
93
+
94
+ it "@wait-down (up)" do
95
+ ENV["FREUD_CONFIG"] = "spec/fixtures/true.json"
96
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(Process.pid)
97
+ args = [ "@wait-down", "-t", "1" ]
98
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(1) }
99
+ end
100
+
101
+ it "generate" do
102
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(unused_pid)
103
+ args = [ "g", "tmp/generated.json" ]
104
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
105
+ generated = "#{root}/tmp/generated.json"
106
+ expect(File.exists?(generated)).to be(true)
107
+ expect { JSON.parse(File.read(generated)) }.to_not raise_error
108
+ end
109
+
110
+ it "usage" do
111
+ Freud::Pidfile.new("#{root}/tmp/true.pid").write(unused_pid)
112
+ try(lambda { runner.run([]) }) do |result|
113
+ expect(result.value).to eq(1)
114
+ expect(result.message).to match(/usage/i)
115
+ end
116
+ end
117
+
118
+ it "help" do
119
+ args = [ "help", "spec/fixtures/true.json" ]
120
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
121
+ log.rewind
122
+ expect(log.read).to match(/quux/)
123
+ end
124
+
125
+ it "FREUD_SERVICE_PATH" do
126
+ ENV["FREUD_SERVICE_PATH"] = "spec/fixtures"
127
+ args = [ "help", "true" ]
128
+ try(lambda { runner.run(args) }) { |r| expect(r.value).to eq(0) }
129
+ log.rewind
130
+ expect(log.read).to match(/quux/)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,25 @@
1
+ root = File.join(File.dirname(File.expand_path(__FILE__)), "..")
2
+ $LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root)
3
+
4
+ require "simplecov"
5
+
6
+ SimpleCov.start do
7
+ add_filter "/spec/"
8
+ end
9
+
10
+ RSpec.configure do |config|
11
+ config.filter_run(:focus)
12
+ config.run_all_when_everything_filtered = true
13
+ config.order = :random
14
+ config.default_formatter = "doc" if config.files_to_run.one?
15
+ Kernel.srand(config.seed)
16
+
17
+ config.expect_with :rspec do |expectations|
18
+ expectations.syntax = :expect
19
+ end
20
+
21
+ config.mock_with :rspec do |mocks|
22
+ mocks.syntax = :expect
23
+ mocks.verify_partial_doubles = true
24
+ end
25
+ end