active_encode 0.4.1 → 0.8.0

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 (93) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +80 -0
  3. data/.rubocop.yml +9 -70
  4. data/.rubocop_todo.yml +68 -0
  5. data/CODE_OF_CONDUCT.md +36 -0
  6. data/CONTRIBUTING.md +23 -21
  7. data/Gemfile +5 -4
  8. data/LICENSE +11 -199
  9. data/README.md +135 -24
  10. data/SUPPORT.md +5 -0
  11. data/active_encode.gemspec +13 -3
  12. data/app/controllers/active_encode/encode_record_controller.rb +13 -0
  13. data/app/jobs/active_encode/polling_job.rb +1 -1
  14. data/app/models/active_encode/encode_record.rb +1 -0
  15. data/config/routes.rb +4 -0
  16. data/db/migrate/20180822021048_create_active_encode_encode_records.rb +1 -0
  17. data/db/migrate/20190702153755_add_create_options_to_active_encode_encode_records.rb +6 -0
  18. data/db/migrate/20190712174821_add_progress_to_active_encode_encode_records.rb +6 -0
  19. data/lib/active_encode.rb +1 -0
  20. data/lib/active_encode/base.rb +2 -2
  21. data/lib/active_encode/callbacks.rb +1 -0
  22. data/lib/active_encode/core.rb +4 -3
  23. data/lib/active_encode/engine.rb +1 -0
  24. data/lib/active_encode/engine_adapter.rb +1 -0
  25. data/lib/active_encode/engine_adapters.rb +4 -1
  26. data/lib/active_encode/engine_adapters/elastic_transcoder_adapter.rb +116 -38
  27. data/lib/active_encode/engine_adapters/ffmpeg_adapter.rb +141 -87
  28. data/lib/active_encode/engine_adapters/matterhorn_adapter.rb +5 -4
  29. data/lib/active_encode/engine_adapters/media_convert_adapter.rb +372 -0
  30. data/lib/active_encode/engine_adapters/media_convert_output.rb +104 -0
  31. data/lib/active_encode/engine_adapters/pass_through_adapter.rb +239 -0
  32. data/lib/active_encode/engine_adapters/test_adapter.rb +5 -4
  33. data/lib/active_encode/engine_adapters/zencoder_adapter.rb +3 -2
  34. data/lib/active_encode/errors.rb +6 -0
  35. data/lib/active_encode/global_id.rb +2 -1
  36. data/lib/active_encode/input.rb +3 -2
  37. data/lib/active_encode/output.rb +3 -2
  38. data/lib/active_encode/persistence.rb +11 -5
  39. data/lib/active_encode/polling.rb +3 -2
  40. data/lib/active_encode/spec/shared_specs.rb +2 -0
  41. data/{spec/shared_specs/engine_adapter_specs.rb → lib/active_encode/spec/shared_specs/engine_adapter.rb} +37 -38
  42. data/lib/active_encode/status.rb +1 -0
  43. data/lib/active_encode/technical_metadata.rb +3 -2
  44. data/lib/active_encode/version.rb +2 -1
  45. data/lib/file_locator.rb +93 -0
  46. data/spec/controllers/encode_record_controller_spec.rb +53 -0
  47. data/spec/fixtures/ffmpeg/cancelled-id/cancelled +0 -0
  48. data/spec/fixtures/file with space.low.mp4 +0 -0
  49. data/spec/fixtures/file with space.mp4 +0 -0
  50. data/spec/fixtures/fireworks.low.mp4 +0 -0
  51. data/spec/fixtures/media_convert/endpoints.json +1 -0
  52. data/spec/fixtures/media_convert/job_canceled.json +412 -0
  53. data/spec/fixtures/media_convert/job_canceling.json +1 -0
  54. data/spec/fixtures/media_convert/job_completed.json +359 -0
  55. data/spec/fixtures/media_convert/job_completed_detail.json +1 -0
  56. data/spec/fixtures/media_convert/job_completed_detail_query.json +1 -0
  57. data/spec/fixtures/media_convert/job_created.json +408 -0
  58. data/spec/fixtures/media_convert/job_failed.json +406 -0
  59. data/spec/fixtures/media_convert/job_progressing.json +414 -0
  60. data/spec/fixtures/pass_through/cancelled-id/cancelled +0 -0
  61. data/spec/fixtures/pass_through/cancelled-id/input_metadata +90 -0
  62. data/spec/fixtures/pass_through/completed-id/completed +0 -0
  63. data/spec/fixtures/pass_through/completed-id/input_metadata +102 -0
  64. data/spec/fixtures/pass_through/completed-id/output_metadata-high +90 -0
  65. data/spec/fixtures/pass_through/completed-id/output_metadata-low +90 -0
  66. data/spec/fixtures/pass_through/completed-id/video-high.mp4 +0 -0
  67. data/spec/fixtures/pass_through/completed-id/video-low.mp4 +0 -0
  68. data/spec/fixtures/pass_through/failed-id/error.log +1 -0
  69. data/spec/fixtures/pass_through/failed-id/input_metadata +90 -0
  70. data/spec/fixtures/pass_through/running-id/input_metadata +90 -0
  71. data/spec/integration/elastic_transcoder_adapter_spec.rb +63 -29
  72. data/spec/integration/ffmpeg_adapter_spec.rb +96 -24
  73. data/spec/integration/matterhorn_adapter_spec.rb +45 -44
  74. data/spec/integration/media_convert_adapter_spec.rb +126 -0
  75. data/spec/integration/pass_through_adapter_spec.rb +151 -0
  76. data/spec/integration/zencoder_adapter_spec.rb +210 -209
  77. data/spec/rails_helper.rb +1 -0
  78. data/spec/routing/encode_record_controller_routing_spec.rb +10 -0
  79. data/spec/spec_helper.rb +2 -2
  80. data/spec/test_app_templates/lib/generators/test_app_generator.rb +13 -12
  81. data/spec/units/callbacks_spec.rb +3 -2
  82. data/spec/units/core_spec.rb +26 -25
  83. data/spec/units/engine_adapter_spec.rb +1 -0
  84. data/spec/units/file_locator_spec.rb +129 -0
  85. data/spec/units/global_id_spec.rb +12 -11
  86. data/spec/units/input_spec.rb +8 -5
  87. data/spec/units/output_spec.rb +8 -5
  88. data/spec/units/persistence_spec.rb +15 -11
  89. data/spec/units/polling_job_spec.rb +7 -6
  90. data/spec/units/polling_spec.rb +1 -0
  91. data/spec/units/status_spec.rb +3 -3
  92. metadata +184 -18
  93. data/.travis.yml +0 -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="file:///Bars_512kb.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>24876</FileSize>
