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
data/spec/rails_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  require 'engine_cart'
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ require 'rails_helper'
3
+
4
+ describe ActiveEncode::EncodeRecordController, type: :routing do
5
+ routes { ActiveEncode::Engine.routes }
6
+
7
+ it "routes to the show action" do
8
+ expect(get: encode_record_path(1)).to route_to(controller: "active_encode/encode_record", action: "show", id: "1")
9
+ end
10
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'coveralls'
2
3
  Coveralls.wear!
3
4
 
@@ -5,7 +6,6 @@ require 'bundler/setup'
5
6
  Bundler.setup
6
7
 
7
8
  require 'byebug'
8
- require 'rspec/its'
9
9
  require 'active_encode'
10
10
 
11
11
  RSpec.configure do |_config|
@@ -13,6 +13,6 @@ end
13
13
 
14
14
  RSpec::Matchers.define :be_the_same_time_as do |expected|
15
15
  match do |actual|
16
- expect(Time.parse(expected)).to eq(Time.parse(actual))
16
+ expect(Time.parse(expected).utc).to eq(Time.parse(actual).utc)
17
17
  end
18
18
  end
@@ -1,15 +1,16 @@
1
- require 'rails/generators'
1
+ # frozen_string_literal: true
2
+ # frozen_string_literal: true
3
+ require 'rails/generators'
2
4
 
3
- class TestAppGenerator < Rails::Generators::Base
4
- source_root "./spec/test_app_templates"
5
+ class TestAppGenerator < Rails::Generators::Base
6
+ source_root "./spec/test_app_templates"
5
7
 
6
- # if you need to generate any additional configuration
7
- # into the test app, this generator will be run immediately
8
- # after setting up the application
9
-
10
- def install_engine
11
- generate 'active_encode:install'
12
- rake 'active_encode:install:migrations'
13
- end
14
- end
8
+ # if you need to generate any additional configuration
9
+ # into the test app, this generator will be run immediately
10
+ # after setting up the application
15
11
 
12
+ def install_engine
13
+ generate 'active_encode:install'
14
+ rake 'active_encode:install:migrations'
15
+ end
16
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe ActiveEncode::Callbacks do
@@ -36,14 +37,14 @@ describe ActiveEncode::Callbacks do
36
37
  end
37
38
 
38
39
  describe 'find callback' do
39
- let(:encode) { CallbackEncode.create("sample.mp4") }
40
40
  subject { CallbackEncode.find(encode.id).history }
41
+ let(:encode) { CallbackEncode.create("sample.mp4") }
41
42
  it { is_expected.to include("CallbackEncode ran after_find") }
42
43
  end
43
44
 
44
45
  describe 'reload callback' do
45
- let(:encode) { CallbackEncode.create("sample.mp4") }
46
46
  subject { encode.reload.history }
47
+ let(:encode) { CallbackEncode.create("sample.mp4") }
47
48
  it { is_expected.to include("CallbackEncode ran after_reload") }
48
49
  end
49
50
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe ActiveEncode::Core do
@@ -5,7 +6,7 @@ describe ActiveEncode::Core do
5
6
  class CustomEncode < ActiveEncode::Base
6
7
  end
7
8
  end
8
- after do
9
+ after do
9
10
  Object.send(:remove_const, :CustomEncode)
10
11
  end
11
12
 
@@ -24,11 +25,11 @@ describe ActiveEncode::Core do
24
25
  end
25
26
 
26
27
  describe 'find' do
27
- let(:id) { encode_class.create(nil).id }
28
28
  subject { encode_class.find(id) }
29
+ let(:id) { encode_class.create(nil).id }
29
30
 
30
31
  it { is_expected.to be_a encode_class }
31
- its(:id) { is_expected.to eq id }
32
+ it { expect(subject.id).to eq id }
32
33
 
33
34
  context 'with no id' do
34
35
  let(:id) { nil }
@@ -42,13 +43,13 @@ describe ActiveEncode::Core do
42
43
  let(:encode_class) { CustomEncode }
43
44
 
44
45
  it { is_expected.to be_a encode_class }
45
- its(:id) { is_expected.to eq id }
46
+ it { expect(subject.id).to eq id }
46
47
 
47
48
  context 'casting' do
48
49
  let(:id) { ActiveEncode::Base.create(nil).id }
49
50
 
50
51
  it { is_expected.to be_a encode_class }
51
- its(:id) { is_expected.to eq id }
52
+ it { expect(subject.id).to eq id }
52
53
  end
