scimitar 1.8.1 → 2.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +20 -94
  3. data/app/controllers/scimitar/application_controller.rb +13 -41
  4. data/app/controllers/scimitar/schemas_controller.rb +0 -5
  5. data/app/models/scimitar/complex_types/address.rb +6 -0
  6. data/app/models/scimitar/engine_configuration.rb +5 -13
  7. data/app/models/scimitar/error_response.rb +0 -12
  8. data/app/models/scimitar/lists/query_parser.rb +10 -25
  9. data/app/models/scimitar/resource_invalid_error.rb +1 -1
  10. data/app/models/scimitar/resources/base.rb +4 -14
  11. data/app/models/scimitar/resources/mixin.rb +13 -140
  12. data/app/models/scimitar/schema/address.rb +0 -1
  13. data/app/models/scimitar/schema/attribute.rb +5 -14
  14. data/app/models/scimitar/schema/base.rb +1 -1
  15. data/app/models/scimitar/schema/vdtp.rb +1 -1
  16. data/app/models/scimitar/service_provider_configuration.rb +3 -14
  17. data/config/initializers/scimitar.rb +3 -28
  18. data/lib/scimitar/version.rb +2 -2
  19. data/lib/scimitar.rb +2 -7
  20. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
  21. data/spec/apps/dummy/app/models/mock_group.rb +1 -1
  22. data/spec/apps/dummy/app/models/mock_user.rb +8 -36
  23. data/spec/apps/dummy/config/application.rb +1 -0
  24. data/spec/apps/dummy/config/environments/test.rb +28 -5
  25. data/spec/apps/dummy/config/initializers/scimitar.rb +10 -61
  26. data/spec/apps/dummy/config/routes.rb +7 -28
  27. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -10
  28. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
  29. data/spec/apps/dummy/db/schema.rb +4 -11
  30. data/spec/controllers/scimitar/application_controller_spec.rb +3 -126
  31. data/spec/controllers/scimitar/resource_types_controller_spec.rb +2 -2
  32. data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -10
  33. data/spec/models/scimitar/complex_types/address_spec.rb +4 -3
  34. data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
  35. data/spec/models/scimitar/lists/query_parser_spec.rb +9 -76
  36. data/spec/models/scimitar/resources/base_spec.rb +70 -208
  37. data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
  38. data/spec/models/scimitar/resources/mixin_spec.rb +43 -790
  39. data/spec/models/scimitar/schema/attribute_spec.rb +3 -22
  40. data/spec/models/scimitar/schema/base_spec.rb +1 -1
  41. data/spec/models/scimitar/schema/user_spec.rb +0 -10
  42. data/spec/requests/active_record_backed_resources_controller_spec.rb +66 -709
  43. data/spec/requests/application_controller_spec.rb +3 -16
  44. data/spec/spec_helper.rb +0 -8
  45. metadata +14 -25
  46. data/LICENSE.txt +0 -21
  47. data/README.md +0 -710
  48. data/lib/scimitar/support/utilities.rb +0 -51
  49. data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +0 -25
  50. data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +0 -25
  51. data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +0 -24
  52. data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +0 -25
@@ -1,42 +1,25 @@
1
1
  require 'spec_helper'
2
- require 'time'
3
2
 
4
3
  RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
5
4
  before :each do
6
5
  allow_any_instance_of(Scimitar::ApplicationController).to receive(:authenticated?).and_return(true)
7
6
 
8
- # If a sort order is unspecified, the controller defaults to ID ascending.
9
- # With UUID based IDs, testing life is made easier by ensuring that the
10
- # creation order matches an ascending UUID sort order (which is what would
11
- # happen if we were using integer primary keys).
12
- #
13
- lmt = Time.parse("2023-01-09 14:25:00 +1300")
14
- ids = 3.times.map { SecureRandom.uuid }.sort()
15
-
16
- @u1 = MockUser.create!(primary_key: ids.shift(), username: '1', first_name: 'Foo', last_name: 'Ark', home_email_address: 'home_1@test.com', scim_uid: '001', created_at: lmt, updated_at: lmt + 1)
17
- @u2 = MockUser.create!(primary_key: ids.shift(), username: '2', first_name: 'Foo', last_name: 'Bar', home_email_address: 'home_2@test.com', scim_uid: '002', created_at: lmt, updated_at: lmt + 2)
18
- @u3 = MockUser.create!(primary_key: ids.shift(), username: '3', first_name: 'Foo', home_email_address: 'home_3@test.com', scim_uid: '003', created_at: lmt, updated_at: lmt + 3)
19
-
20
- @g1 = MockGroup.create!(display_name: 'Group 1')
21
- @g2 = MockGroup.create!(display_name: 'Group 2')
22
- @g3 = MockGroup.create!(display_name: 'Group 3')
7
+ @u1 = MockUser.create(username: '1', first_name: 'Foo', last_name: 'Ark', home_email_address: 'home_1@test.com')
8
+ @u2 = MockUser.create(username: '2', first_name: 'Foo', last_name: 'Bar', home_email_address: 'home_2@test.com')
9
+ @u3 = MockUser.create(username: '3', first_name: 'Foo', home_email_address: 'home_3@test.com')
23
10
  end
24
11
 
25
12
  # ===========================================================================
26
13
 
27
14
  context '#index' do
28
15
  context 'with no items' do
29
- before :each do
16
+ it 'returns empty list' do
30
17
  MockUser.delete_all
31
- end
32
18
 
33
- it 'returns empty list' do
34
19
  expect_any_instance_of(MockUsersController).to receive(:index).once.and_call_original
35
20
  get '/Users', params: { format: :scim }
