active_encode 0.6.0 → 0.7.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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +26 -18
  3. data/.rubocop_todo.yml +3 -0
  4. data/active_encode.gemspec +3 -0
  5. data/lib/active_encode/base.rb +1 -2
  6. data/lib/active_encode/engine_adapters.rb +1 -0
  7. data/lib/active_encode/engine_adapters/elastic_transcoder_adapter.rb +5 -4
  8. data/lib/active_encode/engine_adapters/ffmpeg_adapter.rb +86 -30
  9. data/lib/active_encode/engine_adapters/pass_through_adapter.rb +239 -0
  10. data/lib/active_encode/errors.rb +6 -0
  11. data/lib/active_encode/persistence.rb +5 -3
  12. data/lib/active_encode/version.rb +1 -1
  13. data/spec/controllers/encode_record_controller_spec.rb +2 -2
  14. data/spec/fixtures/ffmpeg/cancelled-id/cancelled +0 -0
  15. data/spec/fixtures/file with space.low.mp4 +0 -0
  16. data/spec/fixtures/file with space.mp4 +0 -0
  17. data/spec/fixtures/fireworks.low.mp4 +0 -0
  18. data/spec/fixtures/pass_through/cancelled-id/cancelled +0 -0
  19. data/spec/fixtures/pass_through/cancelled-id/input_metadata +90 -0
  20. data/spec/fixtures/pass_through/completed-id/completed +0 -0
  21. data/spec/fixtures/pass_through/completed-id/input_metadata +102 -0
  22. data/spec/fixtures/pass_through/completed-id/output_metadata-high +90 -0
  23. data/spec/fixtures/pass_through/completed-id/output_metadata-low +90 -0
  24. data/spec/fixtures/pass_through/completed-id/video-high.mp4 +0 -0
  25. data/spec/fixtures/pass_through/completed-id/video-low.mp4 +0 -0
  26. data/spec/fixtures/pass_through/failed-id/error.log +1 -0
  27. data/spec/fixtures/pass_through/failed-id/input_metadata +90 -0
  28. data/spec/fixtures/pass_through/running-id/input_metadata +90 -0
  29. data/spec/integration/ffmpeg_adapter_spec.rb +66 -2
  30. data/spec/integration/pass_through_adapter_spec.rb +151 -0
  31. data/spec/shared_specs/engine_adapter_specs.rb +7 -8
  32. metadata +50 -2
@@ -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>
@@ -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,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'spec_helper'
2
+ require 'rails_helper'
3
3
  require 'shared_specs/engine_adapter_specs'
4
4
 
5
5
  describe ActiveEncode::EngineAdapters::FfmpegAdapter do
@@ -32,7 +32,9 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
32
32
  end
33
33
  let(:cancelling_job) do
34
34
  allow(Process).to receive(:kill).and_return(nil)
35
- find_encode 'running-id'
35
+ encode = find_encode 'running-id'
36
+ File.write "#{work_dir}/running-id/cancelled", ""
37
+ encode
36
38
  end
37
39
  let(:completed_job) { find_encode "completed-id" }
38
40
  let(:failed_job) { find_encode 'failed-id' }
@@ -107,6 +109,53 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
107
109
  expect(nonmedia_job.percent_complete).to be 1
108
110
  end
109
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
+ its(:errors) { is_expected.not_to be_empty }
158
+ end
110
159
  end
111
160
 
112
161
  describe "#find" do
@@ -124,5 +173,20 @@ describe ActiveEncode::EngineAdapters::FfmpegAdapter do
124
173
  expect(Process).to receive(:kill).with('SIGTERM', running_job.input.id.to_i)
125
174
  running_job.cancel!
126
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
127
191
  end
128
192
  end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+ require 'rails_helper'
