nucleus 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +18 -4
  4. data/README.md +28 -40
  5. data/Rakefile +137 -137
  6. data/config/nucleus_config.rb +0 -4
  7. data/lib/nucleus/adapter_resolver.rb +115 -115
  8. data/lib/nucleus/adapters/buildpack_translator.rb +79 -79
  9. data/lib/nucleus/adapters/v1/cloud_control/application.rb +108 -108
  10. data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +27 -27
  11. data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +153 -153
  12. data/lib/nucleus/adapters/v1/cloud_control/domains.rb +68 -68
  13. data/lib/nucleus/adapters/v1/cloud_control/logs.rb +103 -103
  14. data/lib/nucleus/adapters/v1/cloud_control/vars.rb +88 -88
  15. data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +149 -149
  16. data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +303 -303
  17. data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +286 -286
  18. data/lib/nucleus/adapters/v1/heroku/heroku.rb +2 -2
  19. data/lib/nucleus/adapters/v1/heroku/logs.rb +108 -108
  20. data/lib/nucleus/core/adapter_authentication_inductor.rb +0 -2
  21. data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +37 -37
  22. data/lib/nucleus/core/adapter_extensions/http_client.rb +177 -177
  23. data/lib/nucleus/core/common/files/archive_extractor.rb +112 -112
  24. data/lib/nucleus/core/common/files/archiver.rb +91 -91
  25. data/lib/nucleus/core/common/logging/request_log_formatter.rb +48 -48
  26. data/lib/nucleus/core/error_messages.rb +127 -127
  27. data/lib/nucleus/core/models/abstract_model.rb +29 -29
  28. data/lib/nucleus/scripts/load_dependencies.rb +0 -1
  29. data/lib/nucleus/scripts/setup_config.rb +28 -28
  30. data/lib/nucleus/version.rb +3 -3
  31. data/nucleus.gemspec +10 -12
  32. data/spec/factories/models.rb +63 -61
  33. data/spec/integration/api/auth_spec.rb +58 -58
  34. data/spec/test_suites.rake +31 -31
  35. data/spec/unit/common/helpers/auth_helper_spec.rb +73 -73
  36. data/spec/unit/common/oauth2_auth_client_spec.rb +1 -1
  37. data/tasks/compatibility.rake +113 -113
  38. data/tasks/evaluation.rake +162 -162
  39. metadata +16 -30