36
21
 
37
- expect(response.status ).to eql(200)
38
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
39
-
22
+ expect(response.status).to eql(200)
40
23
  result = JSON.parse(response.body)
41
24
 
42
25
  expect(result['totalResults']).to eql(0)
@@ -46,172 +29,55 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
46
29
  end # "context 'with no items' do"
47
30
 
48
31
  context 'with items' do
49
- context 'with a UUID, renamed primary key column' do
50
- it 'returns all items' do
51
- get '/Users', params: { format: :scim }
52
-
53
- expect(response.status ).to eql(200)
54
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
55
-
56
- result = JSON.parse(response.body)
57
-
58
- expect(result['totalResults']).to eql(3)
59
- expect(result['Resources'].size).to eql(3)
60
-
61
- ids = result['Resources'].map { |resource| resource['id'] }
62
- expect(ids).to match_array([@u1.primary_key.to_s, @u2.primary_key.to_s, @u3.primary_key.to_s])
63
-
64
- usernames = result['Resources'].map { |resource| resource['userName'] }
65
- expect(usernames).to match_array(['1', '2', '3'])
66
- end
67
- end # "context 'with a UUID, renamed primary key column' do"
68
-
69
- context 'with an integer, conventionally named primary key column' do
70
- it 'returns all items' do
71
- get '/Groups', params: { format: :scim }
72
-
73
- expect(response.status ).to eql(200)
74
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
75
-
76
- result = JSON.parse(response.body)
77
-
78
- expect(result['totalResults']).to eql(3)
79
- expect(result['Resources'].size).to eql(3)
80
-
81
- ids = result['Resources'].map { |resource| resource['id'] }
82
- expect(ids).to match_array([@g1.id.to_s, @g2.id.to_s, @g3.id.to_s])
83
-
84
- usernames = result['Resources'].map { |resource| resource['displayName'] }
85
- expect(usernames).to match_array(['Group 1', 'Group 2', 'Group 3'])
86
- end
87
- end # "context 'with an integer, conventionally named primary key column' do"
88
-
89
- it 'applies a filter, with case-insensitive value comparison' do
90
- get '/Users', params: {
91
- format: :scim,
92
- filter: 'name.givenName eq "FOO" and name.familyName pr and emails ne "home_1@test.com"'
93
- }
94
-
95
- expect(response.status ).to eql(200)
96
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
32
+ it 'returns all items' do
33
+ get '/Users', params: { format: :scim }
97
34
 
35
+ expect(response.status).to eql(200)
98
36
  result = JSON.parse(response.body)
99
37
 
100
- expect(result['totalResults']).to eql(1)
101
- expect(result['Resources'].size).to eql(1)
38
+ expect(result['totalResults']).to eql(3)
39
+ expect(result['Resources'].size).to eql(3)
102
40
 
103
41
  ids = result['Resources'].map { |resource| resource['id'] }
104
- expect(ids).to match_array([@u2.primary_key.to_s])
42
+ expect(ids).to match_array([@u1.id.to_s, @u2.id.to_s, @u3.id.to_s])
105
43
 
106
44
  usernames = result['Resources'].map { |resource| resource['userName'] }
107
- expect(usernames).to match_array(['2'])
45
+ expect(usernames).to match_array(['1', '2', '3'])
108
46
  end
109
47
 
110
- it 'applies a filter, with case-insensitive attribute matching (GitHub issue #37)' do
48
+ it 'applies a filter, with case-insensitive value comparison' do
111
49
  get '/Users', params: {
112
50
  format: :scim,
113
- filter: 'name.GIVENNAME eq "Foo" and name.Familyname pr and emails ne "home_1@test.com"'
51
+ filter: 'name.givenName eq "Foo" and name.familyName pr and emails ne "home_1@TEST.COM"'
114
52
  }
115
53
 
116
- expect(response.status ).to eql(200)
117
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
118
-
54
+ expect(response.status).to eql(200)
119
55
  result = JSON.parse(response.body)
120
56
 
121
57
  expect(result['totalResults']).to eql(1)
122
58
  expect(result['Resources'].size).to eql(1)
123
59
 
124
60
  ids = result['Resources'].map { |resource| resource['id'] }
125
- expect(ids).to match_array([@u2.primary_key.to_s])
61
+ expect(ids).to match_array([@u2.id.to_s])
126
62
 
127
63
  usernames = result['Resources'].map { |resource| resource['userName'] }
128
64
  expect(usernames).to match_array(['2'])
129
65
  end
130
66
 