17
+ <Duration>4.928</Duration>
18
+ <OverallBitRate_Mode>VBR</OverallBitRate_Mode>
19
+ <OverallBitRate>40383</OverallBitRate>
20
+ <FrameRate>1.000</FrameRate>
21
+ <FrameCount>1</FrameCount>
22
+ <StreamSize>3216</StreamSize>
23
+ <HeaderSize>3208</HeaderSize>
24
+ <DataSize>21668</DataSize>
25
+ <FooterSize>0</FooterSize>
26
+ <IsStreamable>Yes</IsStreamable>
27
+ <Title>Bars - http://www.archive.org/details/ColorBarsWTone</Title>
28
+ <Movie>Bars - http://www.archive.org/details/ColorBarsWTone</Movie>
29
+ <Recorded_Date>2008</Recorded_Date>
30
+ <Encoded_Date>UTC 1970-01-01 00:00:00</Encoded_Date>
31
+ <Tagged_Date>UTC 2008-11-23 18:44:25</Tagged_Date>
32
+ <Encoded_Application>Lavf51.10.0</Encoded_Application>
33
+ <Comment>license: http://creativecommons.org/licenses/publicdomain/</Comment>
34
+ </track>
35
+ <track type="Video">
36
+ <StreamOrder>0</StreamOrder>
37
+ <ID>1</ID>
38
+ <Format>AVC</Format>
39
+ <Format_Profile>Baseline</Format_Profile>
40
+ <Format_Level>1.3</Format_Level>
41
+ <Format_Settings_CABAC>No</Format_Settings_CABAC>
42
+ <Format_Settings_RefFrames>1</Format_Settings_RefFrames>
43
+ <CodecID>avc1</CodecID>
44
+ <Duration>1.000</Duration>
45
+ <BitRate>18504</BitRate>
46
+ <Width>360</Width>
47
+ <Height>240</Height>
48
+ <Stored_Width>368</Stored_Width>
49
+ <Sampled_Width>360</Sampled_Width>
50
+ <Sampled_Height>240</Sampled_Height>
51
+ <PixelAspectRatio>1.000</PixelAspectRatio>
52
+ <DisplayAspectRatio>1.500</DisplayAspectRatio>
53
+ <Rotation>0.000</Rotation>
54
+ <FrameRate_Mode>CFR</FrameRate_Mode>
55
+ <FrameRate>1.000</FrameRate>
56
+ <FrameRate_Original>0.200</FrameRate_Original>
57
+ <FrameCount>1</FrameCount>
58
+ <ColorSpace>YUV</ColorSpace>
59
+ <ChromaSubsampling>4:2:0</ChromaSubsampling>
60
+ <BitDepth>8</BitDepth>
61
+ <ScanType>Progressive</ScanType>
62
+ <StreamSize>2313</StreamSize>
63
+ <Encoded_Date>UTC 1970-01-01 00:00:00</Encoded_Date>
64
+ <Tagged_Date>UTC 1970-01-01 00:00:00</Tagged_Date>
65
+ </track>
66
+ <track type="Audio">
67
+ <StreamOrder>1</StreamOrder>
68
+ <ID>2</ID>
69
+ <Format>AAC</Format>
70
+ <Format_Profile>LC</Format_Profile>
71
+ <CodecID>mp4a-40-2</CodecID>
72
+ <Duration>4.928</Duration>
73
+ <BitRate_Mode>VBR</BitRate_Mode>
74
+ <BitRate>31407</BitRate>
75
+ <Channels>2</Channels>
76
+ <ChannelPositions>Front: L R</ChannelPositions>
77
+ <ChannelLayout>L R</ChannelLayout>
78
+ <SamplesPerFrame>1024</SamplesPerFrame>
79
+ <SamplingRate>48000</SamplingRate>
80
+ <SamplingCount>236544</SamplingCount>
81
+ <FrameRate>46.875</FrameRate>
82
+ <FrameCount>231</FrameCount>
83
+ <Compression_Mode>Lossy</Compression_Mode>
84
+ <StreamSize>19347</StreamSize>
85
+ <StreamSize_Proportion>0.77774</StreamSize_Proportion>
86
+ <Encoded_Date>UTC 1970-01-01 00:00:00</Encoded_Date>
87
+ <Tagged_Date>UTC 1970-01-01 00:00:00</Tagged_Date>
88
+ </track>
89
+ </media>
90
+ </MediaInfo>
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
- require 'aws-sdk'
3
+ require 'aws-sdk-elastictranscoder'
3
4
  require 'json'
