hive-messages 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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