descope 1.0.7 → 1.1.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.
@@ -3,31 +3,25 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  def poll_for_session(descope_client, pending_ref)
6
- max_tries = 15
7
- i = 0
8
- done = false
9
- while !done && i < max_tries
6
+ @client.logger.info('Waiting for session to be created...')
7
+
8
+ SpecUtils.wait_for_condition(max_wait: 60, interval: 3, description: 'enchanted link session') do
10
9
  begin
11
- i += 1
12
- @client.logger.info('waiting 4 seconds for session to be created...')
13
- sleep(4)
14
- print '.'
15
10
  @client.logger.info("Getting session for pending_ref: #{pending_ref}...")
16
11
  jwt_response = descope_client.enchanted_link_get_session(pending_ref)
17
- done = true
12
+
13
+ if jwt_response
14
+ @client.logger.info("jwt_response: #{jwt_response}")
15
+ refresh_token = jwt_response[Descope::Mixins::Common::REFRESH_SESSION_TOKEN_NAME]['jwt']
16
+ @client.logger.info("refresh_token: #{refresh_token}")
17
+ return refresh_token
18
+ end
19
+
20
+ false
18
21
  rescue Descope::AuthException, Descope::Unauthorized => e
19
- @client.logger.info("Failed pending session, err: #{e}")
20
- nil
22
+ @client.logger.info("Waiting for session, err: #{e}")
23
+ false
21
24
  end
22
-
23
- next unless jwt_response
24
-
25
- @client.logger.info("jwt_response: #{jwt_response}")
26
- refresh_token = jwt_response[Descope::Mixins::Common::REFRESH_SESSION_TOKEN_NAME]['jwt']
27
-
28
- @client.logger.info("refresh_token: #{refresh_token}")
29
- done = true
30
- return refresh_token
31
25
  end
32
26
  end
33
27
 
@@ -62,7 +56,11 @@ describe Descope::Api::V1::Auth::EnchantedLink do
62
56
  all_users['users'].each do |user|
63
57
  if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
64
58
  @client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
65
- @client.delete_user(user['loginIds'][0])
59
+ begin
60
+ @client.delete_user(user['loginIds'][0])
61
+ rescue Descope::NotFound => e
62
+ @client.logger.info("User already deleted: #{e.message}")
63
+ end
66
64
  end
67
65
  end
68
66
  end
@@ -13,7 +13,11 @@ describe Descope::Api::V1::Auth::MagicLink do
13
13
  all_users['users'].each do |user|
14
14
  if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
15
15
  @client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
16
- @client.delete_user(user['loginIds'][0])
16
+ begin
17
+ @client.delete_user(user['loginIds'][0])
18
+ rescue Descope::NotFound => e
19
+ @client.logger.info("User already deleted: #{e.message}")
20
+ end
17
21
  end
18
22
  end
19
23
  end
@@ -21,7 +21,11 @@ describe Descope::Api::V1::Auth::OTP do
21
21
  all_users['users'].each do |user|
22
22
  if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
23
23
  @client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
24
- @client.delete_user(user['loginIds'][0])
24
+ begin
25
+ @client.delete_user(user['loginIds'][0])
26
+ rescue Descope::NotFound => e
27
+ @client.logger.info("User already deleted: #{e.message}")
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -5,6 +5,20 @@ require 'spec_helper'
5
5
  describe Descope::Api::V1::Session do
6
6
  before(:all) do
7
7
  @client = DescopeClient.new(Configuration.config)
8
+
9
+ # Cleanup any existing test users before starting
10
+ @client.logger.info('Cleaning up any existing test users before starting...')
11
+ all_users = @client.search_all_users
12
+ all_users['users'].each do |user|
13
+ if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
14
+ @client.logger.info("Deleting existing ruby spec test user #{user['loginIds'][0]}")
15
+ begin
16
+ @client.delete_user(user['loginIds'][0])
17
+ rescue Descope::NotFound => e
18
+ @client.logger.info("User already deleted: #{e.message}")
19
+ end
20
+ end
21
+ end
8
22
  end
