active_encode 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +26 -17
  3. data/.rubocop.yml +7 -3
  4. data/.rubocop_todo.yml +8 -1
  5. data/CONTRIBUTING.md +42 -12
  6. data/Gemfile +11 -11
  7. data/README.md +64 -10
  8. data/active_encode.gemspec +2 -4
  9. data/app/controllers/active_encode/encode_record_controller.rb +1 -1
  10. data/app/jobs/active_encode/polling_job.rb +1 -1
  11. data/app/models/active_encode/encode_record.rb +1 -1
  12. data/guides/media_convert_adapter.md +208 -0
  13. data/lib/active_encode/base.rb +1 -1
  14. data/lib/active_encode/core.rb +14 -14
  15. data/lib/active_encode/engine_adapter.rb +13 -13
  16. data/lib/active_encode/engine_adapters/elastic_transcoder_adapter.rb +158 -158
  17. data/lib/active_encode/engine_adapters/ffmpeg_adapter.rb +14 -3
  18. data/lib/active_encode/engine_adapters/matterhorn_adapter.rb +204 -202
  19. data/lib/active_encode/engine_adapters/media_convert_adapter.rb +435 -203
  20. data/lib/active_encode/engine_adapters/media_convert_output.rb +67 -5
  21. data/lib/active_encode/engine_adapters/pass_through_adapter.rb +3 -3
  22. data/lib/active_encode/engine_adapters/zencoder_adapter.rb +114 -114
  23. data/lib/active_encode/errors.rb +1 -1
  24. data/lib/active_encode/persistence.rb +19 -19
  25. data/lib/active_encode/version.rb +1 -1
  26. data/lib/file_locator.rb +6 -6
  27. data/spec/fixtures/ffmpeg/cancelled-id/exit_status.code +1 -0
  28. data/spec/fixtures/ffmpeg/completed-id/exit_status.code +1 -0
  29. data/spec/fixtures/ffmpeg/completed-with-warnings-id/error.log +3 -0
  30. data/spec/fixtures/ffmpeg/completed-with-warnings-id/exit_status.code +1 -0
  31. data/spec/fixtures/ffmpeg/completed-with-warnings-id/input_metadata +102 -0
  32. data/spec/fixtures/ffmpeg/completed-with-warnings-id/output_metadata-high +90 -0
  33. data/spec/fixtures/ffmpeg/completed-with-warnings-id/output_metadata-low +90 -0
  34. data/spec/fixtures/ffmpeg/completed-with-warnings-id/pid +1 -0
  35. data/spec/fixtures/ffmpeg/completed-with-warnings-id/progress +11 -0
  36. data/spec/fixtures/ffmpeg/completed-with-warnings-id/video-high.mp4 +0 -0
  37. data/spec/fixtures/ffmpeg/completed-with-warnings-id/video-low.mp4 +0 -0
  38. data/spec/fixtures/ffmpeg/failed-id/exit_status.code +1 -0
  39. data/spec/fixtures/media_convert/job_completed_empty_detail.json +1 -0
  40. data/spec/integration/ffmpeg_adapter_spec.rb +50 -1
  41. data/spec/integration/matterhorn_adapter_spec.rb +1 -2
  42. data/spec/integration/media_convert_adapter_spec.rb +144 -0
  43. data/spec/integration/pass_through_adapter_spec.rb +2 -2
  44. data/spec/integration/zencoder_adapter_spec.rb +3 -3
  45. data/spec/units/core_spec.rb +1 -1
  46. data/spec/units/file_locator_spec.rb +3 -3
  47. data/spec/units/status_spec.rb +1 -1
  48. metadata +52 -19