3
+ require 'shared_specs/engine_adapter_specs'
4
+
5
+ describe ActiveEncode::EngineAdapters::PassThroughAdapter do
6
+ around do |example|
7
+ ActiveEncode::Base.engine_adapter = :pass_through
8
+
9
+ Dir.mktmpdir do |dir|
10
+ @dir = dir
11
+ example.run
12
+ Dir.foreach(dir) do |e|
13
+ next if e == "." || e == ".."
14
+ FileUtils.rm_rf(File.join(dir, e))
15
+ end
16
+ end
17
+
18
+ ActiveEncode::Base.engine_adapter = :test
19
+ end
20
+
21
+ let!(:work_dir) { stub_const "ActiveEncode::EngineAdapters::PassThroughAdapter::WORK_DIR", @dir }
22
+ let(:file) { "file://" + Rails.root.join('..', 'spec', 'fixtures', 'fireworks.mp4').to_s }
23
+ let(:low_derivative) { "file://" + Rails.root.join('..', 'spec', 'fixtures', 'fireworks.low.mp4').to_s }
24
+ let(:created_job) do
25
+ ActiveEncode::Base.create(file, outputs: [{ label: 'low', url: low_derivative }])
26
+ end
27
+ let(:running_job) do
28
+ created_job
29
+ end
30
+ let(:canceled_job) do
31
+ find_encode 'cancelled-id'
32
+ end
33
+ let(:cancelling_job) do
34
+ find_encode 'running-id'
35
+ end
36
+ let(:completed_job) { find_encode "completed-id" }
37
+ let(:failed_job) { find_encode 'failed-id' }
38
+ let(:completed_tech_metadata) do
39
+ {
40
+ audio_bitrate: 171_030,
41
+ audio_codec: 'mp4a-40-2',
42
+ duration: 6315.0,
43
+ file_size: 199_160,
44
+ frame_rate: 23.719,
45
+ height: 110.0,
46
+ id: "completed-id",
47
+ url: "/home/pdinh/Downloads/videoshort.mp4",
48
+ video_bitrate: 74_477,
49
+ video_codec: 'avc1',
50
+ width: 200.0
51
+ }
52
+ end
53
+ let(:completed_output) { [{ id: "completed-id" }] }
54
+ let(:failed_tech_metadata) { {} }
55
+
56
+ it_behaves_like "an ActiveEncode::EngineAdapter"
57
+
58
+ def find_encode(id)
59
+ # Precreate ffmpeg output directory and files
60
+ FileUtils.copy_entry "spec/fixtures/pass_through/#{id}", "#{work_dir}/#{id}"
61
+
62
+ # Simulate that progress is modified later than other files
63
+ sleep 0.1
64
+ FileUtils.touch Dir.glob("#{work_dir}/#{id}/*.mp4")
65
+ touch_fixture(id, "completed")
66
+ touch_fixture(id, "cancelled")
67
+ touch_fixture(id, "error.log")
68
+
69
+ # Stub out system calls
70
+ allow_any_instance_of(ActiveEncode::EngineAdapters::PassThroughAdapter).to receive(:`).and_return(1234)
71
+
72
+ ActiveEncode::Base.find(id)
73
+ end
74
+
75
+ def touch_fixture(id, filename)
76
+ FileUtils.touch("#{work_dir}/#{id}/#{filename}") if File.exist? "#{work_dir}/#{id}/#{filename}"
77
+ end
78
+
79
+ describe "#create" do
80
+ subject { created_job }
81
+
82
+ it "creates a directory whose name is the encode id" do
83
+ expect(File).to exist("#{work_dir}/#{subject.id}")
84
+ end
85
+
86
+ context "input file exists" do
87
+ it "has the input technical metadata in a file" do
88
+ expect(File.read("#{work_dir}/#{subject.id}/input_metadata")).not_to be_empty
89
+ end
90
+ end
91
+
92
+ context "input file doesn't exist" do
93
+ let(:missing_file) { "file:///a_bogus_file.mp4" }
94
+ let(:missing_job) { ActiveEncode::Base.create(missing_file, outputs: [{ label: "low", url: 'mp4' }]) }
95
+
96
+ it "returns the encode with correct error" do
97
+ expect(missing_job.errors).to include("#{missing_file} does not exist or is not accessible")
98
+ expect(missing_job.percent_complete).to be 1
99
+ end
100
+ end
101
+
102
+ context "input file is not media" do
103
+ let(:nonmedia_file) { "file://" + Rails.root.join('Gemfile').to_s }
104
+ let(:nonmedia_job) { ActiveEncode::Base.create(nonmedia_file, outputs: [{ label: "low", url: nonmedia_file }]) }
105
+
106
+ it "returns the encode with correct error" do
107
+ expect(nonmedia_job.errors).to include("Error inspecting input: #{nonmedia_file}")
108
+ expect(nonmedia_job.percent_complete).to be 1
109
+ end
110
+ end
111
+
112
+ context "input filename with spaces" do
113
+ let(:file_with_space) { "file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.mp4').to_s }
114
+ let(:file_with_space_derivative) { "file://" + Rails.root.join('..', 'spec', 'fixtures', 'file with space.low.mp4').to_s }
115
+ let!(:create_space_job) { ActiveEncode::Base.create(file_with_space, outputs: [{ label: "low", url: file_with_space_derivative }]) }
116
+ let(:find_space_job) { ActiveEncode::Base.find create_space_job.id }
117
+
118
+ it "does not have errors" do
119
+ expect(find_space_job.errors).to be_empty
120
+ end
121
+
122
+ it "has the input technical metadata in a file" do
123
+ expect(File.read("#{work_dir}/#{create_space_job.id}/input_metadata")).not_to be_empty
124
+ end
125
+
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) }
129
+
130
+ it "does not have errors" do
131
+ expect(find_space_job.errors).to be_empty
132
+ end
133
+
134
+ it "has the input technical metadata in a file" do
135
+ expect(File.read("#{work_dir}/#{create_space_job.id}/input_metadata")).not_to be_empty
136
+ end
137
+ end
138
+ end
139
+
140
+ context 'when failed' do
141
+ subject { created_job }
142
+
143
+ before do
144
+ allow_any_instance_of(Object).to receive(:`).and_raise Errno::ENOENT
145
+ end
146
+
147
+ it { is_expected.to be_failed }
148
+ its(:errors) { is_expected.not_to be_empty }
149
+ end
150
+ end
151
+ end
@@ -50,12 +50,12 @@ RSpec.shared_examples 'an ActiveEncode::EngineAdapter' do |*_flags|
50
50
  it 'returns an ActiveEncode::Base object' do