9
23
 
10
24
  after(:all) do
@@ -13,7 +27,11 @@ describe Descope::Api::V1::Session do
13
27
  all_users['users'].each do |user|
14
28
  if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
15
29
  @client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
16
- @client.delete_user(user['loginIds'][0])
30
+ begin
31
+ @client.delete_user(user['loginIds'][0])
32
+ rescue Descope::NotFound => e
33
+ @client.logger.info("User already deleted: #{e.message}")
34
+ end
17
35
  end
18
36
  end
19
37
  end
@@ -21,9 +39,10 @@ describe Descope::Api::V1::Session do
21
39
  context 'test session methods' do
22
40
  it 'should refresh session with refresh token' do
23
41
  @password = SpecUtils.generate_password
24
- user = build(:user)
42
+ # Add timestamp to ensure unique login_id across multiple test runs
43
+ user = build(:user, login_id: "session_test_#{Time.now.to_i}_#{SecureRandom.hex(4)}")
25
44
 
26
- @client.logger.info('1. Sign up with password')
45
+ @client.logger.info("1. Sign up with password for user: #{user[:login_id]}")
27
46
  res = @client.password_sign_up(login_id: user[:login_id], password: @password, user:)
28
47
  @client.logger.info("sign up with password res: #{res}")
29
48
  original_refresh_token = res[REFRESH_SESSION_TOKEN_NAME]['jwt']
@@ -32,8 +51,8 @@ describe Descope::Api::V1::Session do
32
51
  login_res = @client.password_sign_in(login_id: user[:login_id], password: @password)
33
52
  @client.logger.info("sign_in res: #{login_res}")
34
53
 
35
- @client.logger.info('3. sleep 1 second before calling refresh_session')
36
- sleep(1)
54
+ @client.logger.info('3. Wait briefly to ensure token timestamps differ')
55
+ sleep(2) # Wait 2 seconds to ensure new token will have different 'iat' timestamp
37
56
 
38
57
  @client.logger.info('4. Refresh session')
39
58
  refresh_session_res = @client.refresh_session(refresh_token: login_res[REFRESH_SESSION_TOKEN_NAME]['jwt'])
@@ -14,7 +14,11 @@ describe Descope::Api::V1::Auth::TOTP do
14
14
  all_users['users'].each do |user|
15
15
  if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
16
16
  @client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
17
- @client.delete_user(user['loginIds'][0])
17
+ begin
18
+ @client.delete_user(user['loginIds'][0])
19
+ rescue Descope::NotFound => e
20
+ @client.logger.info("User already deleted: #{e.message}")
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -30,8 +30,16 @@ describe Descope::Api::V1::Management::AccessKey do
30
30
  @tenant_id = @client.create_tenant(name: 'some-new-tenant')['id']
31
31
  @client.logger.info('creating access key')
32
32
  @access_key = @client.create_access_key(name: @key_name, key_tenants: [{ tenant_id: @tenant_id }])
33
- @client.logger.info("waiting for access key #{@access_key['key']['id']} to be active 60 seconds")
34
- sleep 60
33
+ @client.logger.info("waiting for access key #{@access_key['key']['id']} to be active")
34
+ SpecUtils.wait_for_condition(max_wait: 65, interval: 3, description: 'access key to be active') do
35
+ begin
36
+ key = @client.load_access_key(@access_key['key']['id'])
37
+ key['key']['status'] == 'active'
38
+ rescue StandardError => e
39
+ @client.logger.info("Waiting for key activation: #{e.message}")
40
+ false
41
+ end
42
+ end
35
43
  end
36
44
 
37
45
  it 'should create the access key and load it' do
@@ -12,7 +12,12 @@ describe Descope::Api::V1::Management::Authz do
12
12
 
13
13
  context 'authz ops' do