131
- # Strange attribute capitalisation in tests here builds on test coverage
132
- # for now-fixed GitHub issue #37.
133
- #
134
- context '"meta" / IDs (GitHub issue #36)' do
135
- it 'applies a filter on primary keys, using direct comparison (rather than e.g. case-insensitive operators)' do
136
- get '/Users', params: {
137
- format: :scim,
138
- filter: "id eq \"#{@u3.primary_key}\""
139
- }
140
-
141
- expect(response.status ).to eql(200)
142
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
143
-
144
- result = JSON.parse(response.body)
145
-
146
- expect(result['totalResults']).to eql(1)
147
- expect(result['Resources'].size).to eql(1)
148
-
149
- ids = result['Resources'].map { |resource| resource['id'] }
150
- expect(ids).to match_array([@u3.primary_key.to_s])
151
-
152
- usernames = result['Resources'].map { |resource| resource['userName'] }
153
- expect(usernames).to match_array(['3'])
154
- end
155
-
156
- it 'applies a filter on external IDs, using direct comparison' do
157
- get '/Users', params: {
158
- format: :scim,
159
- filter: "externalID eq \"#{@u2.scim_uid}\""
160
- }
161
-
162
- expect(response.status ).to eql(200)
163
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
164
-
165
- result = JSON.parse(response.body)
166
-
167
- expect(result['totalResults']).to eql(1)
168
- expect(result['Resources'].size).to eql(1)
169
-
170
- ids = result['Resources'].map { |resource| resource['id'] }
171
- expect(ids).to match_array([@u2.primary_key.to_s])
172
-
173
- usernames = result['Resources'].map { |resource| resource['userName'] }
174
- expect(usernames).to match_array(['2'])
175
- end
176
-
177
- it 'applies a filter on "meta" entries, using direct comparison' do
178
- get '/Users', params: {
179
- format: :scim,
180
- filter: "Meta.LastModified eq \"#{@u3.updated_at}\""
181
- }
182
-
183
- expect(response.status ).to eql(200)
184
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
185
-
186
- result = JSON.parse(response.body)
187
-
188
- expect(result['totalResults']).to eql(1)
189
- expect(result['Resources'].size).to eql(1)
190
-
191
- ids = result['Resources'].map { |resource| resource['id'] }
192
- expect(ids).to match_array([@u3.primary_key.to_s])
193
-
194
- usernames = result['Resources'].map { |resource| resource['userName'] }
195
- expect(usernames).to match_array(['3'])
196
- end
197
- end # "context '"meta" / IDs (GitHub issue #36)' do"
198
-
199
67
  it 'obeys a page size' do
200
68
  get '/Users', params: {
201
69
  format: :scim,
202
70
  count: 2
203
71
  }
204
72
 
205
- expect(response.status ).to eql(200)
206
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
207
-
73
+ expect(response.status).to eql(200)
208
74
  result = JSON.parse(response.body)
209
75
 
210
76
  expect(result['totalResults']).to eql(3)
211
77
  expect(result['Resources'].size).to eql(2)
212
78
 
213
79
  ids = result['Resources'].map { |resource| resource['id'] }
214
- expect(ids).to match_array([@u1.primary_key.to_s, @u2.primary_key.to_s])
80
+ expect(ids).to match_array([@u1.id.to_s, @u2.id.to_s])
215
81
 
216
82
  usernames = result['Resources'].map { |resource| resource['userName'] }
217
83
  expect(usernames).to match_array(['1', '2'])
@@ -223,16 +89,14 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
223
89
  startIndex: 2
224
90
  }
225
91
 
226
- expect(response.status ).to eql(200)
227
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
228
-
92
+ expect(response.status).to eql(200)
229
93
  result = JSON.parse(response.body)
230
94
 
231
95
  expect(result['totalResults']).to eql(3)
232
96
  expect(result['Resources'].size).to eql(2)
233
97
 
234
98
  ids = result['Resources'].map { |resource| resource['id'] }
235
- expect(ids).to match_array([@u2.primary_key.to_s, @u3.primary_key.to_s])
99
+ expect(ids).to match_array([@u2.id.to_s, @u3.id.to_s])
236
100
 
237
101
  usernames = result['Resources'].map { |resource| resource['userName'] }
238
102
  expect(usernames).to match_array(['2', '3'])
@@ -246,11 +110,8 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
246
110
  filter: 'name.givenName'
247
111
  }
248
112
 
249
- expect(response.status ).to eql(400)
250
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
251
-
113
+ expect(response.status).to eql(400)
252
114
  result = JSON.parse(response.body)
253
-
254
115
  expect(result['scimType']).to eql('invalidFilter')
255
116
  end
256
117
  end # "context 'with bad calls' do"
@@ -259,47 +120,24 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
259
120
  # ===========================================================================
260
121
 
261
122
  context '#show' do
262
- context 'with a UUID, renamed primary key column' do
263
- it 'shows an item' do
264
- expect_any_instance_of(MockUsersController).to receive(:show).once.and_call_original
265
- get "/Users/#{@u2.primary_key}", params: { format: :scim }
266
-
267
- expect(response.status ).to eql(200)
268
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
269
-
270
- result = JSON.parse(response.body)
271
-
272
- expect(result['id']).to eql(@u2.primary_key.to_s)
273
- expect(result['userName']).to eql('2')
274
- expect(result['name']['familyName']).to eql('Bar')
275
- expect(result['meta']['resourceType']).to eql('User')
276
- end
277
- end # "context 'with a UUID, renamed primary key column' do"
278
-
279
- context 'with an integer, conventionally named primary key column' do
280
- it 'shows an item' do
281
- expect_any_instance_of(MockGroupsController).to receive(:show).once.and_call_original
282
- get "/Groups/#{@g2.id}", params: { format: :scim }
123
+ it 'shows an item' do
124
+ expect_any_instance_of(MockUsersController).to receive(:show).once.and_call_original
125
+ get "/Users/#{@u2.id}", params: { format: :scim }
283
126
 
284
- expect(response.status ).to eql(200)
285
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
286
-
287
- result = JSON.parse(response.body)
127
+ expect(response.status).to eql(200)
128
+ result = JSON.parse(response.body)
288
129
 
289
- expect(result['id']).to eql(@g2.id.to_s) # Note - ID was converted String; not Integer
290
- expect(result['displayName']).to eql('Group 2')
291
- expect(result['meta']['resourceType']).to eql('Group')
292
- end
293
- end # "context 'with an integer, conventionally named primary key column' do"
130
+ expect(result['id']).to eql(@u2.id.to_s) # Note - ID was converted String; not Integer
131
+ expect(result['userName']).to eql('2')
132
+ expect(result['name']['familyName']).to eql('Bar')
133
+ expect(result['meta']['resourceType']).to eql('User')
134
+ end
294
135
 
