hive-messages 1.0.1

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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +35 -0
  6. data/Rakefile +11 -0
  7. data/hive-messages.gemspec +33 -0
  8. data/lib/hive/messages.rb +46 -0
  9. data/lib/hive/messages/artifact.rb +17 -0
  10. data/lib/hive/messages/base.rb +18 -0
  11. data/lib/hive/messages/configuration.rb +12 -0
  12. data/lib/hive/messages/execution_variables_base.rb +27 -0
  13. data/lib/hive/messages/job.rb +100 -0
  14. data/lib/hive/messages/nil_job.rb +15 -0
  15. data/lib/hive/paths.rb +12 -0
  16. data/lib/hive/paths/artifacts.rb +20 -0
  17. data/lib/hive/paths/jobs.rb +48 -0
  18. data/lib/hive/paths/queues.rb +21 -0
  19. data/lib/hive/representers/artifact_representer.rb +13 -0
  20. data/lib/hive/representers/job_representer.rb +25 -0
  21. data/lib/roar/transport/net_http/request_patch.rb +19 -0
  22. data/lib/virtus/attribute/execution_variables.rb +20 -0
  23. data/spec/fixtures/sample.pem +31 -0
  24. data/spec/fixtures/upload_sample.log +1 -0
  25. data/spec/lib/hive/messages/artifact_spec.rb +50 -0
  26. data/spec/lib/hive/messages/configuration_spec.rb +13 -0
  27. data/spec/lib/hive/messages/execution_variables_base_spec.rb +12 -0
  28. data/spec/lib/hive/messages/job_spec.rb +233 -0
  29. data/spec/lib/hive/messages_spec.rb +30 -0
  30. data/spec/lib/hive/paths/artifacts_spec.rb +22 -0
  31. data/spec/lib/hive/paths/jobs_spec.rb +49 -0
  32. data/spec/lib/hive/paths/queues_spec.rb +35 -0
  33. data/spec/lib/hive/paths_spec.rb +10 -0
  34. data/spec/lib/hive/representers/artifact_representer_spec.rb +49 -0
  35. data/spec/lib/hive/representers/job_representer_spec.rb +96 -0
  36. data/spec/lib/roar/transport/net_http/request_patch_spec.rb +84 -0
  37. data/spec/lib/virtus/attribute/execution_variables_spec.rb +60 -0
  38. data/spec/spec_helper.rb +13 -0
  39. metadata +266 -0