14
14
  before(:all) do
15
- @client.authz_delete_schema
15
+ # Instead of deleting the entire schema, we'll work with it
16
+ # This allows parallel test execution
17
+ # Only delete schema if we're running in isolation
18
+ if ENV['AUTHZ_FULL_TEST'] == 'true'
19
+ @client.authz_delete_schema
20
+ end
16
21
  end
17
22
 
18
23
  it 'should create a new schema' do
@@ -160,13 +165,17 @@ describe Descope::Api::V1::Management::Authz do
160
165
  end
161
166
 
162
167
  it 'should create a relation between a resource and user' do
168
+ # Use unique resource name to avoid conflicts between parallel tests
169
+ unique_resource = "#{SpecUtils.build_prefix}some-doc"
170
+ unique_user = "#{SpecUtils.build_prefix}user1"
171
+
163
172
  @client.authz_create_relations(
164
173
  [
165
174
  {
166
- "resource": 'some-doc',
175
+ "resource": unique_resource,
167
176
  "relationDefinition": 'owner',
168
177
  "namespace": 'note',
169
- "target": 'user1'
178
+ "target": unique_user
170
179
  }
171
180
  ]
172
181
  )
@@ -176,14 +185,26 @@ describe Descope::Api::V1::Management::Authz do
176
185
  relations = @client.authz_has_relations?(
177
186
  [
178
187
  {
179
- "resource": 'some-doc',
188
+ "resource": unique_resource,
180
189
  "relationDefinition": 'viewer',
181
190
  "namespace": 'note',
182
- "target": 'user1'
191
+ "target": unique_user
183
192
  }
184
193
  ]
185
194
  )
186
195
  expect(relations['relationQueries'][0]['hasRelation']).to be_truthy
196
+
197
+ # Clean up the test relations
198
+ @client.authz_delete_relations(
199
+ [
200
+ {
201
+ "resource": unique_resource,
202
+ "relationDefinition": 'owner',
203
+ "namespace": 'note',
204
+ "target": unique_user
205
+ }
206
+ ]
207
+ )
187
208
  end
188
209
  end
189
210
  end
@@ -7,16 +7,34 @@ describe Descope::Api::V1::Management::Permission do
7
7
  raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
8
 
9
9
  @client = DescopeClient.new(Configuration.config)
10
+ @test_description = "#{SpecUtils.build_prefix} Ruby SDK"
11
+
12
+ # Cleanup any leftover permissions from previous failed runs
10
13
  @client.load_all_permissions['permissions'].each do |perm|
11
- if perm['description'] == "#{SpecUtils.build_prefix} Ruby SDK"
14
+ if perm['description'] == @test_description
12
15
  puts "Deleting permission: #{perm['name']}"
13
16
  @client.delete_permission(perm['name'])
14
17
  end
15
18
  end
16
19
  end
20
+
21
+ after(:all) do
22
+ # Safety cleanup to ensure no test permissions are left behind
23
+ @client.logger.info('Cleaning up test permissions...')
24
+ begin
25
+ @client.load_all_permissions['permissions'].each do |perm|
26
+ if perm['description'] == @test_description
27
+ @client.logger.info("Deleting leftover permission: #{perm['name']}")
28
+ @client.delete_permission(perm['name'])
29
+ end
30
+ end
31
+ rescue StandardError => e
32
+ @client.logger.info("Error during permission cleanup: #{e.message}")
33
+ end
34
+ end
17
35
 
18
36
  it 'should create update and delete a permission' do
19
- @client.create_permission(name: 'test_permission', description: "#{SpecUtils.build_prefix} Ruby SDK")
37
+ @client.create_permission(name: 'test_permission', description: @test_description)
20
38
  all_permissions = @client.load_all_permissions['permissions']
21
39
  expect(all_permissions.any? { |perm| perm['name'] == 'test_permission' }).to eq(true)
22
40
  @client.update_permission(name: 'test_permission', new_name: 'test_permission_2')