@@ -1,127 +1,127 @@
1
- module Nucleus
2
- # The {ErrorMessages} module groups all error definitions that can be returned by the RESTful API.
3
- # With its constants, it provides the skeleton to create error messages that comply with the error schema of Nucleus.
4
- module ErrorMessages
5
- #################
6
- # CLIENT ERRORS #
7
- #################
8
-
9
- ENDPOINT_BAD_REQUEST = {
10
- status: 400,
11
- error_code: 400_001,
12
- message: 'Bad Request'
13
- }
14
-
15
- AUTH_BAD_REQUEST = {
16
- status: 400,
17
- error_code: 400_002,
18
- message: 'Bad Authentication Request'
19
- }
20
-
21
- BAD_REQUEST_VALIDATION = {
22
- status: 400,
23
- error_code: 400_003,
24
- message: 'Bad Request: Parameter validation failed'
25
- }
26
-
27
- BAD_REQUEST_APP_ARCHIVE = {
28
- status: 400,
29
- error_code: 400_004,
30
- message: 'Bad Request: Application archive is damaged or did not match the declared file format'
31
- }
32
-
33
- AUTH_UNAUTHORIZED = {
34
- status: 401,
35
- error_code: 401_000,
36
- message: 'Unauthorized: Authentication failed'
37
- }
38
-
39
- ENDPOINT_AUTH_FAILED = {
40
- status: 401,
41
- error_code: 401_001,
42
- message: 'Authentication failed, endpoint rejected authentication attempt'
43
- }
44
-
45
- NOT_FOUND = {
46
- status: 404,
47
- error_code: 404_000,
48
- message: 'The resource could not be found'
49
- }
50
-
51
- ENDPOINT_NOT_FOUND = {
52
- status: 404,
53
- error_code: 404_001,
54
- message: 'The resource could not be found'
55
- }
56
-
57
- INVALID_ACCEPT_HEADER = {
58
- status: 406,
59
- error_code: 406_000,
60
- message: 'Invalid Accept header, vendor or version not found'
61
- }
62
-
63
- BAD_REQUEST_ENTITY = {
64
- status: 422,
65
- error_code: 422_000,
66
- message: 'Unprocessable Entity: Request was valid, but has been rejected by the endpoint, '\
67
- 'saying the message was semantically false. Check the dev_message for detailed error analysis'
68
- }
69
-
70
- # All platform specific semantic errors should have a unique error code!
71
- PLATFORM_SPECIFIC_ERROR_ENTITY = {
72
- status: 422,
73
- error_code: 422_001,
74
- message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint, '\
75
- 'saying the message contains data that can not be processed by this specific platform.'
76
- }
77
-
78
- # Quota violations are a common issue and therefore deserve their own message ;)
79
- PLATFORM_QUOTA_ERROR = {
80
- status: 422,
81
- error_code: 422_002,
82
- message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint. '\
83
- 'Your account would exceed its quota limits. Please check your account and its billing status.'
84
- }
85
-
86
- #################
87
- # SERVER ERRORS #
88
- #################
89
-
90
- RESCUED = {
91
- status: 500,
92
- error_code: 500_000,
93
- message: 'Oops, something went terribly wrong here :/'
94
- }
95
-
96
- RESCUED_ADAPTER_CALL = {
97
- status: 500,
98
- error_code: 500_001,
99
- message: 'Endpoint call failed with unforeseen cause'
100
- }
101
-
102
- RESCUED_ADAPTER_CALL_SERVER = {
103
- status: 500,
104
- error_code: 500_002,
105
- message: 'Endpoint crashed with server error'
106
- }
107
-
108
- MISSING_IMPLEMENTATION = {
109
- status: 501,
110
- error_code: 501_000,
111
- message: 'Not Implemented'
112
- }
113
-
114
- UNAVAILABLE = {
115
- status: 503,
116
- error_code: 503_000,
117
- message: 'Service Unavailable'
118
- }
119
-
120
- PLATFORM_GATEWAY_TIMEOUT = {
121
- status: 504,
122
- error_code: 504_000,
123
- message: 'Gateway Timeout. The platform raised an internal Timeout error. We don\'t know to what '\
124
- 'degree the request has been processed, or if it wasn\'t executed at all.'
125
- }
126
- end
127
- end
1
+ module Nucleus
2
+ # The {ErrorMessages} module groups all error definitions that can be returned by the RESTful API.
3
+ # With its constants, it provides the skeleton to create error messages that comply with the error schema of Nucleus.
4
+ module ErrorMessages
5
+ #################
6
+ # CLIENT ERRORS #
7
+ #################
8
+
9
+ ENDPOINT_BAD_REQUEST = {
10
+ status: 400,
11
+ error_code: 400_001,
12
+ message: 'Bad Request'
13
+ }
14
+
15
+ AUTH_BAD_REQUEST = {
16
+ status: 400,
17
+ error_code: 400_002,
18
+ message: 'Bad Authentication Request'
19
+ }
20
+
21
+ BAD_REQUEST_VALIDATION = {
22
+ status: 400,
23
+ error_code: 400_003,
24
+ message: 'Bad Request: Parameter validation failed'
25
+ }
26
+
27
+ BAD_REQUEST_APP_ARCHIVE = {
28
+ status: 400,
29
+ error_code: 400_004,
30
+ message: 'Bad Request: Application archive is damaged or did not match the declared file format'
31
+ }
32
+
33
+ AUTH_UNAUTHORIZED = {
34
+ status: 401,
35
+ error_code: 401_000,
36
+ message: 'Unauthorized: Authentication failed'
37
+ }
38
+
39
+ ENDPOINT_AUTH_FAILED = {
40
+ status: 401,
41
+ error_code: 401_001,
42
+ message: 'Authentication failed, endpoint rejected authentication attempt'
43
+ }
44
+
45
+ NOT_FOUND = {
46
+ status: 404,
47
+ error_code: 404_000,
48
+ message: 'The resource could not be found'
49
+ }
50
+
51
+ ENDPOINT_NOT_FOUND = {
52
+ status: 404,
53
+ error_code: 404_001,
54
+ message: 'The resource could not be found'
55
+ }
56
+
57
+ INVALID_ACCEPT_HEADER = {
58
+ status: 406,
59
+ error_code: 406_000,
60
+ message: 'Invalid Accept header, vendor or version not found'
61
+ }
62
+
63
+ BAD_REQUEST_ENTITY = {
64
+ status: 422,
65
+ error_code: 422_000,
66
+ message: 'Unprocessable Entity: Request was valid, but has been rejected by the endpoint, '\
67
+ 'saying the message was semantically false. Check the dev_message for detailed error analysis'
68
+ }
69
+
70
+ # All platform specific semantic errors should have a unique error code!
71
+ PLATFORM_SPECIFIC_ERROR_ENTITY = {
72
+ status: 422,
73
+ error_code: 422_001,
74
+ message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint, '\
75
+ 'saying the message contains data that can not be processed by this specific platform.'
76
+ }
77
+
78
+ # Quota violations are a common issue and therefore deserve their own message ;)
79
+ PLATFORM_QUOTA_ERROR = {
80
+ status: 422,
81
+ error_code: 422_002,
82
+ message: 'Unprocessable Entity: Request format was valid, but has been rejected by the endpoint. '\
83
+ 'Your account would exceed its quota limits. Please check your account and its billing status.'
84
+ }
85
+
86
+ #################
87
+ # SERVER ERRORS #
88
+ #################
89
+
90
+ RESCUED = {
91
+ status: 500,
92
+ error_code: 500_000,
93
+ message: 'Oops, something went terribly wrong here :/'
94
+ }
95
+
96
+ RESCUED_ADAPTER_CALL = {
97
+ status: 500,
98
+ error_code: 500_001,
99
+ message: 'Endpoint call failed with unforeseen cause'
100
+ }
101
+
102
+ RESCUED_ADAPTER_CALL_SERVER = {
103
+ status: 500,
104
+ error_code: 500_002,
105
+ message: 'Endpoint crashed with server error'
106
+ }
107
+
108
+ MISSING_IMPLEMENTATION = {
109
+ status: 501,
110
+ error_code: 501_000,
111
+ message: 'Not Implemented'
112
+ }
113
+
114
+ UNAVAILABLE = {
115
+ status: 503,
116
+ error_code: 503_000,
117
+ message: 'Service Unavailable'
118
+ }
119
+
120
+ PLATFORM_GATEWAY_TIMEOUT = {
121
+ status: 504,
122
+ error_code: 504_000,
123
+ message: 'Gateway Timeout. The platform raised an internal Timeout error. We don\'t know to what '\
124
+ 'degree the request has been processed, or if it wasn\'t executed at all.'
125
+ }
126
+ end
127
+ end
@@ -1,29 +1,29 @@
1
- module Nucleus
2
- #
3
- # @author Cedric Roeck (cedric.roeck@gmail.com)
4
- # @since 0.1.0
5
- class AbstractModel
6
- include Kwalify::Util::HashLike
7
-
8
- attr_accessor :id
9
- attr_accessor :name
10
- attr_accessor :created_at
11
- attr_accessor :updated_at
12
-
13
- def initialize(hash = nil)
14
- return if hash.nil?
15
- @name = hash['name']
16
- @id = hash['id']
17
- end
18
-
19
- def to_s
20
- return name if self.respond_to?('name')
21
- return id if id
22
- super.to_s
23
- end
24
-
25
- def inspect
26
- to_s
27
- end
28
- end
29
- end
1
+ module Nucleus
2
+ #
3
+ # @author Cedric Roeck (cedric.roeck@gmail.com)
4
+ # @since 0.1.0
5
+ class AbstractModel
6
+ include Kwalify::Util::HashLike
7
+
8
+ attr_accessor :id
9
+ attr_accessor :name
10
+ attr_accessor :created_at
11
+ attr_accessor :updated_at
12
+
13
+ def initialize(hash = nil)
14
+ return if hash.nil?
15
+ @name = hash['name']
16
+ @id = hash['id']
17
+ end
18
+
19
+ def to_s
20
+ return name if respond_to?('name')
21
+ return id if id
22
+ super.to_s
23
+ end
24
+
25
+ def inspect
26
+ to_s
27
+ end
28
+ end
29
+ end
@@ -9,7 +9,6 @@ require 'logger'
9
9
 
