navyrb 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,195 @@
1
+ require 'spec_helper'
2
+
3
+ describe Navy::Container do
4
+ let(:specification) do
5
+ {
6
+ :container_name => 'the_container_name',
7
+ :name => 'the_app_name',
8
+ :type => "application"
9
+ }
10
+ end
11
+
12
+ let(:dependencies) do
13
+ ['dep1', 'dep2']
14
+ end
15
+
16
+ let(:etcd) do
17
+ MockEtcd.new
18
+ end
19
+
20
+ subject do
21
+ described_class.new :specification => specification,
22
+ :dependencies => dependencies
23
+ end
24
+
25
+ describe "#name" do
26
+ it "is the container_name in the specification" do
27
+ expect(subject.name).to eq 'the_container_name'
28
+ end
29
+ end
30
+
31
+ describe "#app" do
32
+ it "is the app name in the specification" do
33
+ expect(subject.app).to eq 'the_app_name'
34
+ end
35
+ end
36
+
37
+ describe "#daemon?" do
38
+ context "when the type is application" do
39
+ before :each do
40
+ specification[:type] = "application"
41
+ end
42
+
43
+ it "is a daemon" do
44
+ expect(subject.daemon?).to be true
45
+ end
46
+ end
47
+
48
+ context "when the type is task" do
49
+ before :each do
50
+ specification[:type] = "task"
51
+ end
52
+
53
+ it "is a daemon" do
54
+ expect(subject.daemon?).to be false
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#can_be_started?" do
60
+ context "when there are no dependencies" do
61
+ let(:dependencies) { [] }
62
+ it "can be started" do
63
+ expect(subject.can_be_started?(etcd)).to be true
64
+ end
65
+ end
66
+
67
+ context "when the dependencies are not in desired state" do
68
+ before :each do
69
+ etcd.setJSON('/navy/containers/dep1/desired', {:state => :desired})
70
+ etcd.setJSON('/navy/containers/dep1/actual', {:state => :not_desired})
71
+ end
72
+
73
+ it "cannot be started" do
74
+ expect(subject.can_be_started?(etcd)).to be false
75
+ end
76
+ end
77
+
78
+ context "when the dependencies are in desired state" do
79
+ before :each do
80
+ etcd.setJSON('/navy/containers/dep1/desired', {:state => :desired})
81
+ etcd.setJSON('/navy/containers/dep1/actual', {:state => :desired})
82
+ etcd.setJSON('/navy/containers/dep2/desired', {:state => :desired})
83
+ etcd.setJSON('/navy/containers/dep2/actual', {:state => :desired})
84
+ end
85
+
86
+ it "can be started" do
87
+ expect(subject.can_be_started?(etcd)).to be true
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#can_never_be_started?" do
93
+ context "when there are no dependencies" do
94
+ let(:dependencies) { [] }
95
+ it "can *always* be started" do
96
+ expect(subject.can_never_be_started?(etcd)).to be false
97
+ end
98
+ end
99
+
100
+ context "when the dependencies exist" do
101
+ context "when one of the dependencies is errored" do
102
+ before :each do
103
+ etcd.setJSON('/navy/containers/dep1/desired', {:state => :desired})
104
+ etcd.setJSON('/navy/containers/dep1/actual', {:state => :error})
105
+ end
106
+
107
+ it "can *never* be started" do
108
+ expect(subject.can_never_be_started?(etcd)).to be true
109
+ end
110
+ end
111
+
112
+ context "when the dependencies are in non errored states" do
113
+ before :each do
114
+ etcd.setJSON('/navy/containers/dep1/desired', {:state => :desired})
115
+ etcd.setJSON('/navy/containers/dep1/actual', {:state => :not_error})
116
+ end
117
+
118
+ it "can be *potentially* started" do
119
+ expect(subject.can_never_be_started?(etcd)).to be false
120
+ end
121
+
122
+ end
123
+ end
124
+ end
125
+
126
+ describe "#start" do
127
+ let(:cmd) { Navy::CommandBuilder.new(subject).build }
128
+ let(:launched) { [] }
129
+ let(:success) { true }
130
+
131
+ before :each do
132
+ allow(Navy::Runner).to receive(:launch) do |cmd|
133
+ launched << cmd
134
+ success
135
+ end
136
+ end
137
+
138
+ it "generates a command for the container and executes it" do
139
+ subject.start
140
+ expect(launched).to eq [cmd]
141
+ end
142
+
143
+ context "when the command succeeds" do
144
+ it "returns true" do
145
+ expect(subject.start).to be true
146
+ end
147
+ end
148
+
149
+ context "when the command fails" do
150
+ let(:success) { false }
151
+ it "returns false" do
152
+ expect(subject.start).to be false
153
+ end
154
+ end
155
+
156
+ context "when it is a task" do
157
+ before :each do
158
+ specification[:type] = "task"
159
+ specification[:cmds] = ["cmd1", "cmd2"]
160
+ end
161
+
162
+ it "runs each command" do
163
+ subject.start
164
+ expect(launched[0].last).to eq "cmd1"
165
+ expect(launched[1].last).to eq "cmd2"
166
+ end
167
+
168
+ context "when one of the items fails" do
169
+ let(:success) { false }
170
+
171
+ it "returns false and does not run other tasks" do
172
+ expect(subject.start).to be false
173
+ expect(launched.length).to eq 1
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "#stop" do
180
+ let(:cmd) { ["docker rm -f", "the_container_name"] }
181
+ let(:launched) { [] }
182
+
183
+ before :each do
184
+ allow(Navy::Runner).to receive(:launch) do |cmd|
185
+ launched << cmd
186
+ true
187
+ end
188
+ end
189
+
190
+ it "generates a rm command for the container and executes it" do
191
+ subject.stop
192
+ expect(launched).to eq [cmd]
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,202 @@
1
+ require 'spec_helper'
2
+ require 'webmock/rspec'
3
+
4
+ describe Navy::Etcd do
5
+ let(:options) do
6
+ {:host => 'etcdhost', :port => '1234'}
7
+ end
8
+
9
+ let(:example_record) do
10
+ <<-JSON
11
+ {
12
+ "action":"The Action",
13
+ "node": {
14
+ "createdIndex": 1,
15
+ "key": "/akey",
16
+ "modifiedIndex": 2,
17
+ "value": "New Value"
18
+ },
19
+ "prevNode": {
20
+ "createdIndex": 1,
21
+ "key": "/akey",
22
+ "value": "Prev Value",
23
+ "modifiedIndex": 3
24
+ }
25
+ }
26
+ JSON
27
+ end
28
+
29
+ let(:example_json_record) do
30
+ <<-JSON
31
+ {
32
+ "action":"The Action",
33
+ "node": {
34
+ "createdIndex": 1,
35
+ "key": "/akey",
36
+ "modifiedIndex": 2,
37
+ "value": "{\\"key\\":\\"value\\"}"
38
+ },
39
+ "prevNode": {
40
+ "createdIndex": 1,
41
+ "key": "/akey",
42
+ "value": "Prev Value",
43
+ "modifiedIndex": 3
44
+ }
45
+ }
46
+ JSON
47
+ end
48
+
49
+ let(:example_headers) do
50
+ {
51
+ "X-Etcd-Index" => "999"
52
+ }
53
+ end
54
+
55
+ subject { described_class.client options }
56
+
57
+ describe "Retrieval" do
58
+ describe "#get" do
59
+ before :each do
60
+ @request = stub_request(:get, 'http://etcdhost:1234/v2/keys/some/key').
61
+ to_return(:body => example_record, :headers => example_headers)
62
+ end
63
+
64
+ it "fetches a response from the given key" do
65
+ record = subject.get('/some/key')
66
+
67
+ #expect(@request).to have_been_made
68
+
69
+ expect(record.key).to eq '/akey'
70
+ expect(record.etcd_index).to be 999
71
+ expect(record.action).to eq "The Action"
72
+ expect(record.node.createdIndex).to eq 1
73
+ expect(record.node.modifiedIndex).to eq 2
74
+ expect(record.node.value).to eq "New Value"
75
+ expect(record.prevNode.value).to eq "Prev Value"
76
+ end
77
+ end
78
+
79
+ describe "#getJSON" do
80
+ before :each do
81
+ @request = stub_request(:get, 'http://etcdhost:1234/v2/keys/some/key').
82
+ to_return(:body => example_json_record, :headers => example_headers)
83
+ end
84
+
85
+ it "fetches and parses as JSON the given jey" do
86
+ hash = subject.getJSON('/some/key')
87
+ #expect(@request).to have_been_made
88
+
89
+ expect(hash['key']).to eq 'value'
90
+ end
91
+ end
92
+
93
+ describe "#watch" do
94
+ before :each do
95
+ @request = stub_request(:get, 'http://etcdhost:1234/v2/keys/some/key?wait=true').
96
+ to_return(:body => example_record, :headers => example_headers)
97
+ end
98
+
99
+ it "fetches with a wait" do
100
+ record = subject.watch('/some/key')
101
+ #expect(@request).to have_been_made
102
+ end
103
+ end
104
+
105
+ describe "#ls" do
106
+ let(:exampledir) do
107
+ {
108
+ :node => {
109
+ :nodes => [
110
+ {:key => '/some/dir/item1'},
111
+ {:key => '/some/dir/item2'}
112
+ ]
113
+ }
114
+ }.to_json
115
+ end
116
+
117
+ before :each do
118
+ @request = stub_request(:get, 'http://etcdhost:1234/v2/keys/some/dir').
119
+ to_return(:body => exampledir)
120
+ end
121
+
122
+ it "returns the keys in the given directory" do
123
+ keys = subject.ls('/some/dir')
124
+ #expect(@request).to have_been_made
125
+ expect(keys).to include '/some/dir/item1'
126
+ expect(keys).to include '/some/dir/item2'
127
+ expect(keys.length).to eq 2
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ describe "Storage" do
134
+ describe "#setJSON" do
135
+ let(:data) do
136
+ data = {:some => :json, :data => [:here]}
137
+ end
138
+
139
+ before :each do
140
+ @request = stub_request(:put, 'http://etcdhost:1234/v2/keys/some/json/key').
141
+ with(:body => {:value => data.to_json})
142
+ end
143
+
144
+ it "stores JSON encoded value at given key" do
145
+ subject.setJSON('/some/json/key', data)
146
+ #expect(@request).to have_been_made
147
+ end
148
+ end
149
+
150
+ describe "#delete" do
151
+ before :each do
152
+ @request = stub_request(:delete, 'http://etcdhost:1234/v2/keys/some/key?with=param').to_return(:status => 202)
153
+ end
154
+
155
+ it "deletes the specified key" do
156
+ result = subject.delete('/some/key', :with => :param)
157
+ expect(@request).to have_been_made
158
+ expect(result).to be true
159
+ end
160
+
161
+ context "when the key is missing" do
162
+ before :each do
163
+ @request = stub_request(:delete, 'http://etcdhost:1234/v2/keys/some/key?with=param').to_return(:status => 404)
164
+ end
165
+
166
+ it "returns false" do
167
+ result = subject.delete('/some/key', :with => :param)
168
+ expect(result).to be false
169
+ end
170
+ end
171
+ end
172
+
173
+ describe "#set" do
174
+ let(:data) { "some data " }
175
+
176
+ before :each do
177
+ @request = stub_request(:put, 'http://etcdhost:1234/v2/keys/some/data/value').
178
+ with(:body => {:value => data })
179
+ end
180
+
181
+ it "stores the string at the given value" do
182
+ subject.set('/some/data/value', data)
183
+ #expect(@request).to have_been_made
184
+ end
185
+ end
186
+
187
+ describe "#queueJSON" do
188
+ let(:data) { {:some => :json } }
189
+
190
+ before :each do
191
+ @request = stub_request(:post, 'http://etcdhost:1234/v2/keys/some/queue').
192
+ with(:body => {:value => data.to_json })
193
+ end
194
+
195
+ it "stores the string at the given value" do
196
+ subject.queueJSON('/some/queue', data)
197
+ expect(@request).to have_been_made
198
+ end
199
+ end
200
+ end
201
+
202
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe Navy::Router do
4
+ class ExampleHandler
5
+ def self.handled
6
+ @handled ||= {}
7
+ end
8
+
9
+ def handle_set(params, request)
10
+ self.class.handled[:set] = params, request
11
+ end
12
+
13
+ def handle_delete(params, request)
14
+ self.class.handled[:delete] = params, request
15
+ end
16
+
17
+ end
18
+
19
+ let(:handler1) { Class.new(ExampleHandler) }
20
+ let(:handler2) { Class.new(ExampleHandler) }
21
+
22
+ subject do
23
+ described_class.new do |r|
24
+ r.route '^/a/route$', handler1
25
+ r.route '^/a/:pattern/route$', handler2
26
+ end
27
+ end
28
+
29
+ it "routes through to defined handlers" do
30
+ request = double :key => '/a/route',
31
+ :action => :set
32
+
33
+ subject.route(request)
34
+ expect(handler1.handled[:set]).to eq [{}, request]
35
+ end
36
+
37
+ it "matches placeholder patters" do
38
+ request = double :key => '/a/matching/route',
39
+ :action => :delete
40
+
41
+ subject.route(request)
42
+ expect(handler2.handled[:delete]).to eq [{'pattern' => 'matching'}, request]
43
+ end
44
+
45
+ it "gracefully handles unknown paths" do
46
+ request = double :key => '/unkonwn/path',
47
+ :action => :delete
48
+ expect { subject.route(request) }.to_not raise_error
49
+ end
50
+
51
+ it "gracefully handle unmapped action" do
52
+ request = double :key => '/a/route',
53
+ :action => :unmapped
54
+ expect { subject.route(request) }.to_not raise_error
55
+ end
56
+
57
+ it "passes down global options into the params" do
58
+ options = {:foo => :bar}
59
+ router = described_class.new(options) do |r|
60
+ r.route 'example', handler1
61
+ end
62
+
63
+ request = double :key => 'example', :action => :set
64
+
65
+ router.route(request)
66
+
67
+ expect(handler1.handled[:set][0]).to eq({:foo => :bar})
68
+ end
69
+ end