4
- require 'shared_specs/engine_adapter_specs'
5
+ require 'active_encode/spec/shared_specs'
5
6
 
6
7
  describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
7
- around(:example) do |example|
8
+ around do |example|
8
9
  # Setting this before each test works around a stubbing + memoization limitation
9
10
  ActiveEncode::Base.engine_adapter = :elastic_transcoder
10
11
  example.run
@@ -12,33 +13,37 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
12
13
  end
13
14
 
14
15
  let(:client) { Aws::ElasticTranscoder::Client.new(stub_responses: true) }
16
+ let(:s3client) { Aws::S3::Client.new(stub_responses: true) }
15
17
 
16
18
  before do
17
19
  allow(Aws::ElasticTranscoder::Client).to receive(:new).and_return(client)
20
+ allow(Aws::S3::Client).to receive(:new).and_return(s3client)
18
21
  end
19
22
 
20
23
  let(:created_job) do
21
24
  j = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_created.json'))
22
25
  j.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_generic.json')))
23
- j.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_submitted.json')))]
26
+ j.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_submitted.json')))]
24
27
 
25
28
  client.stub_responses(:create_job, Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j))
26
29
 
27
30
  ActiveEncode::Base.create(
28
- "somefile.mp4",
29
- pipeline_id: "1471963629141-kmcocm",
30
- output_key_prefix: "elastic-transcoder-samples/output/hls/",
31
- outputs: [{
32
- key: 'hls0400k/' + "e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a",
33
- preset_id: "1351620000001-200050",
34
- segment_duration: "2"
35
- }])
31
+ "spec/fixtures/fireworks.mp4",
32
+ pipeline_id: "1471963629141-kmcocm",
33
+ masterfile_bucket: "BucketName",
34
+ output_key_prefix: "elastic-transcoder-samples/output/hls/",
35
+ outputs: [{
36
+ key: 'hls0400k/' + "e8fe80f5bsomefilesource_bucket7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a",
37
+ preset_id: "1351620000001-200050",
38
+ segment_duration: "2"
39
+ }]
40
+ )
36
41
  end
