Add Hatchet Regression Tests (#969)

I went through all the tests in the Ruby buildpack and cataloged what I think can be generalized between languages to prevent regressions. This PR add tests for these cases:

* Test CI deploys run tests and use the cache [[reference test](https://github.com/heroku/heroku-buildpack-ruby/blob/f488bd53c7ff0b78e17c2405166cbd4a3af75ee2/spec/hatchet/ci_spec.rb#L36)]
* Test cache for regular deploys is used on repeated deploys (This was already tested on the Python buildpack, I moved it) [[reference test](https://github.com/heroku/heroku-buildpack-ruby/blob/e34c583c139911d059f5627bb25125707288f053/spec/hatchet/stack_spec.rb#L21-L25)]
    * Test modifying a requirement clears the cache appropriately (This was already tested on the Python buildpack, I moved it)
* Test deploying the getting started guide works [[reference test](https://github.com/heroku/heroku-buildpack-ruby/blob/424a7245e2da86845a20d58a9482bcf2a00c3a8f/spec/hatchet/getting_started_spec.rb#L5)]
* Test that all paths set by the buildpack are absolute instead of relative [[reference test](https://github.com/heroku/heroku-buildpack-ruby/blob/249d3c1a4e97068f8fd016f10fa0839709d95658/spec/hatchet/rails5_spec.rb#L68])
* Test upgrading stack invalidates the cache [[reference test](https://github.com/heroku/heroku-buildpack-ruby/blob/f488bd53c7ff0b78e17c2405166cbd4a3af75ee2/spec/hatchet/stack_spec.rb#L3)]
* Test that builds fail when a bad version is specified [[reference test](https://github.com/heroku/heroku-buildpack-ruby/blob/249d3c1a4e97068f8fd016f10fa0839709d95658/spec/hatchet/ruby_spec.rb#L5)]


In addition to that I've also got a CNB test with `pack-build` with the getting started app, but since python isn't `cnb` capable yet I didn't add one.
This commit is contained in:
Richard Schneeman
2020-04-27 08:26:42 -05:00
committed by GitHub
parent dd646998d3
commit a06b536109
8 changed files with 121 additions and 76 deletions
+4 -3
View File
@@ -6,7 +6,7 @@ branches:
- master - master
rvm: rvm:
- 2.4.4 - 2.6.6
before_script: before_script:
- gem install bundler -v 1.16.2 - gem install bundler -v 1.16.2
@@ -28,7 +28,8 @@ jobs:
name: Run Hatchet name: Run Hatchet
script: script:
- bundle exec hatchet ci:setup - bundle exec hatchet ci:setup
- bundle exec rspec - PARALLEL_SPLIT_TEST_PROCESSES=11 bundle exec parallel_split_test spec/hatchet/
env: env:
matrix: matrix:
- TESTFOLDER=test/run-deps - TESTFOLDER=test/run-deps
@@ -37,7 +38,7 @@ env:
global: global:
- HATCHET_RETRIES=3 - HATCHET_RETRIES=3
- IS_RUNNING_ON_CI=true - IS_RUNNING_ON_CI=true
- HATCHET_APP_LIMIT=5 - HATCHET_APP_LIMIT=80
- HATCHET_DEPLOY_STRATEGY=git - HATCHET_DEPLOY_STRATEGY=git
- secure: yjtlPE5FbVxTKnjUy/tZUBgSEf4qADD3QOxtgziuid73S0U/1IEXlMGFULsQzIjtlHKmHeywZqpVVEpthIH4RuT7uoX1Pb7SSM/g0T8fT3VoEFbFK1uYl0oZQbUS4Klxv9tPiumj8if3m6ULEGIz1X0wZcMOC0tMLwVCnwmap0E= - secure: yjtlPE5FbVxTKnjUy/tZUBgSEf4qADD3QOxtgziuid73S0U/1IEXlMGFULsQzIjtlHKmHeywZqpVVEpthIH4RuT7uoX1Pb7SSM/g0T8fT3VoEFbFK1uYl0oZQbUS4Klxv9tPiumj8if3m6ULEGIz1X0wZcMOC0tMLwVCnwmap0E=
- secure: ZeFTHWwnpIKE9nAqs88ocmiQh7bKce84lilGm5J23nf3N6V4wNyLwqlkvsM008WGBCaOg9AUx7ZunasT0ANsR5gLP3eV2UUg7ILdRgV2Gy13eNRFheC4PHdN92RqQ3aKoqlIv2K999xlhVjod0NzhkQQXB6PddfQINbuU7ks6As= - secure: ZeFTHWwnpIKE9nAqs88ocmiQh7bKce84lilGm5J23nf3N6V4wNyLwqlkvsM008WGBCaOg9AUx7ZunasT0ANsR5gLP3eV2UUg7ILdRgV2Gy13eNRFheC4PHdN92RqQ3aKoqlIv2K999xlhVjod0NzhkQQXB6PddfQINbuU7ks6As=
+2
View File
@@ -4,3 +4,5 @@ gem "rspec"
gem "heroku_hatchet" gem "heroku_hatchet"
gem "rspec-retry" gem "rspec-retry"
gem "rake" gem "rake"
gem "parallel_split_test"
+16 -9
View File
@@ -1,21 +1,22 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activesupport (5.2.1) activesupport (6.0.2.2)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
concurrent-ruby (1.1.3) zeitwerk (~> 2.2)
concurrent-ruby (1.1.6)
diff-lcs (1.3) diff-lcs (1.3)
erubis (2.7.0) erubis (2.7.0)
excon (0.62.0) excon (0.73.0)
heroics (0.0.25) heroics (0.0.25)
erubis (~> 2.0) erubis (~> 2.0)
excon excon
moneta moneta
multi_json (>= 1.9.2) multi_json (>= 1.9.2)
heroku_hatchet (4.0.6) heroku_hatchet (5.0.2)
excon (~> 0) excon (~> 0)
minitest-retry (~> 0.1.9) minitest-retry (~> 0.1.9)
platform-api (~> 2) platform-api (~> 2)
@@ -23,13 +24,17 @@ GEM
rrrretry (~> 1) rrrretry (~> 1)
thor (~> 0) thor (~> 0)
threaded (~> 0) threaded (~> 0)
i18n (1.1.1) i18n (1.8.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
minitest (5.11.3) minitest (5.14.0)
minitest-retry (0.1.9) minitest-retry (0.1.9)
minitest (>= 5.0) minitest (>= 5.0)
moneta (1.0.0) moneta (1.0.0)
multi_json (1.13.1) multi_json (1.14.1)
parallel (1.19.1)
parallel_split_test (0.7.0)
parallel (>= 0.5.13)
rspec (>= 3.1.0)
platform-api (2.2.0) platform-api (2.2.0)
heroics (~> 0.0.25) heroics (~> 0.0.25)
moneta (~> 1.0.0) moneta (~> 1.0.0)
@@ -55,17 +60,19 @@ GEM
thor (0.20.3) thor (0.20.3)
thread_safe (0.3.6) thread_safe (0.3.6)
threaded (0.0.4) threaded (0.0.4)
tzinfo (1.2.5) tzinfo (1.2.7)
thread_safe (~> 0.1) thread_safe (~> 0.1)
zeitwerk (2.3.0)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
heroku_hatchet heroku_hatchet
parallel_split_test
rake rake
rspec rspec
rspec-retry rspec-retry
BUNDLED WITH BUNDLED WITH
1.16.3 2.1.4
+2 -1
View File
@@ -1,5 +1,6 @@
{ {
"python": [ "python": [
"heroku/python-getting-started" "heroku/python-getting-started",
"sharpstone/python_default"
] ]
} }
+3 -1
View File
@@ -1,3 +1,5 @@
--- ---
- - "./repos/python/python-getting-started" - - "./repos/python/python-getting-started"
- 443a90c58be6881583cd7ef628e3869e3c30bb98 - master
- - "./repos/python/python_default"
- ca947f69027b2a30be5d26f9a42f25e54f4d7a1a
+33
View File
@@ -0,0 +1,33 @@
require_relative '../spec_helper'
describe "Heroku CI" do
it "works" do
before_deploy = Proc.new do
File.open("app.json", "w+") do |f|
f.puts <<~EOM
{
"environments": {
"test": {
"scripts": {
"test": "nosetests"
}
}
}
}
EOM
end
run!("echo nose >> requirements.txt")
end
Hatchet::Runner.new("python_default", before_deploy: before_deploy).run_ci do |test_run|
expect(test_run.output).to match("Downloading nose")
expect(test_run.output).to match("OK")
test_run.run_again
expect(test_run.output).to match("installing from cache")
expect(test_run.output).to_not match("Downloading nose")
end
end
end
+60 -56
View File
@@ -1,68 +1,72 @@
require_relative '../spec_helper' require_relative '../spec_helper'
describe "Default Python Deploy" do describe "Python" do
describe "cache" do
it "functions correctly" do
Hatchet::Runner.new("python_default").deploy do |app|
expect(app.output).to match(/Installing pip/)
def set_python_version(d, v) expect(app.output).to_not match("Requirements file has been changed, clearing cached dependencies")
Dir.chdir(d) do expect(app.output).to_not match("No change in requirements detected, installing from cache")
File.open('runtime.txt', 'w') do |f| expect(app.output).to_not match("No such file or directory")
f.puts "python-#{v}" expect(app.output).to_not match("cp: cannot create regular file")
# Redeploy with changed requirements file
run!(%Q{echo "" >> requirements.txt})
run!(%Q{echo "pygments" >> requirements.txt})
run!(%Q{git add . ; git commit --allow-empty -m next})
app.push!
# Check the cache to have cleared
expect(app.output).to match("Requirements file has been changed, clearing cached dependencies")
expect(app.output).to_not match("No dependencies found, preparing to install")
expect(app.output).to_not match("No change in requirements detected, installing from cache")
# With no changes on redeploy, the cache should be present
run!(%Q{git commit --allow-empty -m next})
app.push!
expect(app.output).to match("No change in requirements detected, installing from cache")
expect(app.output).to_not match("Requirements file has been changed, clearing cached dependencies")
expect(app.output).to_not match("No dependencies found, preparing to install")
end end
`git add runtime.txt && git commit -am "setting python version"`
end end
end end
before(:each) do describe "python versions" do
set_python_version(app.directory, python_version) let(:stack) { ENV["HEROKU_TEST_STACK"] || DEFAULT_STACK }
init_app(app) it "works with 3.7.6" do
version = "3.7.6"
before_deploy = -> { run!(%Q{echo "python-#{version}" >> runtime.txt}) }
Hatchet::Runner.new("python_default", before_deploy: before_deploy, stack: stack).deploy do |app|
expect(app.run('python -V')).to match(version)
end
end
it "works with 3.8.2" do
version = "3.8.2"
before_deploy = -> { run!(%Q{echo "python-#{version}" >> runtime.txt}) }
Hatchet::Runner.new("python_default", before_deploy: before_deploy, stack: stack).deploy do |app|
expect(app.run('python -V')).to match(version)
end
end
it "fails with a bad version" do
version = "3.8.2.lol"
before_deploy = -> { run!(%Q{echo "python-#{version}" >> runtime.txt}) }
Hatchet::Runner.new("python_default", before_deploy: before_deploy, stack: stack, allow_failure: true).deploy do |app|
expect(app.output).to match("not available for this stack")
end
end
end end
["3.7.6", "3.8.2"].each do |version| it "getting started app has no relative paths" do
context "on python-#{version}" do buildpacks = [
let(:app) { Hatchet::Runner.new('python-getting-started', stack: DEFAULT_STACK) } :default,
let(:python_version) { version } "https://github.com/sharpstone/force_absolute_paths_buildpack"
it "🐍" do ]
app.deploy do |app| Hatchet::Runner.new("python-getting-started", buildpacks: buildpacks).deploy do |app|
# What should happen on first deploy # Deploy works
expect(app.output).to match(/Installing pip/)
# What should not happen
expect(app.output).to_not match("Requirements file has been changed, clearing cached dependencies")
expect(app.output).to_not match("No change in requirements detected, installing from cache")
expect(app.output).to_not match("No such file or directory")
expect(app.output).to_not match("cp: cannot create regular file")
# let the previous build finish
sleep(5)
# Redeploy with changed requirements file
run!(%Q{echo "" >> requirements.txt})
run!(%Q{echo "flask" >> requirements.txt})
run!(%Q{git add . ; git commit --allow-empty -m next})
app.push!
# Check the cache to have cleared
expect(app.output).to match("Requirements file has been changed, clearing cached dependencies")
# What should not happen when the requirements file is changed
expect(app.output).to_not match("No dependencies found, preparing to install")
expect(app.output).to_not match("No change in requirements detected, installing from cache")
# let the previous build finish
sleep(5)
run!(%Q{git commit --allow-empty -m next})
app.push!
# With no changes on redeploy, the cache should
expect(app.output).to match("No change in requirements detected, installing from cache")
# With no changes on redeploy, the cache should not
expect(app.output).to_not match("Requirements file has been changed, clearing cached dependencies")
expect(app.output).to_not match("No dependencies found, preparing to install")
expect(app.run('python -V')).to match(version)
end
end
end end
end end
end end
+1 -6
View File
@@ -1,4 +1,4 @@
ENV['HATCHET_BUILDPACK_BASE'] = 'https://github.com/' + ENV['TRAVIS_REPO_SLUG'] + '.git' ENV['HATCHET_BUILDPACK_BASE'] = 'https://github.com/heroku/heroku-buildpack-python.git'
require 'rspec/core' require 'rspec/core'
require 'rspec/retry' require 'rspec/retry'
@@ -32,8 +32,3 @@ def run!(cmd)
raise "Error running command #{cmd} with output: #{out}" unless $?.success? raise "Error running command #{cmd} with output: #{out}" unless $?.success?
return out return out
end end
def init_app(app, stack=DEFAULT_STACK)
app.setup!
app.platform_api.app.update(app.name, {"build_stack" => ENV["HEROKU_TEST_STACK"] || stack})
end