Class: Hatchet::TestRun
- Inherits:
-
Object
- Object
- Hatchet::TestRun
- Defined in:
- lib/hatchet/test_run.rb
Instance Attribute Summary collapse
-
#app ⇒ Object
readonly
Returns the value of attribute app.
Instance Method Summary collapse
- #create_test_run ⇒ Object
- #info ⇒ Object
-
#initialize(token:, buildpacks:, app:, pipeline:, api_rate_limit:, timeout: 10, pause: 5, commit_sha: "sha", commit_branch: "master", commit_message: "commit", organization: nil) ⇒ TestRun
constructor
Hatchet::GitApp.new(“rails3_mri_193”).run_ci do |test_run| assert :succeeded, test_run.status end.
- #output ⇒ Object
- #run_again(&block) ⇒ Object
-
#source_blob_url ⇒ Object
Here’s where the magic happens folks.
- #status ⇒ Object
- #wait! ⇒ Object
Constructor Details
#initialize(token:, buildpacks:, app:, pipeline:, api_rate_limit:, timeout: 10, pause: 5, commit_sha: "sha", commit_branch: "master", commit_message: "commit", organization: nil) ⇒ TestRun
Hatchet::GitApp.new(“rails3_mri_193”).run_ci do |test_run|
assert :succeeded, test_run.status
end
TestRun.new(token: , buildpacks: , test_dir: )
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/hatchet/test_run.rb', line 22 def initialize( token:, buildpacks:, app:, pipeline:, api_rate_limit:, timeout: 10, pause: 5, commit_sha: "sha", commit_branch: "master", commit_message: "commit", organization: nil ) @pipeline = pipeline || "#{Hatchet::APP_PREFIX}#{SecureRandom.hex(5)}" @timeout = timeout @pause = pause @organization = organization @token = token @commit_sha = commit_sha @commit_branch = commit_branch @commit_message = @buildpacks = Array(buildpacks) @app = app @mutex = Mutex.new @status = false @api_rate_limit = api_rate_limit end |
Instance Attribute Details
#app ⇒ Object (readonly)
Returns the value of attribute app.
49 50 51 |
# File 'lib/hatchet/test_run.rb', line 49 def app @app end |
Instance Method Details
#create_test_run ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/hatchet/test_run.rb', line 62 def create_test_run @mutex.synchronize do raise "Test is already running" if @status @status = :building body = { source_blob_url: source_blob_url, pipeline: @pipeline, organization: @organization, commit_sha: @commit_sha, commit_branch: @commit_branch, commit_message: @commit_message, } # https://github.com/heroku/api/blob/master/schema/variants/3.ci/platform-api-reference.md#test-run-create attributes = excon_request( method: :post, path: "/test-runs", version: "3.ci", body: body, expects: [201] ) @test_run_id = attributes["id"] end info end |
#info ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/hatchet/test_run.rb', line 89 def info # GET /test-runs/{test_run_id} response = excon_request( method: :get, path: "/test-runs/#{@test_run_id}", version: "3.ci", expects: [201, 200] ) @status = response["status"].to_sym end |
#output ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/hatchet/test_run.rb', line 105 def output test_nodes = excon_request( method: :get, path: "/test-runs/#{@test_run_id}/test-nodes", version: "3.ci", expects: [200] ) node_output_urls = [] test_nodes.each do |test_node| node_output_urls << test_node.fetch("setup_stream_url") node_output_urls << test_node.fetch("output_stream_url") end output = String.new node_output_urls.each do |url| output << get_contents_or_whatever(url) end output end |
#run_again(&block) ⇒ Object
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/hatchet/test_run.rb', line 51 def run_again(&block) @mutex.synchronize do @status = false end Hatchet::RETRIES.times.retry do create_test_run end wait!(&block) end |
#source_blob_url ⇒ Object
Here’s where the magic happens folks
Set the buildpack
We take the current directory structure and see if it has an ‘app.json` This is how Heroku CI knows what buildpacks to use to run your tests Hatchet will inject whatever buildpack you pass to it, by default it uses the same buildpack you have specified in your Hatchet constants and uses the same branch your tests are using
Generate source blob url
The CI endpoint takes a url that has a ‘.tgz` file to execute your tests. We pull down the app you’re testing against, inject an ‘app.json` (or modify if it already exists). We the use the heroku “source” api to generate a url that we can put our newly generated `.tgz` file. It also returns a “get” url where those contents can be downloaded. We pass this url back to CI
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/hatchet/test_run.rb', line 170 def source_blob_url @app.in_directory do app_json = JSON.parse(File.read("app.json")) if File.exist?("app.json") app_json ||= {} app_json["environments"] ||= {} app_json["environments"]["test"] ||= {} app_json["environments"]["test"]["buildpacks"] = @buildpacks.map {|b| { url: b } } app_json["environments"]["test"]["env"] ||= {} app_json["environments"]["test"]["env"] = @app.app_config.merge(app_json["environments"]["test"]["env"]) # copy in explicitly set app config app_json["stack"] ||= @app.stack if @app.stack && !@app.stack.empty? File.open("app.json", "w") {|f| f.write(JSON.generate(app_json)) } Tempfile.create("slug.tgz") do |slug| out = `tar c . | gzip -9 > #{slug.path}` raise "Tar command failed: #{out}" unless $?.success? source_put_url = @app.create_source Hatchet::RETRIES.times.retry do PlatformAPI.rate_throttle.call do Excon.put(source_put_url, expects: [200], body: slug.read) end end end end return @app.source_get_url end |
#status ⇒ Object
101 102 103 |
# File 'lib/hatchet/test_run.rb', line 101 def status @status # :pending, :building, :creating, :succeeded, :failed, :errored end |
#wait! ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/hatchet/test_run.rb', line 126 def wait! Timeout::timeout(@timeout) do while true do info case @status when :succeeded yield self if block_given? return self when :failed, :errored raise FailedTestError.new(self.app, self.output) unless app.allow_failure? yield self if block_given? return self else # keep looping end sleep @pause end end rescue Timeout::Error = "Timed out status: #{@status}, timeout: #{@timeout}, app: #{app.name}" puts raise FailedTestError.new(self.app, "#{}, output:\n#{self.output}") unless app.allow_failure? yield self return self end |