37
42
 
38
43
  let(:running_job) do
39
44
  j = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_progressing.json'))
40
45
  j.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_progressing.json')))
41
- j.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_progressing.json')))]
46
+ j.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_progressing.json')))]
42
47
 
43
48
  client.stub_responses(:read_job, Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j))
44
49
  ActiveEncode::Base.find('running-id')
@@ -47,7 +52,7 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
47
52
  let(:canceled_job) do
48
53
  j = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_canceled.json'))
49
54
  j.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_generic.json')))
50
- j.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_canceled.json')))]
55
+ j.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_canceled.json')))]
51
56
 
52
57
  client.stub_responses(:read_job, Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j))
53
58
 
@@ -57,11 +62,11 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
57
62
  let(:cancelling_job) do
58
63
  j1 = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_progressing.json'))
59
64
  j1.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_progressing.json')))
60
- j1.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_progressing.json')))]
65
+ j1.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_progressing.json')))]
61
66
 
62
67
  j2 = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_canceled.json'))
63
68
  j2.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_generic.json')))
64
- j2.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_canceled.json')))]
69
+ j2.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_canceled.json')))]
65
70
 
66
71
  client.stub_responses(:read_job, [Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j1), Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j2)])
67
72
 
@@ -75,7 +80,7 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
75
80
  let(:completed_job) do
76
81
  j = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_completed.json'))
77
82
  j.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_completed.json')))
78
- j.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_completed.json')))]
83
+ j.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_completed.json')))]
79
84
 
80
85
  client.stub_responses(:read_job, Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j))
81
86
  ActiveEncode::Base.find('completed-id')
@@ -84,29 +89,28 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
84
89
  let(:failed_job) do
85
90
  j = Aws::ElasticTranscoder::Types::Job.new JSON.parse(File.read('spec/fixtures/elastic_transcoder/job_failed.json'))
86
91
  j.input = Aws::ElasticTranscoder::Types::JobInput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/input_generic.json')))