295
136
  it 'renders 404' do
296
137
  get '/Users/xyz', params: { format: :scim }
297
138
 
298
- expect(response.status ).to eql(404)
299
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
300
-
139
+ expect(response.status).to eql(404)
301
140
  result = JSON.parse(response.body)
302
-
303
141
  expect(result['status']).to eql('404')
304
142
  end
305
143
  end # "context '#show' do"
@@ -312,15 +150,10 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
312
150
  it 'with minimal parameters' do
313
151
  mock_before = MockUser.all.to_a
314
152
 
315
- attributes = { userName: '4' } # Minimum required by schema
153
+ attributes = { userName: '4' } # Minimum required by schema
316
154
  attributes = spec_helper_hupcase(attributes) if force_upper_case
317
155
 
318
- # Prove that certain known pathways are called; can then unit test
319
- # those if need be and be sure that this covers #create actions.
320
- #
321
156
  expect_any_instance_of(MockUsersController).to receive(:create).once.and_call_original
322
- expect_any_instance_of(MockUsersController).to receive(:save! ).once.and_call_original
323
-
324
157
  expect {
325
158
  post "/Users", params: attributes.merge(format: :scim)
326
159
  }.to change { MockUser.count }.by(1)
@@ -328,12 +161,10 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
328
161
  mock_after = MockUser.all.to_a
329
162
  new_mock = (mock_after - mock_before).first
330
163
 
331
- expect(response.status ).to eql(201)
332
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
333
-
164
+ expect(response.status).to eql(201)
334
165
  result = JSON.parse(response.body)
335
166
 
336
- expect(result['id']).to eql(new_mock.primary_key.to_s)
167
+ expect(result['id']).to eql(new_mock.id.to_s)
337
168
  expect(result['meta']['resourceType']).to eql('User')
338
169
  expect(new_mock.username).to eql('4')
339
170
  end
@@ -349,7 +180,6 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
349
180
  givenName: 'Given',
350
181
  familyName: 'Family'
351
182
  },
352
- meta: { resourceType: 'User' },
353
183
  emails: [
354
184
  {
355
185
  type: 'work',
@@ -371,9 +201,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
371
201
  mock_after = MockUser.all.to_a
372
202
  new_mock = (mock_after - mock_before).first
373
203
 
374
- expect(response.status ).to eql(201)
375
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
376
-
204
+ expect(response.status).to eql(201)
377
205
  result = JSON.parse(response.body)
378
206
 
379
207
  expect(result['id']).to eql(new_mock.id.to_s)
@@ -404,11 +232,8 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
404
232
  }
405
233
  }.to_not change { MockUser.count }
406
234
 
407
- expect(response.status ).to eql(409)
408
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
409
-
235
+ expect(response.status).to eql(409)
410
236
  result = JSON.parse(response.body)
411
-
412
237
  expect(result['scimType']).to eql('uniqueness')
413
238
  expect(result['detail']).to include('already been taken')
414
239
  end
@@ -421,11 +246,8 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
421
246
  }
422
247
  }.to_not change { MockUser.count }
423
248
 
424
- expect(response.status ).to eql(400)
425
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
426
-
249
+ expect(response.status).to eql(400)
427
250
  result = JSON.parse(response.body)
428
-
429
251
  expect(result['scimType']).to eql('invalidValue')
430
252
  expect(result['detail']).to include('is required')
431
253
  end
@@ -438,83 +260,12 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
438
260
  }
439
261
  }.to_not change { MockUser.count }
440
262
 
441
- expect(response.status ).to eql(400)
442
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
443
-
263
+ expect(response.status).to eql(400)
444
264
  result = JSON.parse(response.body)
445
265
 
446
266
  expect(result['scimType']).to eql('invalidValue')
447
267
  expect(result['detail']).to include('is reserved')
448
268
  end
449
-
450
- context 'with a block' do
451
- it 'invokes the block' do
452
- mock_before = MockUser.all.to_a
453
-
454
- expect_any_instance_of(CustomCreateMockUsersController).to receive(:create).once.and_call_original
455
- expect {
456
- post "/CustomCreateUsers", params: {
457
- format: :scim,
458
- userName: '4' # Minimum required by schema
459
- }
460
- }.to change { MockUser.count }.by(1)
461
-
462
- mock_after = MockUser.all.to_a
463
- new_mock = (mock_after - mock_before).first
464
-
465
- expect(response.status ).to eql(201)
466
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
467
-
468
- result = JSON.parse(response.body)
469
-
470
- expect(result['id']).to eql(new_mock.id.to_s)
471
- expect(result['meta']['resourceType']).to eql('User')
472
- expect(new_mock.first_name).to eql(CustomCreateMockUsersController::OVERRIDDEN_NAME)
473
- end
474
-
475
- it 'returns 409 for duplicates (by Rails validation)' do
476
- existing_user = MockUser.create!(
477
- username: '4',
478
- first_name: 'Will Be Overridden',
479
- last_name: 'Baz',
480
- home_email_address: 'random@test.com',
481
- scim_uid: '999'
482
- )
483
-
484
- expect_any_instance_of(CustomCreateMockUsersController).to receive(:create).once.and_call_original
485
- expect {
486
- post "/CustomCreateUsers", params: {
487
- format: :scim,
488
- userName: '4' # Already exists
489
- }
490
- }.to_not change { MockUser.count }
491
-
492
- expect(response.status ).to eql(409)
493
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
494
-
495
- result = JSON.parse(response.body)
496
-
497
- expect(result['scimType']).to eql('uniqueness')
498
- expect(result['detail']).to include('already been taken')
499
- end
500
-
501
- it 'notes Rails validation failures' do
502
- expect_any_instance_of(CustomCreateMockUsersController).to receive(:create).once.and_call_original
503
- expect {
504
- post "/CustomCreateUsers", params: {
505
- format: :scim,
506
- userName: MockUser::INVALID_USERNAME
507
- }
508
- }.to_not change { MockUser.count }
509
-
510
- expect(response.status ).to eql(400)
511
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
512
-
513
- result = JSON.parse(response.body)
514
- expect(result['scimType']).to eql('invalidValue')
515
- expect(result['detail']).to include('is reserved')
516
- end
517
- end # "context 'with a block' do"
518
269
  end # "context '#create' do"