10
10
  # database
11
11
  require 'moneta'
12
- require 'daybreak'
13
12
  require 'lmdb'
14
13
 
15
14
  # schema
@@ -1,28 +1,28 @@
1
- # configuration
2
- require 'logger'
3
- require 'configatron/core'
4
- require 'nucleus/ext/kernel'
5
- require 'nucleus/os'
6
-
7
- # import the configuration file that resides in the user's home directory as initial choice
8
- if OS.windows?
9
- home_dir_config = File.expand_path(File.join(Dir.home, 'nucleus', 'nucleus_config.rb'))
10
- else
11
- home_dir_config = File.expand_path(File.join(Dir.home, '.nucleus', 'nucleus_config.rb'))
12
- end
13
- if File.exist?(home_dir_config)
14
- puts "Applying configuration from: #{home_dir_config}"
15
- require home_dir_config
16
- end
17
-
18
- # include the configuration of the project to overwrite the home dir config
19
- project_dir_config = '../../../config/nucleus_config.rb'
20
- if File.exist?(File.expand_path(project_dir_config, File.dirname(__FILE__)))
21
- puts "Applying configuration from: #{File.expand_path(project_dir_config, File.dirname(__FILE__))}"
22
- require_relative project_dir_config
23
- end
24
-
25
- # make sure we have a logging directory
26
- unless nucleus_config.logging.key?(:path)
27
- nucleus_config.logging.path = File.join(__dir__, '..', '..', '..', 'log')
28
- end
1
+ # configuration
2
+ require 'logger'
3
+ require 'configatron/core'
4
+ require 'nucleus/ext/kernel'
5
+ require 'nucleus/os'
6
+
7
+ # import the configuration file that resides in the user's home directory as initial choice
8
+ home_dir_config = if OS.windows?
9
+ File.expand_path(File.join(Dir.home, 'nucleus', 'nucleus_config.rb'))
10
+ else
11
+ File.expand_path(File.join(Dir.home, '.nucleus', 'nucleus_config.rb'))
12
+ end
13
+ if File.exist?(home_dir_config)
14
+ puts "Applying configuration from: #{home_dir_config}"
15
+ require home_dir_config
16
+ end
17
+
18
+ # include the configuration of the project to overwrite the home dir config
19
+ project_dir_config = '../../../config/nucleus_config.rb'
20
+ if File.exist?(File.expand_path(project_dir_config, File.dirname(__FILE__)))
21
+ puts "Applying configuration from: #{File.expand_path(project_dir_config, File.dirname(__FILE__))}"
22
+ require_relative project_dir_config
23
+ end
24
+
25
+ # make sure we have a logging directory
26
+ unless nucleus_config.logging.key?(:path)
27
+ nucleus_config.logging.path = File.join(__dir__, '..', '..', '..', 'log')
28
+ end
@@ -1,3 +1,3 @@
1
- module Nucleus
2
- VERSION = '0.1.0'
3
- end
1
+ module Nucleus
2
+ VERSION = '0.2.0'.freeze
3
+ end
@@ -17,16 +17,14 @@ Gem::Specification.new do |spec|
17
17
  spec.required_ruby_version = '>= 2.0'
