helix 0.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ require 'helix/base'
2
+
3
+ module Helix
4
+
5
+ module Statistics
6
+
7
+ unless defined?(self::STORAGE_ACTION_FOR)
8
+ STORAGE_ACTION_FOR = {
9
+ track: "track_ingest/disk_usage",
10
+ image: "image_ingest/disk_usage",
11
+ video: "video_publish/disk_usage",
12
+ }
13
+ end
14
+
15
+ # @example
16
+ # Helix::Statistics.album_delivery #=> Array of Hashes of stats data
17
+ #
18
+ # @return [Array of Hashes] Statistics information.
19
+ def self.album_delivery(opts={})
20
+ self.image_delivery(opts)
21
+ end
22
+
23
+ # @example
24
+ # Helix::Statistics.album_storage #=> Array of Hashes of stats data
25
+ #
26
+ # @return [Array of Hashes] Statistics information.
27
+ def self.album_storage(opts={})
28
+ self.image_storage(opts)
29
+ end
30
+
31
+ # @example
32
+ # Helix::Statistics.audio_delivery #=> Array of Hashes of stats data
33
+ #
34
+ # @return [Array of Hashes] Statistics information.
35
+ def self.audio_delivery(opts={})
36
+ self.delivery(:track, opts)
37
+ end
38
+
39
+ # @example
40
+ # Helix::Statistics.audio_ingest #=> Array of Hashes of stats data
41
+ #
42
+ # @return [Array of Hashes] Statistics information.
43
+ def self.audio_ingest(opts={})
44
+ end
45
+
46
+ # @example
47
+ # Helix::Statistics.audio_storage #=> Array of Hashes of stats data
48
+ #
49
+ # @return [Array of Hashes] Statistics information.
50
+ def self.audio_storage(opts={})
51
+ self.storage(:track, opts)
52
+ end
53
+
54
+ # @example
55
+ # Helix::Statistics.image_delivery #=> Array of Hashes of stats data
56
+ #
57
+ # @return [Array of Hashes] Statistics information.
58
+ def self.image_delivery(opts={})
59
+ self.delivery(:image, opts)
60
+ end
61
+
62
+ # @example
63
+ # Helix::Statistics.image_storage #=> Array of Hashes of stats data
64
+ #
65
+ # @return [Array of Hashes] Statistics information.
66
+ def self.image_storage(opts={})
67
+ self.storage(:image, opts)
68
+ end
69
+
70
+ # @example
71
+ # Helix::Statistics.track_delivery #=> Array of Hashes of stats data
72
+ #
73
+ # @return [Array of Hashes] Statistics information.
74
+ def self.track_delivery(opts={})
75
+ self.audio_delivery(opts)
76
+ end
77
+
78
+ # @example
79
+ # Helix::Statistics.track_ingest #=> Array of Hashes of stats data
80
+ #
81
+ # @return [Array of Hashes] Statistics information.
82
+ def self.track_ingest(opts={})
83
+ self.audio_ingest(opts)
84
+ end
85
+
86
+ # @example
87
+ # Helix::Statistics.track_storage #=> Array of Hashes of stats data
88
+ #
89
+ # @return [Array of Hashes] Statistics information.
90
+ def self.track_storage(opts={})
91
+ self.audio_storage(opts)
92
+ end
93
+
94
+ # @example
95
+ # Helix::Statistics.video_delivery #=> Array of Hashes of stats data
96
+ #
97
+ # @return [Array of Hashes] Statistics information.
98
+ def self.video_delivery(opts={})
99
+ self.delivery(:video, opts)
100
+ end
101
+
102
+ # @example
103
+ # Helix::Statistics.video_ingest #=> Array of Hashes of stats data
104
+ #
105
+ # @return [Array of Hashes] Statistics information.
106
+ def self.video_ingest(opts={})
107
+ # encode, source, or breakdown
108
+ end
109
+
110
+ # @example
111
+ # Helix::Statistics.video_storage #=> Array of Hashes of stats data
112
+ #
113
+ # @return [Array of Hashes] Statistics information.
114
+ def self.video_storage(opts={})
115
+ self.storage(:video, opts)
116
+ end
117
+
118
+ private
119
+
120
+ def self.delivery(media_type, opts)
121
+ memo_cfg = Helix::Config.instance
122
+ guid = opts.delete("#{media_type}_id".to_sym)
123
+ url_opts = guid ?
124
+ {guid: guid, media_type: "#{media_type}s".to_sym, action: :statistics} :
125
+ {media_type: :statistics, action: "#{media_type}_delivery".to_sym}
126
+ url = memo_cfg.build_url(url_opts)
127
+ # We allow opts[:sig_type] for internal negative testing only.
128
+ memo_cfg.get_response(url, {sig_type: :view}.merge(opts))
129
+ end
130
+
131
+ def self.storage(media_type, opts)
132
+ memo_cfg = Helix::Config.instance
133
+ url_opts = {media_type: :statistics, action: storage_action_for(media_type)}
134
+ url = memo_cfg.build_url(url_opts)
135
+ # We allow opts[:sig_type] for internal negative testing only.
136
+ memo_cfg.get_response(url, {sig_type: :view}.merge(opts))
137
+ end
138
+
139
+ def self.storage_action_for(media_type)
140
+ STORAGE_ACTION_FOR[media_type].to_sym
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,17 @@
1
+ module Helix
2
+
3
+ class Track < Base
4
+
5
+ # The class name, to be used by supporting classes. Such as Config which uses
6
+ # this method as a way to build URLs.
7
+ #
8
+ #
9
+ # @example
10
+ # Helix::Track.media_type_sym #=> :track
11
+ #
12
+ # @return [Symbol] Name of the class.
13
+ def self.media_type_sym; :track; end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,19 @@
1
+ require 'helix/base'
2
+
3
+ module Helix
4
+
5
+ class Video < Base
6
+
7
+ # The class name, to be used by supporting classes. Such as Config which uses
8
+ # this method as a way to build URLs.
9
+ #
10
+ #
11
+ # @example
12
+ # Helix::Video.media_type_sym #=> :video
13
+ #
14
+ # @return [Symbol] Name of the class.
15
+ def self.media_type_sym; :video; end
16
+
17
+ end
18
+
19
+ end
data/lib/helix.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'helix/video'
2
+ require 'helix/track'
3
+ require 'helix/album'
4
+ require 'helix/image'
5
+ require 'helix/config'
6
+ require 'helix/statistics'
7
+
8
+ module Helix
9
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'helix'
3
+
4
+ describe Helix::Album do
5
+ let(:klass) { Helix::Album }
6
+
7
+ subject { klass }
8
+ its(:ancestors) { should include(Helix::Base) }
9
+ its(:guid_name) { should eq('album_id') }
10
+ its(:media_type_sym) { should be(:album) }
11
+ its(:plural_media_type) { should eq('albums') }
12
+
13
+ describe "Constants"
14
+
15
+ describe "an instance" do
16
+ let(:obj) { klass.new({'album_id' => 'some_album_guid'}) }
17
+ subject { obj }
18
+ its(:media_type_sym) { should be(:album) }
19
+ describe "#update" do
20
+ let(:meth) { :update }
21
+ it "should raise an error" do
22
+ expect(lambda { obj.send(meth) }).to raise_error("Albums Update is not currently supported.")
23
+ end
24
+ end
25
+ end
26
+
27
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,325 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'helix'
3
+
4
+ describe Helix::Base do
5
+
6
+ def set_stubs(obj, even_sig=false)
7
+ obj.instance_variable_set(:@attributes, {})
8
+ obj.stub(:media_type_sym) { :video }
9
+ obj.stub(:plural_media_type) { 'videos' }
10
+ obj.stub(:guid) { 'some_guid' }
11
+ obj.stub(:signature) { 'some_sig' } if even_sig
12
+ end
13
+
14
+ let(:klass) { Helix::Base }
15
+
16
+ subject { klass }
17
+
18
+ describe "Constants" do
19
+ describe "METHODS_DELEGATED_TO_CLASS" do
20
+ subject { klass::METHODS_DELEGATED_TO_CLASS }
21
+ it { should eq([:guid_name, :media_type_sym, :plural_media_type]) }
22
+ end
23
+ end
24
+
25
+ ### CLASS METHODS
26
+
27
+ describe ".create" do
28
+ let(:meth) { :create }
29
+ let(:mock_config) { mock(Helix::Config) }
30
+ subject { klass.method(meth) }
31
+ its(:arity) { should eq(-1) }
32
+ let(:klass_sym) { :klass }
33
+ let(:resp_value) { { klass_sym.to_s => { attribute: :value } } }
34
+ let(:resp_json) { "JSON" }
35
+ let(:params) { { signature: "some_sig" } }
36
+ let(:expected) { { attributes: { attribute: :value }, config: mock_config } }
37
+ before(:each) do
38
+ klass.stub(:plural_media_type) { :klasses }
39
+ klass.stub(:media_type_sym) { klass_sym }
40
+ mock_config.stub(:build_url).with(action: :create_many, media_type: :klasses) { :url }
41
+ mock_config.stub(:signature).with(:update) { "some_sig" }
42
+ Helix::Config.stub(:instance) { mock_config }
43
+ end
44
+ it "should get an ingest signature" do
45
+ mock_config.should_receive(:build_url).with(media_type: :klasses,
46
+ format: :xml)
47
+ RestClient.stub(:post).with(:url, params) { resp_json }
48
+ Crack::XML.should_receive(:parse).with(resp_json) { resp_value }
49
+ klass.stub(:new).with(expected)
50
+ mock_config.should_receive(:signature).with(:update) { "some_sig" }
51
+ klass.send(meth)
52
+ end
53
+ it "should do an HTTP post call, parse response and call new" do
54
+ mock_config.should_receive(:build_url).with(media_type: :klasses,
55
+ format: :xml)
56
+ RestClient.should_receive(:post).with(:url, params) { resp_json }
57
+ Crack::XML.should_receive(:parse).with(resp_json) { resp_value }
58
+ klass.should_receive(:new).with(expected)
59
+ klass.send(meth)
60
+ end
61
+ end
62
+
63
+ describe ".find" do
64
+ let(:meth) { :find }
65
+ let(:mock_config) { mock(Helix::Config) }
66
+ let(:mock_obj) { mock(klass, :load => :output_of_load) }
67
+ subject { klass.method(meth) }
68
+ its(:arity) { should eq(1) }
69
+ before(:each) do Helix::Config.stub(:instance) { mock_config } end
70
+ context "when given a Helix::Config instance and a guid" do
71
+ let(:guid) { :a_guid }
72
+ let(:guid_name) { :the_guid_name }
73
+ let(:mock_attrs) { mock(Object, :[]= => :output_of_setting_val) }
74
+ before(:each) do
75
+ klass.stub(:attributes) { mock_attrs }
76
+ klass.stub(:guid_name) { guid_name }
77
+ klass.stub(:new) { mock_obj }
78
+ end
79
+ it "should instantiate with {attributes: guid_name => the_guid, config: config}" do
80
+ klass.should_receive(:new).with({attributes: {guid_name => guid}, config: mock_config})
81
+ klass.send(meth, guid)
82
+ end
83
+ it "should load" do
84
+ mock_obj.should_receive(:load)
85
+ klass.send(meth, guid)
86
+ end
87
+ end
88
+ end
89
+
90
+ describe ".find_all" do
91
+ let(:meth) { :find_all }
92
+ let(:mock_config) { mock(Helix::Config, build_url: :built_url, get_response: {}) }
93
+ subject { klass.method(meth) }
94
+ its(:arity) { should eq(1) }
95
+ before(:each) do Helix::Config.stub(:instance) { mock_config } end
96
+ context "when given a config instances and an opts Hash" do
97
+ let(:opts) { {opts_key1: :opts_val1} }
98
+ let(:plural_media_type) { :videos }
99
+ before(:each) do klass.stub(:plural_media_type) { plural_media_type } end
100
+ it "should build a JSON URL -> the_url" do
101
+ mock_config.should_receive(:build_url).with(format: :json)
102
+ klass.send(meth, opts)
103
+ end
104
+ it "should get_response(the_url, {sig_type: :view}.merge(opts) -> raw_response" do
105
+ mock_config.should_receive(:get_response).with(:built_url, {sig_type: :view}.merge(opts))
106
+ klass.send(meth, opts)
107
+ end
108
+ it "should read raw_response[plural_media_type] -> data_sets" do
109
+ mock_raw_response = mock(Object)
110
+ mock_config.stub(:get_response) { mock_raw_response }
111
+ mock_raw_response.should_receive(:[]).with(plural_media_type)
112
+ klass.send(meth, opts)
113
+ end
114
+ context "when data_sets is nil" do
115
+ it "should return []" do expect(klass.send(meth, opts)).to eq([]) end
116
+ end
117
+ context "when data_sets is NOT nil" do
118
+ let(:data_set) { (0..2).to_a }
119
+ before(:each) do mock_config.stub(:get_response) { {plural_media_type => data_set } } end
120
+ it "should map instantiation with attributes: each data set element" do
121
+ klass.should_receive(:new).with(attributes: data_set[0]) { :a }
122
+ klass.should_receive(:new).with(attributes: data_set[1]) { :b }
123
+ klass.should_receive(:new).with(attributes: data_set[2]) { :c }
124
+ expect(klass.send(meth, opts)).to eq([:a, :b, :c])
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ describe "an instance" do
131
+ let(:obj) { klass.new({}) }
132
+
133
+ ### INSTANCE METHODS
134
+
135
+ describe "#destroy" do
136
+ let(:meth) { :destroy }
137
+ let(:mock_config) { mock(Helix::Config, build_url: :the_built_url, signature: :some_sig) }
138
+ subject { obj.method(meth) }
139
+ let(:params) { { params: {signature: :some_sig } } }
140
+ before do
141
+ obj.stub(:config) { mock_config }
142
+ obj.stub(:guid) { :some_guid }
143
+ obj.stub(:plural_media_type) { :media_type }
144
+ end
145
+ it "should get an update signature" do
146
+ url = mock_config.build_url(media_type: :media_type,
147
+ guid: :some_guid,
148
+ format: :xml)
149
+ RestClient.stub(:delete).with(url, params)
150
+ mock_config.should_receive(:signature).with(:update) { :some_sig }
151
+ obj.send(meth)
152
+ end
153
+ it "should call for an HTTP delete and return nil" do
154
+ url = mock_config.build_url(media_type: :media_type,
155
+ guid: :some_guid,
156
+ format: :xml)
157
+ RestClient.should_receive(:delete).with(url, params)
158
+ expect(obj.send(meth)).to be_nil
159
+ end
160
+ end
161
+
162
+ describe "#guid" do
163
+ let(:meth) { :guid }
164
+ it "should return @attributes[guid_name]" do
165
+ mock_attributes = mock(Object)
166
+ obj.instance_variable_set(:@attributes, mock_attributes)
167
+ obj.should_receive(:guid_name) { :the_guid_name }
168
+ mock_attributes.should_receive(:[]).with(:the_guid_name) { :expected }
169
+ expect(obj.send(meth)).to eq(:expected)
170
+ end
171
+ end
172
+
173
+ describe "#guid_name" do
174
+ let(:meth) { :guid_name }
175
+ it "should delegate to the class" do
176
+ klass.should_receive(meth) { :expected }
177
+ expect(obj.send(meth)).to be(:expected)
178
+ end
179
+ end
180
+
181
+ describe "#load" do
182
+ let(:meth) { :load }
183
+ let(:mock_config) { mock(Helix::Config) }
184
+ subject { obj.method(meth) }
185
+ its(:arity) { should eq(-1) }
186
+ before(:each) do
187
+ obj.stub(:config) { mock_config }
188
+ obj.stub(:guid) { 'some_guid' }
189
+ obj.stub(:signature) { 'some_sig' }
190
+ obj.stub(:massage_raw_attrs) { :massaged_attrs }
191
+ mock_config.stub(:build_url) { :expected_url }
192
+ mock_config.stub(:get_response) { :raw_attrs }
193
+ klass.stub(:media_type_sym) { :video }
194
+ end
195
+ shared_examples_for "builds URL for load" do
196
+ it "should call #guid" do
197
+ obj.should_receive(:guid) { 'some_guid' }
198
+ obj.send(meth)
199
+ end
200
+ it "should build_url(format: :json, guid: the_guid, media_type: 'videos')" do
201
+ mock_config.should_receive(:build_url).with(format: :json, guid: 'some_guid', media_type: 'videos')
202
+ RestClient.stub(:put)
203
+ obj.send(meth)
204
+ end
205
+ end
206
+ context "when given no argument" do
207
+ it_behaves_like "builds URL for load"
208
+ it "should call klass.get_response(output_of_build_url, {sig_type: :view}) and return instance of klass" do
209
+ mock_config.should_receive(:get_response).with(:expected_url, {sig_type: :view})
210
+ expect(obj.send(meth)).to be_an_instance_of(klass)
211
+ end
212
+ it "should massage the raw_attrs" do
213
+ obj.should_receive(:massage_raw_attrs).with(:raw_attrs)
214
+ obj.send(meth)
215
+ end
216
+ end
217
+ context "when given an opts argument of {key1: :value1}" do
218
+ let(:opts) { {key1: :value1} }
219
+ it_behaves_like "builds URL for load"
220
+ it "should call klass.get_response(output_of_build_url, opts.merge(sig_type: :view)) and return instance of klass" do
221
+ mock_config.should_receive(:get_response).with(:expected_url, opts.merge(sig_type: :view))
222
+ expect(obj.send(meth, opts)).to be_an_instance_of(klass)
223
+ end
224
+ it "should massage the raw_attrs" do
225
+ obj.should_receive(:massage_raw_attrs).with(:raw_attrs)
226
+ obj.send(meth, opts)
227
+ end
228
+ end
229
+ end
230
+
231
+ describe "#massage_raw_attrs" do
232
+ let(:meth) { :massage_raw_attrs }
233
+ let(:guid_name) { :the_guid_name }
234
+
235
+ subject { obj.method(meth) }
236
+ its(:arity) { should eq(1) }
237
+
238
+ before(:each) { obj.stub(:guid_name) { guid_name } }
239
+ context "when given {}" do
240
+ let(:raw_attrs) { {} }
241
+ subject { obj.send(meth, raw_attrs) }
242
+ it { should eq(nil) }
243
+ end
244
+ context "when given { guid_name => :the_val }" do
245
+ let(:raw_attrs) { { guid_name => :the_val } }
246
+ subject { obj.send(meth, raw_attrs) }
247
+ it { should eq(raw_attrs) }
248
+ end
249
+ context "when given [{ guid_name => :the_val }]" do
250
+ let(:raw_attrs) { [{ guid_name => :the_val }] }
251
+ subject { obj.send(meth, raw_attrs) }
252
+ it { should eq(raw_attrs.first) }
253
+ end
254
+ end
255
+
256
+ describe "#method_missing" do
257
+ let(:meth) { :method_missing }
258
+ subject { obj.method(meth) }
259
+ its(:arity) { should eq(1) }
260
+ context "when given method_sym" do
261
+ let(:method_sym) { :method_sym }
262
+ let(:mock_attributes) { mock(Object) }
263
+ before(:each) do obj.instance_variable_set(:@attributes, mock_attributes) end
264
+ context "and @attributes[method_sym.to_s] raises an exception" do
265
+ before(:each) do mock_attributes.should_receive(:[]).with(method_sym.to_s).and_raise("some exception") end
266
+ it "should raise a NoMethodError" do
267
+ msg = "#{method_sym} is not recognized within #{klass}'s @attributes"
268
+ expect(lambda { obj.send(meth, method_sym) }).to raise_error(msg)
269
+ end
270
+ end
271
+ context "and @attributes[method_sym.to_s] does NOT raise an exception" do
272
+ before(:each) do mock_attributes.should_receive(:[]).with(method_sym.to_s) { :expected } end
273
+ it "should return @attributes[method_sym.to_s]" do
274
+ expect(obj.send(meth, method_sym)).to eq(:expected)
275
+ end
276
+ end
277
+ end
278
+ end
279
+
280
+ describe "#update" do
281
+ let(:meth) { :update }
282
+ let(:mock_config) { mock(Helix::Config) }
283
+ subject { obj.method(meth) }
284
+ its(:arity) { should eq(-1) }
285
+ before(:each) do
286
+ obj.stub(:config) { mock_config }
287
+ obj.stub(:guid) { :the_guid }
288
+ obj.stub(:media_type_sym) { :video }
289
+ obj.stub(:plural_media_type) { :the_media_type }
290
+ mock_config.stub(:signature).with(:update) { 'some_sig' }
291
+ mock_config.stub(:build_url) { :expected_url }
292
+ end
293
+ shared_examples_for "builds URL for update" do
294
+ it "should build_url(format: :xml, guid: guid, media_type: plural_media_type)" do
295
+ mock_config.should_receive(:build_url).with(format: :xml, guid: :the_guid, media_type: :the_media_type)
296
+ RestClient.stub(:put)
297
+ obj.send(meth)
298
+ end
299
+ it "should get an update signature" do
300
+ mock_config.stub(:build_url)
301
+ RestClient.stub(:put)
302
+ mock_config.should_receive(:signature).with(:update) { 'some_sig' }
303
+ obj.send(meth)
304
+ end
305
+ end
306
+ context "when given no argument" do
307
+ it_behaves_like "builds URL for update"
308
+ it "should call RestClient.put(output_of_build_url, {signature: the_sig, video: {}}) and return instance of klass" do
309
+ RestClient.should_receive(:put).with(:expected_url, {signature: 'some_sig', video: {}})
310
+ expect(obj.send(meth)).to be_an_instance_of(klass)
311
+ end
312
+ end
313
+ context "when given an opts argument of {key1: :value1}" do
314
+ let(:opts) { {key1: :value1} }
315
+ it_behaves_like "builds URL for update"
316
+ it "should call RestClient.put(output_of_build_url, {signature: the_sig, video: opts}) and return instance of klass" do
317
+ RestClient.should_receive(:put).with(:expected_url, {signature: 'some_sig', video: opts})
318
+ expect(obj.send(meth, opts)).to be_an_instance_of(klass)
319
+ end
320
+ end
321
+ end
322
+
323
+ end
324
+
325
+ end