mamiya 0.0.1.alpha2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +16 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +43 -0
- data/Rakefile +6 -0
- data/bin/mamiya +17 -0
- data/config.example.yml +11 -0
- data/docs/sequences/deploy.png +0 -0
- data/docs/sequences/deploy.uml +58 -0
- data/example.rb +74 -0
- data/lib/mamiya.rb +5 -0
- data/lib/mamiya/agent.rb +181 -0
- data/lib/mamiya/agent/actions.rb +12 -0
- data/lib/mamiya/agent/fetcher.rb +137 -0
- data/lib/mamiya/agent/handlers/abstract.rb +20 -0
- data/lib/mamiya/agent/handlers/fetch.rb +68 -0
- data/lib/mamiya/cli.rb +322 -0
- data/lib/mamiya/cli/client.rb +172 -0
- data/lib/mamiya/config.rb +57 -0
- data/lib/mamiya/dsl.rb +192 -0
- data/lib/mamiya/helpers/git.rb +75 -0
- data/lib/mamiya/logger.rb +190 -0
- data/lib/mamiya/master.rb +118 -0
- data/lib/mamiya/master/agent_monitor.rb +146 -0
- data/lib/mamiya/master/agent_monitor_handlers.rb +44 -0
- data/lib/mamiya/master/web.rb +148 -0
- data/lib/mamiya/package.rb +122 -0
- data/lib/mamiya/script.rb +117 -0
- data/lib/mamiya/steps/abstract.rb +19 -0
- data/lib/mamiya/steps/build.rb +72 -0
- data/lib/mamiya/steps/extract.rb +26 -0
- data/lib/mamiya/steps/fetch.rb +24 -0
- data/lib/mamiya/steps/push.rb +34 -0
- data/lib/mamiya/storages.rb +17 -0
- data/lib/mamiya/storages/abstract.rb +48 -0
- data/lib/mamiya/storages/mock.rb +61 -0
- data/lib/mamiya/storages/s3.rb +127 -0
- data/lib/mamiya/util/label_matcher.rb +38 -0
- data/lib/mamiya/version.rb +3 -0
- data/mamiya.gemspec +35 -0
- data/misc/logger_test.rb +12 -0
- data/spec/agent/actions_spec.rb +37 -0
- data/spec/agent/fetcher_spec.rb +199 -0
- data/spec/agent/handlers/fetch_spec.rb +121 -0
- data/spec/agent_spec.rb +255 -0
- data/spec/config_spec.rb +50 -0
- data/spec/dsl_spec.rb +291 -0
- data/spec/fixtures/dsl_test_load.rb +1 -0
- data/spec/fixtures/dsl_test_use.rb +1 -0
- data/spec/fixtures/helpers/foo.rb +1 -0
- data/spec/fixtures/test-package-source/.mamiya.meta.json +1 -0
- data/spec/fixtures/test-package-source/greeting +1 -0
- data/spec/fixtures/test-package.tar.gz +0 -0
- data/spec/fixtures/test.yml +4 -0
- data/spec/logger_spec.rb +68 -0
- data/spec/master/agent_monitor_spec.rb +269 -0
- data/spec/master/web_spec.rb +121 -0
- data/spec/master_spec.rb +94 -0
- data/spec/package_spec.rb +394 -0
- data/spec/script_spec.rb +78 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/steps/build_spec.rb +261 -0
- data/spec/steps/extract_spec.rb +68 -0
- data/spec/steps/fetch_spec.rb +96 -0
- data/spec/steps/push_spec.rb +73 -0
- data/spec/storages/abstract_spec.rb +22 -0
- data/spec/storages/s3_spec.rb +342 -0
- data/spec/storages_spec.rb +33 -0
- data/spec/support/dummy_serf.rb +70 -0
- data/spec/util/label_matcher_spec.rb +85 -0
- metadata +272 -0
data/mamiya.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mamiya/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "mamiya"
|
8
|
+
spec.version = Mamiya::VERSION
|
9
|
+
spec.authors = ["Shota Fukumori (sora_h)"]
|
10
|
+
spec.email = ["her@sorah.jp"]
|
11
|
+
spec.summary = %q{Fast deploy tool using tarballs and serf}
|
12
|
+
spec.description = %q{Deploy tool using tarballs and serf for lot of servers}
|
13
|
+
spec.homepage = "https://github.com/sorah/mamiya"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "thor", "~> 0.18.1"
|
22
|
+
spec.add_runtime_dependency "aws-sdk-core", "2.0.0.rc6"
|
23
|
+
spec.add_runtime_dependency "term-ansicolor", ">= 1.3.0"
|
24
|
+
unless ENV["MAMIYA_VILLEIN_PATH"]
|
25
|
+
spec.add_runtime_dependency "villein", ">= 0.3.1"
|
26
|
+
end
|
27
|
+
|
28
|
+
spec.add_runtime_dependency "sinatra", ">= 1.4.5"
|
29
|
+
|
30
|
+
spec.add_development_dependency "rspec", "2.14.1"
|
31
|
+
spec.add_development_dependency 'rack-test', '~> 0.6.2'
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
34
|
+
spec.add_development_dependency "rake"
|
35
|
+
end
|
data/misc/logger_test.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
$:.unshift File.join(__dir__, '..' ,'lib')
|
3
|
+
require 'mamiya/logger'
|
4
|
+
|
5
|
+
[true,false].each {|color|
|
6
|
+
l = Mamiya::Logger.new(level: Logger::DEBUG, color: color)
|
7
|
+
[nil, "app"].each {|n|
|
8
|
+
(0..5).each {|s|
|
9
|
+
l.log s, "hi", n
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'villein/event'
|
5
|
+
|
6
|
+
require 'mamiya/agent'
|
7
|
+
require 'mamiya/agent/actions'
|
8
|
+
|
9
|
+
require_relative '../support/dummy_serf.rb'
|
10
|
+
|
11
|
+
describe Mamiya::Agent::Actions do
|
12
|
+
let(:serf) { DummySerf.new }
|
13
|
+
let(:fetcher) { double('fetcher', start!: nil) }
|
14
|
+
|
15
|
+
let(:config) do
|
16
|
+
{serf: {agent: {rpc_addr: '127.0.0.1:17373', bind: '127.0.0.1:17946'}}}
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
allow(Villein::Agent).to receive(:new).and_return(serf)
|
21
|
+
allow(Mamiya::Agent::Fetcher).to receive(:new).and_return(fetcher)
|
22
|
+
end
|
23
|
+
|
24
|
+
subject(:agent) { Mamiya::Agent.new(config) }
|
25
|
+
|
26
|
+
|
27
|
+
describe "#distribute" do
|
28
|
+
it "sends fetch request" do
|
29
|
+
expect(serf).to receive(:event).with(
|
30
|
+
'mamiya:fetch',
|
31
|
+
{application: 'app', package: 'pkg'}.to_json
|
32
|
+
)
|
33
|
+
|
34
|
+
agent.distribute('app', 'pkg')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pathname'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
require 'mamiya/agent/fetcher'
|
7
|
+
require 'mamiya/steps/fetch'
|
8
|
+
|
9
|
+
describe Mamiya::Agent::Fetcher do
|
10
|
+
let!(:tmpdir) { Dir.mktmpdir('mamiya-agent-fetcher-spec') }
|
11
|
+
after { FileUtils.remove_entry_secure(tmpdir) if File.exist?(tmpdir) }
|
12
|
+
|
13
|
+
let(:config) do
|
14
|
+
{packages_dir: tmpdir, keep_packages: 2}
|
15
|
+
end
|
16
|
+
|
17
|
+
subject(:fetcher) { described_class.new(config) }
|
18
|
+
|
19
|
+
describe "lifecycle" do
|
20
|
+
it "can start and stop" do
|
21
|
+
expect(fetcher.thread).to be_nil
|
22
|
+
expect(fetcher).not_to be_running
|
23
|
+
|
24
|
+
fetcher.start!
|
25
|
+
|
26
|
+
expect(fetcher).to be_running
|
27
|
+
expect(fetcher.thread).to be_a(Thread)
|
28
|
+
expect(fetcher.thread).to be_alive
|
29
|
+
th = fetcher.thread
|
30
|
+
|
31
|
+
fetcher.stop!
|
32
|
+
|
33
|
+
10.times { break unless th.alive?; sleep 0.1 }
|
34
|
+
expect(th).not_to be_alive
|
35
|
+
|
36
|
+
expect(fetcher.thread).to be_nil
|
37
|
+
expect(fetcher).not_to be_running
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can graceful stop"
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#cleanup" do
|
44
|
+
before do
|
45
|
+
path = Pathname.new(tmpdir)
|
46
|
+
|
47
|
+
path.join('a').mkdir
|
48
|
+
File.write path.join('a', "a.tar.gz"), "\n"
|
49
|
+
File.write path.join('a', "a.json"), "\n"
|
50
|
+
File.write path.join('a', "b.json"), "\n"
|
51
|
+
File.write path.join('a', "b.tar.gz"), "\n"
|
52
|
+
File.write path.join('a', "c.json"), "\n"
|
53
|
+
File.write path.join('a', "c.tar.gz"), "\n"
|
54
|
+
path.join('b').mkdir
|
55
|
+
File.write path.join('b', "a.tar.gz"), "\n"
|
56
|
+
File.write path.join('b', "a.json"), "\n"
|
57
|
+
|
58
|
+
path.join('c').mkdir
|
59
|
+
File.write path.join('c', "a.tar.gz"), "\n"
|
60
|
+
File.write path.join('c', "b.json"), "\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "cleans up" do
|
64
|
+
called = []
|
65
|
+
fetcher.cleanup_hook = proc { |a,b| called << [a,b] }
|
66
|
+
|
67
|
+
fetcher.cleanup
|
68
|
+
|
69
|
+
path = Pathname.new(tmpdir)
|
70
|
+
existences = Hash[
|
71
|
+
[
|
72
|
+
path.join('a', 'a.tar.gz'),
|
73
|
+
path.join('a', 'a.json'),
|
74
|
+
path.join('a', 'b.tar.gz'),
|
75
|
+
path.join('a', 'b.json'),
|
76
|
+
path.join('a', 'c.tar.gz'),
|
77
|
+
path.join('a', 'c.json'),
|
78
|
+
].map { |file|
|
79
|
+
[file, file.exist?]
|
80
|
+
}
|
81
|
+
]
|
82
|
+
|
83
|
+
expect(called).to eq([['a', 'a']])
|
84
|
+
expect(existences).to eq(
|
85
|
+
path.join('a', 'a.tar.gz') => false,
|
86
|
+
path.join('a', 'a.json') => false,
|
87
|
+
path.join('a', 'b.tar.gz') => true,
|
88
|
+
path.join('a', 'b.json') => true,
|
89
|
+
path.join('a', 'c.tar.gz') => true,
|
90
|
+
path.join('a', 'c.json') => true,
|
91
|
+
)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "mainloop" do
|
96
|
+
before do
|
97
|
+
allow(step).to receive(:run!)
|
98
|
+
allow(Mamiya::Steps::Fetch).to receive(:new).with(
|
99
|
+
application: 'myapp',
|
100
|
+
package: 'package',
|
101
|
+
destination: File.join(tmpdir, 'myapp'),
|
102
|
+
config: config,
|
103
|
+
).and_return(step)
|
104
|
+
|
105
|
+
fetcher.start!
|
106
|
+
end
|
107
|
+
|
108
|
+
let(:step) { double('fetch-step') }
|
109
|
+
|
110
|
+
it "starts fetch step for each order" do
|
111
|
+
flag = false
|
112
|
+
|
113
|
+
expect(step).to receive(:run!) do
|
114
|
+
flag = true
|
115
|
+
end
|
116
|
+
|
117
|
+
fetcher.enqueue('myapp', 'package')
|
118
|
+
fetcher.stop!(:graceful)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "calls callback" do
|
122
|
+
received = true
|
123
|
+
|
124
|
+
fetcher.enqueue('myapp', 'package') do |succeeded|
|
125
|
+
received = succeeded
|
126
|
+
end
|
127
|
+
|
128
|
+
fetcher.stop!(:graceful)
|
129
|
+
|
130
|
+
expect(received).to be_nil
|
131
|
+
end
|
132
|
+
|
133
|
+
it "calls cleanup" do
|
134
|
+
expect(fetcher).to receive(:cleanup)
|
135
|
+
fetcher.enqueue('myapp', 'package')
|
136
|
+
fetcher.stop!(:graceful)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "claims itself as working" do
|
140
|
+
expect(fetcher.working?).to be_false
|
141
|
+
expect(fetcher.current_job).to be_nil
|
142
|
+
|
143
|
+
received = false
|
144
|
+
fetcher.enqueue('myapp', 'package') do |error|
|
145
|
+
received = true
|
146
|
+
expect(fetcher.working?).to be_true
|
147
|
+
expect(fetcher.current_job).to eq %w(myapp package)
|
148
|
+
end
|
149
|
+
|
150
|
+
fetcher.stop!(:graceful)
|
151
|
+
expect(received).to be_true
|
152
|
+
expect(fetcher.working?).to be_false
|
153
|
+
expect(fetcher.current_job).to be_nil
|
154
|
+
end
|
155
|
+
|
156
|
+
context "with before hook" do
|
157
|
+
it "calls callback" do
|
158
|
+
run = false
|
159
|
+
received = false
|
160
|
+
|
161
|
+
allow(step).to receive(:run!) do
|
162
|
+
run = true
|
163
|
+
end
|
164
|
+
|
165
|
+
fetcher.enqueue('myapp', 'package', before: proc {
|
166
|
+
received = true
|
167
|
+
expect(run).to be_false
|
168
|
+
})
|
169
|
+
fetcher.stop!(:graceful)
|
170
|
+
|
171
|
+
expect(received).to be_true
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "when fetch step raised error" do
|
176
|
+
let(:exception) { Exception.new("he he...") }
|
177
|
+
|
178
|
+
before do
|
179
|
+
allow(step).to receive(:run!).and_raise(exception)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "calls callback with error" do
|
183
|
+
received = nil
|
184
|
+
|
185
|
+
fetcher.enqueue('myapp', 'package') do |error|
|
186
|
+
received = error
|
187
|
+
end
|
188
|
+
|
189
|
+
fetcher.stop!(:graceful)
|
190
|
+
|
191
|
+
expect(received).to eq exception
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
after do
|
196
|
+
fetcher.stop!
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'villein/event'
|
5
|
+
|
6
|
+
require 'mamiya/agent/handlers/fetch'
|
7
|
+
|
8
|
+
describe Mamiya::Agent::Handlers::Fetch do
|
9
|
+
let(:event) do
|
10
|
+
Villein::Event.new(
|
11
|
+
{
|
12
|
+
'SERF_EVENT' => 'user',
|
13
|
+
'SERF_USER_EVENT' => 'mamiya:fetch',
|
14
|
+
},
|
15
|
+
payload: {
|
16
|
+
application: 'app',
|
17
|
+
package: 'package',
|
18
|
+
}.to_json,
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:fetcher) { double('fetcher', start!: nil) }
|
23
|
+
let(:serf) { double('serf', name: 'myname', event: nil) }
|
24
|
+
|
25
|
+
let(:agent) do
|
26
|
+
double('agent', fetcher: fetcher, serf: serf, update_tags!: nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
subject(:handler) { described_class.new(agent, event) }
|
30
|
+
|
31
|
+
before do
|
32
|
+
allow(fetcher).to receive(:queue_size).and_return(0)
|
33
|
+
allow(fetcher).to receive(:enqueue) do |&block|
|
34
|
+
block.call
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "enqueue a request" do
|
39
|
+
expect(fetcher).to receive(:enqueue).with('app', 'package', kind_of(Hash))
|
40
|
+
|
41
|
+
handler.run!
|
42
|
+
end
|
43
|
+
|
44
|
+
it "responds ack" do
|
45
|
+
allow(fetcher).to receive(:enqueue).with('app', 'package')
|
46
|
+
expect(serf).to receive(:event).with('mamiya:fetch-result:ack',
|
47
|
+
{name: serf.name, application: 'app', package: 'package', pending: 1}.to_json)
|
48
|
+
|
49
|
+
handler.run!
|
50
|
+
end
|
51
|
+
|
52
|
+
it "kicks update_tag! on start" do
|
53
|
+
allow(fetcher).to receive(:enqueue) do |app, package, options, &block|
|
54
|
+
options[:before].call
|
55
|
+
end
|
56
|
+
expect(agent).to receive(:update_tags!)
|
57
|
+
handler.run!
|
58
|
+
end
|
59
|
+
|
60
|
+
it "reports start" do
|
61
|
+
allow(fetcher).to receive(:enqueue) do |app, package, options, &block|
|
62
|
+
options[:before].call
|
63
|
+
end
|
64
|
+
expect(serf).to receive(:event).with('mamiya:fetch-result:start',
|
65
|
+
{name: serf.name, application: 'app', package: 'package', pending: 1}.to_json)
|
66
|
+
|
67
|
+
handler.run!
|
68
|
+
end
|
69
|
+
|
70
|
+
it "responds success" do
|
71
|
+
callback = nil
|
72
|
+
allow(fetcher).to receive(:enqueue).with('app', 'package', kind_of(Hash)) do |&block|
|
73
|
+
callback = block
|
74
|
+
end
|
75
|
+
|
76
|
+
handler.run!
|
77
|
+
|
78
|
+
expect(serf).to receive(:event).with(
|
79
|
+
'mamiya:fetch-result:success',
|
80
|
+
{name: serf.name, application: 'app', package: 'package', pending: 0}.to_json
|
81
|
+
)
|
82
|
+
|
83
|
+
callback.call
|
84
|
+
end
|
85
|
+
|
86
|
+
it "updates tag" do
|
87
|
+
expect(agent).to receive(:update_tags!)
|
88
|
+
handler.run!
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when failed" do
|
92
|
+
it "notifies error" do
|
93
|
+
callback = nil
|
94
|
+
allow(fetcher).to receive(:enqueue).with('app', 'package', kind_of(Hash)) do |&block|
|
95
|
+
callback = block
|
96
|
+
end
|
97
|
+
|
98
|
+
handler.run!
|
99
|
+
|
100
|
+
error = RuntimeError.new('test')
|
101
|
+
expect(serf).to receive(:event).with(
|
102
|
+
'mamiya:fetch-result:error',
|
103
|
+
{
|
104
|
+
name: serf.name, application: 'app', package: 'package',
|
105
|
+
error: error.inspect, pending: 0,
|
106
|
+
}.to_json,
|
107
|
+
)
|
108
|
+
|
109
|
+
callback.call(error)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "updates tag" do
|
113
|
+
allow(fetcher).to receive(:enqueue) do |&block|
|
114
|
+
block.call(Exception.new)
|
115
|
+
end
|
116
|
+
|
117
|
+
expect(agent).to receive(:update_tags!)
|
118
|
+
handler.run!
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/spec/agent_spec.rb
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'json'
|
6
|
+
require 'villein/event'
|
7
|
+
|
8
|
+
require 'mamiya/agent'
|
9
|
+
require 'mamiya/agent/fetcher'
|
10
|
+
require 'mamiya/agent/actions'
|
11
|
+
|
12
|
+
require_relative './support/dummy_serf.rb'
|
13
|
+
|
14
|
+
describe Mamiya::Agent do
|
15
|
+
|
16
|
+
let(:serf) { DummySerf.new }
|
17
|
+
let(:fetcher) do
|
18
|
+
double('fetcher', start!: nil, working?: false).tap do |f|
|
19
|
+
cleanup_hook = nil
|
20
|
+
allow(f).to receive(:cleanup_hook=) { |_| cleanup_hook = _ }
|
21
|
+
allow(f).to receive(:cleanup_hook) { cleanup_hook }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:config) do
|
26
|
+
{serf: {agent: {rpc_addr: '127.0.0.1:17373', bind: '127.0.0.1:17946'}}}
|
27
|
+
end
|
28
|
+
|
29
|
+
before do
|
30
|
+
allow(Villein::Agent).to receive(:new).and_return(serf)
|
31
|
+
allow(Mamiya::Agent::Fetcher).to receive(:new).and_return(fetcher)
|
32
|
+
end
|
33
|
+
|
34
|
+
subject(:agent) { described_class.new(config) }
|
35
|
+
|
36
|
+
it "includes actions" do
|
37
|
+
expect(described_class.ancestors).to include(Mamiya::Agent::Actions)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "fetcher" do
|
41
|
+
it "sends events on cleanup hook" do
|
42
|
+
expect(serf).to receive(:event).with(
|
43
|
+
'mamiya:fetch-result:remove',
|
44
|
+
{
|
45
|
+
name: serf.name, application: 'foo', package: 'bar',
|
46
|
+
}.to_json,
|
47
|
+
)
|
48
|
+
|
49
|
+
agent.fetcher.cleanup_hook.call('foo', 'bar')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#run!" do
|
54
|
+
it "starts serf and fetcher" do
|
55
|
+
begin
|
56
|
+
flag = false
|
57
|
+
|
58
|
+
expect(fetcher).to receive(:start!)
|
59
|
+
expect(serf).to receive(:start!)
|
60
|
+
expect(serf).to receive(:auto_stop) do
|
61
|
+
flag = true
|
62
|
+
end
|
63
|
+
|
64
|
+
th = Thread.new { agent.run! }
|
65
|
+
|
66
|
+
10.times { break if flag; sleep 0.1 }
|
67
|
+
ensure
|
68
|
+
th.kill if th && th.alive?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#update_tags!" do
|
74
|
+
describe "(status)" do
|
75
|
+
context "when it is not busy" do
|
76
|
+
it "shows ready" do
|
77
|
+
agent.update_tags!
|
78
|
+
|
79
|
+
expect(serf.tags['mamiya']).to eq ',ready,'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when it is fetching" do
|
84
|
+
before do
|
85
|
+
allow(fetcher).to receive(:working?).and_return(true)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "shows fetching" do
|
89
|
+
agent.update_tags!
|
90
|
+
|
91
|
+
expect(serf.tags['mamiya']).to eq ',fetching,'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when it is running multiple jobs" do
|
96
|
+
pending
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "(prepared)" do
|
101
|
+
pending
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "(current)" do
|
105
|
+
pending
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "#status" do
|
110
|
+
before do
|
111
|
+
allow(agent).to receive(:existing_packages).and_return("app" => ["pkg"])
|
112
|
+
allow(fetcher).to receive(:queue_size).and_return(42)
|
113
|
+
allow(fetcher).to receive(:working?).and_return(false)
|
114
|
+
allow(fetcher).to receive(:current_job).and_return(nil)
|
115
|
+
end
|
116
|
+
|
117
|
+
subject(:status) { agent.status }
|
118
|
+
|
119
|
+
it "includes agent name" do
|
120
|
+
expect(status[:name]).to eq serf.name
|
121
|
+
end
|
122
|
+
|
123
|
+
it "includes packages" do
|
124
|
+
expect(status[:packages]).to eq agent.existing_packages
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "(fetcher)" do
|
128
|
+
it "includes queue_size as pending" do
|
129
|
+
expect(status[:fetcher][:pending]).to eq 42
|
130
|
+
end
|
131
|
+
|
132
|
+
it "shows fetching status" do
|
133
|
+
expect(status[:fetcher][:fetching]).to be_nil
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when it's fetching" do
|
137
|
+
before do
|
138
|
+
allow(fetcher).to receive(:working?).and_return(true)
|
139
|
+
allow(fetcher).to receive(:current_job).and_return(%w(foo bar))
|
140
|
+
end
|
141
|
+
|
142
|
+
it "shows fetching true" do
|
143
|
+
expect(status[:fetcher][:fetching]).to eq ['foo', 'bar']
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "#existing_packages" do
|
150
|
+
let!(:packages_dir) { Dir.mktmpdir('mamiya-agent-spec') }
|
151
|
+
after { FileUtils.remove_entry_secure(packages_dir) }
|
152
|
+
|
153
|
+
let(:config) { {packages_dir: packages_dir} }
|
154
|
+
|
155
|
+
subject(:existing_packages) { agent.existing_packages }
|
156
|
+
|
157
|
+
before do
|
158
|
+
dir = Pathname.new(packages_dir)
|
159
|
+
%w(a b).each do |app|
|
160
|
+
dir.join(app).mkdir
|
161
|
+
%w(valid.tar.gz valid.json
|
162
|
+
valid-2.tar.gz valid-2.json
|
163
|
+
invalid-1.tar.gz invalid-2.json invalid-3.txt).each do |name|
|
164
|
+
File.write dir.join(app, name), "\n"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "returns valid packages" do
|
170
|
+
expect(existing_packages).to eq(
|
171
|
+
"a" => ["valid", "valid-2"],
|
172
|
+
"b" => ["valid", "valid-2"],
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "query responder" do
|
178
|
+
it "responds to 'mamiya:status'" do
|
179
|
+
allow(agent).to receive(:status).and_return("my" => "status")
|
180
|
+
|
181
|
+
response = serf.trigger_query('mamiya:status', '')
|
182
|
+
expect(JSON.parse(response)).to eq("my" => "status")
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "event handler" do
|
187
|
+
let(:handler_class) do
|
188
|
+
Class.new(Mamiya::Agent::Handlers::Abstract) do
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def trigger(name, payload={})
|
193
|
+
serf.trigger('user_event', Villein::Event.new(
|
194
|
+
{
|
195
|
+
'SERF_EVENT' => 'user',
|
196
|
+
'SERF_USER_EVENT' => "mamiya:#{name}",
|
197
|
+
},
|
198
|
+
payload: payload.to_json,
|
199
|
+
))
|
200
|
+
end
|
201
|
+
|
202
|
+
before do
|
203
|
+
stub_const("Mamiya::Agent::Handlers::Test", handler_class)
|
204
|
+
agent # to create
|
205
|
+
end
|
206
|
+
|
207
|
+
it "finds handler class then call #run!" do
|
208
|
+
expect_any_instance_of(handler_class).to receive(:run!)
|
209
|
+
|
210
|
+
trigger('test')
|
211
|
+
end
|
212
|
+
|
213
|
+
it "passes proper argument to handler"
|
214
|
+
|
215
|
+
context "when handler not found" do
|
216
|
+
it "ignores event"
|
217
|
+
end
|
218
|
+
|
219
|
+
context "with events_only" do
|
220
|
+
subject(:agent) { described_class.new(config, events_only: [/foo/]) }
|
221
|
+
|
222
|
+
let(:handler_foo) do
|
223
|
+
Class.new(Mamiya::Agent::Handlers::Abstract) do
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
let(:handler_bar) do
|
228
|
+
Class.new(Mamiya::Agent::Handlers::Abstract) do
|
229
|
+
def run!
|
230
|
+
raise 'oops?'
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
before do
|
236
|
+
stub_const("Mamiya::Agent::Handlers::Foo", handler_foo)
|
237
|
+
stub_const("Mamiya::Agent::Handlers::Bar", handler_bar)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "handles events only matches any of them" do
|
241
|
+
expect_any_instance_of(handler_foo).to receive(:run!)
|
242
|
+
|
243
|
+
trigger('foo')
|
244
|
+
trigger('bar')
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
context "with action" do
|
249
|
+
it "calls another method instead of run!" do
|
250
|
+
expect_any_instance_of(handler_class).to receive(:hello)
|
251
|
+
trigger('test:hello')
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|