foreman 0.31.0 → 0.50.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.
Files changed (73) hide show
  1. data/README.md +46 -0
  2. data/bin/foreman-runner +32 -0
  3. data/bin/taskman +8 -0
  4. data/data/example/Procfile +4 -2
  5. data/data/example/spawnee +14 -0
  6. data/data/example/spawner +7 -0
  7. data/data/example/utf8 +11 -0
  8. data/data/export/bluepill/master.pill.erb +11 -10
  9. data/data/export/launchd/launchd.plist.erb +22 -0
  10. data/data/export/runit/log/run.erb +7 -0
  11. data/data/export/runit/run.erb +2 -2
  12. data/data/export/supervisord/app.conf.erb +27 -0
  13. data/data/export/upstart/master.conf.erb +2 -2
  14. data/data/export/upstart/process.conf.erb +3 -3
  15. data/lib/foreman/cli.rb +83 -34
  16. data/lib/foreman/engine/cli.rb +105 -0
  17. data/lib/foreman/engine.rb +232 -140
  18. data/lib/foreman/env.rb +27 -0
  19. data/lib/foreman/export/base.rb +108 -6
  20. data/lib/foreman/export/bluepill.rb +4 -20
  21. data/lib/foreman/export/inittab.rb +11 -16
  22. data/lib/foreman/export/launchd.rb +15 -0
  23. data/lib/foreman/export/runit.rb +15 -41
  24. data/lib/foreman/export/supervisord.rb +16 -0
  25. data/lib/foreman/export/upstart.rb +10 -28
  26. data/lib/foreman/export.rb +23 -0
  27. data/lib/foreman/helpers.rb +45 -0
  28. data/lib/foreman/process.rb +80 -46
  29. data/lib/foreman/procfile.rb +68 -14
  30. data/lib/foreman/version.rb +1 -1
  31. data/lib/foreman.rb +12 -7
  32. data/man/foreman.1 +29 -3
  33. data/spec/foreman/cli_spec.rb +54 -60
  34. data/spec/foreman/engine_spec.rb +64 -46
  35. data/spec/foreman/export/base_spec.rb +19 -0
  36. data/spec/foreman/export/bluepill_spec.rb +24 -6
  37. data/spec/foreman/export/inittab_spec.rb +40 -0
  38. data/spec/foreman/export/launchd_spec.rb +21 -0
  39. data/spec/foreman/export/runit_spec.rb +23 -22
  40. data/spec/foreman/export/supervisord_spec.rb +36 -0
  41. data/spec/foreman/export/upstart_spec.rb +49 -16
  42. data/spec/foreman/export_spec.rb +22 -0
  43. data/spec/foreman/helpers_spec.rb +26 -0
  44. data/spec/foreman/process_spec.rb +48 -2
  45. data/spec/foreman/procfile_spec.rb +41 -0
  46. data/spec/foreman_spec.rb +3 -20
  47. data/spec/helper_spec.rb +18 -0
  48. data/spec/resources/Procfile +4 -0
  49. data/spec/resources/bin/echo +2 -0
  50. data/spec/resources/bin/env +2 -0
  51. data/spec/resources/bin/test +2 -0
  52. data/spec/resources/bin/utf8 +2 -0
  53. data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
  54. data/spec/resources/export/bluepill/app.pill +6 -25
  55. data/spec/resources/export/inittab/inittab.concurrency +4 -0
  56. data/spec/resources/export/inittab/inittab.default +4 -0
  57. data/spec/resources/export/launchd/launchd-a.default +22 -0
  58. data/spec/resources/export/launchd/launchd-b.default +22 -0
  59. data/spec/resources/export/supervisord/app-alpha-1.conf +24 -0
  60. data/spec/resources/export/supervisord/app-alpha-2.conf +24 -0
  61. data/spec/spec_helper.rb +93 -10
  62. metadata +72 -76
  63. data/README.markdown +0 -49
  64. data/bin/runner +0 -2
  65. data/data/export/runit/log_run.erb +0 -7
  66. data/lib/foreman/procfile_entry.rb +0 -22
  67. data/lib/foreman/utils.rb +0 -15
  68. /data/spec/resources/export/runit/{app-alpha-1-log-run → app-alpha-1/log/run} +0 -0
  69. /data/spec/resources/export/runit/{app-alpha-1-run → app-alpha-1/run} +0 -0
  70. /data/spec/resources/export/runit/{app-alpha-2-log-run → app-alpha-2/log/run} +0 -0
  71. /data/spec/resources/export/runit/{app-alpha-2-run → app-alpha-2/run} +0 -0
  72. /data/spec/resources/export/runit/{app-bravo-1-log-run → app-bravo-1/log/run} +0 -0
  73. /data/spec/resources/export/runit/{app-bravo-1-run → app-bravo-1/run} +0 -0