18
18
 
19
19
  # we ignore the test files and icons as they tremendously increase the gem size (up to 43MB)
20
- spec.files = `git ls-files -z --exclude-standard`.split("\x0").reject do |f|
20
+ spec.files = `git ls-files -z --exclude-standard`.split("\x0").reject do |f|
21
21
  f[%r{^(lib/nucleus_api|spec/adapter|icons)/}]
22
22
  end
23
23
  # again only unit and integration, but no adapter test files
24
- spec.test_files = spec.files.grep(%r{^(spec)/})
24
+ spec.test_files = spec.files.grep(%r{^(spec)/})
25
25
 
26
26
  # used as global configuration
27
27
  spec.add_runtime_dependency 'configatron', '~> 4.5'
28
- # DB store (1)
29
- spec.add_runtime_dependency 'daybreak', '~> 0.3'
30
28
  # Required for log tailing against HTTP endpoints
31
29
  spec.add_runtime_dependency 'em-http-request', '~> 1.1'
32
30
  # Used as main HTTP / REST client
@@ -36,24 +34,24 @@ Gem::Specification.new do |spec|
36
34
  # Application data handling
37
35
  spec.add_runtime_dependency 'git', '~> 1.2'
38
36
  # Used to build the API
39
- spec.add_runtime_dependency 'grape', '~> 0.12'
40
- spec.add_runtime_dependency 'grape-entity', '~> 0.4', '>= 0.4.5'
37
+ spec.add_runtime_dependency 'grape', '~> 0.13.0'
38
+ spec.add_runtime_dependency 'grape-entity', '~> 0.4.8', '>= 0.4.5'
41
39
  # Used to document the API