519
270
 
520
271
  # ===========================================================================
@@ -525,22 +276,15 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
525
276
  attributes = { userName: '4' } # Minimum required by schema
526
277
  attributes = spec_helper_hupcase(attributes) if force_upper_case
527
278
 
528
- # Prove that certain known pathways are called; can then unit test
529
- # those if need be and be sure that this covers #replace actions.
530
- #
531
279
  expect_any_instance_of(MockUsersController).to receive(:replace).once.and_call_original
532
- expect_any_instance_of(MockUsersController).to receive(:save! ).once.and_call_original
533
-
534
280
  expect {
535
- put "/Users/#{@u2.primary_key}", params: attributes.merge(format: :scim)
281
+ put "/Users/#{@u2.id}", params: attributes.merge(format: :scim)
536
282
  }.to_not change { MockUser.count }
537
283
 
538
- expect(response.status ).to eql(200)
539
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
540
-
284
+ expect(response.status).to eql(200)
541
285
  result = JSON.parse(response.body)
542
286
 
543
- expect(result['id']).to eql(@u2.primary_key.to_s)
287
+ expect(result['id']).to eql(@u2.id.to_s)
544
288
  expect(result['meta']['resourceType']).to eql('User')
545
289
 
546
290
  @u2.reload
@@ -562,17 +306,14 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
562
306
 
563
307
  it 'notes schema validation failures' do
564
308
  expect {
565
- put "/Users/#{@u2.primary_key}", params: {
309
+ put "/Users/#{@u2.id}", params: {
566
310
  format: :scim
567
311
  # userName parameter is required by schema, but missing
568
312
  }
569
313
  }.to_not change { MockUser.count }
570
314
 
571
- expect(response.status ).to eql(400)
572
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
573
-
315
+ expect(response.status).to eql(400)
574
316
  result = JSON.parse(response.body)
575
-
576
317
  expect(result['scimType']).to eql('invalidValue')
577
318
  expect(result['detail']).to include('is required')
578
319
 
@@ -586,15 +327,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
586
327
 
587
328
  it 'notes Rails validation failures' do
588
329
  expect {
589
- put "/Users/#{@u2.primary_key}", params: {
330
+ post "/Users", params: {
590
331
  format: :scim,
591
332
  userName: MockUser::INVALID_USERNAME
592
333
  }
593
334
  }.to_not change { MockUser.count }
594
335
 
595
- expect(response.status ).to eql(400)
596
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
597
-
336
+ expect(response.status).to eql(400)
598
337
  result = JSON.parse(response.body)
599
338
 
600
339
  expect(result['scimType']).to eql('invalidValue')
@@ -616,65 +355,10 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
616
355
  }
617
356
  }.to_not change { MockUser.count }
618
357
 
619
- expect(response.status ).to eql(404)
620
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
621
-
358
+ expect(response.status).to eql(404)
622
359
  result = JSON.parse(response.body)
623
-
624
360
  expect(result['status']).to eql('404')
625
361
  end
626
-
627
- context 'with a block' do
628
- it 'invokes the block' do
629
- attributes = { userName: '4' } # Minimum required by schema
630
-
631
- expect_any_instance_of(CustomReplaceMockUsersController).to receive(:replace).once.and_call_original
632
- expect {
633
- put "/CustomReplaceUsers/#{@u2.primary_key}", params: {
634
- format: :scim,
635
- userName: '4'
636
- }
637
- }.to_not change { MockUser.count }
638
-
639
- expect(response.status ).to eql(200)
640
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
641
-
642
- result = JSON.parse(response.body)
643
-
644
- expect(result['id']).to eql(@u2.primary_key.to_s)
645
- expect(result['meta']['resourceType']).to eql('User')
646
-
647
- @u2.reload
648
-
649
- expect(@u2.username ).to eql('4')
650
- expect(@u2.first_name).to eql(CustomReplaceMockUsersController::OVERRIDDEN_NAME)
651
- end
652
-
653
- it 'notes Rails validation failures' do
654
- expect_any_instance_of(CustomReplaceMockUsersController).to receive(:replace).once.and_call_original
655
- expect {
656
- put "/CustomReplaceUsers/#{@u2.primary_key}", params: {
657
- format: :scim,
658
- userName: MockUser::INVALID_USERNAME
659
- }
660
- }.to_not change { MockUser.count }
661
-
662
- expect(response.status ).to eql(400)
663
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
664
-
665
- result = JSON.parse(response.body)
666
-
667
- expect(result['scimType']).to eql('invalidValue')
668
- expect(result['detail']).to include('is reserved')
669
-
670
- @u2.reload
671
-
672
- expect(@u2.username).to eql('2')
673
- expect(@u2.first_name).to eql('Foo')
674
- expect(@u2.last_name).to eql('Bar')
675
- expect(@u2.home_email_address).to eql('home_2@test.com')
676
- end
677
- end # "context 'with a block' do"
678
362
  end # "context '#replace' do"