@@ -1,12 +1,25 @@
1
1
  require "spec_helper"
2
2
  require "foreman/cli"
3
3
 
4
- describe "Foreman::CLI" do
4
+ describe "Foreman::CLI", :fakefs do
5
5
  subject { Foreman::CLI.new }
6
6
 
7
+ describe ".foreman" do
8
+ before { File.open(".foreman", "w") { |f| f.puts "formation: alpha=2" } }
9
+
10
+ it "provides default options" do
11
+ subject.send(:options)["formation"].should == "alpha=2"
12
+ end
13
+
14
+ it "is overridden by options at the cli" do
15
+ subject = Foreman::CLI.new([], :formation => "alpha=3")
16
+ subject.send(:options)["formation"].should == "alpha=3"
17
+ end
18
+ end
19
+
7
20
  describe "start" do
8
- describe "with a non-existent Procfile" do
9
- it "prints an error" do
21
+ describe "when a Procfile doesnt exist", :fakefs do
22
+ it "displays an error" do
10
23
  mock_error(subject, "Procfile does not exist.") do
11
24
  dont_allow.instance_of(Foreman::Engine).start
12
25
  subject.start
@@ -14,79 +27,60 @@ describe "Foreman::CLI" do
14
27
  end
15
28
  end
16
29
 
17
- describe "with a Procfile" do
18
- before(:each) { write_procfile }
30
+ describe "with a valid Procfile" do
31
+ it "can run a single command" do
32
+ without_fakefs do
33
+ output = foreman("start env -f #{resource_path("Procfile")}")
34
+ output.should =~ /env.1/
35
+ output.should_not =~ /test.1/
36
+ end
37
+ end
19
38
 
20
- it "runs successfully" do
21
- dont_allow(subject).error
22
- mock.instance_of(Foreman::Engine).start
23
- subject.start
39
+ it "can run all commands" do
40
+ without_fakefs do
41
+ output = foreman("start -f #{resource_path("Procfile")} -e #{resource_path(".env")}")
42
+ output.should =~ /echo.1 \| echoing/
43
+ output.should =~ /env.1 \| bar/
44
+ output.should =~ /test.1 \| testing/
45
+ end
24
46
  end
25
47
  end
26
48
  end
27
49
 
28
- describe "export" do
29
- describe "options" do
30
- it "respects --env" do
31
- write_procfile
32
- write_env("envfile")
33
- mock.instance_of(Foreman::Export::Upstart).export("/upstart", { "env" => "envfile" })
34
- foreman %{ export upstart /upstart --env envfile }
35
- end
50
+ describe "check" do
51
+ it "with a valid Procfile displays the jobs" do
52
+ write_procfile
53
+ foreman("check").should == "valid procfile detected (alpha, bravo)\n"
36
54
  end
37
55
 
38
- describe "with a non-existent Procfile" do
39
- it "prints an error" do
40
- mock_error(subject, "Procfile does not exist.") do
41
- dont_allow.instance_of(Foreman::Engine).export
42
- subject.export("testapp")
43
- end
44
- end
56
+ it "with a blank Procfile displays an error" do
57
+ FileUtils.touch "Procfile"
58
+ foreman("check").should == "ERROR: no processes defined\n"
45
59
  end
46
60
 
47
- describe "with a Procfile" do
48
- before(:each) { write_procfile }
49
-
50
- describe "with an invalid formatter" do
51
- it "prints an error" do
52
- mock_error(subject, "Unknown export format: invalidformatter.") do
53
- subject.export("invalidformatter")
54
- end
55
- end
56
- end
57
-
58
- describe "with a valid config" do
59
- before(:each) { write_foreman_config("testapp") }
60
-
61
- it "runs successfully" do
62
- dont_allow(subject).error
63
- mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {})
64
- subject.export("upstart", "/tmp/foo")
65
- end
66
- end
61
+ it "without a Procfile displays an error" do
62
+ FileUtils.rm_f "Procfile"
63
+ foreman("check").should == "ERROR: Procfile does not exist.\n"
67
64
  end