87
- j.outputs = [ Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_failed.json')))]
92
+ j.outputs = [Aws::ElasticTranscoder::Types::JobOutput.new(JSON.parse(File.read('spec/fixtures/elastic_transcoder/output_failed.json')))]
88
93
 
89
94
  client.stub_responses(:read_job, Aws::ElasticTranscoder::Types::ReadJobResponse.new(job: j))
90
95
  ActiveEncode::Base.find('failed-id')
91
96
  end
92
97
 
93
- let(:completed_output) { [{ id: "2", url: "elastic-transcoder-samples/output/hls/hls0400k/e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a", label: "hls0400k", :width=>400, :height=>224, :frame_rate=>25, :file_size=>6901104, :duration=>117353 }] }
94
- let(:completed_tech_metadata) { { :width=>1280, :height=>720, :frame_rate=>25, :file_size=>21069678, :duration=>117312 } }
98
+ let(:completed_output) { [{ id: "2", url: "s3://BucketName/elastic-transcoder-samples/output/hls/hls0400k/e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a", label: "hls0400k", width: 400, height: 224, frame_rate: 25, file_size: 6_901_104, duration: 117_353 }] }
99
+ let(:completed_tech_metadata) { { width: 1280, height: 720, frame_rate: 25, file_size: 21_069_678, duration: 117_312 } }
95
100
  let(:failed_tech_metadata) { {} }
96
101
 
97
102
  it_behaves_like "an ActiveEncode::EngineAdapter"
98
103
 
99
104
  describe "#create" do
100
- let(:create_output) { [{ id: "2", url: "elastic-transcoder-samples/output/hls/hls0400k/e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a", label: "hls0400k" }] }
101
-
102
105
  subject { created_job }
106
+ let(:create_output) { [{ id: "2", url: "s3://BucketName/elastic-transcoder-samples/output/hls/hls0400k/e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a", label: "hls0400k" }] }
103
107
 
104
108
  it { is_expected.to be_running }
105
- its(:current_operations) { is_expected.to be_empty }
109
+ it { expect(subject.current_operations).to be_empty }
106
110
 
107
111
  it 'output has technical metadata' do
108
112
  subject.output.each do |output|
109
- expected_output = create_output.find {|expected_out| expected_out[:id] == output.id }
113
+ expected_output = create_output.find { |expected_out| expected_out[:id] == output.id }
110
114
  expect(output.as_json.symbolize_keys).to include expected_output
111
115
  end
112
116
  end
@@ -114,12 +118,11 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
114
118
 
115
119
  describe "#find" do
116
120
  context "a running encode" do
117
- let(:running_output) { [{ id: "2", url: "elastic-transcoder-samples/output/hls/hls0400k/e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a", label: "hls0400k" }] }
118
- let(:running_tech_metadata) { {:width=>1280, :height=>720, :frame_rate=>25, :file_size=>21069678, :duration=>117312} }
119
-
120
121
  subject { running_job }
122
+ let(:running_output) { [{ id: "2", url: "s3://BucketName/elastic-transcoder-samples/output/hls/hls0400k/e8fe80f5b7063b12d567b90c0bdf6322116bba11ac458fe9d62921644159fe4a", label: "hls0400k" }] }
123
+ let(:running_tech_metadata) { { width: 1280, height: 720, frame_rate: 25, file_size: 21_069_678, duration: 117_312 } }
121
124
 
122
- its(:current_operations) { is_expected.to be_empty }
125
+ it { expect(subject.current_operations).to be_empty }
123
126
 
124
127
  it 'input has technical metadata' do
125
128
  expect(subject.input.as_json.symbolize_keys).to include running_tech_metadata
@@ -127,10 +130,41 @@ describe ActiveEncode::EngineAdapters::ElasticTranscoderAdapter do
127
130
 
128
131
  it 'output has technical metadata' do
129
132
  subject.output.each do |output|
130
- expected_output = running_output.find {|expected_out| expected_out[:id] == output.id }
133
+ expected_output = running_output.find { |expected_out| expected_out[:id] == output.id }
131
134
  expect(output.as_json.symbolize_keys).to include expected_output
132
135
  end
133
136
  end
134
137
  end
135
138
  end
139
+
140
+ describe "#check_s3_bucket" do
141
+ context "when file exists in masterfile_bucket" do
142
+ let(:input_url) { "s3://bucket1/file.mp4" }
143
+ let(:source_bucket) { "bucket1" }
144
+
145
+ it "just returns the key" do
146
+ # TODO: move these bucket helpers out to a service class so we don't have to test private methods
147
+ expect(described_class.new.send(:check_s3_bucket, input_url, source_bucket)).to eq "file.mp4"
148
+ end
149
+ end
150
+
151
+ context "when file is in another bucket" do
152
+ let(:input_url) { "s3://bucket1/file.mp4" }
153
+ let(:source_bucket) { "bucket2" }
154
+
155
+ it "copies to masterfile_bucket" do
156
+ # TODO: move these bucket helpers out to a service class so we don't have to test private methods
157
+ allow(SecureRandom).to receive(:uuid).and_return("randomstring")
158
+ expect(described_class.new.send(:check_s3_bucket, input_url, source_bucket)).to eq "randomstring/file.mp4"
159
+ end
160
+ end
161
+ end
162
+
163
+ describe "#output_percentage" do
164
+ let(:output) { double(ActiveEncode::Output, status: "Random status") }
165
+
166
+ it "returns 0 for any other status" do
167
+ expect(described_class.new.send(:output_percentage, output)).to eq 0
168
+ end
169
+ end
136
170
  end
@@ -1,22 +1,27 @@
1
- require 'spec_helper'
2
- require 'shared_specs/engine_adapter_specs'
1
+ # frozen_string_literal: true
2
+ require 'rails_helper'
3
+ require 'active_encode/spec/shared_specs'
3
4
 
4
5
  describe ActiveEncode::EngineAdapters::FfmpegAdapter do
5
- around(:example) do |example|
6
+ around do |example|
6
7
  ActiveEncode::Base.engine_adapter = :ffmpeg
7
8
 
8
9
  Dir.mktmpdir do |dir|
9
10
  @dir = dir
10
11
  example.run
12
+ Dir.foreach(dir) do |e|
13
+ next if e == "." || e == ".."
14
+ FileUtils.rm_rf(File.join(dir, e))
15
+ end
11
16
  end
12
17
 
13
18
  ActiveEncode::Base.engine_adapter = :test
14
19
  end
15
20
 
16
21
  let!(:work_dir) { stub_const "ActiveEncode::EngineAdapters::FfmpegAdapter::WORK_DIR", @dir }
17
- let(:file) { "file://#{File.absolute_path "spec/fixtures/fireworks.mp4"}" }
22
+ let(:file) { "file://" + Rails.root.join('..', 'spec', 'fixtures', 'fireworks.mp4').to_s }
18
23
  let(:created_job) do
19
- ActiveEncode::Base.create(file, { outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: "mp4"}, { label: "high", ffmpeg_opt: "-s 1280x720", extension: "mp4"}] })
24
+ ActiveEncode::Base.create(file, outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: "mp4" }, { label: "high", ffmpeg_opt: "-s 1280x720", extension: "mp4" }])
20
25
  end