679
363
 
680
364
  # ===========================================================================
@@ -699,22 +383,15 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
699
383
 
700
384
  payload = spec_helper_hupcase(payload) if force_upper_case
701
385
 
702
- # Prove that certain known pathways are called; can then unit test
703
- # those if need be and be sure that this covers #update actions.
704
- #
705
386
  expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
706
- expect_any_instance_of(MockUsersController).to receive(:save! ).once.and_call_original
707
-
708
387
  expect {
709
- patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
388
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
710
389
  }.to_not change { MockUser.count }
711
390
 
712
- expect(response.status ).to eql(200)
713
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
714
-
391
+ expect(response.status).to eql(200)
715
392
  result = JSON.parse(response.body)
716
393
 
717
- expect(result['id']).to eql(@u2.primary_key.to_s)
394
+ expect(result['id']).to eql(@u2.id.to_s)
718
395
  expect(result['meta']['resourceType']).to eql('User')
719
396
 
720
397
  @u2.reload
@@ -745,15 +422,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
745
422
 
746
423
  expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
747
424
  expect {
748
- patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
425
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
749
426
  }.to_not change { MockUser.count }
750
427
 
751
- expect(response.status ).to eql(200)
752
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
753
-
428
+ expect(response.status).to eql(200)
754
429
  result = JSON.parse(response.body)
755
430
 
756
- expect(result['id']).to eql(@u2.primary_key.to_s)
431
+ expect(result['id']).to eql(@u2.id.to_s)
757
432
  expect(result['meta']['resourceType']).to eql('User')
758
433
 
759
434
  @u2.reload
@@ -779,15 +454,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
779
454
 
780
455
  expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
781
456
  expect {
782
- patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
457
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
783
458
  }.to_not change { MockUser.count }
784
459
 
785
- expect(response.status ).to eql(200)
786
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
787
-
460
+ expect(response.status).to eql(200)
788
461
  result = JSON.parse(response.body)
789
462
 
790
- expect(result['id']).to eql(@u2.primary_key.to_s)
463
+ expect(result['id']).to eql(@u2.id.to_s)
791
464
  expect(result['meta']['resourceType']).to eql('User')
792
465
 
793
466
  @u2.reload
@@ -813,15 +486,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
813
486
 
814
487
  expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
815
488
  expect {
816
- patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
489
+ patch "/Users/#{@u2.id}", params: payload.merge(format: :scim)
817
490
  }.to_not change { MockUser.count }
818
491
 
819
- expect(response.status ).to eql(200)
820
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
821
-
492
+ expect(response.status).to eql(200)
822
493
  result = JSON.parse(response.body)
823
494
 
824
- expect(result['id']).to eql(@u2.primary_key.to_s)
495
+ expect(result['id']).to eql(@u2.id.to_s)
825
496
  expect(result['meta']['resourceType']).to eql('User')
826
497
 
827
498
  @u2.reload
@@ -845,7 +516,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
845
516
 
846
517
  it 'notes Rails validation failures' do