68
65
  end
69
66
 
70
- describe "check" do
71
- describe "with a valid Procfile" do
72
- before { write_procfile }
67
+ describe "run" do
68
+ it "can run a command" do
69
+ forked_foreman("run echo 1").should == "1\n"
70
+ end
73
71
 
74
- it "displays the jobs" do
75
- mock(subject).display("valid procfile detected (alpha, bravo)")
76
- subject.check
77
- end
72
+ it "includes the environment" do
73
+ forked_foreman("run #{resource_path("bin/env FOO")} -e #{resource_path(".env")}").should == "bar\n"
78
74
  end
75
+ end
79
76
 
80
- describe "with a blank Procfile" do
81
- before do
82
- FileUtils.touch("Procfile")
83
- end
77
+ describe "version" do
78
+ it "displays gem version" do
79
+ foreman("version").chomp.should == Foreman::VERSION
80
+ end
84
81
 
85
- it "displays an error" do
86
- mock_error(subject, "no processes defined") do
87
- subject.check
88
- end
89
- end
82
+ it "displays gem version on shortcut command" do
83
+ foreman("-v").chomp.should == Foreman::VERSION
90
84
  end
91
85
  end
92
86
 
@@ -1,86 +1,104 @@
1
1
  require "spec_helper"
2
2
  require "foreman/engine"
3
3
 
4
- describe "Foreman::Engine" do
5
- subject { Foreman::Engine.new("Procfile", {}) }
4
+ class Foreman::Engine::Tester < Foreman::Engine
5
+ attr_reader :buffer
6
6
 
7
- describe "initialize" do
8
- describe "without an existing Procfile" do
9
- it "raises an error" do
10
- lambda { subject }.should raise_error
11
- end
12
- end
7
+ def startup
8
+ @buffer = ""
9
+ end
10
+
11
+ def output(name, data)
12
+ @buffer += "#{name}: #{data}"
13
+ end
14
+
15
+ def shutdown
16
+ end
17
+ end
18
+
19
+ describe "Foreman::Engine", :fakefs do
20
+ subject do
21
+ write_procfile "Procfile"
22
+ Foreman::Engine::Tester.new.load_procfile("Procfile")
23
+ end
13
24
 
25
+ describe "initialize" do
14
26
  describe "with a Procfile" do
15
27
  before { write_procfile }
16
28
 
17
29
  it "reads the processes" do
18
- subject.procfile["alpha"].command.should == "./alpha"
19
- subject.procfile["bravo"].command.should == "./bravo"
30
+ subject.process("alpha").command.should == "./alpha"
31
+ subject.process("bravo").command.should == "./bravo"
20
32
  end
21
33
  end
22
34
  end
23
35
 
24
36
  describe "start" do
25
37
  it "forks the processes" do
26
- write_procfile
27
- mock.instance_of(Foreman::Process).run_process("./alpha", is_a(IO))
28
- mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO))
38
+ mock(subject.process("alpha")).run(anything)
39
+ mock(subject.process("bravo")).run(anything)
29
40
  mock(subject).watch_for_output
30
41
  mock(subject).watch_for_termination
31
42
  subject.start
32
43
  end
33
44
 
34
45
  it "handles concurrency" do
35
- write_procfile
36
- engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
37
- mock.instance_of(Foreman::Process).run_process("./alpha", is_a(IO)).twice
38
- mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO))
39
- mock(engine).watch_for_output
40
- mock(engine).watch_for_termination
41
- engine.start
46
+ subject.options[:formation] = "alpha=2"
47
+ mock(subject.process("alpha")).run(anything).twice
48
+ mock(subject.process("bravo")).run(anything).never
49
+ mock(subject).watch_for_output
50
+ mock(subject).watch_for_termination
51
+ subject.start
42
52
  end
43
53
  end
44
54
 