21
26
  let(:running_job) do
22
27
  allow(Process).to receive(:getpgid).and_return 8888
@@ -27,28 +32,33 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
27
32
  end
28
33
  let(:cancelling_job) do
29
34
  allow(Process).to receive(:kill).and_return(nil)
30
- find_encode 'running-id'
35
+ encode = find_encode 'running-id'
36
+ File.write "#{work_dir}/running-id/cancelled", ""
37
+ encode
31
38
  end
32
39
  let(:completed_job) { find_encode "completed-id" }
33
40
  let(:failed_job) { find_encode 'failed-id' }
34
- let(:completed_tech_metadata) { {:audio_bitrate => 171030,
35
- :audio_codec => 'mp4a-40-2',
36
- :duration => 6.315,
37
- :file_size => 199160,
38
- :frame_rate => 23.719,
39
- :height => 110.0,
40
- :id => "99999",
41
- :url => "/home/pdinh/Downloads/videoshort.mp4",
42
- :video_bitrate => 74477,
43
- :video_codec => 'avc1',
44
- :width => 200.0
45
- } }
41
+ let(:completed_tech_metadata) do
42
+ {
43
+ audio_bitrate: 171_030,
44
+ audio_codec: 'mp4a-40-2',
45
+ duration: 6315,
46
+ file_size: 199_160,
47
+ frame_rate: 23.719,
48
+ height: 110.0,
49
+ id: "99999",
50
+ url: "/home/pdinh/Downloads/videoshort.mp4",
51
+ video_bitrate: 74_477,
52
+ video_codec: 'avc1',
53
+ width: 200.0
54
+ }
55
+ end
46
56
  let(:completed_output) { [{ id: "99999" }] }
47
- let(:failed_tech_metadata) { { } }
57
+ let(:failed_tech_metadata) { {} }
48
58
 
49
59
  it_behaves_like "an ActiveEncode::EngineAdapter"
50
60
 
51
- def find_encode id
61
+ def find_encode(id)
52
62
  # Precreate ffmpeg output directory and files
53
63
  FileUtils.copy_entry "spec/fixtures/ffmpeg/#{id}", "#{work_dir}/#{id}"
54
64
 
@@ -57,7 +67,7 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
57
67
  FileUtils.touch "#{work_dir}/#{id}/progress"
58
68
  FileUtils.touch Dir.glob("#{work_dir}/#{id}/*.mp4")
59
69
 
