heroku_hatchet 6.0.0 → 7.0.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.
@@ -2,6 +2,10 @@ require "spec_helper"
2
2
  require 'yaml'
3
3
 
4
4
  describe "LockTest" do
5
+ before(:all) do
6
+ puts(`bundle exec hatchet lock`)
7
+ end
8
+
5
9
  it "app with failure can be locked to prior commit" do
6
10
  Hatchet::GitApp.new("lock_fail").deploy do |app|
7
11
  expect(app.deployed?).to be_truthy
@@ -9,11 +13,18 @@ describe "LockTest" do
9
13
  end
10
14
 
11
15
  it "app with failure can be locked to master" do
12
- puts(`bundle exec hatchet lock`)
13
16
  lock = YAML.load_file("hatchet.lock")
14
17
  name, branch = lock.select { |k, v| k.end_with?("lock_fail_master") }.first
15
18
 
16
19
  expect(name).to eq("repo_fixtures/repos/lock/lock_fail_master")
17
20
  expect(branch).to eq("master")
18
21
  end
22
+
23
+ it "app with failure can be locked to main" do
24
+ lock = YAML.load_file("hatchet.lock")
25
+ name, branch = lock.select { |k, v| k.end_with?("lock_fail_main") }.first
26
+
27
+ expect(name).to eq("repo_fixtures/repos/lock/lock_fail_main")
28
+ expect(branch).to eq("main")
29
+ end
19
30
  end