45
- describe "environment" do
46
- before(:each) do
47
- write_procfile
48
- stub(Process).fork
55
+ describe "directories" do
56
+ it "has the directory default relative to the Procfile" do
57
+ write_procfile "/some/app/Procfile"
58
+ engine = Foreman::Engine.new.load_procfile("/some/app/Procfile")
59
+ engine.root.should == "/some/app"
49
60
  end
61
+ end
50
62
 
51
- it "should read if specified" do
63
+ describe "environment" do
64
+ it "should read env files" do
52
65
  File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
53
- engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
54
- stub(engine).info
55
- mock(engine).spawn_processes
56
- mock(engine).watch_for_termination
57
- engine.environment.should == {"FOO"=>"baz"}
58
- engine.start
66
+ subject.load_env("/tmp/env")
67
+ subject.env["FOO"].should == "baz"
59
68
  end
60
69
 
61
70
  it "should read more than one if specified" do
62
71
  File.open("/tmp/env1", "w") { |f| f.puts("FOO=bar") }
63
72
  File.open("/tmp/env2", "w") { |f| f.puts("BAZ=qux") }
64
- engine = Foreman::Engine.new("Procfile", :env => "/tmp/env1,/tmp/env2")
65
- stub(engine).info
66
- mock(engine).spawn_processes
67
- mock(engine).watch_for_termination
68
- engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
69
- engine.start
73
+ subject.load_env "/tmp/env1"
74
+ subject.load_env "/tmp/env2"
75
+ subject.env["FOO"].should == "bar"
76
+ subject.env["BAZ"].should == "qux"
77
+ end
78
+
79
+ it "should handle quoted values" do
80
+ File.open("/tmp/env", "w") do |f|
81
+ f.puts 'FOO=bar'
82
+ f.puts 'BAZ="qux"'
83
+ f.puts "FRED='barney'"
84
+ f.puts 'OTHER="escaped\"quote"'
85
+ end
86
+ subject.load_env "/tmp/env"
87
+ subject.env["FOO"].should == "bar"
88
+ subject.env["BAZ"].should == "qux"
89
+ subject.env["FRED"].should == "barney"
90
+ subject.env["OTHER"].should == 'escaped"quote'
70
91
  end
71
92
 
72
93
  it "should fail if specified and doesnt exist" do
73
- mock.instance_of(Foreman::Engine).error("No such file: /tmp/env")
74
- engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
94
+ lambda { subject.load_env "/tmp/env" }.should raise_error(Errno::ENOENT)
75
95
  end
76
96
 
77
- it "should read .env if none specified" do
78
- File.open(".env", "w") { |f| f.puts("FOO=qoo") }
79
- engine = Foreman::Engine.new("Procfile")
80
- mock(engine).spawn_processes
81
- mock(engine).watch_for_termination
82
- engine.environment.should == {"FOO"=>"qoo"}
83
- engine.start
97
+ it "should set port from .env if specified" do
98
+ File.open("/tmp/env", "w") { |f| f.puts("PORT=9000") }
99
+ subject.load_env "/tmp/env"
100
+ subject.send(:base_port).should == 9000
84
101
  end
85
102
  end
103
+
86
104
  end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
3
+ require "foreman/export"
4
+
5
+ describe "Foreman::Export::Base", :fakefs do
6
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
7
+ let(:location) { "/tmp/init" }
8
+ let(:engine) { Foreman::Engine.new().load_procfile(procfile) }
9
+ let(:subject) { Foreman::Export::Base.new(location, engine) }
10
+
11
+ it "has a say method for displaying info" do
12
+ mock(subject).puts("[foreman export] foo")
13
+ subject.send(:say, "foo")
14
+ end
15
+
16
+ it "raises errors as a Foreman::Export::Exception" do
17
+ lambda { subject.send(:error, "foo") }.should raise_error(Foreman::Export::Exception, "foo")
18
+ end
19
+ end
@@ -3,17 +3,35 @@ require "foreman/engine"
3
3
  require "foreman/export/bluepill"
4
4
  require "tmpdir"
5
5
 
6
- describe Foreman::Export::Bluepill do
7
- let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
- let(:engine) { Foreman::Engine.new(procfile) }
9
- let(:bluepill) { Foreman::Export::Bluepill.new(engine) }
6
+ describe Foreman::Export::Bluepill, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:formation) { nil }
9
+ let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
10
+ let(:options) { Hash.new }
11
+ let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) }
10
12
 