@@ -0,0 +1,90 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <MediaInfo
3
+ xmlns="https://mediaarea.net/mediainfo"
4
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
+ xsi:schemaLocation="https://mediaarea.net/mediainfo https://mediaarea.net/mediainfo/mediainfo_2_0.xsd"
6
+ version="2.0">
7
+ <creatingLibrary version="18.05" url="https://mediaarea.net/MediaInfo">MediaInfoLib</creatingLibrary>
8
+ <media ref="spec/fixtures/ffmpeg/completed-id/low.mp4">
9
+ <track type="General">
10
+ <VideoCount>1</VideoCount>
11
+ <AudioCount>1</AudioCount>
12
+ <FileExtension>mp4</FileExtension>
13
+ <Format>MPEG-4</Format>
14
+ <Format_Profile>Base Media</Format_Profile>
15
+ <CodecID>isom</CodecID>
16
+ <FileSize>125403</FileSize>
17
+ <Duration>6.336</Duration>
18
+ <OverallBitRate>158337</OverallBitRate>
19
+ <FrameRate>24.000</FrameRate>
20
+ <FrameCount>150</FrameCount>
21
+ <StreamSize>5648</StreamSize>
22
+ <HeaderSize>40</HeaderSize>
23
+ <DataSize>119763</DataSize>
24
+ <FooterSize>5600</FooterSize>
25
+ <IsStreamable>No</IsStreamable>
26
+ <File_Modified_Date>UTC 2018-09-07 17:36:26</File_Modified_Date>
27
+ <File_Modified_Date_Local>2018-09-07 13:36:26</File_Modified_Date_Local>
28
+ <Encoded_Application>Lavf58.12.100</Encoded_Application>
29
+ </track>
30
+ <track type="Video">
31
+ <StreamOrder>0</StreamOrder>
32
+ <ID>1</ID>
33
+ <Format>AVC</Format>
34
+ <Format_Profile>High</Format_Profile>
35
+ <Format_Level>1.1</Format_Level>
36
+ <Format_Settings_CABAC>Yes</Format_Settings_CABAC>
37
+ <Format_Settings_RefFrames>4</Format_Settings_RefFrames>
38
+ <CodecID>avc1</CodecID>
39
+ <Duration>6.250</Duration>
40
+ <BitRate>79302</BitRate>
41
+ <Width>200</Width>
42
+ <Height>110</Height>
43
+ <Stored_Width>208</Stored_Width>
44
+ <Stored_Height>112</Stored_Height>
45
+ <Sampled_Width>200</Sampled_Width>
46
+ <Sampled_Height>110</Sampled_Height>
47
+ <PixelAspectRatio>1.000</PixelAspectRatio>
48
+ <DisplayAspectRatio>1.818</DisplayAspectRatio>
49
+ <Rotation>0.000</Rotation>
50
+ <FrameRate_Mode>CFR</FrameRate_Mode>
51
+ <FrameRate_Mode_Original>VFR</FrameRate_Mode_Original>
52
+ <FrameRate>24.000</FrameRate>
53
+ <FrameCount>150</FrameCount>
54
+ <ColorSpace>YUV</ColorSpace>
55
+ <ChromaSubsampling>4:2:0</ChromaSubsampling>
56
+ <BitDepth>8</BitDepth>
57
+ <ScanType>Progressive</ScanType>
58
+ <StreamSize>61955</StreamSize>
59
+ <Encoded_Library>x264 - core 152 r2854 e9a5903</Encoded_Library>
60
+ <Encoded_Library_Name>x264</Encoded_Library_Name>
61
+ <Encoded_Library_Version>core 152 r2854 e9a5903</Encoded_Library_Version>
62
+ <Encoded_Library_Settings>cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=3 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=24 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00</Encoded_Library_Settings>
63
+ </track>
64
+ <track type="Audio">
65
+ <StreamOrder>1</StreamOrder>
66
+ <ID>2</ID>
67
+ <Format>AAC</Format>
68
+ <Format_Profile>LC</Format_Profile>
69
+ <Format_Settings_SBR>No (Explicit)</Format_Settings_SBR>
70
+ <CodecID>mp4a-40-2</CodecID>
71
+ <Duration>6.336</Duration>
72
+ <BitRate_Mode>CBR</BitRate_Mode>
73
+ <BitRate>72000</BitRate>
74
+ <Channels>2</Channels>
75
+ <Channels_Original>1</Channels_Original>
76
+ <ChannelPositions>Front: C</ChannelPositions>
77
+ <ChannelLayout>C</ChannelLayout>
78
+ <SamplesPerFrame>1024</SamplesPerFrame>
79
+ <SamplingRate>48000</SamplingRate>
80
+ <SamplingCount>304128</SamplingCount>
81
+ <FrameRate>46.875</FrameRate>
82
+ <FrameCount>297</FrameCount>
83
+ <Compression_Mode>Lossy</Compression_Mode>
84
+ <StreamSize>57800</StreamSize>
85
+ <StreamSize_Proportion>0.46091</StreamSize_Proportion>
86
+ <Default>Yes</Default>
87
+ <AlternateGroup>1</AlternateGroup>
88
+ </track>
89
+ </media>
90
+ </MediaInfo>
@@ -0,0 +1,90 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <MediaInfo
3
+ xmlns="https://mediaarea.net/mediainfo"
4
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
+ xsi:schemaLocation="https://mediaarea.net/mediainfo https://mediaarea.net/mediainfo/mediainfo_2_0.xsd"
6
+ version="2.0">
7
+ <creatingLibrary version="18.05" url="https://mediaarea.net/MediaInfo">MediaInfoLib</creatingLibrary>
8
+ <media ref="spec/fixtures/ffmpeg/completed-id/low.mp4">
9
+ <track type="General">
10
+ <VideoCount>1</VideoCount>
11
+ <AudioCount>1</AudioCount>
12
+ <FileExtension>mp4</FileExtension>
13
+ <Format>MPEG-4</Format>
14
+ <Format_Profile>Base Media</Format_Profile>
15
+ <CodecID>isom</CodecID>
16
+ <FileSize>125403</FileSize>
17
+ <Duration>6.336</Duration>
18
+ <OverallBitRate>158337</OverallBitRate>
19
+ <FrameRate>24.000</FrameRate>
20
+ <FrameCount>150</FrameCount>
21
+ <StreamSize>5648</StreamSize>
22
+ <HeaderSize>40</HeaderSize>
23
+ <DataSize>119763</DataSize>
24
+ <FooterSize>5600</FooterSize>
25
+ <IsStreamable>No</IsStreamable>
26
+ <File_Modified_Date>UTC 2018-09-07 17:36:26</File_Modified_Date>
27
+ <File_Modified_Date_Local>2018-09-07 13:36:26</File_Modified_Date_Local>
28
+ <Encoded_Application>Lavf58.12.100</Encoded_Application>
29
+ </track>
30
+ <track type="Video">
31
+ <StreamOrder>0</StreamOrder>
32
+ <ID>1</ID>
33
+ <Format>AVC</Format>
34
+ <Format_Profile>High</Format_Profile>
35
+ <Format_Level>1.1</Format_Level>
36
+ <Format_Settings_CABAC>Yes</Format_Settings_CABAC>
37
+ <Format_Settings_RefFrames>4</Format_Settings_RefFrames>
38
+ <CodecID>avc1</CodecID>
39
+ <Duration>6.250</Duration>
40
+ <BitRate>79302</BitRate>
41
+ <Width>200</Width>
42
+ <Height>110</Height>
43
+ <Stored_Width>208</Stored_Width>
44
+ <Stored_Height>112</Stored_Height>
45
+ <Sampled_Width>200</Sampled_Width>
46
+ <Sampled_Height>110</Sampled_Height>
47
+ <PixelAspectRatio>1.000</PixelAspectRatio>
48
+ <DisplayAspectRatio>1.818</DisplayAspectRatio>
49
+ <Rotation>0.000</Rotation>
50
+ <FrameRate_Mode>CFR</FrameRate_Mode>
51
+ <FrameRate_Mode_Original>VFR</FrameRate_Mode_Original>
52
+ <FrameRate>24.000</FrameRate>
53
+ <FrameCount>150</FrameCount>
54
+ <ColorSpace>YUV</ColorSpace>
55
+ <ChromaSubsampling>4:2:0</ChromaSubsampling>
56
+ <BitDepth>8</BitDepth>
57
+ <ScanType>Progressive</ScanType>
58
+ <StreamSize>61955</StreamSize>
59
+ <Encoded_Library>x264 - core 152 r2854 e9a5903</Encoded_Library>
60
+ <Encoded_Library_Name>x264</Encoded_Library_Name>
61
+ <Encoded_Library_Version>core 152 r2854 e9a5903</Encoded_Library_Version>
62
+ <Encoded_Library_Settings>cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=3 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=24 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00</Encoded_Library_Settings>
63
+ </track>
64
+ <track type="Audio">
65
+ <StreamOrder>1</StreamOrder>
66
+ <ID>2</ID>
67
+ <Format>AAC</Format>
68
+ <Format_Profile>LC</Format_Profile>
69
+ <Format_Settings_SBR>No (Explicit)</Format_Settings_SBR>
70
+ <CodecID>mp4a-40-2</CodecID>
71
+ <Duration>6.336</Duration>
72
+ <BitRate_Mode>CBR</BitRate_Mode>
73
+ <BitRate>72000</BitRate>
74
+ <Channels>2</Channels>
75
+ <Channels_Original>1</Channels_Original>
76
+ <ChannelPositions>Front: C</ChannelPositions>
77
+ <ChannelLayout>C</ChannelLayout>
78
+ <SamplesPerFrame>1024</SamplesPerFrame>
79
+ <SamplingRate>48000</SamplingRate>
80
+ <SamplingCount>304128</SamplingCount>
81
+ <FrameRate>46.875</FrameRate>
82
+ <FrameCount>297</FrameCount>
83
+ <Compression_Mode>Lossy</Compression_Mode>
84
+ <StreamSize>57800</StreamSize>
85
+ <StreamSize_Proportion>0.46091</StreamSize_Proportion>
86
+ <Default>Yes</Default>
87
+ <AlternateGroup>1</AlternateGroup>
88
+ </track>
89
+ </media>
90
+ </MediaInfo>
@@ -0,0 +1,11 @@
1
+ frame=150
2
+ fps=0.0
3
+ stream_0_0_q=-1.0
4
+ bitrate= 158.9kbits/s
5
+ total_size=125403
6
+ out_time_ms=6314667
7
+ out_time=00:00:06.314667
8
+ dup_frames=1
9
+ drop_frames=0
10
+ speed=43.1x
11
+ progress=end
@@ -0,0 +1 @@
1
+ {"results":[],"statistics":{"records_matched":1.0,"records_scanned":13.0,"bytes_scanned":10750.0},"status":"Complete"}
@@ -37,6 +37,7 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
37
37
  encode
