freud 0.0.1

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.
@@ -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