53
54
  end
54
55
  end
@@ -57,44 +58,44 @@ describe ActiveEncode::Core do
57
58
  subject { encode_class.create(nil) }
58
59
 
59
60
  it { is_expected.to be_a encode_class }
60
- its(:id) { is_expected.not_to be nil }
61
- its(:state) { is_expected.not_to be nil }
61
+ it { expect(subject.id).not_to be nil }
62
+ it { expect(subject.state).not_to be nil }
62
63
 
63
64
  context 'with an ActiveEncode::Base subclass' do
64
65
  let(:encode_class) { CustomEncode }
65
66
 
66
67
  it { is_expected.to be_a encode_class }
67
- its(:id) { is_expected.not_to be nil }
68
- its(:state) { is_expected.not_to be nil }
68
+ it { expect(subject.id).not_to be nil }
69
+ it { expect(subject.state).not_to be nil }
69
70
  end
70
71
  end
71
72
 
72
73
  describe '#create!' do
73
- let(:encode) { encode_class.new(nil) }
74
74
  subject { encode.create! }
75
+ let(:encode) { encode_class.new(nil) }
75
76
 
76
77
  it { is_expected.to equal encode }
77
78
  it { is_expected.to be_a encode_class }
78
- its(:id) { is_expected.not_to be nil }
79
- its(:state) { is_expected.not_to be nil }
79
+ it { expect(subject.id).not_to be nil }
80
+ it { expect(subject.state).not_to be nil }
80
81
 
81
82
  context 'with an ActiveEncode::Base subclass' do
82
83
  let(:encode_class) { CustomEncode }
83
84
 
84
85
  it { is_expected.to equal encode }
85
86
  it { is_expected.to be_a encode_class }
86
- its(:id) { is_expected.not_to be nil }
87
- its(:state) { is_expected.not_to be nil }
87
+ it { expect(subject.id).not_to be nil }
88
+ it { expect(subject.state).not_to be nil }
88
89
  end
89
90
  end
90
91
 
91
92
  describe '#cancel!' do
92
- let(:encode) { encode_class.create(nil) }
93
93
  subject { encode.cancel! }
94
+ let(:encode) { encode_class.create(nil) }
94
95
 
95
96
  it { is_expected.to equal encode }
96
97
  it { is_expected.to be_a encode_class }
97
- its(:id) { is_expected.not_to be nil }
98
+ it { expect(subject.id).not_to be nil }
98
99
  it { is_expected.to be_cancelled }
99
100
 
100
101
  context 'with an ActiveEncode::Base subclass' do
@@ -102,27 +103,27 @@ describe ActiveEncode::Core do
102
103
 
103
104
  it { is_expected.to equal encode }
104
105
  it { is_expected.to be_a encode_class }
105
- its(:id) { is_expected.not_to be nil }
106
+ it { expect(subject.id).not_to be nil }
106
107
  it { is_expected.to be_cancelled }
107
108
  end
108
109
  end
109
110
 
110
111
  describe '#reload' do
111
- let(:encode) { encode_class.create(nil) }
112
112
  subject { encode.reload }
113
+ let(:encode) { encode_class.create(nil) }
113
114
 
114
115
  it { is_expected.to equal encode }
115
116
  it { is_expected.to be_a encode_class }
116
- its(:id) { is_expected.not_to be nil }
117
- its(:state) { is_expected.not_to be nil }
117
+ it { expect(subject.id).not_to be nil }
118
+ it { expect(subject.state).not_to be nil }
118
119
 
119
120
  context 'with an ActiveEncode::Base subclass' do
120
121
  let(:encode_class) { CustomEncode }
121
122
 
122
123
  it { is_expected.to equal encode }
123
124
  it { is_expected.to be_a encode_class }
124
- its(:id) { is_expected.not_to be nil }
125
- its(:state) { is_expected.not_to be nil }
125
+ it { expect(subject.id).not_to be nil }
126
+ it { expect(subject.state).not_to be nil }
126
127
  end
127
128
  end
128
129
 
@@ -134,15 +135,15 @@ describe ActiveEncode::Core do
134
135
  end
135
136
  end
136
137
  end
137
- after do
138
+ after do
138
139
  Object.send(:remove_const, :DefaultOptionsEncode)
139
140
  end
140
141
 
142
+ subject { encode.options }
141
143
  let(:encode_class) { DefaultOptionsEncode }
142
144
  let(:default_options) { { preset: 'video' } }