51
51
  expect(subject.class).to be ActiveEncode::Base
52
52
  end
53
- its(:id) { is_expected.to eq 'running-id' }
53
+ its(:id) { is_expected.to be_present }
54
54
  it { is_expected.to be_running }
55
55
  its(:percent_complete) { is_expected.to be > 0 }
56
56
  its(:errors) { is_expected.to be_empty }
57
57
  its(:created_at) { is_expected.to be_kind_of Time }
58
- its(:updated_at) { is_expected.to be > subject.created_at }
58
+ its(:updated_at) { is_expected.to be >= subject.created_at }
59
59
 
60
60
  it 'input is a valid ActiveEncode::Input object' do
61
61
  expect(subject.input).to be_a ActiveEncode::Input
@@ -77,7 +77,7 @@ RSpec.shared_examples 'an ActiveEncode::EngineAdapter' do |*_flags|
77
77
  it 'returns an ActiveEncode::Base object' do
78
78
  expect(subject.class).to be ActiveEncode::Base
79
79
  end
80
- its(:id) { is_expected.to eq 'cancelled-id' }
80
+ its(:id) { is_expected.to be_present }
81
81
  it { is_expected.to be_cancelled }
82
82
  its(:percent_complete) { is_expected.to be > 0 }
83
83
  its(:errors) { is_expected.to be_empty }
@@ -104,7 +104,7 @@ RSpec.shared_examples 'an ActiveEncode::EngineAdapter' do |*_flags|
104
104
  it 'returns an ActiveEncode::Base object' do
105
105
  expect(subject.class).to be ActiveEncode::Base
106
106
  end
107
- its(:id) { is_expected.to eq 'completed-id' }
107
+ its(:id) { is_expected.to be_present }
108
108
  it { is_expected.to be_completed }
109
109
  its(:percent_complete) { is_expected.to eq 100 }
110
110
  its(:errors) { is_expected.to be_empty }
@@ -142,7 +142,7 @@ RSpec.shared_examples 'an ActiveEncode::EngineAdapter' do |*_flags|
142
142
  it 'returns an ActiveEncode::Base object' do
143
143
  expect(subject.class).to be ActiveEncode::Base
144
144
  end
145
- its(:id) { is_expected.to eq 'failed-id' }
145
+ its(:id) { is_expected.to be_present }
146
146
  it { is_expected.to be_failed }
147
147
  its(:percent_complete) { is_expected.to be > 0 }
148
148
  its(:errors) { is_expected.not_to be_empty }
@@ -201,12 +201,11 @@ RSpec.shared_examples 'an ActiveEncode::EngineAdapter' do |*_flags|
201
201
  it 'returns an ActiveEncode::Base object' do
202
202
  expect(subject.class).to be ActiveEncode::Base
203
203
  end
204
- its(:id) { is_expected.to eq 'running-id' }
205
- it { is_expected.to be_running }
204
+ its(:id) { is_expected.to be_present }
206
205
  its(:percent_complete) { is_expected.to be > 0 }
207
206
  its(:errors) { is_expected.to be_empty }
208
207
  its(:created_at) { is_expected.to be_kind_of Time }
209
- its(:updated_at) { is_expected.to be > subject.created_at }
208
+ its(:updated_at) { is_expected.to be >= subject.created_at }
210
209
 
211
210
  it 'input is a valid ActiveEncode::Input object' do
212
211
  expect(subject.input).to be_a ActiveEncode::Input