@@ -8,15 +8,29 @@ describe Descope::Api::V1::Management::Project do
8
8
 
9
9
  @client = DescopeClient.new(Configuration.config)
10
10
  @export_output = @client.export_project
11
+ @original_project_name = nil
11
12
  end
12
13
 
13
14
  context 'Test project methods' do
15
+ before(:all) do
16
+ # Get the current project name before we modify it
17
+ # Store it so we can restore it later
18
+ begin
19
+ @original_project_name = @client.export_project['project']['name']
20
+ rescue StandardError
21
+ @original_project_name = 'Ruby-SDK-Prod'
22
+ end
23
+ end
24
+
14
25
  after(:all) do
15
- @client.rename_project('Ruby-SDK-Prod')
26
+ # Restore the original project name
27
+ @client.rename_project(@original_project_name) if @original_project_name
16
28
  end
17
29
 
18
30
  it 'should rename a project' do
19
- @client.rename_project('TEST-Ruby-SDK-Prod')
31
+ # Use a unique name based on build prefix to avoid conflicts
32
+ unique_name = "#{SpecUtils.build_prefix}TEST-Ruby-SDK-Prod"
33
+ @client.rename_project(unique_name)
20
34
  end
21
35
 
22
36
  it 'should export a project' do
@@ -7,74 +7,144 @@ describe Descope::Api::V1::Management::Role do
7
7
  raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
8
 
9
9
  @client = DescopeClient.new(Configuration.config)
10
- @client.logger.info('Staring cleanup before tests...')
11
- @client.logger.info('Deleting all permissions for Ruby SDK...')
10
+ @test_prefix = SpecUtils.build_prefix
11
+ @client.logger.info("Starting cleanup before tests with prefix: #{@test_prefix}...")
12
+
13
+ # Define resource names with unique prefix for parallel execution
14
+ @permission_viewer = "#{@test_prefix}viewer"
15
+ @permission_editor = "#{@test_prefix}editor"
16
+ @permission_admin = "#{@test_prefix}admin"
17
+ @role_viewer = "#{@test_prefix}Ruby-SDK-test-viewer"
18
+ @role_editor = "#{@test_prefix}Ruby-SDK-test-editor"
19
+ @role_admin = "#{@test_prefix}Ruby-SDK-test-admin"
20
+ @tenant_name = "#{@test_prefix}Ruby-SDK-test"
21
+ @description = "#{@test_prefix}Ruby SDK"
22
+
23
+ # Cleanup any leftover resources from previous failed runs
24
+ @client.logger.info('Deleting all permissions for this test run...')
12
25
  @client.load_all_permissions['permissions'].each do |perm|
13
- if perm['description'] =~ /Ruby SDK/
26
+ if perm['description'] == @description
14
27
  @client.logger.info("Deleting permission: #{perm['name']}")
15
28
  @client.delete_permission(perm['name'])
16
29
  end
17
30
  end
18
31
 
19
- @client.logger.info('Deleting all roles for Ruby SDK...')
32
+ @client.logger.info('Deleting all roles for this test run...')
20
33
  @client.load_all_roles['roles'].each do |role|
21
- puts "got role: #{role}"
22
- if role['description'] == 'Ruby SDK'
34
+ if role['description'] == @description
23
35
  @client.logger.info("Deleting role: #{role['name']}")
24
36
  @client.delete_role(name: role['name'], tenant_id: role['tenantId'])
25
37
  end
26
38
  end
27
39
 
28
- @client.logger.info('Deleting all tenants for Ruby SDK...')
29
- @client.search_all_tenants(names: ['Ruby-SDK-test'])['tenants'].each do |tenant|
40
+ @client.logger.info('Deleting all tenants for this test run...')
41
+ @client.search_all_tenants(names: [@tenant_name])['tenants'].each do |tenant|
30
42
  @client.logger.info("Deleting tenant: #{tenant['name']}")
