kensa 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f100c19fcb05b5c0dd0a94287ac64d745050905
4
- data.tar.gz: ac3f713db8e27febba8a41b276de592fa63e469d
3
+ metadata.gz: a1b0f6152cc582f8ce121149cbf51c06d3a31146
4
+ data.tar.gz: 2cf35428fd4e02beb72d185581ea8ed500330c74
5
5
  SHA512:
6
- metadata.gz: c222175a5ce64e55ea5afad73536e716bb38eb66224dd4d84810adcae537dcbb5af2f2b2aea11ee0c7100a3ceeec4c286810962e465149a1bb8673acaede5e1f
7
- data.tar.gz: d9cd6cffdd76e56bf78b9d7c1ad8b21abca12729fa59c0deedd4985d29ec9355f8fe8736002d6357d314c6a1216d60ee5a079de494c19d70953acbb9f8a59e16
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.2.0)
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
@@ -38,5 +38,6 @@ Gem::Specification.new do |s|
38
38
  s.add_development_dependency(%q<sinatra>, "~> 1.4.2")
39
39
  s.add_development_dependency(%q<timecop>, "~> 0.6.1")
40
40
  s.add_development_dependency(%q<pry>)
41
+ s.add_development_dependency(%q<test-unit>)
41
42
  end
42
43
 
@@ -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
- addon_key = data['id'].upcase.gsub('-', '_')
146
- if k =~ /^#{addon_key}_/
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 #{addon_key}_"
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.has_key?("id")
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 data.has_key?("requires") && data["requires"].include?("syslog_drain")
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": {
@@ -1,5 +1,5 @@
1
1
  module Heroku
2
2
  module Kensa
3
- VERSION = '2.2.0'
3
+ VERSION = '2.3.0'
4
4
  end
5
5
  end
@@ -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)
@@ -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
@@ -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 logplex_token options})
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.2.0
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-04-09 00:00:00.000000000 Z
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