60
- # # Stub out system calls
70
+ # Stub out system calls
61
71
  allow_any_instance_of(ActiveEncode::EngineAdapters::FfmpegAdapter).to receive(:`).and_return(1234)
62
72
 
63
73
  ActiveEncode::Base.find(id)
@@ -82,7 +92,7 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
82
92
 
83
93
  context "input file doesn't exist" do
84
94
  let(:missing_file) { "file:///a_bogus_file.mp4" }
85
- let(:missing_job) { ActiveEncode::Base.create(missing_file, { outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: 'mp4' }]}) }
95
+ let(:missing_job) { ActiveEncode::Base.create(missing_file, outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: 'mp4' }]) }
86
96
 
87
97
  it "returns the encode with correct error" do
88
98
  expect(missing_job.errors).to include("#{missing_file} does not exist or is not accessible")
@@ -91,14 +101,61 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
91
101
  end
92
102
 
93
103
  context "input file is not media" do
94
- let(:nonmedia_file) { "file://#{File.absolute_path "spec/integration/ffmpeg_adapter_spec.rb"}" }
95
- let(:nonmedia_job) { ActiveEncode::Base.create(nonmedia_file, { outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: 'mp4' }]}) }
104
+ let(:nonmedia_file) { "file://" + Rails.root.join('Gemfile').to_s }
105
+ let(:nonmedia_job) { ActiveEncode::Base.create(nonmedia_file, outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: 'mp4' }]) }
96
106
 
97
107
  it "returns the encode with correct error" do
98
108
  expect(nonmedia_job.errors).to include("Error inspecting input: #{nonmedia_file}")
99
109
  expect(nonmedia_job.percent_complete).to be 1
100
110
  end
101
111
  end
112
+
113
+ context "input filename with spaces" do
114
+ let(:file_with_space) { "file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.mp4').to_s }
115
+ let!(:create_space_job) { ActiveEncode::Base.create(file_with_space, outputs: [{ label: "low", ffmpeg_opt: "-s 640x480", extension: 'mp4' }]) }
116
+ let(:find_space_job) { ActiveEncode::Base.find create_space_job.id }
117
+
118
+ it "does not have errors" do
119
+ sleep 2
120
+ expect(find_space_job.errors).to be_empty
121
+ end
122
+
123
+ it "has the input technical metadata in a file" do
124
+ expect(File.read("#{work_dir}/#{create_space_job.id}/input_metadata")).not_to be_empty
125
+ end
126
+
127
+ it "has the pid in a file" do
128
+ expect(File.read("#{work_dir}/#{create_space_job.id}/pid")).not_to be_empty
129
+ end
130
+
131
+ 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
+
134
+ it "does not have errors" do
135
+ sleep 2
136
+ expect(find_space_job.errors).to be_empty
137
+ end
138
+
139
+ it "has the input technical metadata in a file" do
140
+ expect(File.read("#{work_dir}/#{create_space_job.id}/input_metadata")).not_to be_empty
141
+ end
142
+
143
+ it "has the pid in a file" do
144
+ expect(File.read("#{work_dir}/#{create_space_job.id}/pid")).not_to be_empty
145
+ end
146
+ end
147
+ end
148
+
149
+ context 'when failed' do
150
+ subject { created_job }
151
+
152
+ before do
153
+ allow_any_instance_of(Object).to receive(:`).and_raise Errno::ENOENT
154
+ end
155
+
156
+ it { is_expected.to be_failed }
157
+ it { expect(subject.errors).to be_present }
158
+ end
102
159
  end
103
160
 
104
161
  describe "#find" do
@@ -116,5 +173,20 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
116
173
  expect(Process).to receive(:kill).with('SIGTERM', running_job.input.id.to_i)
117
174
  running_job.cancel!
118
175
  end
176
+
177
+ it "does not attempt to stop a non-running encode" do
178
+ expect(Process).not_to receive(:kill).with('SIGTERM', completed_job.input.id.to_i)
179
+ completed_job.cancel!
180
+ end
181
+
182
+ it "raises an error if the process can not be found" do
183
+ expect(Process).to receive(:kill).with('SIGTERM', running_job.input.id.to_i).and_raise(Errno::ESRCH)
184
+ expect { running_job.cancel! }.to raise_error(ActiveEncode::NotRunningError)
185
+ end
186
+
187
+ it "raises an error" do
188
+ expect(Process).to receive(:kill).with('SIGTERM', running_job.input.id.to_i).and_raise(Errno::EPERM)
189
+ expect { running_job.cancel! }.to raise_error(ActiveEncode::CancelError)
190
+ end
119
191
  end
120
192
  end