42
- spec.add_runtime_dependency 'grape-swagger', '~> 0.10', '>= 0.10.1'
40
+ spec.add_runtime_dependency 'grape-swagger', '~> 0.10.2', '>= 0.10.1'
43
41
  # Used to import the vendor, provider & adapter setup from configuration with schema validation
44
42
  spec.add_runtime_dependency 'kwalify', '~> 0.7'
45
- # DB store (2)
43
+ # DB store
46
44
  spec.add_runtime_dependency 'lmdb', '~> 0.4'
47
45
  # Logging
48
46
  spec.add_runtime_dependency 'logger', '~> 1.2'
49
47
  # Application archive handling, detect unsupported uploads
50
- spec.add_runtime_dependency 'mime-types', '~> 2.4'
48
+ spec.add_runtime_dependency 'mime-types', '~> 2.6'
51
49
  # Generic interface for DB store implementations
52
50
  spec.add_runtime_dependency 'moneta', '~> 0.8'
53
51
  # Openshift logging access and direct Git SSH requests
54
52
  spec.add_runtime_dependency 'net-ssh', '~> 3.0'
55
53
  # Used for JSON / Hash conversion and test cassette serialization (is way faster than other JSON libs)
56
- spec.add_runtime_dependency 'oj', '~> 2.12'
54
+ spec.add_runtime_dependency 'oj', '~> 2.14'
57
55
  # Required for Cloud Foundry log messages
58
56
  spec.add_runtime_dependency 'protobuf', '~> 3.4'
59
57
  # To make sure HTTPS is used instead of HTTP
@@ -81,8 +79,8 @@ Gem::Specification.new do |spec|
81
79
  spec.add_development_dependency 'guard-yard'
82
80
  spec.add_development_dependency 'inch', '~> 0.7'
83
81
  spec.add_development_dependency 'rake', '~> 10.4'
84
- spec.add_development_dependency 'rubocop', '~> 0.34'
85
- spec.add_development_dependency 'vcr', '~> 2.9'
82
+ spec.add_development_dependency 'rubocop', '~> 0.36.0'
83
+ spec.add_development_dependency 'vcr', '~> 3.0'
86
84
  spec.add_development_dependency 'webmock', '~> 1.20'
87
85
  spec.add_development_dependency 'yard', '~> 0.8'
88
86
  end
