kensa 2.2.0 → 2.3.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +5 -1
- data/kensa.gemspec +1 -0
- data/lib/heroku/kensa/check.rb +78 -16
- data/lib/heroku/kensa/manifest.rb +3 -1
- data/lib/heroku/kensa/version.rb +1 -1
- data/test/all_check_test.rb +1 -0
- data/test/duplicate_provision_check_test.rb +34 -0
- data/test/helper.rb +18 -0
- data/test/manifest_check_test.rb +28 -0
- data/test/provision_check_test.rb +8 -0
- data/test/provision_response_check_test.rb +7 -1
- data/test/resources/server.rb +38 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1b0f6152cc582f8ce121149cbf51c06d3a31146
|
4
|
+
data.tar.gz: 2cf35428fd4e02beb72d185581ea8ed500330c74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c90f46e0e4c4757e000078525c306ac07b90e20ca0a2cdd0ce4a718bdfec2dfd24b3a16e8bfc59f39b4c1feedabd92e949d81b5867162fb7fca46dd733f42696
|
7
|
+
data.tar.gz: 3e8f395728af6bbb4a3999c7434aaea9f6b44f5b59879e66bcb99909e0da913ab6dac403bdbb825eca500a8754b653b9d1e71042c8d1a74d6cc88519946889dc
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
kensa (2.
|
4
|
+
kensa (2.3.0)
|
5
5
|
launchy (~> 2.2.0)
|
6
6
|
mechanize (~> 2.6.0)
|
7
7
|
netrc (~> 0.10.3)
|
@@ -38,6 +38,7 @@ GEM
|
|
38
38
|
nokogiri (1.6.5)
|
39
39
|
mini_portile (~> 0.6.0)
|
40
40
|
ntlm-http (0.1.1)
|
41
|
+
power_assert (0.2.2)
|
41
42
|
pry (0.9.11.4)
|
42
43
|
coderay (~> 1.0.5)
|
43
44
|
method_source (~> 0.8)
|
@@ -60,6 +61,8 @@ GEM
|
|
60
61
|
slop (3.4.3)
|
61
62
|
term-ansicolor (1.3.0)
|
62
63
|
tins (~> 1.0)
|
64
|
+
test-unit (3.0.9)
|
65
|
+
power_assert
|
63
66
|
tilt (1.3.6)
|
64
67
|
timecop (0.6.1)
|
65
68
|
tins (1.3.5)
|
@@ -80,4 +83,5 @@ DEPENDENCIES
|
|
80
83
|
rake
|
81
84
|
rr (~> 1.0.4)
|
82
85
|
sinatra (~> 1.4.2)
|
86
|
+
test-unit
|
83
87
|
timecop (~> 0.6.1)
|
data/kensa.gemspec
CHANGED
data/lib/heroku/kensa/check.rb
CHANGED
@@ -68,6 +68,10 @@ module Heroku
|
|
68
68
|
data['api'][env].chomp("/")
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
def api_requires?(feature)
|
73
|
+
data["api"].fetch("requires", []).include?(feature)
|
74
|
+
end
|
71
75
|
end
|
72
76
|
|
73
77
|
|
@@ -142,11 +146,11 @@ module Heroku
|
|
142
146
|
end
|
143
147
|
check "all config vars are prefixed with the addon id" do
|
144
148
|
data["api"]["config_vars"].each do |k|
|
145
|
-
|
146
|
-
if k =~ /^#{
|
149
|
+
prefix = data["api"]["config_vars_prefix"] || data['id'].upcase.gsub('-', '_')
|
150
|
+
if k =~ /^#{prefix}_/
|
147
151
|
true
|
148
152
|
else
|
149
|
-
error "#{k} is not a valid ENV key - must be prefixed with #{
|
153
|
+
error "#{k} is not a valid ENV key - must be prefixed with #{prefix}_"
|
150
154
|
end
|
151
155
|
end
|
152
156
|
end
|
@@ -170,7 +174,15 @@ module Heroku
|
|
170
174
|
test "response"
|
171
175
|
|
172
176
|
check "contains an id" do
|
173
|
-
response.is_a?(Hash) && response
|
177
|
+
response.is_a?(Hash) && response["id"]
|
178
|
+
end
|
179
|
+
|
180
|
+
check "id does not contain heroku_id" do
|
181
|
+
if response["id"].to_s.include? data["heroku_id"].scan(/app(\d+)@/).flatten.first
|
182
|
+
error "id cannot include heroku_id"
|
183
|
+
else
|
184
|
+
true
|
185
|
+
end
|
174
186
|
end
|
175
187
|
|
176
188
|
screen.message " (id #{response['id']})"
|
@@ -222,7 +234,7 @@ module Heroku
|
|
222
234
|
end
|
223
235
|
|
224
236
|
check "syslog_drain_url is returned if required" do
|
225
|
-
return true unless
|
237
|
+
return true unless api_requires?("syslog_drain")
|
226
238
|
|
227
239
|
drain_url = response['syslog_drain_url']
|
228
240
|
|
@@ -244,7 +256,6 @@ module Heroku
|
|
244
256
|
|
245
257
|
end
|
246
258
|
|
247
|
-
|
248
259
|
class ApiCheck < Check
|
249
260
|
def base_path
|
250
261
|
if data['api'][env].is_a? Hash
|
@@ -261,6 +272,61 @@ module Heroku
|
|
261
272
|
def credentials
|
262
273
|
[ data['id'], data['api']['password'] ]
|
263
274
|
end
|
275
|
+
|
276
|
+
def callback
|
277
|
+
"http://localhost:7779/callback/999"
|
278
|
+
end
|
279
|
+
|
280
|
+
def create_provision_payload
|
281
|
+
payload = {
|
282
|
+
:heroku_id => heroku_id,
|
283
|
+
:plan => data[:plan] || 'test',
|
284
|
+
:callback_url => callback,
|
285
|
+
:logplex_token => nil,
|
286
|
+
:region => "amazon-web-services::us-east-1",
|
287
|
+
:options => data[:options] || {},
|
288
|
+
:uuid => SecureRandom.uuid
|
289
|
+
}
|
290
|
+
|
291
|
+
if api_requires?("syslog_drain")
|
292
|
+
payload[:log_drain_token] = SecureRandom.hex
|
293
|
+
end
|
294
|
+
payload
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
class DuplicateProvisionCheck < ApiCheck
|
299
|
+
include HTTP
|
300
|
+
|
301
|
+
READLEN = 1024 * 10
|
302
|
+
|
303
|
+
def call!
|
304
|
+
|
305
|
+
json = nil
|
306
|
+
response = nil
|
307
|
+
|
308
|
+
code = nil
|
309
|
+
json = nil
|
310
|
+
reader, writer = nil
|
311
|
+
|
312
|
+
payload = create_provision_payload
|
313
|
+
|
314
|
+
code1, json1 = post(credentials, base_path, payload)
|
315
|
+
code2, json2 = post(credentials, base_path, payload)
|
316
|
+
|
317
|
+
json1 = OkJson.decode(json1)
|
318
|
+
json2 = OkJson.decode(json2)
|
319
|
+
|
320
|
+
if api_requires?("many_per_app")
|
321
|
+
check "returns different ids" do
|
322
|
+
if json1["id"] == json2["id"]
|
323
|
+
error "multiple provisions cannot return the same id"
|
324
|
+
else
|
325
|
+
true
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
264
330
|
end
|
265
331
|
|
266
332
|
class ProvisionCheck < ApiCheck
|
@@ -274,17 +340,9 @@ module Heroku
|
|
274
340
|
|
275
341
|
code = nil
|
276
342
|
json = nil
|
277
|
-
callback = "http://localhost:7779/callback/999"
|
278
343
|
reader, writer = nil
|
279
344
|
|
280
|
-
payload =
|
281
|
-
:heroku_id => heroku_id,
|
282
|
-
:plan => data[:plan] || 'test',
|
283
|
-
:callback_url => callback,
|
284
|
-
:logplex_token => nil,
|
285
|
-
:region => "amazon-web-services::us-east-1",
|
286
|
-
:options => data[:options] || {}
|
287
|
-
}
|
345
|
+
payload = create_provision_payload
|
288
346
|
|
289
347
|
if data[:async]
|
290
348
|
reader, writer = IO.pipe
|
@@ -345,7 +403,11 @@ module Heroku
|
|
345
403
|
|
346
404
|
data[:provision_response] = response
|
347
405
|
|
348
|
-
run ProvisionResponseCheck, data
|
406
|
+
run ProvisionResponseCheck, data.merge("heroku_id" => heroku_id)
|
407
|
+
|
408
|
+
if !api_requires?("many_per_app")
|
409
|
+
run DuplicateProvisionCheck, data
|
410
|
+
end
|
349
411
|
end
|
350
412
|
|
351
413
|
ensure
|
@@ -26,7 +26,8 @@ module Heroku
|
|
26
26
|
"regions": [ "us" ],
|
27
27
|
"password": "#{@password}",#{ sso_key }
|
28
28
|
"production": "https://yourapp.com/",
|
29
|
-
"test": "http://localhost:#{@port}/"
|
29
|
+
"test": "http://localhost:#{@port}/",
|
30
|
+
"requires": []
|
30
31
|
}
|
31
32
|
}
|
32
33
|
JSON
|
@@ -38,6 +39,7 @@ JSON
|
|
38
39
|
"id": "myaddon",
|
39
40
|
"api": {
|
40
41
|
"config_vars": [ "MYADDON_URL" ],
|
42
|
+
"requires": [],
|
41
43
|
"regions": [ "us" ],
|
42
44
|
"password": "#{@password}",#{ sso_key }
|
43
45
|
"production": {
|
data/lib/heroku/kensa/version.rb
CHANGED
data/test/all_check_test.rb
CHANGED
@@ -7,6 +7,7 @@ class AllCheckTest < Test::Unit::TestCase
|
|
7
7
|
|
8
8
|
setup do
|
9
9
|
@data = Manifest.new(:method => :get).skeleton
|
10
|
+
@data["api"]["requires"] << "many_per_app"
|
10
11
|
@data['api']['password'] = 'secret'
|
11
12
|
@data['api']['test'] += "working"
|
12
13
|
@file = File.dirname(__FILE__) + "/resources/runner.rb"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class DuplicateProvisionCheckTest < Test::Unit::TestCase
|
4
|
+
include Heroku::Kensa
|
5
|
+
include ProviderMock
|
6
|
+
|
7
|
+
def check; DuplicateProvisionCheck; end
|
8
|
+
|
9
|
+
setup do
|
10
|
+
@data = Manifest.new(method: :post).skeleton
|
11
|
+
@data["api"]["password"] = "secret"
|
12
|
+
ProviderServer::ProvisionRecord.reset
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when the provider supports many_per_app" do
|
16
|
+
setup { @data["api"]["requires"] = ["many_per_app"] }
|
17
|
+
|
18
|
+
test "allows duplicate provision attempts" do
|
19
|
+
use_provider_endpoint "working_duplicate"
|
20
|
+
assert_valid
|
21
|
+
end
|
22
|
+
|
23
|
+
test "duplicate provisions return different provider ids" do
|
24
|
+
use_provider_endpoint "working_duplicate"
|
25
|
+
assert_valid
|
26
|
+
end
|
27
|
+
|
28
|
+
test "fails when deuplicate provisions return the same provider id" do
|
29
|
+
use_provider_endpoint "working"
|
30
|
+
assert_invalid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
data/test/helper.rb
CHANGED
@@ -10,6 +10,24 @@ require 'fakefs/safe'
|
|
10
10
|
class Test::Unit::TestCase
|
11
11
|
include RR::Adapters::TestUnit
|
12
12
|
|
13
|
+
class ProvisionRecord
|
14
|
+
def self.provisions
|
15
|
+
@provisions ||= 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.incr
|
19
|
+
@provisions += 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.reset
|
23
|
+
@provisions = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.count
|
27
|
+
@provisions
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
13
31
|
module ProviderMock
|
14
32
|
def setup
|
15
33
|
Artifice.activate_with(ProviderServer)
|
data/test/manifest_check_test.rb
CHANGED
@@ -97,6 +97,34 @@ class ManifestCheckTest < Test::Unit::TestCase
|
|
97
97
|
assert_invalid
|
98
98
|
end
|
99
99
|
|
100
|
+
context "when config_var_prefix is set" do
|
101
|
+
context "to something other than the slug" do
|
102
|
+
test "config vars matching config_vars_prefix are valid" do
|
103
|
+
@data["api"]["config_vars_prefix"] = "THING"
|
104
|
+
@data["api"]["config_vars"] = ['THING_URL']
|
105
|
+
assert_valid
|
106
|
+
end
|
107
|
+
|
108
|
+
test "config vars matching slug are invalid" do
|
109
|
+
@data["api"]["config_vars_prefix"] = "THING"
|
110
|
+
@data["api"]["config_vars"] << "MYADDON_URL"
|
111
|
+
assert_invalid
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when config_var_prefix is not set" do
|
117
|
+
test "config vars matching slug are valid" do
|
118
|
+
@data["api"]["config_vars"] << 'MYADDON_URL'
|
119
|
+
assert_valid
|
120
|
+
end
|
121
|
+
|
122
|
+
test "config vars not matching slug are invalid" do
|
123
|
+
@data["api"]["config_vars"] << "NOT_SLUG_URL"
|
124
|
+
assert_invalid
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
100
128
|
test "assert config var prefixes match addon id" do
|
101
129
|
@data["api"]["config_vars"] << 'MONGO_URL'
|
102
130
|
assert_invalid
|
@@ -10,6 +10,7 @@ class ProvisionCheckTest < Test::Unit::TestCase
|
|
10
10
|
context "with sso #{method}" do
|
11
11
|
setup do
|
12
12
|
@data = Manifest.new(:method => method).skeleton
|
13
|
+
@data["api"]["requires"] = ["many_per_app"]
|
13
14
|
@data['api']['password'] = 'secret'
|
14
15
|
end
|
15
16
|
|
@@ -29,6 +30,13 @@ class ProvisionCheckTest < Test::Unit::TestCase
|
|
29
30
|
assert_valid
|
30
31
|
end
|
31
32
|
|
33
|
+
context "when supporting many_per_app" do
|
34
|
+
test "passes duplicate provision check" do
|
35
|
+
@data["api"]["requires"] = ["many_per_app"]
|
36
|
+
assert_valid
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
32
40
|
test "provision call with extra params" do
|
33
41
|
use_provider_endpoint "cmd-line-options"
|
34
42
|
@data[:options] = {:foo => 'bar', :bar => 'baz'}
|
@@ -13,6 +13,7 @@ class ProvisionResponseCheckTest < Test::Unit::TestCase
|
|
13
13
|
}}
|
14
14
|
@data = Manifest.new.skeleton.merge(:provision_response => @response)
|
15
15
|
@data['api']['config_vars'] << "MYADDON_CONFIG"
|
16
|
+
@data["heroku_id"] = "app987@kensa.heroku.com"
|
16
17
|
end
|
17
18
|
|
18
19
|
test "is valid if no errors" do
|
@@ -24,6 +25,11 @@ class ProvisionResponseCheckTest < Test::Unit::TestCase
|
|
24
25
|
assert_invalid
|
25
26
|
end
|
26
27
|
|
28
|
+
test "id does not contain the heroku_id" do
|
29
|
+
@response["id"] = "987"
|
30
|
+
assert_invalid
|
31
|
+
end
|
32
|
+
|
27
33
|
describe "when config is present" do
|
28
34
|
|
29
35
|
test "is a hash" do
|
@@ -74,7 +80,7 @@ class ProvisionResponseCheckTest < Test::Unit::TestCase
|
|
74
80
|
|
75
81
|
describe "when syslog drain is required" do
|
76
82
|
setup do
|
77
|
-
@data["requires"] = ["syslog_drain"]
|
83
|
+
@data["api"]["requires"] = ["syslog_drain"]
|
78
84
|
end
|
79
85
|
|
80
86
|
test "response is invalid without a syslog_drain_url" do
|
data/test/resources/server.rb
CHANGED
@@ -53,13 +53,50 @@ ERB
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
class ProvisionRecord
|
57
|
+
def self.provisions
|
58
|
+
@provisions ||= 0
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.incr
|
62
|
+
@provisions += 1
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.reset
|
66
|
+
@provisions = 0
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.count
|
70
|
+
@provisions
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
post '/working_duplicate/heroku/resources' do
|
75
|
+
heroku_only!
|
76
|
+
ProvisionRecord.incr
|
77
|
+
{ id: ProvisionRecord.count }.to_json
|
78
|
+
end
|
79
|
+
|
80
|
+
post '/duplicate/heroku/resources' do
|
81
|
+
heroku_only!
|
82
|
+
ProvisionRecord.incr
|
83
|
+
|
84
|
+
if ProvisionRecord.count > 1
|
85
|
+
status 422
|
86
|
+
{}.to_json
|
87
|
+
else
|
88
|
+
status 201
|
89
|
+
{ id: 123 }.to_json
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
56
93
|
post '/heroku/resources' do
|
57
94
|
heroku_only!
|
58
95
|
{ :id => 123 }.to_json
|
59
96
|
end
|
60
97
|
|
61
98
|
post '/working/heroku/resources' do
|
62
|
-
json_must_include(%w{heroku_id plan callback_url
|
99
|
+
json_must_include(%w{heroku_id plan callback_url options})
|
63
100
|
heroku_only!
|
64
101
|
{ :id => 123 }.to_json
|
65
102
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kensa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Mizerany
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2015-
|
16
|
+
date: 2015-05-14 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: launchy
|
@@ -203,6 +203,20 @@ dependencies:
|
|
203
203
|
- - ">="
|
204
204
|
- !ruby/object:Gem::Version
|
205
205
|
version: '0'
|
206
|
+
- !ruby/object:Gem::Dependency
|
207
|
+
name: test-unit
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
209
|
+
requirements:
|
210
|
+
- - ">="
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
213
|
+
type: :development
|
214
|
+
prerelease: false
|
215
|
+
version_requirements: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: '0'
|
206
220
|
description: Kensa is a command-line tool to help add-on providers integrating their
|
207
221
|
services with Heroku. It manages manifest files, and provides a TDD-like approach
|
208
222
|
for programmers to test and develop their APIs.
|
@@ -236,6 +250,7 @@ files:
|
|
236
250
|
- test/all_check_test.rb
|
237
251
|
- test/create_test.rb
|
238
252
|
- test/deprovision_check_test.rb
|
253
|
+
- test/duplicate_provision_check_test.rb
|
239
254
|
- test/helper.rb
|
240
255
|
- test/init_test.rb
|
241
256
|
- test/manifest_check_test.rb
|
@@ -276,6 +291,7 @@ test_files:
|
|
276
291
|
- test/all_check_test.rb
|
277
292
|
- test/create_test.rb
|
278
293
|
- test/deprovision_check_test.rb
|
294
|
+
- test/duplicate_provision_check_test.rb
|
279
295
|
- test/helper.rb
|
280
296
|
- test/init_test.rb
|
281
297
|
- test/manifest_check_test.rb
|