@@ -0,0 +1,153 @@
1
+ require "spec_helper"
2
+
3
+ describe "Reaper" do
4
+ describe "cycle" do
5
+ it "does not delete anything if under the limit" do
6
+ reaper = Hatchet::Reaper.new(api_rate_limit: Object.new, hatchet_app_limit: 1, io: StringIO.new)
7
+
8
+ def reaper.get_heroku_apps
9
+ @called_get_heroku_apps = true
10
+
11
+ @mock_apps ||= [{"name" => "hatchet-t-foo", "id" => 1, "maintenance" => true, "created_at" => Time.now.to_s}]
12
+ end
13
+ def reaper.check_get_heroku_apps_called; @called_get_heroku_apps ; end
14
+ def reaper.reap_once; raise "should not be called"; end
15
+
16
+ reaper.cycle
17
+
18
+ expect(reaper.check_get_heroku_apps_called).to be_truthy
19
+ end
20
+
21
+ it "deletes a maintenance mode app on error" do
22
+ reaper = Hatchet::Reaper.new(api_rate_limit: Object.new, hatchet_app_limit: 1, io: StringIO.new)
23
+
24
+ def reaper.get_heroku_apps
25
+ @mock_apps ||= [
26
+ {"name" => "hatchet-t-unfinished", "id" => 2, "maintenance" => false, "created_at" => Time.now.to_s},
27
+ {"name" => "hatchet-t-foo", "id" => 1, "maintenance" => true, "created_at" => Time.now.to_s}
28
+ ]
29
+ end
30
+ def reaper.destroy_with_log(name: , id: )
31
+ @reaper_destroy_called_with = {"name" => name, "id" => id}
32
+ end
33
+ def reaper.destroy_called_with; @reaper_destroy_called_with; end
34
+
35
+ reaper.cycle(app_exception_message: true)
36
+
37
+ expect(reaper.destroy_called_with).to eq({"name" => "hatchet-t-foo", "id" => 1})
38
+ end
39
+
40
+ it "deletes maintenance mode app when over limit" do
41
+ reaper = Hatchet::Reaper.new(api_rate_limit: Object.new, hatchet_app_limit: 0, io: StringIO.new)
42
+
43
+ def reaper.get_heroku_apps
44
+ @mock_apps ||= [{"name" => "hatchet-t-foo", "id" => 1, "maintenance" => true, "created_at" => Time.now.to_s}]
45
+ end
46
+ def reaper.destroy_with_log(name: , id: )
47
+ @reaper_destroy_called_with = {"name" => name, "id" => id}
48
+ end
49
+ def reaper.destroy_called_with; @reaper_destroy_called_with; end
50
+
51
+ reaper.cycle
52
+
53
+ expect(reaper.destroy_called_with).to eq({"name" => "hatchet-t-foo", "id" => 1})
54
+ end
55
+
56
+ it "deletes an old app that is past TLL" do
57
+ reaper = Hatchet::Reaper.new(api_rate_limit: Object.new, hatchet_app_limit: 0, io: StringIO.new)
58
+
59
+ def reaper.get_heroku_apps
60
+ two_days_ago = DateTime.now.new_offset(0) - 2
61
+ @mock_apps ||= [{"name" => "hatchet-t-foo", "id" => 1, "maintenance" => false, "created_at" => two_days_ago.to_s }]
62
+ end
63
+ def reaper.destroy_with_log(name: , id: )
64
+ @reaper_destroy_called_with = {"name" => name, "id" => id}
65
+ end
66
+ def reaper.destroy_called_with; @reaper_destroy_called_with; end
67
+
68
+ reaper.cycle
69
+
70
+ expect(reaper.destroy_called_with).to eq({"name" => "hatchet-t-foo", "id" => 1})
71
+ end
72
+
73
+ it "sleeps, refreshes app list, and tries again when an old app is not past TTL" do
74
+ warning = StringIO.new
75
+ reaper = Hatchet::Reaper.new(api_rate_limit: Object.new, hatchet_app_limit: 1, initial_sleep: 0, io: warning)
76
+
77
+ def reaper.get_heroku_apps
78
+ now = DateTime.now.new_offset(0)
79
+ @mock_apps ||= [{"name" => "hatchet-t-foo", "id" => 1, "maintenance" => false, "created_at" => now.to_s }]
80
+ end
81
+ def reaper.destroy_with_log(name: , id: )
82
+ @reaper_destroy_called_with = {"name" => name, "id" => id}
83
+ end
84
+ def reaper.destroy_called_with; @reaper_destroy_called_with; end
85
+ def reaper.sleep(val)
86
+ @_slept_for = val
87
+ end
88
+
89
+ def reaper.get_slept_for_val; @_slept_for; end
90
+
91
+ reaper.cycle(app_exception_message: true)
92
+
93
+ expect(reaper.get_slept_for_val).to eq(0)
94
+ expect(reaper.destroy_called_with).to eq(nil)
95
+
96
+ expect(warning.string).to match("WARNING")
97
+ expect(warning.string).to match("total_app_count: 1, hatchet_app_count: 1/#{Hatchet::Reaper::HATCHET_APP_LIMIT}, finished: 0, unfinished: 1")
98
+ end
99
+ end
100
+
101
+ describe "app age" do
102
+ it "calculates young apps" do
103
+ time_now = DateTime.parse("2020-07-28T14:40:00Z")
104
+ age = Hatchet::Reaper::AppAge.new(created_at: time_now, time_now: time_now, ttl_minutes: 1)
105
+ expect(age.in_minutes).to eq(0.0)
106
+ expect(age.too_young_to_die?).to be_truthy
107
+ expect(age.can_delete?).to be_falsey
108
+ expect(age.sleep_for_ttl).to eq(60)
109
+ end
110
+
111
+ it "calculates old apps" do
112
+ time_now = DateTime.parse("2020-07-28T14:40:00Z")
113
+ created_at = time_now - 2
114
+ age = Hatchet::Reaper::AppAge.new(created_at: created_at, time_now: time_now, ttl_minutes: 1)
115
+ expect(age.in_minutes).to eq(2880.0)
116
+ expect(age.too_young_to_die?).to be_falsey
117
+ expect(age.can_delete?).to be_truthy
118
+ expect(age.sleep_for_ttl).to eq(0)
119
+ end
120
+ end
121
+
122
+ describe "reaper throttle" do
123
+ it "increments and decrements based on min_sleep" do
124
+ reaper_throttle = Hatchet::Reaper::ReaperThrottle.new(initial_sleep: 2)
125
+ reaper_throttle.call(max_sleep: 5) do |sleep_for|
126
+ expect(sleep_for).to eq(2)
127
+ end
128
+ reaper_throttle.call(max_sleep: 5) do |sleep_for|
129
+ expect(sleep_for).to eq(4)
130
+ end
131
+ reaper_throttle.call(max_sleep: 5) do |sleep_for|
132
+ expect(sleep_for).to eq(5)
133
+ end
134
+ # The throttle is now reset since it hit the min_sleep value
135
+
136
+ reaper_throttle.call(max_sleep: 5) do |sleep_for|
137
+ expect(sleep_for).to eq(2)
138
+ end
139
+ end
140
+ end
141
+
142
+ it "over limit" do
143
+ reaper = Hatchet::Reaper.new(api_rate_limit: -> (){}, io: StringIO.new)
144
+ def reaper.hatchet_app_count; Hatchet::Reaper::HATCHET_APP_LIMIT + 1; end
145
+
146
+ expect(reaper.over_limit?).to be_truthy
147
+
148
+ reaper = Hatchet::Reaper.new(api_rate_limit: -> (){}, io: StringIO.new)
149
+ def reaper.hatchet_app_count; Hatchet::Reaper::HATCHET_APP_LIMIT - 1; end
150
+
151
+ expect(reaper.over_limit?).to be_falsey
152
+ end
153
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe "ShellThrottle" do
4
+ it "throttles when throw is called" do
5
+ platform_api = Hatchet::Runner.new("default_ruby").platform_api
6
+
7
+ @count = 0
8
+ Hatchet::ShellThrottle.new(platform_api: platform_api).call do
9
+ @count += 1
10
+ if @count >= 2
11
+ # No throttle
12
+ else
13
+ throw(:throttle)
14
+ end
15
+ end
16
+ expect(@count).to eq(2)
17
+ end
18
+
19
+ it "does not throttle when throw is NOT called" do
20
+ platform_api = Hatchet::Runner.new("default_ruby").platform_api
21
+
22
+ @count = 0
23
+ Hatchet::ShellThrottle.new(platform_api: platform_api).call do
24
+ @count += 1
25
+ end
26
+ expect(@count).to eq(1)
27
+ end
28
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heroku_hatchet
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0
4
+ version: 7.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Schneeman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-06 00:00:00.000000000 Z
11
+ date: 2020-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: platform-api
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.0.pre.1
19
+ version: '3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.0.pre.1
26
+ version: '3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rrrretry
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: repl_runner
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 0.0.3
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 0.0.3
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: threaded
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -207,6 +193,9 @@ files:
207
193
  - lib/hatchet/config.rb