38
38
  end
39
39
  let(:completed_job) { find_encode "completed-id" }
40
+ let(:completed_with_warnings_job) { find_encode "completed-with-warnings-id" }
40
41
  let(:failed_job) { find_encode 'failed-id' }
41
42
  let(:completed_tech_metadata) do
42
43
  {
@@ -129,7 +130,7 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
129
130
  end
130
131
 
131
132
  context 'when uri encoded' do
132
- let(:file_with_space) { URI.encode("file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.mp4').to_s) }
133
+ let(:file_with_space) { Addressable::URI.encode("file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.mp4').to_s) }
133
134
 
134
135
  it "does not have errors" do
135
136
  sleep 2
@@ -164,6 +165,54 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
164
165
  it "has a progress file" do
165
166
  expect(File).to exist("#{work_dir}/#{subject.id}/progress")
166
167
  end
168
+
169
+ it "does not have an exit code file" do
170
+ expect(File).not_to exist("#{work_dir}/#{subject.id}/exit_status.code")
171
+ end
172
+
173
+ context "completed job" do
174
+ subject { completed_job }
175
+
176
+ it { is_expected.to be_completed }
177
+ it "has an exit code of 0" do
178
+ expect(File).to exist("#{work_dir}/#{subject.id}/exit_status.code")
179
+ expect(File.read("#{work_dir}/#{subject.id}/exit_status.code").to_i).to eq 0
180
+ end
181
+ end
182
+
183
+ context "completed with warnings job" do
184
+ subject { completed_with_warnings_job }
185
+
186
+ it { is_expected.to be_completed }
187
+ it "has an exit code of 0" do
188
+ expect(File).to exist("#{work_dir}/#{subject.id}/exit_status.code")
189
+ expect(File.read("#{work_dir}/#{subject.id}/exit_status.code").to_i).to eq 0
190
+ end
191
+ it "has warnings in the error log" do
192
+ expect(File).to exist("#{work_dir}/#{subject.id}/error.log")
193
+ expect(File.read("#{work_dir}/#{subject.id}/error.log")).not_to be_empty
194
+ end
195
+ end
196
+
197
+ context "cancelled job" do
198
+ subject { canceled_job }
199
+
200
+ it { is_expected.to be_cancelled }
201
+ it "has an exit code of 143" do
202
+ expect(File).to exist("#{work_dir}/#{subject.id}/exit_status.code")
203
+ expect(File.read("#{work_dir}/#{subject.id}/exit_status.code").to_i).to eq 143
204
+ end
205
+ end
206
+
207
+ context "failed job" do
208
+ subject { failed_job }
209
+
210
+ it { is_expected.to be_failed }
211
+ it "has an exit code of -22" do
212
+ expect(File).to exist("#{work_dir}/#{subject.id}/exit_status.code")
213
+ expect(File.read("#{work_dir}/#{subject.id}/exit_status.code").to_i).to eq(-22)
214
+ end
215
+ end
167
216
  end
168
217
 
169
218
  describe "#cancel!" do
@@ -102,12 +102,11 @@ describe ActiveEncode::EngineAdapters::MatterhornAdapter do
102
102
  end
103
103
 
104
104
  describe "reload" do
105
+ subject { running_job.reload }
105
106
  before do
106
107
  expect(Rubyhorn.client).to receive(:instance_xml).twice.with('running-id').and_return(Rubyhorn::Workflow.from_xml(File.open('spec/fixtures/matterhorn/running_response.xml')))
107
108
  end
108
109
 
109
- subject { running_job.reload }
110
-
111
110
  it { expect(subject.output).to be_empty }
112
111
  it { expect(subject.options).to include(preset: 'full') }
113
112
  it { expect(subject.current_operations).to include("Hold for workflow selection") }
@@ -87,6 +87,16 @@ describe ActiveEncode::EngineAdapters::MediaConvertAdapter do
87
87
  ActiveEncode::Base.find(job_id)
88
88
  end
89
89
 
90
+ let(:recent_completed_job_without_results) do
91
+ job_response = reconstitute_response("media_convert/job_completed.json")
92
+ job_response["job"]["timing"]["finish_time"] = 5.minutes.ago
93
+ mediaconvert.stub_responses(:get_job, job_response)
94
+ cloudwatch_logs.stub_responses(:start_query, reconstitute_response("media_convert/job_completed_detail_query.json"))
95
+ cloudwatch_logs.stub_responses(:get_query_results, reconstitute_response("media_convert/job_completed_empty_detail.json"))
96
+
97
+ ActiveEncode::Base.find(job_id)
98
+ end
99
+
90
100
  let(:failed_job) do
91
101
  mediaconvert.stub_responses(:get_job, reconstitute_response("media_convert/job_failed.json"))
92
102
 
@@ -113,6 +123,102 @@ describe ActiveEncode::EngineAdapters::MediaConvertAdapter do
113
123
 
114
124
  it_behaves_like "an ActiveEncode::EngineAdapter"
115
125
 
126
+ describe "output location specification" do
127
+ let(:operations) { mediaconvert.api_requests(exclude_presign: true) }
128
+ before do
129
+ mediaconvert.stub_responses(:create_job, reconstitute_response("media_convert/job_created.json"))
130
+ end
131
+
132
+ it "can use output_bucket and output_prefix" do
133
+ ActiveEncode::Base.create(
134
+ "s3://input-bucket/test_files/source_file.mp4",
135
+ output_prefix: "active-encode-test/output",
136
+ outputs: [],
137
+ use_original_url: true
138
+ )
139
+ create_job_operation = operations.find { |o| o[:operation_name] == :create_job }
140
+ expect(create_job_operation).to be_present
141
+
142
+ destination = create_job_operation.dig(:params, :settings, :output_groups, 0,
143
+ :output_group_settings, :hls_group_settings, :destination)
144
+
145
+ expect(destination).to eq("s3://output-bucket/active-encode-test/output")
146
+ end
147
+
148
+ it "can use destination arg" do
149
+ ActiveEncode::Base.create(
150
+ "s3://input-bucket/test_files/source_file.mp4",
151
+ destination: "s3://alternate-output-bucket/my-path/output",
152
+ outputs: [],
153
+ use_original_url: true
154
+ )
155
+ create_job_operation = operations.find { |o| o[:operation_name] == :create_job }
156
+ expect(create_job_operation).to be_present
157
+
158
+ destination = create_job_operation.dig(:params, :settings, :output_groups, 0,
159
+ :output_group_settings, :hls_group_settings, :destination)
160
+
161
+ expect(destination).to eq("s3://alternate-output-bucket/my-path/output")
162
+ end
163
+ end
164
+
165
+ describe "output_group_destination_settings" do
166
+ let(:operations) { mediaconvert.api_requests(exclude_presign: true) }
167
+ before do
168
+ mediaconvert.stub_responses(:create_job, reconstitute_response("media_convert/job_created.json"))
169
+ end
170
+
171
+ it "are sent to MediaConvert" do
172
+ ActiveEncode::Base.create(
173
+ "s3://input-bucket/test_files/source_file.mp4",
174
+ destination: "s3://alternate-output-bucket/my-path/output",
175
+ outputs: [],
176
+ use_original_url: true,
177
+ output_group_destination_settings: {
178
+ s3_settings: {
179
+ access_control: {
180
+ canned_acl: "PUBLIC_READ"
181
+ }
182
+ }
183
+ }
184
+ )
185
+
186
+ create_job_operation = operations.find { |o| o[:operation_name] == :create_job }
187
+ expect(create_job_operation).to be_present
188
+
189
+ destination_settings = create_job_operation.dig(:params, :settings, :output_groups, 0,
190
+ :output_group_settings, :hls_group_settings, :destination_settings)
191
+ expect(destination_settings).to eq({ s3_settings: { access_control: { canned_acl: "PUBLIC_READ" } } })
192
+ end
193
+ end
194
+
195
+ describe "queue" do
196
+ let(:operations) { mediaconvert.api_requests(exclude_presign: true) }
197
+
198
+ it "uses the default queue" do
199
+ mediaconvert.stub_responses(:create_job, reconstitute_response("media_convert/job_created.json"))
200
+ ActiveEncode::Base.create(
201
+ "s3://input-bucket/test_files/source_file.mp4",
202
+ output_prefix: "active-encode-test/output",
203
+ outputs: [],
204
+ use_original_url: true
205
+ )
206
+ expect(operations).to include(include(operation_name: :create_job, params: include(queue: 'Default')))
207
+ end
208
+
209
+ it "uses a specific queue" do
210
+ mediaconvert.stub_responses(:create_job, reconstitute_response("media_convert/job_created.json"))
211
+ ActiveEncode::Base.engine_adapter.queue = 'test-queue'
212
+ ActiveEncode::Base.create(
213
+ "s3://input-bucket/test_files/source_file.mp4",
214
+ output_prefix: "active-encode-test/output",
215
+ outputs: [],
216
+ use_original_url: true
217
+ )
218
+ expect(operations).to include(include(operation_name: :create_job, params: include(queue: 'test-queue')))
219
+ end
220
+ end
221
+
116
222
  describe "output" do
117
223
  it "contains all expected outputs" do
118
224
  completed_output.each do |expected_output|
@@ -122,5 +228,43 @@ describe ActiveEncode::EngineAdapters::MediaConvertAdapter do
122
228
  end
123
229
  end
124
230
  end
231
+
232
+ it "has no logging entries but finished within the last 10 minutes" do
233
+ expect(recent_completed_job_without_results.state).to eq(:running)
234
+ end
235
+
236
+ it "finished more than 10 minutes ago but has no logging entries" do
237
+ mediaconvert.stub_responses(:get_job, reconstitute_response("media_convert/job_completed.json"))
238
+ cloudwatch_logs.stub_responses(:start_query, reconstitute_response("media_convert/job_completed_detail_query.json"))
239
+ cloudwatch_logs.stub_responses(:get_query_results, reconstitute_response("media_convert/job_completed_empty_detail.json"))
240
+
241
+ expect { ActiveEncode::Base.find(job_id) }.to raise_error do |error|
242
+ expect(error).to be_a(ActiveEncode::EngineAdapters::MediaConvertAdapter::ResultsNotAvailable)
243
+ expect(error.encode).to be_a(ActiveEncode::Base)
244
+ expect(error.encode.state).to eq(:completed)
245
+ end
246
+ end
247
+ end
248
+
249
+ describe "direct_output_lookup" do
250
+ before do
251
+ ActiveEncode::Base.engine_adapter.direct_output_lookup = true
252
+ end
253
+
254
+ it "contains all expected outputs" do
255
+ completed_output.each do |expected_output|
256
+ found_output = completed_job.output.find { |output| output.id == expected_output[:id] }
257
+ expected_output.each_pair do |key, value|
258
+ expect(found_output.send(key)).to eq(value)
259
+ end
260
+ end
261
+ end
262
+
263
+ it "does not make cloudwatch queries" do
264
+ expect(cloudwatch_logs).not_to receive(:start_query)
265
+ expect(cloudwatch_logs).not_to receive(:get_query_results)
266
+
267
+ completed_job
268
+ end
125
269
  end
126
270
  end
@@ -124,8 +124,8 @@ describe ActiveEncode::EngineAdapters::PassThroughAdapter do
124
124
  end
125
125
 
126
126
  context 'when uri encoded' do
127
- let(:file_with_space) { URI.encode("file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.mp4').to_s) }
128
- let(:file_with_space_derivative) { URI.encode("file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.low.mp4').to_s) }
127
+ let(:file_with_space) { Addressable::URI.encode("file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.mp4').to_s) }
128
+ let(:file_with_space_derivative) { Addressable::URI.encode("file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.low.mp4').to_s) }
129
129
 
130
130
  it "does not have errors" do
131
131
  expect(find_space_job.errors).to be_empty
@@ -20,12 +20,12 @@ describe ActiveEncode::EngineAdapters::ZencoderAdapter do
20
20
  let(:file) { "file://#{File.absolute_path('spec/fixtures/Bars_512kb.mp4')}" }
21
21
 
22
22
  describe "#create" do
23
+ subject { ActiveEncode::Base.create(file) }
23
24
  before do
24
25
  allow(Zencoder::Job).to receive(:details).and_return(details_response)
25
26
  allow(Zencoder::Job).to receive(:progress).and_return(progress_response)
26
27
  end
27
28
 
28
- subject { ActiveEncode::Base.create(file) }
29
29
  let(:details_response) { Zencoder::Response.new(body: JSON.parse(File.read('spec/fixtures/zencoder/job_details_create.json'))) }
30
30
  let(:progress_response) { Zencoder::Response.new(body: JSON.parse(File.read('spec/fixtures/zencoder/job_progress_create.json'))) }
31
31
  let(:create_output) { [{ id: "511404522", url: "https://zencoder-temp-storage-us-east-1.s3.amazonaws.com/o/20150610/c09b61e4d130ddf923f0653418a80b9c/399ae101c3f99b4f318635e78a4e587a.mp4?AWSAccessKeyId=AKIAI456JQ76GBU7FECA&Signature=GY/9LMkQAiDOrMQwS5BkmOE200s%3D&Expires=1434033527", label: nil }] }
@@ -302,13 +302,13 @@ describe ActiveEncode::EngineAdapters::ZencoderAdapter do
302
302
  end
303
303
 
304
304
  describe "#cancel!" do
305
+ subject { encode.cancel! }
305
306
  before do
306
307
  allow(Zencoder::Job).to receive(:cancel).and_return(cancel_response)
307
308
  allow(Zencoder::Job).to receive(:details).and_return(details_response)
308
309
  allow(Zencoder::Job).to receive(:progress).and_return(progress_response)
309
310
  end
310
311
 
311
- subject { encode.cancel! }
312
312
  let(:cancel_response) { Zencoder::Response.new(code: 200) } # TODO: check that this is the correct response code for a successful cancel
313
313
  let(:details_response) { Zencoder::Response.new(body: JSON.parse(File.read('spec/fixtures/zencoder/job_details_cancelled.json'))) }
314
314
  let(:progress_response) { Zencoder::Response.new(body: JSON.parse(File.read('spec/fixtures/zencoder/job_progress_cancelled.json'))) }
@@ -320,12 +320,12 @@ describe ActiveEncode::EngineAdapters::ZencoderAdapter do
320
320
  end
321
321
 
322
322
  describe "reload" do
323
+ subject { ActiveEncode::Base.find('166019107').reload }
323
324
  before do
324
325
  allow(Zencoder::Job).to receive(:details).and_return(details_response)
325
326
  allow(Zencoder::Job).to receive(:progress).and_return(progress_response)
326
327
  end
327
328
 
328
- subject { ActiveEncode::Base.find('166019107').reload }
329
329
  let(:details_response) { Zencoder::Response.new(body: JSON.parse(File.read('spec/fixtures/zencoder/job_details_running.json'))) }
330
330
  let(:progress_response) { Zencoder::Response.new(body: JSON.parse(File.read('spec/fixtures/zencoder/job_progress_running.json'))) }
331
331
  # let(:reload_output) { [{ id: "510582971", url: "https://zencoder-temp-storage-us-east-1.s3.amazonaws.com/o/20150609/48a6907086c012f68b9ca43461280515/1726d7ec3e24f2171bd07b2abb807b6c.mp4?AWSAccessKeyId=AKIAI456JQ76GBU7FECA&Signature=vSvlxU94wlQLEbpG3Zs8ibp4MoY%3D&Expires=1433953106", label: nil }] }
@@ -128,6 +128,7 @@ describe ActiveEncode::Core do
128
128
  end
129
129
 
130
130
  describe '#new' do
131
+ subject { encode.options }
131
132
  before do
132
133
  class DefaultOptionsEncode < ActiveEncode::Base
133
134
  def self.default_options(_input_url)
@@ -139,7 +140,6 @@ describe ActiveEncode::Core do
139
140
  Object.send(:remove_const, :DefaultOptionsEncode)
140
141
  end
141
142
 
142
- subject { encode.options }
143
143
  let(:encode_class) { DefaultOptionsEncode }
144
144
  let(:default_options) { { preset: 'video' } }
145
145
  let(:options) { { output: [{ label: 'high', ffmpeg_opt: "640x480" }] } }
@@ -41,7 +41,7 @@ describe FileLocator, type: :service do
41
41
  describe "Local file" do
42
42
  let(:path) { "/path/to/file.mp4" }
43
43
  let(:source) { "file://#{path}" }
44
- let(:locator) { FileLocator.new(source) }
44
+ let(:locator) { described_class.new(source) }
45
45
 
46
46
  it "returns the correct uri" do
47
47
  expect(locator.uri).to eq Addressable::URI.parse(source)
@@ -76,7 +76,7 @@ describe FileLocator, type: :service do
76
76
  let(:bucket) { "mybucket" }
77
77
  let(:key) { "mykey.mp4" }
78
78
  let(:source) { "s3://#{bucket}/#{key}" }
79
- let(:locator) { FileLocator.new(source) }
79
+ let(:locator) { described_class.new(source) }
80
80
 
81
81
  it "returns the correct uri" do
82
82
  expect(locator.uri).to eq Addressable::URI.parse(source)
@@ -102,7 +102,7 @@ describe FileLocator, type: :service do
102
102
  describe "Other file" do
103
103
  let(:path) { "/path/to/file.mp4" }
104
104
  let(:source) { "bogus://#{path}" }
105
- let(:locator) { FileLocator.new(source) }
105
+ let(:locator) { described_class.new(source) }
106
106
 
107
107
  it "returns the correct uri" do
108
108
  expect(locator.uri).to eq Addressable::URI.parse(source)
@@ -2,6 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe ActiveEncode::Status do
5
+ subject { encode_class.new(nil) }
5
6
  before do
6
7
  class CustomEncode < ActiveEncode::Base
7
8
  end
@@ -10,7 +11,6 @@ describe ActiveEncode::Status do
10
11
  Object.send(:remove_const, :CustomEncode)
11
12
  end
12
13
 
13
- subject { encode_class.new(nil) }
14
14
  let(:encode_class) { ActiveEncode::Base }
15
15
 
16
16
  describe 'attributes' do