31
43
  @client.delete_tenant(tenant['id'])
32
44
  end
33
45
  @client.logger.info('Cleanup completed. Starting tests...')
34
46
  end
47
+
48
+ after(:all) do
49
+ # Cleanup after tests to ensure no resources are left behind
50
+ @client.logger.info('Cleaning up test resources...')
51
+
52
+ begin
53
+ @client.delete_permission(@permission_viewer) if defined?(@permission_viewer)
54
+ rescue StandardError => e
55
+ @client.logger.info("Permission #{@permission_viewer} already deleted or doesn't exist: #{e.message}")
56
+ end
57
+
58
+ begin
59
+ @client.delete_permission(@permission_editor) if defined?(@permission_editor)
60
+ rescue StandardError => e
61
+ @client.logger.info("Permission #{@permission_editor} already deleted or doesn't exist: #{e.message}")
62
+ end
63
+
64
+ begin
65
+ @client.delete_permission(@permission_admin) if defined?(@permission_admin)
66
+ rescue StandardError => e
67
+ @client.logger.info("Permission #{@permission_admin} already deleted or doesn't exist: #{e.message}")
68
+ end
69
+
70
+ # Delete any roles with our test description
71
+ begin
72
+ @client.load_all_roles['roles'].each do |role|
73
+ if role['description'] == @description
74
+ @client.delete_role(name: role['name'], tenant_id: role['tenantId'])
75
+ end
76
+ end
77
+ rescue StandardError => e
78
+ @client.logger.info("Error cleaning up roles: #{e.message}")
79
+ end
80
+
81
+ # Delete tenant
82
+ begin
83
+ @client.search_all_tenants(names: [@tenant_name])['tenants'].each do |tenant|
84
+ @client.delete_tenant(tenant['id'])
85
+ end
86
+ rescue StandardError => e
87
+ @client.logger.info("Error cleaning up tenant: #{e.message}")
88
+ end
89
+
90
+ @client.logger.info('Cleanup completed.')
91
+ end
35
92
 
36
93
  it 'should create update and delete a role' do
37
94
  @client.logger.info('Testing role creation, update, deletion and search...')
38
95
 
39
96
  # Create permissions
40
97
  @client.logger.info('creating viewer permission for role')
41
- @client.create_permission(name: 'viewer', description: 'Viewer Permission Ruby SDK')
98
+ @client.create_permission(name: @permission_viewer, description: @description)
42
99
 
43
100
  @client.logger.info('creating editor permission for role')
44
- @client.create_permission(name: 'editor', description: 'Editor Permission Ruby SDK')
101
+ @client.create_permission(name: @permission_editor, description: @description)
45
102
 
46
103
  @client.logger.info('creating admin permission for role')
47
- @client.create_permission(name: 'admin', description: 'Admin Permission Ruby SDK')
104
+ @client.create_permission(name: @permission_admin, description: @description)
48
105
 
49
106
  # Create tenants
50
- @client.logger.info('creating Ruby-SDK-test tenant')
51
- tenant_id = @client.create_tenant(name: 'Ruby-SDK-test')['id']
107
+ @client.logger.info("creating #{@tenant_name} tenant")
108
+ tenant_id = @client.create_tenant(name: @tenant_name)['id']
109
+ @client.logger.info("Created tenant with id: #{tenant_id}")
110
+
111
+ # Wait for tenant to be available (polling, up to 5 seconds)
112
+ timeout = 5.0
113
+ interval = 0.1
114
+ waited = 0.0
115
+ loop do
116
+ tenants = @client.search_all_tenants(names: [@tenant_name])['tenants']
117
+ break if tenants.any? { |t| t['id'] == tenant_id }
118
+ raise "Tenant #{@tenant_name} not available after #{timeout} seconds" if waited >= timeout
119
+ sleep(interval)
120
+ waited += interval
121
+ end
52
122
 
53
123
  # Create roles