208
194
  - lib/hatchet/git_app.rb
209
195
  - lib/hatchet/reaper.rb
196
+ - lib/hatchet/reaper/app_age.rb
197
+ - lib/hatchet/reaper/reaper_throttle.rb
198
+ - lib/hatchet/shell_throttle.rb
210
199
  - lib/hatchet/tasks.rb
211
200
  - lib/hatchet/test_run.rb
212
201
  - lib/hatchet/version.rb
@@ -222,12 +211,14 @@ files:
222
211
  - spec/hatchet/local_repo_spec.rb
223
212
  - spec/hatchet/lock_spec.rb
224
213
  - spec/spec_helper.rb
214
+ - spec/unit/reaper_spec.rb
215
+ - spec/unit/shell_throttle.rb
225
216
  - tmp/parallel_runtime_test.log
226
217
  homepage: https://github.com/heroku/hatchet
227
218
  licenses:
228
219
  - MIT
229
220
  metadata: {}
230
- post_install_message:
221
+ post_install_message:
231
222
  rdoc_options: []
232
223
  require_paths:
233
224
  - lib
@@ -243,7 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
234
  version: '0'
244
235
  requirements: []
245
236
  rubygems_version: 3.1.2
246
- signing_key:
237
+ signing_key:
247
238
  specification_version: 4
248
239
  summary: Hatchet is a an integration testing library for developing Heroku buildpacks.
249
240
  test_files:
@@ -257,3 +248,5 @@ test_files:
257
248
  - spec/hatchet/local_repo_spec.rb
258
249
  - spec/hatchet/lock_spec.rb
259
250
  - spec/spec_helper.rb
251
+ - spec/unit/reaper_spec.rb
252
+ - spec/unit/shell_throttle.rb