847
518
  expect {
848
- patch "/Users/#{@u2.primary_key}", params: {
519
+ patch "/Users/#{@u2.id}", params: {
849
520
  format: :scim,
850
521
  Operations: [
851
522
  {
@@ -857,9 +528,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
857
528
  }
858
529
  }.to_not change { MockUser.count }
859
530
 
860
- expect(response.status ).to eql(400)
861
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
862
-
531
+ expect(response.status).to eql(400)
863
532
  result = JSON.parse(response.body)
864
533
 
865
534
  expect(result['scimType']).to eql('invalidValue')
@@ -887,329 +556,20 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
887
556
  }
888
557
  }.to_not change { MockUser.count }
889
558
 
890
- expect(response.status ).to eql(404)
891
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
892
-
559
+ expect(response.status).to eql(404)
893
560
  result = JSON.parse(response.body)
894
-
895
561
  expect(result['status']).to eql('404')
896
562
  end
897
-
898
- context 'when removing users from groups' do
899
- before :each do
900
- @g1.mock_users << @u1
901
- @g1.mock_users << @u2
902
- @g1.mock_users << @u3
903
-
904
- # (Self-check) Verify group representation
905
- #
906
- get "/Groups/#{@g1.id}", params: { format: :scim }
907
-
908
- expect(response.status).to eql(200)
909
- result = JSON.parse(response.body)
910
-
911
- expect(result['members'].map { |m| m['value'] }.sort()).to eql(MockUser.pluck(:primary_key).sort())
912
- end
913
-
914
- it 'can remove all users' do
915
- expect {
916
- expect {
917
- patch "/Groups/#{@g1.id}", params: {
918
- format: :scim,
919
- Operations: [
920
- {
921
- op: 'remove',
922
- path: 'members'
923
- }
924
- ]
925
- }
926
- }.to_not change { MockUser.count }
927
- }.to_not change { MockGroup.count }
928
-
929
- get "/Groups/#{@g1.id}", params: { format: :scim }
930
-
931
- expect(response.status ).to eql(200)
932
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
933
-
934
- result = JSON.parse(response.body)
935
-
936
- expect(result['members']).to be_empty
937
- expect(@g1.reload().mock_users).to be_empty
938
- end
939
-
940
- # Define via 'let':
941
- #
942
- # * Hash 'payload', to send via 'patch'
943
- # * MockUser 'removed_user', which is the user that should be removed
944
- #
945
- shared_examples 'a user remover' do
946
- it 'which removes the identified user' do
947
- expect {
948
- expect {
949
- patch "/Groups/#{@g1.id}", params: payload()
950
- }.to_not change { MockUser.count }
951
- }.to_not change { MockGroup.count }
952
-
953
- expected_remaining_user_ids = MockUser
954
- .where.not(primary_key: removed_user().id)
955
- .pluck(:primary_key)
956
- .sort()
957
-
958
- get "/Groups/#{@g1.id}", params: { format: :scim }
959
-
960
- expect(response.status ).to eql(200)
961
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
962
-
963
- result = JSON.parse(response.body)
964
-
965
- expect(result['members'].map { |m| m['value'] }.sort()).to eql(expected_remaining_user_ids)
966
- expect(@g1.reload().mock_users.map(&:primary_key).sort()).to eql(expected_remaining_user_ids)
967
- end
968
- end
969
-
970
- # https://tools.ietf.org/html/rfc7644#section-3.5.2.2
971
- #
972
- context 'and using an RFC-compliant payload' do
973
- let(:removed_user) { @u2 }
974
- let(:payload) do
975
- {
976
- format: :scim,
977
- Operations: [
978
- {
979
- op: 'remove',
980
- path: "members[value eq \"#{removed_user().primary_key}\"]",
981
- }
982
- ]
983
- }
984
- end
985
-
986
- it_behaves_like 'a user remover'
987
- end # context 'and using an RFC-compliant payload' do
988
-
989
- # https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#update-group-remove-members
990
- #
991
- context 'and using a Microsoft variant payload' do
992
- let(:removed_user) { @u2 }
993
- let(:payload) do
994
- {
995
- format: :scim,
996
- Operations: [
997
- {
998
- op: 'remove',
999
- path: 'members',
1000
- value: [{
1001
- '$ref' => nil,
1002
- 'value' => removed_user().primary_key
1003
- }]
1004
- }
1005
- ]
1006
- }
1007
- end
1008
-
1009
- it_behaves_like 'a user remover'
1010
- end # context 'and using a Microsoft variant payload' do
1011
-
1012
- # https://help.salesforce.com/s/articleView?id=sf.identity_scim_manage_groups.htm&type=5
1013
- #
1014
- context 'and using a Salesforce variant payload' do
1015
- let(:removed_user) { @u2 }
1016
- let(:payload) do
1017
- {
1018
- format: :scim,
1019
- Operations: [
1020
- {
1021
- op: 'remove',
1022
- path: 'members',
1023
- value: {
1024
- 'members' => [{
1025
- '$ref' => nil,
1026
- 'value' => removed_user().primary_key
1027
- }]
1028
- }
1029
- }
1030
- ]
1031
- }
1032
- end
1033
-
1034
- it_behaves_like 'a user remover'
1035
- end # context 'and using a Salesforce variant payload' do
1036
- end # "context 'when removing users from groups' do"
1037
-
1038
- context 'with a block' do
1039
- it 'invokes the block' do
1040
- payload = {
1041
- format: :scim,
1042
- Operations: [
1043
- {
1044
- op: 'add',
1045
- path: 'userName',
1046
- value: '4'
1047
- },
1048
- {
1049
- op: 'replace',
1050
- path: 'emails[type eq "work"]',
1051
- value: { type: 'work', value: 'work_4@test.com' }
1052
- }
1053
- ]
1054
- }
1055
-
1056
- expect_any_instance_of(CustomUpdateMockUsersController).to receive(:update).once.and_call_original
1057
- expect {
1058
- patch "/CustomUpdateUsers/#{@u2.primary_key}", params: payload
1059
- }.to_not change { MockUser.count }
1060
-
1061
- expect(response.status ).to eql(200)
1062
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1063
-
1064
- result = JSON.parse(response.body)
1065
-
1066
- expect(result['id']).to eql(@u2.primary_key.to_s)
1067
- expect(result['meta']['resourceType']).to eql('User')
1068
-
1069
- @u2.reload
1070
-
1071
- expect(@u2.username ).to eql('4')
1072
- expect(@u2.first_name ).to eql(CustomUpdateMockUsersController::OVERRIDDEN_NAME)
1073
- expect(@u2.work_email_address).to eql('work_4@test.com')
1074
- end
1075
-
1076
- it 'notes Rails validation failures' do
1077
- expect_any_instance_of(CustomUpdateMockUsersController).to receive(:update).once.and_call_original
1078
- expect {
1079
- patch "/CustomUpdateUsers/#{@u2.primary_key}", params: {
1080
- format: :scim,
1081
- Operations: [
1082
- {
1083
- op: 'add',
1084
- path: 'userName',
1085
- value: MockUser::INVALID_USERNAME
1086
- }
1087
- ]
1088
- }
1089
- }.to_not change { MockUser.count }
1090
-
1091
- expect(response.status ).to eql(400)
1092
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1093
-
1094
- result = JSON.parse(response.body)
1095
-
1096
- expect(result['scimType']).to eql('invalidValue')
1097
- expect(result['detail']).to include('is reserved')
1098
-
1099
- @u2.reload
1100
-
1101
- expect(@u2.username).to eql('2')
1102
- expect(@u2.first_name).to eql('Foo')
1103
- expect(@u2.last_name).to eql('Bar')
1104
- expect(@u2.home_email_address).to eql('home_2@test.com')
1105
- end
1106
- end # "context 'with a block' do"
1107
563
  end # "context '#update' do"
1108
564
 
1109
- # ===========================================================================
1110
- # In-passing parts of tests above show that #create, #replace and #update all
1111
- # route through #save!, so now add some unit tests for that and for exception
1112
- # handling overrides invoked via #save!.
1113
- # ===========================================================================
1114
-
1115
- context 'overriding #save!' do
1116
- it 'invokes a block if given one' do
1117
- mock_before = MockUser.all.to_a
1118
- attributes = { userName: '5' } # Minimum required by schema
1119
-
1120
- expect_any_instance_of(CustomSaveMockUsersController).to receive(:create).once.and_call_original
1121
- expect {
1122
- post "/CustomSaveUsers", params: attributes.merge(format: :scim)
1123
- }.to change { MockUser.count }.by(1)
1124
-
1125
- mock_after = MockUser.all.to_a
1126
- new_mock = (mock_after - mock_before).first
1127
-
1128
- expect(response.status ).to eql(201)
1129
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1130
-
1131
- expect(new_mock.username).to eql(CustomSaveMockUsersController::CUSTOM_SAVE_BLOCK_USERNAME_INDICATOR)
1132
- end
1133
- end # "context 'overriding #save!' do
1134
-
1135
- context 'custom on-save exceptions' do
1136
- MockUsersController.new.send(:scimitar_rescuable_exceptions).each do | exception_class |
1137
- it "handles out-of-box exception #{exception_class}" do
1138
- expect_any_instance_of(MockUsersController).to receive(:create).once.and_call_original
1139
- expect_any_instance_of(MockUsersController).to receive(:save! ).once.and_call_original
1140
-
1141
- expect_any_instance_of(MockUser).to receive(:save!).once { raise exception_class }
1142
-
1143
- expect {
1144
- post "/Users", params: { format: :scim, userName: SecureRandom.uuid }
1145
- }.to_not change { MockUser.count }
1146
-
1147
- expected_status, expected_prefix = if exception_class == ActiveRecord::RecordNotUnique
1148
- [409, 'Operation failed due to a uniqueness constraint: ']
1149
- else
1150
- [400, 'Operation failed since record has become invalid: ']
1151
- end
1152
-
1153
- expect(response.status ).to eql(expected_status)
1154
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1155
-
1156
- result = JSON.parse(response.body)
1157
-
1158
- # Check basic SCIM error rendering - good enough given other tests
1159
- # elsewhere. Exact message varies by exception.
1160
- #
1161
- expect(result['detail']).to start_with(expected_prefix)
1162
- end
1163
- end
1164
-
1165
- it 'handles custom exceptions' do
1166
- exception_class = RuntimeError # (for testing only; usually, this would provoke a 500 response)
1167
-
1168
- expect_any_instance_of(MockUsersController).to receive(:create).once.and_call_original
1169
- expect_any_instance_of(MockUsersController).to receive(:save! ).once.and_call_original
1170
-
1171
- expect_any_instance_of(MockUsersController).to receive(:scimitar_rescuable_exceptions).once { [ exception_class ] }
1172
- expect_any_instance_of(MockUser ).to receive(:save! ).once { raise exception_class }
1173
-
1174
- expect {
1175
- post "/Users", params: { format: :scim, userName: SecureRandom.uuid }
1176
- }.to_not change { MockUser.count }
1177
-
1178
- expect(response.status ).to eql(400)
1179
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1180
-
1181
- result = JSON.parse(response.body)
1182
-
1183
- expect(result['detail']).to start_with('Operation failed since record has become invalid: ')
1184
- end
1185
-
1186
- it 'reports other exceptions as 500s' do
1187
- expect_any_instance_of(MockUsersController).to receive(:create).once.and_call_original
1188
- expect_any_instance_of(MockUsersController).to receive(:save! ).once.and_call_original
1189
-
1190
- expect_any_instance_of(MockUser).to receive(:save!).once { raise RuntimeError }
1191
-
1192
- expect {
1193
- post "/Users", params: { format: :scim, userName: SecureRandom.uuid }
1194
- }.to_not change { MockUser.count }
1195
-
1196
- expect(response.status ).to eql(500)
1197
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1198
-
1199
- result = JSON.parse(response.body)
1200
-
1201
- expect(result['detail']).to eql('RuntimeError')
1202
- end
1203
- end
1204
-
1205
565
  # ===========================================================================
1206
566
 
1207
567
  context '#destroy' do
1208
- it 'deletes an item if given no block' do
568
+ it 'deletes an item if given no blok' do
1209
569
  expect_any_instance_of(MockUsersController).to receive(:destroy).once.and_call_original
1210
570
  expect_any_instance_of(MockUser).to receive(:destroy!).once.and_call_original
1211
571
  expect {
1212
- delete "/Users/#{@u2.primary_key}", params: { format: :scim }
572
+ delete "/Users/#{@u2.id}", params: { format: :scim }
1213
573
  }.to change { MockUser.count }.by(-1)
1214
574
 
1215
575
  expect(response.status).to eql(204)
@@ -1221,7 +581,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
1221
581
  expect_any_instance_of(MockUser).to_not receive(:destroy!)
1222
582
 
1223
583
  expect {
1224
- delete "/CustomDestroyUsers/#{@u2.primary_key}", params: { format: :scim }
584
+ delete "/CustomDestroyUsers/#{@u2.id}", params: { format: :scim }
1225
585
  }.to_not change { MockUser.count }
1226
586
 
1227
587
  expect(response.status).to eql(204)
@@ -1236,11 +596,8 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
1236
596
  delete '/Users/xyz', params: { format: :scim }
1237
597
  }.to_not change { MockUser.count }
1238
598
 
1239
- expect(response.status ).to eql(404)
1240
- expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
1241
-
599
+ expect(response.status).to eql(404)
1242
600
  result = JSON.parse(response.body)
1243
-
1244
601
  expect(result['status']).to eql('404')
1245
602
  end
1246
603
  end # "context '#destroy' do"