@@ -1,61 +1,63 @@
1
- FactoryGirl.define do
2
- sequence :uuid do |_|
3
- SecureRandom.uuid
4
- end
5
-
6
- factory :adapter, class: Nucleus::AdapterIndexEntry do
7
- url { Faker::Internet.url }
8
- id nil
9
- adapter_clazz nil
10
- end
11
-
12
- factory :endpoint, class: Nucleus::Endpoint do
13
- id { generate(:uuid) }
14
- name { Faker::Internet.slug }
15
- url { Faker::Internet.url }
16
- created_at { (Faker::Date.between(180.days.ago, 90.days.ago)).iso8601 }
17
- updated_at { (Faker::Date.between(90.days.ago, Date.today)).iso8601 }
18
- provider nil
19
-
20
- after(:create) do |endpoint|
21
- # associate with provider
22
- unless endpoint.provider.nil?
23
- # TODO: find a solution how to test when multiple API versions are to be supported
24
- dao = Nucleus::API::DB::ProviderDao.instance('v1')
25
- provider = dao.get endpoint.provider
26
- provider.endpoints = [] if provider.endpoints.nil?
27
- provider.endpoints << endpoint.id
28
- # save updated association
29
- dao.set provider
30
- end
31
- end
32
- end
33
-
34
- factory :provider, class: Nucleus::Provider do
35
- id { generate(:uuid) }
36
- name { Faker::App.name }
37
- created_at { (Faker::Date.between(180.days.ago, 90.days.ago)).iso8601 }
38
- updated_at { (Faker::Date.between(90.days.ago, Date.today)).iso8601 }
39
- vendor nil
40
-
41
- after(:create) do |provider|
42
- # associate with vendor
43
- unless provider.vendor.nil?
44
- # TODO: find a solution how to test when multiple API versions are to be supported
45
- dao = Nucleus::API::DB::VendorDao.instance('v1')
46
- vendor = dao.get provider.vendor
47
- vendor.providers = [] if vendor.providers.nil?
48
- vendor.providers << provider.id
49
- # save updated association
50
- dao.set vendor
51
- end
52
- end
53
- end
54
-
55
- factory :vendor, class: Nucleus::Vendor do
56
- id { generate(:uuid) }
57
- name { Faker::App.name }
58
- created_at { (Faker::Date.between(180.days.ago, 90.days.ago)).iso8601 }
59
- updated_at { (Faker::Date.between(90.days.ago, Date.today)).iso8601 }
60
- end
61
- end
1
+ require 'active_support/core_ext'
2
+
3
+ FactoryGirl.define do
4
+ sequence :uuid do |_|
5
+ SecureRandom.uuid
6
+ end
7
+
8
+ factory :adapter, class: Nucleus::AdapterIndexEntry do
9
+ url { Faker::Internet.url }
10
+ id nil
11
+ adapter_clazz nil
12
+ end
13
+
14
+ factory :endpoint, class: Nucleus::Endpoint do
15
+ id { generate(:uuid) }
16
+ name { Faker::Internet.slug }
17
+ url { Faker::Internet.url }
18
+ created_at { Faker::Date.between(180.days.ago, 90.days.ago).iso8601 }
19
+ updated_at { Faker::Date.between(90.days.ago, Date.today).iso8601 }
20
+ provider nil
21
+
22
+ after(:create) do |endpoint|
23
+ # associate with provider
24
+ unless endpoint.provider.nil?
25
+ # TODO: find a solution how to test when multiple API versions are to be supported
26
+ dao = Nucleus::API::DB::ProviderDao.instance('v1')
27
+ provider = dao.get endpoint.provider
28
+ provider.endpoints = [] if provider.endpoints.nil?
29
+ provider.endpoints << endpoint.id
30
+ # save updated association
31
+ dao.set provider
32
+ end
33
+ end
34
+ end
35
+
36
+ factory :provider, class: Nucleus::Provider do
37
+ id { generate(:uuid) }
38
+ name { Faker::App.name }
39
+ created_at { Faker::Date.between(180.days.ago, 90.days.ago).iso8601 }
40
+ updated_at { Faker::Date.between(90.days.ago, Date.today).iso8601 }
41
+ vendor nil
42
+
43
+ after(:create) do |provider|
44
+ # associate with vendor
45
+ unless provider.vendor.nil?
46
+ # TODO: find a solution how to test when multiple API versions are to be supported
47
+ dao = Nucleus::API::DB::VendorDao.instance('v1')
48
+ vendor = dao.get provider.vendor
49
+ vendor.providers = [] if vendor.providers.nil?
50
+ vendor.providers << provider.id
51
+ # save updated association
52
+ dao.set vendor
53
+ end
54
+ end
55
+ end
56
+
57
+ factory :vendor, class: Nucleus::Vendor do
58
+ id { generate(:uuid) }
59
+ name { Faker::App.name }
60
+ created_at { Faker::Date.between(180.days.ago, 90.days.ago).iso8601 }
61
+ updated_at { Faker::Date.between(90.days.ago, Date.today).iso8601 }
62
+ end
63
+ end