metasploit-credential 1.0.0.pre.rails.pre.4.0c → 1.0.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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +20 -41
- data/app/models/metasploit/credential/core.rb +1 -1
- data/app/models/metasploit/credential/login.rb +1 -1
- data/app/models/metasploit/credential/postgres_md5.rb +4 -0
- data/app/models/metasploit/credential/search/operator/type.rb +2 -2
- data/lib/metasploit/credential/creation.rb +1 -1
- data/lib/metasploit/credential/exporter/core.rb +5 -5
- data/lib/metasploit/credential/exporter/pwdump.rb +2 -2
- data/lib/metasploit/credential/importer/pwdump.rb +6 -5
- data/lib/metasploit/credential/migrator.rb +1 -1
- data/lib/metasploit/credential/version.rb +32 -7
- data/spec/lib/metasploit/credential/creation_spec.rb +6 -8
- data/spec/lib/metasploit/credential/exporter/core_spec.rb +99 -84
- data/spec/lib/metasploit/credential/exporter/pwdump_spec.rb +14 -16
- data/spec/lib/metasploit/credential/importer/core_spec.rb +10 -12
- data/spec/lib/metasploit/credential/importer/multi_spec.rb +4 -6
- data/spec/lib/metasploit/credential/importer/pwdump_spec.rb +11 -13
- data/spec/lib/metasploit/credential/importer/zip_spec.rb +5 -7
- data/spec/lib/metasploit/credential/migrator_spec.rb +8 -9
- data/spec/lib/metasploit/credential/version_spec.rb +3 -139
- data/spec/lib/metasploit/credential_spec.rb +4 -15
- data/spec/models/mdm/service_spec.rb +3 -5
- data/spec/models/mdm/session_spec.rb +2 -4
- data/spec/models/mdm/task_spec.rb +4 -6
- data/spec/models/mdm/user_spec.rb +2 -4
- data/spec/models/mdm/workspace_spec.rb +2 -4
- data/spec/models/metasploit/credential/blank_username_spec.rb +4 -7
- data/spec/models/metasploit/credential/core_spec.rb +43 -45
- data/spec/models/metasploit/credential/login/status_spec.rb +19 -21
- data/spec/models/metasploit/credential/login_spec.rb +33 -35
- data/spec/models/metasploit/credential/nonreplayable_hash_spec.rb +3 -5
- data/spec/models/metasploit/credential/ntlm_hash_spec.rb +13 -15
- data/spec/models/metasploit/credential/origin/cracked_password_spec.rb +5 -7
- data/spec/models/metasploit/credential/origin/import_spec.rb +7 -10
- data/spec/models/metasploit/credential/origin/manual_spec.rb +7 -9
- data/spec/models/metasploit/credential/origin/service_spec.rb +9 -11
- data/spec/models/metasploit/credential/origin/session_spec.rb +10 -12
- data/spec/models/metasploit/credential/password_hash_spec.rb +4 -6
- data/spec/models/metasploit/credential/password_spec.rb +3 -5
- data/spec/models/metasploit/credential/postgres_md5_spec.rb +4 -6
- data/spec/models/metasploit/credential/private_spec.rb +7 -9
- data/spec/models/metasploit/credential/public_spec.rb +4 -6
- data/spec/models/metasploit/credential/realm_spec.rb +12 -14
- data/spec/models/metasploit/credential/replayable_hash_spec.rb +3 -5
- data/spec/models/metasploit/credential/ssh_key_spec.rb +15 -17
- data/spec/models/metasploit/credential/username_spec.rb +5 -9
- data/spec/models/metasploit_data_models/search/visitor/relation_spec.rb +1 -3
- data/spec/spec_helper.rb +95 -25
- data/spec/support/shared/contexts/mdm/workspace.rb +1 -1
- data/spec/support/shared/examples/core_validations.rb +117 -42
- data/spec/support/shared/examples/single_table_inheritance_database_columns.rb +2 -2
- data/spec/support/shared/examples/timestamp_database_column.rb +2 -2
- metadata +30 -16
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Login do
|
1
|
+
RSpec.describe Metasploit::Credential::Login, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
9
|
-
it {
|
5
|
+
it { is_expected.to belong_to(:core).class_name('Metasploit::Credential::Core') }
|
6
|
+
it { is_expected.to have_one(:host).class_name('Mdm::Host') }
|
7
|
+
it { is_expected.to belong_to(:service).class_name('Mdm::Service')}
|
10
8
|
end
|
11
9
|
|
12
10
|
context 'callbacks' do
|
@@ -39,7 +37,7 @@ describe Metasploit::Credential::Login do
|
|
39
37
|
''
|
40
38
|
end
|
41
39
|
|
42
|
-
it {
|
40
|
+
it { is_expected.to be_nil }
|
43
41
|
end
|
44
42
|
|
45
43
|
context 'with nil' do
|
@@ -47,7 +45,7 @@ describe Metasploit::Credential::Login do
|
|
47
45
|
nil
|
48
46
|
end
|
49
47
|
|
50
|
-
it {
|
48
|
+
it { is_expected.to be_nil }
|
51
49
|
end
|
52
50
|
|
53
51
|
context 'with present' do
|
@@ -66,21 +64,21 @@ describe Metasploit::Credential::Login do
|
|
66
64
|
|
67
65
|
context 'database' do
|
68
66
|
context 'columns' do
|
69
|
-
it {
|
70
|
-
it {
|
71
|
-
it {
|
67
|
+
it { is_expected.to have_db_column(:access_level).of_type(:string).with_options(null: true) }
|
68
|
+
it { is_expected.to have_db_column(:last_attempted_at).of_type(:datetime).with_options(null: true) }
|
69
|
+
it { is_expected.to have_db_column(:status).of_type(:string).with_options(null: false) }
|
72
70
|
|
73
71
|
it_should_behave_like 'timestamp database columns'
|
74
72
|
|
75
73
|
context 'foreign keys' do
|
76
|
-
it {
|
77
|
-
it {
|
74
|
+
it { is_expected.to have_db_column(:core_id).of_type(:integer).with_options(null: false) }
|
75
|
+
it { is_expected.to have_db_column(:service_id).of_type(:integer).with_options(null: false) }
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
81
79
|
context 'indices' do
|
82
|
-
it {
|
83
|
-
it {
|
80
|
+
it { is_expected.to have_db_index([:core_id, :service_id]).unique(true) }
|
81
|
+
it { is_expected.to have_db_index([:service_id, :core_id]).unique(true) }
|
84
82
|
end
|
85
83
|
end
|
86
84
|
|
@@ -92,7 +90,7 @@ describe Metasploit::Credential::Login do
|
|
92
90
|
FactoryGirl.build(:metasploit_credential_login)
|
93
91
|
end
|
94
92
|
|
95
|
-
it {
|
93
|
+
it { is_expected.to be_valid }
|
96
94
|
|
97
95
|
context '#status' do
|
98
96
|
subject(:metasploit_credential_login) do
|
@@ -107,7 +105,7 @@ describe Metasploit::Credential::Login do
|
|
107
105
|
Metasploit::Model::Login::Status::DENIED_ACCESS
|
108
106
|
end
|
109
107
|
|
110
|
-
it {
|
108
|
+
it { is_expected.to be_valid }
|
111
109
|
end
|
112
110
|
|
113
111
|
context 'with Metasploit::Model::Login::Status::DISABLED' do
|
@@ -115,7 +113,7 @@ describe Metasploit::Credential::Login do
|
|
115
113
|
Metasploit::Model::Login::Status::DISABLED
|
116
114
|
end
|
117
115
|
|
118
|
-
it {
|
116
|
+
it { is_expected.to be_valid }
|
119
117
|
end
|
120
118
|
|
121
119
|
context 'with Metasploit::Model::Login::Status::LOCKED_OUT' do
|
@@ -123,7 +121,7 @@ describe Metasploit::Credential::Login do
|
|
123
121
|
Metasploit::Model::Login::Status::LOCKED_OUT
|
124
122
|
end
|
125
123
|
|
126
|
-
it {
|
124
|
+
it { is_expected.to be_valid }
|
127
125
|
end
|
128
126
|
|
129
127
|
context 'with Metasploit::Model::Login::Status::SUCCESSFUL' do
|
@@ -131,7 +129,7 @@ describe Metasploit::Credential::Login do
|
|
131
129
|
Metasploit::Model::Login::Status::SUCCESSFUL
|
132
130
|
end
|
133
131
|
|
134
|
-
it {
|
132
|
+
it { is_expected.to be_valid }
|
135
133
|
end
|
136
134
|
|
137
135
|
context 'with Metasploit::Model::Login::Status::UNABLE_TO_CONNECT' do
|
@@ -139,7 +137,7 @@ describe Metasploit::Credential::Login do
|
|
139
137
|
Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
140
138
|
end
|
141
139
|
|
142
|
-
it {
|
140
|
+
it { is_expected.to be_valid }
|
143
141
|
end
|
144
142
|
|
145
143
|
context 'with Metasploit::Model::Login::Status::UNTRIED' do
|
@@ -147,7 +145,7 @@ describe Metasploit::Credential::Login do
|
|
147
145
|
Metasploit::Model::Login::Status::UNTRIED
|
148
146
|
end
|
149
147
|
|
150
|
-
it {
|
148
|
+
it { is_expected.to be_valid }
|
151
149
|
end
|
152
150
|
end
|
153
151
|
end
|
@@ -179,7 +177,7 @@ describe Metasploit::Credential::Login do
|
|
179
177
|
end
|
180
178
|
|
181
179
|
context 'validations' do
|
182
|
-
it {
|
180
|
+
it { is_expected.to validate_presence_of :core }
|
183
181
|
|
184
182
|
context 'with existent Metasploit::Credential::Login' do
|
185
183
|
include_context 'Mdm::Workspace'
|
@@ -192,11 +190,11 @@ describe Metasploit::Credential::Login do
|
|
192
190
|
)
|
193
191
|
end
|
194
192
|
|
195
|
-
it {
|
193
|
+
it { is_expected.to validate_uniqueness_of(:core_id).scoped_to(:service_id) }
|
196
194
|
end
|
197
195
|
|
198
|
-
it {
|
199
|
-
it {
|
196
|
+
it { is_expected.to validate_presence_of :service }
|
197
|
+
it { is_expected.to validate_inclusion_of(:status).in_array(Metasploit::Model::Login::Status::ALL) }
|
200
198
|
|
201
199
|
context '#consistent_last_attempted_at' do
|
202
200
|
include_context 'Mdm::Workspace'
|
@@ -240,7 +238,7 @@ describe Metasploit::Credential::Login do
|
|
240
238
|
DateTime.now.utc
|
241
239
|
end
|
242
240
|
|
243
|
-
it {
|
241
|
+
it { is_expected.to include(error) }
|
244
242
|
end
|
245
243
|
|
246
244
|
context 'without #last_attempted' do
|
@@ -278,7 +276,7 @@ describe Metasploit::Credential::Login do
|
|
278
276
|
nil
|
279
277
|
end
|
280
278
|
|
281
|
-
it {
|
279
|
+
it { is_expected.to include(error) }
|
282
280
|
end
|
283
281
|
end
|
284
282
|
end
|
@@ -351,7 +349,7 @@ describe Metasploit::Credential::Login do
|
|
351
349
|
FactoryGirl.build(:mdm_workspace)
|
352
350
|
end
|
353
351
|
|
354
|
-
it {
|
352
|
+
it { is_expected.to include(error) }
|
355
353
|
end
|
356
354
|
end
|
357
355
|
|
@@ -360,7 +358,7 @@ describe Metasploit::Credential::Login do
|
|
360
358
|
nil
|
361
359
|
end
|
362
360
|
|
363
|
-
it {
|
361
|
+
it { is_expected.to include(error) }
|
364
362
|
end
|
365
363
|
end
|
366
364
|
|
@@ -369,7 +367,7 @@ describe Metasploit::Credential::Login do
|
|
369
367
|
nil
|
370
368
|
end
|
371
369
|
|
372
|
-
it {
|
370
|
+
it { is_expected.to include(error) }
|
373
371
|
end
|
374
372
|
end
|
375
373
|
|
@@ -378,7 +376,7 @@ describe Metasploit::Credential::Login do
|
|
378
376
|
nil
|
379
377
|
end
|
380
378
|
|
381
|
-
it {
|
379
|
+
it { is_expected.to include(error) }
|
382
380
|
end
|
383
381
|
end
|
384
382
|
|
@@ -410,7 +408,7 @@ describe Metasploit::Credential::Login do
|
|
410
408
|
FactoryGirl.build(:mdm_workspace)
|
411
409
|
end
|
412
410
|
|
413
|
-
it {
|
411
|
+
it { is_expected.to include(error) }
|
414
412
|
end
|
415
413
|
|
416
414
|
context 'without Mdm::Host#workspace' do
|
@@ -467,7 +465,7 @@ describe Metasploit::Credential::Login do
|
|
467
465
|
FactoryGirl.build(:mdm_workspace)
|
468
466
|
end
|
469
467
|
|
470
|
-
it {
|
468
|
+
it { is_expected.to include(error) }
|
471
469
|
end
|
472
470
|
|
473
471
|
context 'without Mdm::Host#workspace' do
|
@@ -510,7 +508,7 @@ describe Metasploit::Credential::Login do
|
|
510
508
|
subject(:login){ FactoryGirl.create :metasploit_credential_login, core: core}
|
511
509
|
|
512
510
|
it 'should find the right objects' do
|
513
|
-
Metasploit::Credential::Login.in_workspace_including_hosts_and_services(service.host.workspace).
|
511
|
+
expect(Metasploit::Credential::Login.in_workspace_including_hosts_and_services(service.host.workspace)).to include(login)
|
514
512
|
end
|
515
513
|
end
|
516
514
|
end
|
@@ -1,9 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::NonreplayableHash do
|
1
|
+
RSpec.describe Metasploit::Credential::NonreplayableHash, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
|
-
it {
|
4
|
+
it { is_expected.to be_a Metasploit::Credential::PasswordHash }
|
7
5
|
|
8
6
|
context 'factories' do
|
9
7
|
context 'metasploit_credential_nonreplayable_hash' do
|
@@ -11,7 +9,7 @@ describe Metasploit::Credential::NonreplayableHash do
|
|
11
9
|
FactoryGirl.build(:metasploit_credential_nonreplayable_hash)
|
12
10
|
end
|
13
11
|
|
14
|
-
it {
|
12
|
+
it { is_expected.to be_valid }
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -1,9 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::NTLMHash do
|
1
|
+
RSpec.describe Metasploit::Credential::NTLMHash, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
|
-
it {
|
4
|
+
it { is_expected.to be_a Metasploit::Credential::ReplayableHash }
|
7
5
|
|
8
6
|
context 'CONSTANTS' do
|
9
7
|
context 'DATA_REGEXP' do
|
@@ -38,7 +36,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
38
36
|
described_class::LAN_MANAGER_MAX_CHARACTERS
|
39
37
|
end
|
40
38
|
|
41
|
-
it {
|
39
|
+
it { is_expected.to eq 14 }
|
42
40
|
end
|
43
41
|
|
44
42
|
context 'LAN_MANAGER_HEX_DIGEST_REGEXP' do
|
@@ -101,7 +99,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
101
99
|
nil
|
102
100
|
end
|
103
101
|
|
104
|
-
it {
|
102
|
+
it { is_expected.to be_nil }
|
105
103
|
end
|
106
104
|
|
107
105
|
context 'with upper case characters' do
|
@@ -133,7 +131,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
133
131
|
FactoryGirl.build(:metasploit_credential_ntlm_hash)
|
134
132
|
end
|
135
133
|
|
136
|
-
it {
|
134
|
+
it { is_expected.to be_valid }
|
137
135
|
end
|
138
136
|
end
|
139
137
|
|
@@ -191,7 +189,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
191
189
|
super().gsub(':', '')
|
192
190
|
end
|
193
191
|
|
194
|
-
it {
|
192
|
+
it { is_expected.to include(error) }
|
195
193
|
end
|
196
194
|
|
197
195
|
context 'without LAN Manager hex_digest' do
|
@@ -199,7 +197,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
199
197
|
":#{nt_lan_manager_hex_digest}"
|
200
198
|
end
|
201
199
|
|
202
|
-
it {
|
200
|
+
it { is_expected.to include(error) }
|
203
201
|
end
|
204
202
|
|
205
203
|
context 'with incorrect hash length(s)' do
|
@@ -207,7 +205,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
207
205
|
"123456:abcdef"
|
208
206
|
end
|
209
207
|
|
210
|
-
it {
|
208
|
+
it { is_expected.to include(error) }
|
211
209
|
end
|
212
210
|
end
|
213
211
|
end
|
@@ -375,26 +373,26 @@ describe Metasploit::Credential::NTLMHash do
|
|
375
373
|
context 'blank_password?' do
|
376
374
|
|
377
375
|
it 'returns true if the hash is for a blank password' do
|
378
|
-
expect(blank_password_hash.blank_password?).to
|
376
|
+
expect(blank_password_hash.blank_password?).to eq(true)
|
379
377
|
end
|
380
378
|
|
381
379
|
it 'returns false if the hash is not for a blank password' do
|
382
|
-
expect(non_blank_password.blank_password?).to
|
380
|
+
expect(non_blank_password.blank_password?).to eq(false)
|
383
381
|
end
|
384
382
|
|
385
383
|
it 'returns false if the nt hash is not blank but the lm hash is' do
|
386
|
-
expect(no_lm_hash.blank_password?).to
|
384
|
+
expect(no_lm_hash.blank_password?).to eq(false)
|
387
385
|
end
|
388
386
|
end
|
389
387
|
|
390
388
|
context 'lm_hash_present?' do
|
391
389
|
|
392
390
|
it 'returns false if the lm_hash is blank' do
|
393
|
-
expect(no_lm_hash.lm_hash_present?).to
|
391
|
+
expect(no_lm_hash.lm_hash_present?).to eq(false)
|
394
392
|
end
|
395
393
|
|
396
394
|
it 'returns true if the lm_hash is not blank' do
|
397
|
-
expect(non_blank_password.lm_hash_present?).to
|
395
|
+
expect(non_blank_password.lm_hash_present?).to eq(true)
|
398
396
|
end
|
399
397
|
end
|
400
398
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Origin::CrackedPassword do
|
1
|
+
RSpec.describe Metasploit::Credential::Origin::CrackedPassword, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
5
|
+
it { is_expected.to have_many(:cores).class_name('Metasploit::Credential::Core').dependent(:destroy) }
|
6
|
+
it { is_expected.to belong_to(:originating_core).class_name('Metasploit::Credential::Core') }
|
9
7
|
end
|
10
8
|
|
11
9
|
context 'database' do
|
@@ -13,13 +11,13 @@ describe Metasploit::Credential::Origin::CrackedPassword do
|
|
13
11
|
it_should_behave_like 'timestamp database columns'
|
14
12
|
|
15
13
|
context 'foreign keys' do
|
16
|
-
it {
|
14
|
+
it { is_expected.to have_db_column(:metasploit_credential_core_id).of_type(:integer).with_options(null: false) }
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
18
|
context 'indices' do
|
21
19
|
context 'foreign keys' do
|
22
|
-
it {
|
20
|
+
it { is_expected.to have_db_index(:metasploit_credential_core_id) }
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -1,27 +1,25 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Origin::Import do
|
1
|
+
RSpec.describe Metasploit::Credential::Origin::Import, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
5
|
+
it { is_expected.to have_many(:cores).class_name('Metasploit::Credential::Core').dependent(:destroy) }
|
6
|
+
it { is_expected.to belong_to(:task).class_name('Mdm::Task') }
|
9
7
|
end
|
10
8
|
|
11
9
|
context 'database' do
|
12
10
|
context 'columns' do
|
13
|
-
it {
|
11
|
+
it { is_expected.to have_db_column(:filename).of_type(:text).with_options(null: false) }
|
14
12
|
|
15
13
|
it_should_behave_like 'timestamp database columns'
|
16
14
|
|
17
15
|
context 'foreign keys' do
|
18
|
-
it {
|
16
|
+
it { is_expected.to have_db_column(:task_id).of_type(:integer) }
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
20
|
context 'indices' do
|
23
21
|
context 'foreign keys' do
|
24
|
-
it {
|
22
|
+
it { is_expected.to have_db_index(:task_id) }
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -33,7 +31,6 @@ describe Metasploit::Credential::Origin::Import do
|
|
33
31
|
FactoryGirl.build(:metasploit_credential_origin_import)
|
34
32
|
end
|
35
33
|
|
36
|
-
it {
|
34
|
+
it { is_expected.to be_valid }
|
37
35
|
end
|
38
|
-
|
39
36
|
end
|
@@ -1,17 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Origin::Manual do
|
1
|
+
RSpec.describe Metasploit::Credential::Origin::Manual, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
5
|
+
it { is_expected.to have_many(:cores).class_name('Metasploit::Credential::Core').dependent(:destroy) }
|
6
|
+
it { is_expected.to belong_to(:user).class_name('Mdm::User') }
|
9
7
|
end
|
10
8
|
|
11
9
|
context 'database' do
|
12
10
|
context 'columns' do
|
13
11
|
context 'foreign keys' do
|
14
|
-
it {
|
12
|
+
it { is_expected.to have_db_column(:user_id).of_type(:integer).with_options(null: false) }
|
15
13
|
end
|
16
14
|
|
17
15
|
it_should_behave_like 'timestamp database columns'
|
@@ -19,7 +17,7 @@ describe Metasploit::Credential::Origin::Manual do
|
|
19
17
|
|
20
18
|
context 'indices' do
|
21
19
|
context 'foreign keys' do
|
22
|
-
it {
|
20
|
+
it { is_expected.to have_db_index(:user_id) }
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -30,11 +28,11 @@ describe Metasploit::Credential::Origin::Manual do
|
|
30
28
|
FactoryGirl.build(:metasploit_credential_origin_manual)
|
31
29
|
end
|
32
30
|
|
33
|
-
it {
|
31
|
+
it { is_expected.to be_valid }
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
context 'validations' do
|
38
|
-
it {
|
36
|
+
it { is_expected.to validate_presence_of :user }
|
39
37
|
end
|
40
38
|
end
|