54
- @client.logger.info('creating Ruby-SDK-test role')
55
- @client.create_role(name: 'Ruby-SDK-test-viewer', description: 'Ruby SDK', permission_names: ['viewer'])
56
- @client.logger.info('creating Ruby-SDK-test-admin role')
57
- @client.create_role(name: 'Ruby-SDK-test-admin', description: 'Ruby SDK', permission_names: ['admin'], tenant_id:)
124
+ @client.logger.info("creating #{@role_viewer} role")
125
+ @client.create_role(name: @role_viewer, description: @description, permission_names: [@permission_viewer])
126
+ @client.logger.info("creating #{@role_admin} role")
127
+ @client.create_role(name: @role_admin, description: @description, permission_names: [@permission_admin], tenant_id:)
58
128
 
59
129
  # check all roles matching the correct permission
60
130
  @client.logger.info('check all roles matching the correct permission (load roles)')
61
131
  roles = @client.load_all_roles['roles']
62
132
  roles.each do |role|
63
- expect(role['permissionNames']).to include('viewer') if role['name'] == 'Ruby-SDK-test-viewer'
64
- expect(role['permissionNames']).to include('admin') if role['name'] == 'Ruby-SDK-test-admin'
133
+ expect(role['permissionNames']).to include(@permission_viewer) if role['name'] == @role_viewer
134
+ expect(role['permissionNames']).to include(@permission_admin) if role['name'] == @role_admin
65
135
  end
66
136
 
67
137
  @client.logger.info('updating role')
68
138
  @client.update_role(
69
- name: 'Ruby-SDK-test-viewer',
70
- new_name: 'Ruby-SDK-test-editor',
71
- description: 'Ruby SDK',
72
- permission_names: ['editor']
139
+ name: @role_viewer,
140
+ new_name: @role_editor,
141
+ description: @description,
142
+ permission_names: [@permission_editor]
73
143
  )
74
144
 
75
145
  @client.logger.info('searching for roles by role names...')
76
- all_roles = @client.search_roles(role_names: %w[Ruby-SDK-test-admin Ruby-SDK-test-editor])['roles']
77
- expected_roles = %w[Ruby-SDK-test-editor Ruby-SDK-test-admin]
146
+ all_roles = @client.search_roles(role_names: [@role_admin, @role_editor])['roles']
147
+ expected_roles = [@role_editor, @role_admin]
78
148
  role_count = 0
79
149
  expected_roles.each do |expected_role|
80
150
  expect(all_roles.map { |role| role['name'] }).to include(expected_role)
@@ -83,8 +153,8 @@ describe Descope::Api::V1::Management::Role do
83
153
  expect(role_count).to eq(2)
84
154
 
85
155
  @client.logger.info('searching for roles with role name like...')
86
- all_roles = @client.search_roles(role_name_like: 'Ruby-SDK-test')['roles']
87
- expected_roles = %w[Ruby-SDK-test-editor Ruby-SDK-test-admin]
156
+ all_roles = @client.search_roles(role_name_like: "#{@test_prefix}Ruby-SDK-test")['roles']
157
+ expected_roles = [@role_editor, @role_admin]
88
158
  role_count = 0
89
159
  expected_roles.each do |expected_role|
90
160
  expect(all_roles.map { |role| role['name'] }).to include(expected_role)
@@ -94,25 +164,33 @@ describe Descope::Api::V1::Management::Role do
94
164
  expect(role_count).to eq(2)
95
165
 
96
166
  @client.logger.info('searching for roles with permission names...')
97
- all_roles = @client.search_roles(permission_names: %w[admin])['roles']
98
- expect(all_roles.map { |role| role['name'] }).to include('Ruby-SDK-test-admin')
167
+ all_roles = @client.search_roles(permission_names: [@permission_admin])['roles']
168
+ expect(all_roles.map { |role| role['name'] }).to include(@role_admin)
99
169
 
100
170
  @client.logger.info('searching for roles with tenant ids...')