143
- let(:options) { { output: [{label: 'high', ffmpeg_opt: "640x480" }] } }
145
+ let(:options) { { output: [{ label: 'high', ffmpeg_opt: "640x480" }] } }
144
146
  let(:encode) { encode_class.new(nil, options) }
145
- subject { encode.options }
146
147
 
147
148
  it 'merges default options and options parameter' do
148
149
  expect(subject).to include default_options
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe ActiveEncode::EngineAdapter do
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2011-2018, The Trustees of Indiana University and Northwestern
3
+ # University. Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ #
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software distributed
11
+ # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12
+ # CONDITIONS OF ANY KIND, either express or implied. See the License for the
13
+ # specific language governing permissions and limitations under the License.
14
+ # --- END LICENSE_HEADER BLOCK ---
15
+ require 'aws-sdk-s3'
16
+ require 'rails_helper'
17
+
18
+ describe FileLocator, type: :service do
19
+ before do
20
+ Aws.config[:stub_responses] = true
21
+ end
22
+
23
+ describe 'S3File Class' do
24
+ let(:bucket) { "mybucket" }
25
+ let(:key) { "mykey.mp4" }
26
+ let(:s3file) { FileLocator::S3File.new("s3://#{bucket}/#{key}") }
27
+
28
+ it "is able to initialize from an S3 URI" do
29
+ expect(s3file.bucket).to eq bucket
30
+ expect(s3file.key).to eq key
31
+ end
32
+
33
+ it "returns an S3 Object" do
34
+ s3_object = s3file.object
35
+ expect(s3_object).to be_an Aws::S3::Object
36
+ expect(s3_object.bucket_name).to eq bucket
37
+ expect(s3_object.key).to eq key
38
+ end
39
+ end
40
+
41
+ describe "Local file" do
42
+ let(:path) { "/path/to/file.mp4" }
43
+ let(:source) { "file://#{path}" }
44
+ let(:locator) { FileLocator.new(source) }
45
+
46
+ it "returns the correct uri" do
47
+ expect(locator.uri).to eq Addressable::URI.parse(source)
48
+ end
49
+
50
+ it "returns the correct location" do
51
+ expect(locator.location).to eq path
52
+ end
53
+
54
+ it "tells if file exists" do
55
+ allow(File).to receive(:exist?).with(path) { true }
56
+ expect(locator.exist?).to be_truthy
57
+ end
58
+
59
+ context "return file" do
60
+ let(:file) { double(File) }
61
+ before do
62
+ allow(File).to receive(:open).and_return file
63
+ end
64
+
65
+ it "returns reader" do
66
+ expect(locator.reader).to eq file
67
+ end
68
+
69
+ it "returns attachment" do
70
+ expect(locator.attachment).to eq file
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "s3 file" do
76
+ let(:bucket) { "mybucket" }
77
+ let(:key) { "mykey.mp4" }
78
+ let(:source) { "s3://#{bucket}/#{key}" }
79
+ let(:locator) { FileLocator.new(source) }
80
+
81
+ it "returns the correct uri" do
82
+ expect(locator.uri).to eq Addressable::URI.parse(source)
83
+ end
84
+
85
+ it "returns the correct location" do
86
+ expect(locator.location).to start_with "https://#{bucket}.s3.us-stubbed-1.amazonaws.com/#{key}"
87
+ end
88
+
89
+ it "tells if file exists" do
90
+ expect(locator.exist?).to be_truthy
91
+ end
92
+
93
+ it "returns reader" do
94
+ expect(locator.reader).to be_a StringIO
95
+ end
96
+
97
+ it "returns attachment" do
98
+ expect(locator.attachment).to eq Addressable::URI.parse(source)
99
+ end
100
+ end
101
+
102
+ describe "Other file" do
103
+ let(:path) { "/path/to/file.mp4" }
104
+ let(:source) { "bogus://#{path}" }
105
+ let(:locator) { FileLocator.new(source) }
106
+
107
+ it "returns the correct uri" do
108
+ expect(locator.uri).to eq Addressable::URI.parse(source)
109
+ end
110
+
111
+ it "returns the correct location" do
112
+ expect(locator.location).to eq source
113
+ end
114
+
115
+ it "tells if file exists" do
116
+ expect(locator.exist?).to be_falsy
117
+ end
118
+
119
+ it "returns reader" do
120
+ io = double(IO)
121
+ allow(Kernel).to receive(:open).and_return io
122
+ expect(locator.reader).to eq io
123
+ end
124
+
125
+ it "returns attachment" do
126
+ expect(locator.attachment).to eq locator.location
127
+ end
128
+ end
129
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe ActiveEncode::GlobalID do
@@ -11,39 +12,39 @@ describe ActiveEncode::GlobalID do
11
12
  end
