|
5 | 5 |
|
6 | 6 | import assert from 'assert'
|
7 | 7 | import * as sinon from 'sinon'
|
8 |
| -import { AuthUtil } from 'aws-core-vscode/codewhisperer' |
9 |
| -import { createTestAuthUtil } from 'aws-core-vscode/test' |
10 |
| -import { constants } from 'aws-core-vscode/auth' |
| 8 | +import * as path from 'path' |
| 9 | +import { AuthUtil, amazonQScopes } from 'aws-core-vscode/codewhisperer' |
| 10 | +import { createTestAuthUtil, TestFolder } from 'aws-core-vscode/test' |
| 11 | +import { constants, cache } from 'aws-core-vscode/auth' |
11 | 12 | import { auth2 } from 'aws-core-vscode/auth'
|
| 13 | +import { mementoUtils, fs } from 'aws-core-vscode/shared' |
12 | 14 |
|
13 | 15 | describe('AuthUtil', async function () {
|
14 | 16 | let auth: any
|
@@ -193,4 +195,145 @@ describe('AuthUtil', async function () {
|
193 | 195 | assert.ok(clearCacheSpy.called)
|
194 | 196 | })
|
195 | 197 | })
|
| 198 | + |
| 199 | + describe('migrateSsoConnectionToLsp', function () { |
| 200 | + let memento: any |
| 201 | + let cacheDir: string |
| 202 | + let fromRegistrationFile: string |
| 203 | + let fromTokenFile: string |
| 204 | + |
| 205 | + const validProfile = { |
| 206 | + type: 'sso', |
| 207 | + startUrl: 'https://test2.com', |
| 208 | + ssoRegion: 'us-east-1', |
| 209 | + scopes: amazonQScopes, |
| 210 | + metadata: { |
| 211 | + connectionState: 'valid', |
| 212 | + }, |
| 213 | + } |
| 214 | + |
| 215 | + beforeEach(async function () { |
| 216 | + memento = { |
| 217 | + get: sinon.stub(), |
| 218 | + update: sinon.stub().resolves(), |
| 219 | + } |
| 220 | + cacheDir = (await TestFolder.create()).path |
| 221 | + |
| 222 | + sinon.stub(mementoUtils, 'getEnvironmentSpecificMemento').returns(memento) |
| 223 | + sinon.stub(cache, 'getCacheDir').returns(cacheDir) |
| 224 | + |
| 225 | + fromTokenFile = cache.getTokenCacheFile(cacheDir, 'profile1') |
| 226 | + const registrationKey = { |
| 227 | + startUrl: validProfile.startUrl, |
| 228 | + region: validProfile.ssoRegion, |
| 229 | + scopes: amazonQScopes, |
| 230 | + } |
| 231 | + fromRegistrationFile = cache.getRegistrationCacheFile(cacheDir, registrationKey) |
| 232 | + |
| 233 | + const registrationData = { test: 'registration' } |
| 234 | + const tokenData = { test: 'token' } |
| 235 | + |
| 236 | + await fs.writeFile(fromRegistrationFile, JSON.stringify(registrationData)) |
| 237 | + await fs.writeFile(fromTokenFile, JSON.stringify(tokenData)) |
| 238 | + }) |
| 239 | + |
| 240 | + afterEach(async function () { |
| 241 | + sinon.restore() |
| 242 | + }) |
| 243 | + |
| 244 | + it('migrates valid SSO connection', async function () { |
| 245 | + memento.get.returns({ profile1: validProfile }) |
| 246 | + |
| 247 | + const updateProfileStub = sinon.stub((auth as any).session, 'updateProfile').resolves() |
| 248 | + |
| 249 | + await auth.migrateSsoConnectionToLsp('test-client') |
| 250 | + |
| 251 | + assert.ok(updateProfileStub.calledOnce) |
| 252 | + assert.ok(memento.update.calledWith('auth.profiles', undefined)) |
| 253 | + |
| 254 | + const files = await fs.readdir(cacheDir) |
| 255 | + assert.strictEqual(files.length, 2) // Should have both the token and registration file |
| 256 | + |
| 257 | + // Verify file contents were preserved |
| 258 | + const newFiles = files.map((f) => path.join(cacheDir, f[0])) |
| 259 | + for (const file of newFiles) { |
| 260 | + const content = await fs.readFileText(file) |
| 261 | + const parsed = JSON.parse(content) |
| 262 | + assert.ok(parsed.test === 'registration' || parsed.test === 'token') |
| 263 | + } |
| 264 | + }) |
| 265 | + |
| 266 | + it('does not migrate if no matching SSO profile exists', async function () { |
| 267 | + const mockProfiles = { |
| 268 | + 'test-profile': { |
| 269 | + type: 'iam', |
| 270 | + startUrl: 'https://test.com', |
| 271 | + ssoRegion: 'us-east-1', |
| 272 | + }, |
| 273 | + } |
| 274 | + memento.get.returns(mockProfiles) |
| 275 | + |
| 276 | + await auth.migrateSsoConnectionToLsp('test-client') |
| 277 | + |
| 278 | + // Assert that the file names have not updated |
| 279 | + const files = await fs.readdir(cacheDir) |
| 280 | + assert.ok(files.length === 2) |
| 281 | + assert.ok(await fs.exists(fromRegistrationFile)) |
| 282 | + assert.ok(await fs.exists(fromTokenFile)) |
| 283 | + assert.ok(!memento.update.called) |
| 284 | + }) |
| 285 | + |
| 286 | + it('migrates only profile with matching scopes', async function () { |
| 287 | + const mockProfiles = { |
| 288 | + profile1: validProfile, |
| 289 | + profile2: { |
| 290 | + type: 'sso', |
| 291 | + startUrl: 'https://test.com', |
| 292 | + ssoRegion: 'us-east-1', |
| 293 | + scopes: ['different:scope'], |
| 294 | + metadata: { |
| 295 | + connectionState: 'valid', |
| 296 | + }, |
| 297 | + }, |
| 298 | + } |
| 299 | + memento.get.returns(mockProfiles) |
| 300 | + |
| 301 | + const updateProfileStub = sinon.stub((auth as any).session, 'updateProfile').resolves() |
| 302 | + |
| 303 | + await auth.migrateSsoConnectionToLsp('test-client') |
| 304 | + |
| 305 | + assert.ok(updateProfileStub.calledOnce) |
| 306 | + assert.ok(memento.update.calledWith('auth.profiles', undefined)) |
| 307 | + assert.deepStrictEqual(updateProfileStub.firstCall.args[0], { |
| 308 | + startUrl: validProfile.startUrl, |
| 309 | + region: validProfile.ssoRegion, |
| 310 | + scopes: validProfile.scopes, |
| 311 | + }) |
| 312 | + }) |
| 313 | + |
| 314 | + it('uses valid connection state when multiple profiles exist', async function () { |
| 315 | + const mockProfiles = { |
| 316 | + profile2: { |
| 317 | + ...validProfile, |
| 318 | + metadata: { |
| 319 | + connectionState: 'invalid', |
| 320 | + }, |
| 321 | + }, |
| 322 | + profile1: validProfile, |
| 323 | + } |
| 324 | + memento.get.returns(mockProfiles) |
| 325 | + |
| 326 | + const updateProfileStub = sinon.stub((auth as any).session, 'updateProfile').resolves() |
| 327 | + |
| 328 | + await auth.migrateSsoConnectionToLsp('test-client') |
| 329 | + |
| 330 | + assert.ok( |
| 331 | + updateProfileStub.calledWith({ |
| 332 | + startUrl: validProfile.startUrl, |
| 333 | + region: validProfile.ssoRegion, |
| 334 | + scopes: validProfile.scopes, |
| 335 | + }) |
| 336 | + ) |
| 337 | + }) |
| 338 | + }) |
196 | 339 | })
|
0 commit comments