101
- all_roles = @client.search_roles(role_name_like: 'Ruby-SDK-test', tenant_ids: [tenant_id])['roles']
102
- expect(all_roles.map { |role| role['name'] }).to include('Ruby-SDK-test-admin')
171
+ all_roles = @client.search_roles(role_name_like: "#{@test_prefix}Ruby-SDK-test", tenant_ids: [tenant_id])['roles']
172
+ expect(all_roles.map { |role| role['name'] }).to include(@role_admin)
103
173
 
104
174
  @client.logger.info('deleting permission')
105
175
 
106
- @client.delete_permission('editor')
107
- @client.delete_permission('admin')
176
+ @client.delete_permission(@permission_editor)
177
+ @client.delete_permission(@permission_admin)
108
178
 
109
179
  @client.logger.info('deleting editor role')
110
- @client.delete_role(name: 'Ruby-SDK-test-editor')
180
+ @client.delete_role(name: @role_editor)
111
181
 
112
182
  @client.logger.info('deleting admin role')
113
- @client.delete_role(name: 'Ruby-SDK-test-admin', tenant_id:)
183
+ begin
184
+ @client.delete_role(name: @role_admin, tenant_id:)
185
+ rescue Descope::Unauthorized, Descope::NotFound => e
186
+ @client.logger.info("Admin role already deleted or tenant invalid: #{e.message}")
187
+ end
114
188
 
115
189
  @client.logger.info('deleting tenant')
116
- @client.delete_tenant(tenant_id)
190
+ begin
191
+ @client.delete_tenant(tenant_id)
192
+ rescue Descope::NotFound => e
193
+ @client.logger.info("Tenant already deleted: #{e.message}")
194
+ end
117
195
  end
118
196
  end
@@ -102,7 +102,17 @@ describe Descope::Api::V1::Management::User do
102
102
  created_user = @client.create_user(**user)['user']
103
103
  loaded_user = @client.load_user(created_user['loginIds'][0])['user']
104
104
  expect(loaded_user['loginIds']).to eq(created_user['loginIds'])
105
- sleep 10
105
+
106
+ # Wait for user to be fully propagated before deletion
107
+ SpecUtils.wait_for_condition(max_wait: 15, interval: 2, description: 'user to be ready for deletion') do
108
+ begin
109
+ @client.load_user(created_user['loginIds'][0])
110
+ true
111
+ rescue StandardError => e
112
+ @client.logger.info("Waiting for user propagation: #{e.message}")
113
+ false
114
+ end
115
+ end
106
116
 
107
117
  @client.delete_user(created_user['loginIds'][0])
108
118
  begin
@@ -115,8 +125,10 @@ describe Descope::Api::V1::Management::User do
115
125
  it 'should search all users' do
116
126
  users = FactoryBot.build_list(:user, 5)
117
127
  @client.create_batch_users(users)
128
+ # Wait for batch creation to propagate
129
+ sleep 1.0
118
130
  all_users = @client.search_all_users