11
13
  before(:each) { load_export_templates_into_fakefs("bluepill") }
12
14
  before(:each) { stub(bluepill).say }
13
15
 
14
16
  it "exports to the filesystem" do
15
- bluepill.export("/tmp/init", :concurrency => "alpha=2")
16
- File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
17
+ bluepill.export
18
+ normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill"))
19
+ end
20
+
21
+ it "cleans up if exporting into an existing dir" do
22
+ mock(FileUtils).rm("/tmp/init/app.pill")
23
+
24
+ bluepill.export
25
+ bluepill.export
26
+ end
27
+
28
+ context "with a process formation" do
29
+ let(:formation) { "alpha=2" }
30
+
31
+ it "exports to the filesystem with concurrency" do
32
+ bluepill.export
33
+ normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app-concurrency.pill"))
34
+ end
17
35
  end
18
36
 
19
37
  end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
3
+ require "foreman/export/inittab"
4
+ require "tmpdir"
5
+
6
+ describe Foreman::Export::Inittab, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:location) { "/tmp/inittab" }
9
+ let(:formation) { nil }
10
+ let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
11
+ let(:options) { Hash.new }
12
+ let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) }
13
+
14
+ before(:each) { load_export_templates_into_fakefs("inittab") }
15
+ before(:each) { stub(inittab).say }
16
+
17
+ it "exports to the filesystem" do
18
+ inittab.export
19
+ File.read("/tmp/inittab").should == example_export_file("inittab/inittab.default")
20
+ end
21
+
22
+ context "to stdout" do
23
+ let(:location) { "-" }
24
+
25
+ it "exports to stdout" do
26
+ mock(inittab).puts example_export_file("inittab/inittab.default")
27
+ inittab.export
28
+ end
29
+ end
30
+
31
+ context "with concurrency" do
32
+ let(:formation) { "alpha=2" }
33
+
34
+ it "exports to the filesystem with concurrency" do
35
+ inittab.export
36
+ File.read("/tmp/inittab").should == example_export_file("inittab/inittab.concurrency")
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
3
+ require "foreman/export/launchd"
4
+ require "tmpdir"
5
+
6
+ describe Foreman::Export::Launchd, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:options) { Hash.new }
9
+ let(:engine) { Foreman::Engine.new().load_procfile(procfile) }
10
+ let(:launchd) { Foreman::Export::Launchd.new("/tmp/init", engine, options) }
11
+
12
+ before(:each) { load_export_templates_into_fakefs("launchd") }
13
+ before(:each) { stub(launchd).say }
14
+
15
+ it "exports to the filesystem" do
16
+ launchd.export
17
+ File.read("/tmp/init/app-alpha-1.plist").should == example_export_file("launchd/launchd-a.default")
18
+ File.read("/tmp/init/app-bravo-1.plist").should == example_export_file("launchd/launchd-b.default")
19
+ end
20
+
21
+ end
@@ -3,33 +3,34 @@ require "foreman/engine"
3
3
  require "foreman/export/runit"
4
4
  require "tmpdir"
5
5
 
6
- describe Foreman::Export::Runit do
6
+ describe Foreman::Export::Runit, :fakefs do
7
7
  let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') }
8
- let(:engine) { Foreman::Engine.new(procfile) }
9
- let(:runit) { Foreman::Export::Runit.new(engine) }
10
-
8
+ let(:engine) { Foreman::Engine.new(:formation => "alpha=2,bravo=1").load_procfile(procfile) }
9
+ let(:options) { Hash.new }
10
+ let(:runit) { Foreman::Export::Runit.new('/tmp/init', engine, options) }
11
+
11
12
  before(:each) { load_export_templates_into_fakefs("runit") }
12
13
  before(:each) { stub(runit).say }
13
-
14
+ before(:each) { stub(FakeFS::FileUtils).chmod }
15
+
14
16
  it "exports to the filesystem" do
15
- FileUtils.mkdir_p('/tmp/init')
16
- runit.export('/tmp/init', :concurrency => 'alpha=2')
17
-
18
- File.read("/tmp/init/app-alpha-1/run").should == example_export_file('runit/app-alpha-1-run')
19
- File.read("/tmp/init/app-alpha-1/log/run").should ==
20
- example_export_file('runit/app-alpha-1-log-run')
17
+ engine.env["BAR"] = "baz"
18
+ runit.export
19
+
20
+ File.read("/tmp/init/app-alpha-1/run").should == example_export_file('runit/app-alpha-1/run')
21
+ File.read("/tmp/init/app-alpha-1/log/run").should == example_export_file('runit/app-alpha-1/log/run')
21
22
  File.read("/tmp/init/app-alpha-1/env/PORT").should == "5000\n"