12
13
 
13
14
  describe '#to_global_id' do
15
+ subject { encode.to_global_id }
14
16
  let(:encode_class) { ActiveEncode::Base }
15
17
  let(:encode) { encode_class.create(nil) }
16
- subject { encode.to_global_id }
17
18
 
18
19
  it { is_expected.to be_a GlobalID }
19
- its(:model_class) { is_expected.to eq encode_class }
20
- its(:model_id) { is_expected.to eq encode.id }
21
- its(:app) { is_expected.to eq 'ActiveEncode' }
20
+ it { expect(subject.model_class).to eq encode_class }
21
+ it { expect(subject.model_id).to eq encode.id }
22
+ it { expect(subject.app).to eq 'ActiveEncode' }
22
23
 
23
24
  context 'with an ActiveEncode::Base subclass' do
24
25
  let(:encode_class) { CustomEncode }
25
26
 
26
27
  it { is_expected.to be_a GlobalID }
27
- its(:model_class) { is_expected.to eq encode_class }
28
- its(:model_id) { is_expected.to eq encode.id }
29
- its(:app) { is_expected.to eq 'ActiveEncode' }
28
+ it { expect(subject.model_class).to eq encode_class }
29
+ it { expect(subject.model_id).to eq encode.id }
30
+ it { expect(subject.app).to eq 'ActiveEncode' }
30
31
  end
31
32
  end
32
33
 
33
34
  describe 'GlobalID::Locator#locate' do
35
+ subject { GlobalID::Locator.locate(global_id) }
34
36
  let(:encode_class) { ActiveEncode::Base }
35
37
  let(:encode) { encode_class.create(nil) }
36
38
  let(:global_id) { encode.to_global_id }
37
- subject { GlobalID::Locator.locate(global_id) }
38
39
 
39
40
  it { is_expected.to be_a encode_class }
40
- its(:id) { is_expected.to eq encode.id }
41
+ it { expect(subject.id).to eq encode.id }
41
42
 
42
43
  context 'with an ActiveEncode::Base subclass' do
43
44
  let(:encode_class) { CustomEncode }
44
-
45
+
45
46
  it { is_expected.to be_a encode_class }
46
- its(:id) { is_expected.to eq encode.id }
47
+ it { expect(subject.id).to eq encode.id }
47
48
  end
48
49
  end
49
50
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe ActiveEncode::Input do
@@ -6,8 +7,10 @@ describe ActiveEncode::Input do
6
7
  describe 'attributes' do
7
8
  it { is_expected.to respond_to(:id, :url) }
8
9
  it { is_expected.to respond_to(:state, :errors, :created_at, :updated_at) }
9
- it { is_expected.to respond_to(:width, :height, :frame_rate, :checksum,
10
- :audio_codec, :video_codec, :audio_bitrate, :video_bitrate) }
10
+ it {
11
+ is_expected.to respond_to(:width, :height, :frame_rate, :checksum,
12
+ :audio_codec, :video_codec, :audio_bitrate, :video_bitrate)
13
+ }
11
14
  end
12
15
 
13
16
  describe '#valid?' do
@@ -15,8 +18,8 @@ describe ActiveEncode::Input do
15
18
  described_class.new.tap do |obj|
16
19
  obj.id = "1"
17
20
  obj.url = "file:///tmp/video.mp4"
18
- obj.created_at = Time.now
19
- obj.updated_at = Time.now
21
+ obj.created_at = Time.now.utc
22
+ obj.updated_at = Time.now.utc
20
23
  end
21
24
  end
22
25
 
@@ -31,7 +34,7 @@ describe ActiveEncode::Input do
31
34
  expect(valid_input.tap { |obj| obj.created_at = "today" }).not_to be_valid
32
35
  expect(valid_input.tap { |obj| obj.updated_at = nil }).not_to be_valid
33
36
  expect(valid_input.tap { |obj| obj.updated_at = "today" }).not_to be_valid
34
- expect(valid_input.tap { |obj| obj.created_at = Time.now }).not_to be_valid
37
+ expect(valid_input.tap { |obj| obj.created_at = Time.now.utc }).not_to be_valid
35
38
  end
36
39
  end
37
40
  end