119
- sdk_users = all_users['users'].select { |user| user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User" }
131
+ sdk_users = all_users['users'].select { |user| user['middleName']&.include?('Ruby-SDK-User') }
120
132
  expect(sdk_users.length).to be >= 5
121
133
  end
122
134
 
@@ -128,7 +140,12 @@ describe Descope::Api::V1::Management::User do
128
140
  all_roles['roles'].each do |role|
129
141
  @client.delete_role(name: role['name']) if role['name'] == role_name
130
142
  end
131
- sleep 5
143
+
144
+ # Wait for role deletion to propagate
145
+ SpecUtils.wait_for_condition(max_wait: 10, interval: 1, description: 'role deletion to propagate') do
146
+ all_roles = @client.load_all_roles
147
+ all_roles['roles'].none? { |role| role['name'] == role_name }
148
+ end
132
149
 
133
150
  user_args = build(:user)
134
151
  test_user = @client.create_test_user(**user_args)['user']
@@ -94,6 +94,17 @@ describe Descope::Mixins::HTTP do
94
94
  expect(result['cookies']['DSR']).to eq('refresh_jwt_token')
95
95
  end
96
96
 
97
+ it 'parses cookies from Set-Cookie headers with symbol key (real RestClient behavior)' do
98
+ # RestClient returns headers with symbol keys like :set_cookie, not string keys
99
+ mock_headers = { set_cookie: set_cookie_headers }
100
+
101
+ result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
102
+
103
+ expect(result['cookies']).to_not be_nil
104
+ expect(result['cookies']['DS']).to eq('session_jwt_token')
105
+ expect(result['cookies']['DSR']).to eq('refresh_jwt_token')
106
+ end
107
+
97
108
  it 'parses cookies from Set-Cookie header when headers is a string' do
98
109
  mock_headers = { 'Set-Cookie' => set_cookie_headers.first }
99
110
 
@@ -120,7 +131,7 @@ describe Descope::Mixins::HTTP do
120
131
  "DS=#{jwt_session}; Path=/; Domain=custom.example.com; HttpOnly; Secure; SameSite=None",
121
132
  "DSR=#{jwt_refresh}; Path=/; Domain=custom.example.com; HttpOnly; Secure; SameSite=None; Max-Age=2592000"
122
133
  ]
123
- mock_headers = { 'set-cookie' => complex_headers }
134
+ mock_headers = { set_cookie: complex_headers }
124
135
 
125
136
  result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
126
137
 
@@ -134,7 +145,7 @@ describe Descope::Mixins::HTTP do
134
145
  'CLOUDFLARE_SESSION=cf_token; Path=/; Domain=.example.com; HttpOnly',
135
146
  'DSR=refresh_token; Path=/; Domain=dev.example.com; HttpOnly'
136
147
  ]
137
- mock_headers = { 'set-cookie' => mixed_headers }
148
+ mock_headers = { set_cookie: mixed_headers }
138
149
 
139
150
  result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
140
151
 
@@ -175,7 +186,7 @@ describe Descope::Mixins::HTTP do
175
186
  'DS=; Path=/; Domain=example.com', # Empty value
176
187
  '=value_without_name; Path=/', # No name
177
188
  ]
178
- mock_headers = { 'set-cookie' => malformed_headers }
189
+ mock_headers = { set_cookie: malformed_headers }
179
190
 
180
191
  result = @instance.safe_parse_json(mock_body, cookies: {}, headers: mock_headers)
181
192
 
@@ -186,7 +197,7 @@ describe Descope::Mixins::HTTP do
186
197
  it 'prefers RestClient cookies over Set-Cookie headers when both available' do
187
198
  mock_cookies = { 'DS' => 'restclient_token' }
188
199
  set_cookie_headers = ['DS=header_token; Path=/; Domain=example.com']
189
- mock_headers = { 'set-cookie' => set_cookie_headers }
200
+ mock_headers = { set_cookie: set_cookie_headers }
190
201
 
191
202
  result = @instance.safe_parse_json(mock_body, cookies: mock_cookies, headers: mock_headers)
192
203
 
@@ -204,7 +215,7 @@ describe Descope::Mixins::HTTP do
204
215
  allow(mock_response).to receive(:body).and_return('{"success": true}')
205
216
  allow(mock_response).to receive(:cookies).and_return({})
206
217
  allow(mock_response).to receive(:headers).and_return({
207
- 'set-cookie' => ['DS=test_token; Domain=custom.example.com']
218
+ set_cookie: ['DS=test_token; Domain=custom.example.com']
208
219
  })
209
220
 
210
221
  allow(@instance).to receive(:call).and_return(mock_response)
@@ -215,4 +226,4 @@ describe Descope::Mixins::HTTP do
215
226
  expect(result['cookies']['DS']).to eq('test_token')
216
227
  end
217
228
  end
218
- end
229
+ end