22
- File.read("/tmp/init/app-alpha-1/env/BAR").should == "baz\n"
23
-
24
- File.read("/tmp/init/app-alpha-2/run").should == example_export_file('runit/app-alpha-2-run')
25
- File.read("/tmp/init/app-alpha-2/log/run").should ==
26
- example_export_file('runit/app-alpha-2-log-run')
23
+ File.read("/tmp/init/app-alpha-1/env/BAR").should == "baz\n"
24
+ File.read("/tmp/init/app-alpha-2/run").should == example_export_file('runit/app-alpha-2/run')
25
+ File.read("/tmp/init/app-alpha-2/log/run").should == example_export_file('runit/app-alpha-2/log/run')
27
26
  File.read("/tmp/init/app-alpha-2/env/PORT").should == "5001\n"
28
- File.read("/tmp/init/app-alpha-2/env/BAR").should == "baz\n"
29
-
30
- File.read("/tmp/init/app-bravo-1/run").should == example_export_file('runit/app-bravo-1-run')
31
- File.read("/tmp/init/app-bravo-1/log/run").should ==
32
- example_export_file('runit/app-bravo-1-log-run')
27
+ File.read("/tmp/init/app-alpha-2/env/BAR").should == "baz\n"
28
+ File.read("/tmp/init/app-bravo-1/run").should == example_export_file('runit/app-bravo-1/run')
29
+ File.read("/tmp/init/app-bravo-1/log/run").should == example_export_file('runit/app-bravo-1/log/run')
33
30
  File.read("/tmp/init/app-bravo-1/env/PORT").should == "5100\n"
34
31
  end
35
- end
32
+
33
+ it "creates a full path to the export directory" do
34
+ expect { runit.export }.to_not raise_error(Errno::ENOENT)
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
3
+ require "foreman/export/supervisord"
4
+ require "tmpdir"
5
+
6
+ describe Foreman::Export::Supervisord, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:formation) { nil }
9
+ let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
10
+ let(:options) { Hash.new }
11
+ let(:supervisord) { Foreman::Export::Supervisord.new("/tmp/init", engine, options) }
12
+
13
+ before(:each) { load_export_templates_into_fakefs("supervisord") }
14
+ before(:each) { stub(supervisord).say }
15
+
16
+ it "exports to the filesystem" do
17
+ supervisord.export
18
+ File.read("/tmp/init/app.conf").should == example_export_file("supervisord/app-alpha-1.conf")
19
+ end
20
+
21
+ it "cleans up if exporting into an existing dir" do
22
+ mock(FileUtils).rm("/tmp/init/app.conf")
23
+ supervisord.export
24
+ supervisord.export
25
+ end
26
+
27
+ context "with concurrency" do
28
+ let(:formation) { "alpha=2" }
29
+
30
+ it "exports to the filesystem with concurrency" do
31
+ supervisord.export
32
+ File.read("/tmp/init/app.conf").should == example_export_file("supervisord/app-alpha-2.conf")
33
+ end
34
+ end
35
+
36
+ end
@@ -3,51 +3,84 @@ require "foreman/engine"
3
3
  require "foreman/export/upstart"
4
4
  require "tmpdir"
5
5
 
6
- describe Foreman::Export::Upstart do
7
- let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
- let(:engine) { Foreman::Engine.new(procfile) }
9
- let(:upstart) { Foreman::Export::Upstart.new(engine) }
6
+ describe Foreman::Export::Upstart, :fakefs do
7
+ let(:procfile) { write_procfile("/tmp/app/Procfile") }
8
+ let(:formation) { nil }
9
+ let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
10
+ let(:options) { Hash.new }
11
+ let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, options) }
10
12
 
11
13
  before(:each) { load_export_templates_into_fakefs("upstart") }
12
14
  before(:each) { stub(upstart).say }
13
15
 
14
16
  it "exports to the filesystem" do