@@ -0,0 +1,21 @@
1
+ module Hive
2
+ module Paths
3
+
4
+ class Queues
5
+
6
+ class << self
7
+
8
+ def job_reservation_url(queues)
9
+ queues=[*queues].join(",")
10
+ "#{queues_base}/#{queues}/jobs/reserve"
11
+ end
12
+
13
+ private
14
+
15
+ def queues_base
16
+ "#{Hive::Paths.base}/api/queues"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module Hive
2
+ module Representers
3
+ module ArtifactRepresenter
4
+ include Roar::JSON
5
+
6
+ property :artifact_id
7
+ property :job_id
8
+ property :asset_file_name
9
+ property :asset_content_type
10
+ property :asset_file_size
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module Hive
2
+ module Representers
3
+ module JobRepresenter
4
+ include Roar::JSON
5
+
6
+ property :command
7
+ property :job_id
8
+ property :repository
9
+ property :execution_directory
10
+ property :target
11
+ property :execution_variables
12
+ property :reservation_details
13
+ property :device_id
14
+ property :running_count
15
+ property :passed_count
16
+ property :failed_count
17
+ property :errored_count
18
+ property :state
19
+ property :result
20
+ property :exit_value
21
+ property :message
22
+ property :result_details
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require "roar/transport/net_http/request"
2
+
3
+ module Roar
4
+ module Transport
5
+ class NetHTTP
6
+ class Request
7
+
8
+ class <<self
9
+
10
+ def new(options)
11
+ options[:pem_file] = Hive::Messages.configuration.pem_file
12
+ options[:ssl_verify_mode] = Hive::Messages.configuration.ssl_verify_mode
13
+ super(options)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Virtus
2
+ class Attribute
3
+ class ExecutionVariables < Attribute
4
+
5
+ def coerce(values)
6
+ unless values.blank?
7
+ klass = Class.new(Hive::Messages::ExecutionVariablesBase)
8
+
9
+ attributes = klass.attribute_set.collect(&:name)
10
+ new_attributes = values.keys-attributes
11
+ new_attributes.each do |attribute|
12
+ klass.attribute attribute
13
+ end
14
+
15
+ klass.new(values)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICcTCCAdqgAwIBAgIJAMvA30EY1rKtMA0GCSqGSIb3DQEBBQUAMDAxCzAJBgNV
3
+ BAYTAlVTMQ0wCwYDVQQKEwRLZWFzMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMDgw
4
+ OTA0MTU1MTU5WhcNMTgwOTAyMTU1MTU5WjAwMQswCQYDVQQGEwJVUzENMAsGA1UE
5
+ ChMES2VhczESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GN
6
+ ADCBiQKBgQDK17rB/KVaK8MVjiEkvA4ZncOOIC3nStZ/erXM+qwkghPM4Tfr2FTU
7
+ iTgwwdLdu/ht74oWnppttfaTQ+sVz2rFXnPgfqKTGoJTwWFiuNuZhSRDVssGVnL/
8
+ RatZW6wns8UNf+W4hUe6/vGQP6obNTe2T4R+t2hXP51OkOy4BMcq0QIDAQABo4GS
9
+ MIGPMB0GA1UdDgQWBBQDIsX7HoSqbxKrCawi64MkXRmtmzBgBgNVHSMEWTBXgBQD
10
+ IsX7HoSqbxKrCawi64MkXRmtm6E0pDIwMDELMAkGA1UEBhMCVVMxDTALBgNVBAoT
11
+ BEtlYXMxEjAQBgNVBAMTCWxvY2FsaG9zdIIJAMvA30EY1rKtMAwGA1UdEwQFMAMB
12
+ Af8wDQYJKoZIhvcNAQEFBQADgYEAW5UBM7EIMpARzQwpQ8N1gyTR/VqJ9fSm4MIw
13
+ Y5m90HRgsDcXVbhn0rRfcC8o4EtGDvCjqsFYXy/ImF9tjEiuaysxbqepl+XMszPE
14
+ 1kO50quWsV1FLSdcJX6t/ofJYOxiQkqPvg9t/ovTnEZ+w4NfPo+0MJgudjJoD2+w
15
+ 5UTsKtU=
16
+ -----END CERTIFICATE-----
17
+ -----BEGIN RSA PRIVATE KEY-----
18
+ MIICXQIBAAKBgQDK17rB/KVaK8MVjiEkvA4ZncOOIC3nStZ/erXM+qwkghPM4Tfr
19
+ 2FTUiTgwwdLdu/ht74oWnppttfaTQ+sVz2rFXnPgfqKTGoJTwWFiuNuZhSRDVssG
20
+ VnL/RatZW6wns8UNf+W4hUe6/vGQP6obNTe2T4R+t2hXP51OkOy4BMcq0QIDAQAB
21
+ AoGAHcDJDx1M784NfoLrj6TZ+J3wik9kDFIo5mgMdLWsPGqsFthOSJTh1I8QI+66
22
+ THX++bkyKyE2i7MuKOnEeN2Ezo2jAThF7XoWhm6/+pSXhSqmL1jKr/1CZRaR9jv0
23
+ cCVJc3mTuAGH+yFVeGpWNvDaCmOUlD5M48xTROJXteDQ0TECQQDuDM9pmQdqkGIp
24
+ dvbIviS8donYn0kJ0TKS14pMtb/C63lcld513rHS43ru3FRY9baR/q5vV9vW5RhH
25
+ S7w4cYvVAkEA2iNLsFEAkY88oZJYbdyybeKxZdReyes1/zPe4RYzRdbDHRNAa+zk
26
+ mZIZDI820E0Y+DeoT+q3nXkXiiOS/iRNDQJBAKdAvOH2sO1AcJetjArS/cCkkIlw
27
+ sMKDB0OAyRzIfekXxPc2HU03oD0Jsy/sAh9W1GWTST/VvRIpeHtvTNljfdkCQF5T
28
+ UuBcNoW6zXoEYU6oV1Oi6hjhW1eu6PuAv4jPY754XoiNEZdZqYQqo8BFkWtDW1/C
29
+ GXrtQRbMDPzD40UYB2UCQQCmJpJp+u2lHj7zuZikHIHQBNyXyoGnzgNs6XUj1Bs6
30
+ Y4vjue8w6RkRLZ1YGP+xqsngVqb9IRygyLDpEgwEnOT4
31
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1 @@
1
+ This is a sample log file.
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+ require "shoulda/matchers"
3
+ require "shoulda/matchers/active_model/validate_presence_of_matcher"
4
+ require 'webmock/rspec'
5
+
6
+ describe Hive::Messages::Artifact, type: :model do
7
+
8
+ describe "validations" do
9
+
10
+ it { should validate_presence_of(:artifact_id) }
11
+ it { should validate_presence_of(:job_id) }
12
+ it { should validate_presence_of(:asset_file_name) }
13
+ it { should validate_presence_of(:asset_content_type) }
14
+ it { should validate_presence_of(:asset_file_size) }
15
+ end
16
+
17
+ describe "serialization" do
18
+
19
+ let(:artifact_attributes) do
20
+ {
21
+ artifact_id: 321,
22
+ job_id: 123,
23
+ asset_file_name: "screenshot1.png",
24
+ asset_content_type: "image/png",
25
+ asset_file_size: 2300
26
+ }
27
+ end
28
+
29
+ describe "#to_json" do
30
+
31
+ let(:artifact_message) { Hive::Messages::Artifact.new(artifact_attributes) }
32
+
33
+ it "outputs valid payload JSON" do
34
+ expect(artifact_message.to_json).to eq artifact_attributes.to_json
35
+ end
36
+ end
37
+
38
+ describe "#from_json" do
39
+
40
+ let(:artifact_message) { Hive::Messages::Artifact.new.from_json(artifact_attributes.to_json) }
41
+ subject { artifact_message }
42
+
43
+ its(:artifact_id) { should eq artifact_attributes[:artifact_id] }
44
+ its(:job_id) { should eq artifact_attributes[:job_id] }
45
+ its(:asset_file_name) { should eq artifact_attributes[:asset_file_name] }
46
+ its(:asset_content_type) { should eq artifact_attributes[:asset_content_type] }
47
+ its(:asset_file_size) { should eq artifact_attributes[:asset_file_size] }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Hive::Messages::Configuration do
4
+
5
+ describe "attributes" do
6
+
7
+ subject { Hive::Messages::Configuration.new.attributes.keys }
8
+
9
+ it { should include(:base_path) }
10
+ it { should include(:pem_file) }
11
+ it { should include(:ssl_verify_mode) }
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require "spec_helper"
2
+ require "shoulda/matchers"
3
+
4
+ describe Hive::Messages::ExecutionVariablesBase, type: :model do
5
+
6
+ describe "validations" do
7
+
8
+ it { should validate_presence_of(:job_id) }
9
+ it { should validate_presence_of(:version) }
10
+ it { should validate_presence_of(:queue_name) }
11
+ end
12
+ end
@@ -0,0 +1,233 @@
1
+ require "spec_helper"
2
+ require "shoulda/matchers"
3
+ require "shoulda/matchers/active_model/validate_presence_of_matcher"
4
+ require 'webmock/rspec'
5
+
6
+ describe Hive::Messages::Job, type: :model do
7
+
8
+ describe "validations" do
9
+
10
+ it { should validate_presence_of(:command) }
11
+ it { should validate_presence_of(:job_id) }
12
+ end
13
+
14
+ describe "serialization" do
15
+
16
+ let(:job_attributes) do
17
+ {
18
+ command: "cucumber -t @all",
19
+ job_id: 99,
20
+ repository: "svn://...",
21
+ execution_directory: "/some_dir",
22
+ target: { application_url: "http://www.bbc.co.uk/mobile", application_url_parameters: "thing=value" },
23
+ execution_variables: { job_id: 99, version: "1.0", queue_name: "nexus-4", run_id: "88", tests: ["test one", "test two"] },
24
+ reservation_details: { hive_id: 99, pid: 1024 },
25
+ device_id: 23,
26
+ state: "running"
27
+
28
+ }
29
+ end
30
+
31
+ describe "#to_json" do
32
+
33
+ let(:job_message) { Hive::Messages::Job.new(job_attributes) }
34
+
35
+ it "outputs valid payload JSON" do
36
+ expect(job_message.to_json).to eq job_attributes.to_json
37
+ end
38
+ end
39
+
40
+ describe "#from_json" do
41
+
42
+ let(:job_message) { Hive::Messages::Job.new.from_json(job_attributes.to_json) }
43
+ subject { job_message }
44
+
45
+ its(:command) { should eq job_attributes[:command] }
46
+ its(:job_id) { should eq job_attributes[:job_id] }
47
+ its(:repository) { should eq job_attributes[:repository] }
48
+ its(:execution_directory) { should eq job_attributes[:execution_directory] }
49
+ its(:target) { should eq job_attributes[:target].stringify_keys }
50
+ it "assigned the correct values to the execution variables object" do
51
+ expect(job_message.execution_variables.attributes).to eq job_attributes[:execution_variables]
52
+ end
53
+ its(:reservation_details) { should eq job_attributes[:reservation_details].stringify_keys }
54
+ its(:device_id) { should eq job_attributes[:device_id] }
55
+ its(:state) { should eq job_attributes[:state] }
56
+ end
57
+ end
58
+
59
+ describe "class methods" do
60
+
61
+ describe ".reserve" do
62
+
63
+ let(:base_path) { "http://hive.bbc" }
64
+ let(:remote_job) { Hive::Messages::Job.new(job_id: 99, command: "cmd", repository: "repository") }
65
+ let(:queue_names) { ["queue_one", "queue_two"] }
66
+ let(:reservation_details) { { hive_id: 99, worker_pid: 1024 } }
67
+
68
+ before(:each) do
69
+ Hive::Messages.configure { |config| config.base_path = base_path }
70
+ stub_request(:patch, Hive::Paths::Queues.job_reservation_url(queue_names))
71
+ .with( body: {reservation_details: reservation_details}.to_json, headers: { "Content-Type" => "application/json" } )
72
+ .to_return( body: http_body, status: http_status )
73
+ end
74
+
75
+ subject { Hive::Messages::Job.reserve(queue_names, reservation_details) }
76
+
77
+ context "when a job is available for reservation" do
78
+
79
+ let(:http_status) { 200 }
80
+ let(:http_body) { remote_job.to_json }
81
+
82
+ its(:job_id) { should eq remote_job.job_id }
83
+ its(:command) { should eq remote_job.command }
84
+ its(:repository) { should eq remote_job.repository }
85
+ end
86
+
87
+ context "when NO job is available for reservation" do
88
+
89
+ let(:http_status) { 404 }
90
+ let(:http_body) { nil }
91
+
92
+ it { should be_nil }
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "instance methods" do
98
+
99
+ let(:base_path) { "http://hive.bbc" }
100
+ let(:remote_job) { Hive::Messages::Job.new(job_id: job_id, command: "cmd", repository: "repository") }
101
+
102
+ let(:local_job) { Hive::Messages::Job.new(job_id: job_id) }
103
+
104
+ let(:job_id) { 99 }
105
+
106
+ before(:each) do
107
+ Hive::Messages.configure { |config| config.base_path = base_path }
108
+ end
109
+
110
+ describe "#start" do
111
+ let(:device_id) { 33 }
112
+
113
+ let!(:stubbed_request) do
114
+ stub_request(:patch, Hive::Paths::Jobs.start_url(job_id))
115
+ .with( body: {job_id: job_id, device_id: device_id}.to_json, headers: { "Content-Type" => "application/json" } )
116
+ .to_return( body: remote_job.to_json )
117
+ end
118
+
119
+ before(:each) do
120
+ pending "Behaviour of start has changed"
121
+ local_job.start(device_id)
122
+ end
123
+
124
+ it "made the request to start the job" do
125
+ expect(stubbed_request).to have_been_requested
126
+ end
127
+ end
128
+
129
+
130
+ describe "#update_results" do
131
+
132
+ let(:device_id) { 33 }
133
+
134
+ let(:running_count) { 4 }
135
+ let(:failed_count) { 3 }
136
+ let(:errored_count) { 2 }
137
+ let(:passed_count) { 1 }
138
+
139
+ let(:counts) {
140
+ { running_count: running_count,
141
+ passed_count: passed_count,
142
+ failed_count: failed_count,
143
+ errored_count: errored_count
144
+ }
145
+ }
146
+
147
+ let!(:stubbed_request) do
148
+ stub_request(:patch, Hive::Paths::Jobs.update_results_url(job_id))
149
+ .with( body: {job_id:job_id}.merge(counts).to_json,
150
+ headers: { "Content-Type" => "application/json" }
151
+ )
152
+ .to_return( body: remote_job.to_json )
153
+ end
154
+
155
+ before(:each) do
156
+ local_job.update_results(counts)
157
+ end
158
+
159
+ it "made the request to start the job" do
160
+ expect(stubbed_request).to have_been_requested
161
+ end
162
+ end
163
+
164
+ describe "#report_artifact" do
165
+
166
+ let(:remote_artifact) { Hive::Messages::Artifact.new(job_id: 99, asset_file_name: "screenshot_1.png", asset_content_type: "image/png", asset_file_size: 2300) }
167
+
168
+ let!(:stubbed_request) do
169
+ stub_request(:post, Hive::Paths::Artifacts.create_url(job_id))
170
+ .with(
171
+ body: "-------------RubyMultipartPost\r\nContent-Disposition: form-data; name=\"data\"; filename=\"#{artifact_basename}\"\r\nContent-Length: 26\r\nContent-Type: #{artifact_mime}\r\nContent-Transfer-Encoding: binary\r\n\r\nThis is a sample log file.\r\n-------------RubyMultipartPost--\r\n\r\n",
172
+ headers: {'Accept'=>'*/*', 'Content-Length'=>'254', 'Content-Type'=>'multipart/form-data; boundary=-----------RubyMultipartPost', 'User-Agent'=>'Ruby'}
173
+ )
174
+ .to_return( body: remote_artifact.to_json )
175
+ end
176
+
177
+ let(:artifact_mime) { MimeMagic.by_path(artifact_path) }
178
+ let(:artifact_basename) { Pathname.new(artifact_path).basename }
179
+
180
+ let(:artifact_path) { File.expand_path("spec/fixtures/upload_sample.log", Hive::Messages.root) }
181
+
182
+ let!(:returned_artifact) { Hive::Messages::Job.new(job_id: job_id).report_artifact(artifact_path) }
183
+
184
+ it "returns an Artifact object" do
185
+ expect(returned_artifact).to be_instance_of(Hive::Messages::Artifact)
186
+ end
187
+
188
+ it "populates the resulting Artifact with the attributes returned upstream" do
189
+ expect(returned_artifact.attributes).to eq remote_artifact.attributes
190
+ end
191
+
192
+ it "uploaded the artifact" do
193
+ expect(stubbed_request).to have_been_requested
194
+ end
195
+ end
196
+
197
+ describe "#end" do
198
+
199
+ let!(:stubbed_request) do
200
+ stub_request(:patch, Hive::Paths::Jobs.end_url(job_id))
201
+ .with( body: {job_id: job_id}.to_json, headers: { "Content-Type" => "application/json" } )
202
+ .to_return( body: remote_job.to_json )
203
+ end
204
+
205
+ before(:each) do
206
+ pending "Behaviour of new has changed"
207
+ Hive::Messages::Job.new(job_id: job_id).end
208
+ end
209
+
210
+ it "made the request to start the job" do
211
+ expect(stubbed_request).to have_been_requested
212
+ end
213
+ end
214
+
215
+ describe "#error" do
216
+
217
+ let!(:stubbed_request) do
218
+ stub_request(:patch, Hive::Paths::Jobs.error_url(job_id))
219
+ .with( body: {job_id: job_id}.to_json, headers: { "Content-Type" => "application/json" } )
220
+ .to_return( body: remote_job.to_json )
221
+ end
222
+
223
+ before(:each) do
224
+ pending "Behaviour of new has changed"
225
+ Hive::Messages::Job.new(job_id: job_id).error
226
+ end
227
+
228
+ it "made the request to start the job" do
229
+ expect(stubbed_request).to have_been_requested
230
+ end
231
+ end
232
+ end
233
+ end