15
- upstart.export("/tmp/init", :concurrency => "alpha=2")
17
+ upstart.export
16
18
 
17
19
  File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf")
18
20
  File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf")
19
21
  File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.conf")
20
- File.read("/tmp/init/app-alpha-2.conf").should == example_export_file("upstart/app-alpha-2.conf")
21
22
  File.read("/tmp/init/app-bravo.conf").should == example_export_file("upstart/app-bravo.conf")
22
23
  File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
23
24
  end
24
25
 
26
+ it "cleans up if exporting into an existing dir" do
27
+ mock(FileUtils).rm("/tmp/init/app.conf")
28
+ mock(FileUtils).rm("/tmp/init/app-alpha.conf")
29
+ mock(FileUtils).rm("/tmp/init/app-alpha-1.conf")
30
+ mock(FileUtils).rm("/tmp/init/app-bravo.conf")
31
+ mock(FileUtils).rm("/tmp/init/app-bravo-1.conf")
32
+
33
+ upstart.export
34
+ upstart.export
35
+ end
36
+
37
+ it "quotes and escapes environment variables" do
38
+ engine.env['KEY'] = 'd"\|d'
39
+ upstart.export
40
+ "foobarfoo".should include "bar"
41
+ File.read("/tmp/init/app-alpha-1.conf").should =~ /KEY="d\\"\\\\\\\|d/
42
+ end
43
+
44
+ context "with a formation" do
45
+ let(:formation) { "alpha=2" }
46
+
47
+ it "exports to the filesystem with concurrency" do
48
+ upstart.export
49
+
50
+ File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf")
51
+ File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf")
52
+ File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.conf")
53
+ File.read("/tmp/init/app-alpha-2.conf").should == example_export_file("upstart/app-alpha-2.conf")
54
+ File.exists?("/tmp/init/app-bravo-1.conf").should == false
55
+ end
56
+ end
57
+
25
58
  context "with alternate templates" do
26
- let(:template_root) { "/tmp/alternate" }
59
+ let(:template) { "/tmp/alternate" }
60
+ let(:options) { { :app => "app", :template => template } }
27
61
 
28
62
  before do
29
- FileUtils.mkdir_p template_root
30
- File.open("#{template_root}/master.conf.erb", "w") { |f| f.puts "alternate_template" }
63
+ FileUtils.mkdir_p template
64
+ File.open("#{template}/master.conf.erb", "w") { |f| f.puts "alternate_template" }
31
65
  end
32
66
 
33
67
  it "can export with alternate template files" do
34
- upstart.export("/tmp/init", :template => template_root)
35
-
68
+ upstart.export
36
69
  File.read("/tmp/init/app.conf").should == "alternate_template\n"
37
70
  end
38
71
  end
39
72
 
40
73
  context "with alternate templates from home dir" do
41
- let(:default_template_root) {File.expand_path("~/.foreman/templates")}
42
74
 
43
75
  before do
44
- FileUtils.mkdir_p default_template_root
45
- File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" }
76
+ FileUtils.mkdir_p File.expand_path("~/.foreman/templates/upstart")
77
+ File.open(File.expand_path("~/.foreman/templates/upstart/master.conf.erb"), "w") do |file|
78
+ file.puts "default_alternate_template"
79
+ end
46
80
  end
47
81
 
48
82
  it "can export with alternate template files" do
49
- upstart.export("/tmp/init")
50
-
83
+ upstart.export
51
84
  File.read("/tmp/init/app.conf").should == "default_alternate_template\n"
52
85
  end
53
86
  end
@@ -1,2 +1,24 @@
1
1
  require "spec_helper"
2
2
  require "foreman/export"
3
+
4
+ describe "Foreman::Export" do
5
+ subject { Foreman::Export }
6
+
7
+ describe "with a formatter that doesn't declare the appropriate class" do
8
+ it "prints an error" do
9
+ mock(subject).require("foreman/export/invalidformatter")
10
+ mock_export_error("Unknown export format: invalidformatter (no class Foreman::Export::Invalidformatter).") do
11
+ subject.formatter("invalidformatter")
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "with an invalid formatter" do
17
+
18
+ it "prints an error" do
19
+ mock_export_error("Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
20
+ subject.formatter("invalidformatter")
21
+ end
22
+ end
23
+ end
24
+ end