Skip to content

Commit d699533

Browse files
committed
address the comments and add unit tests
1 parent 025781d commit d699533

File tree

4 files changed

+83
-5
lines changed

4 files changed

+83
-5
lines changed

packages/core/src/awsService/sagemaker/sagemakerSpace.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import { getIcon, IconPath } from '../../shared/icons'
1111
import { generateSpaceStatus, updateIdleFile, startMonitoringTerminalActivity, ActivityCheckInterval } from './utils'
1212
import { UserActivity } from '../../shared/extensionUtilities'
1313
import { getLogger } from '../../shared/logger/logger'
14+
import { ToolkitError } from '../../shared/errors'
15+
16+
const logger = getLogger('sagemaker')
1417

1518
export class SagemakerSpace {
1619
public label: string = ''
@@ -109,6 +112,8 @@ export class SagemakerSpace {
109112
DomainId: this.spaceApp.DomainId,
110113
SpaceName: this.spaceApp.SpaceName,
111114
})
115+
// If the App is not null and AppName exists -> use DescribeApp API (requires AppName as a parameter)
116+
// otherwise -> use ListApp API, with given DomainId and SpaceName
112117
let app
113118
if (this.spaceApp.App?.AppName) {
114119
app = await this.client.describeApp({
@@ -118,7 +123,14 @@ export class SagemakerSpace {
118123
SpaceName: this.spaceApp.SpaceName,
119124
})
120125
} else if (this.spaceApp.DomainId && this.spaceApp.SpaceName) {
121-
app = await this.client.getAppBySpace(this.spaceApp.DomainId, this.spaceApp.SpaceName)
126+
app = await this.client.listAppForSpace(this.spaceApp.DomainId, this.spaceApp.SpaceName)
127+
} else {
128+
logger.error(
129+
`updateSpaceAppStatus: unable to get app, [AppName: ${this.spaceApp.App?.AppName}], [DomainId: ${this.spaceApp.DomainId}], [SpaceName: ${this.spaceApp.SpaceName}]`
130+
)
131+
throw new ToolkitError(
132+
`Cannot update app status without [AppName: ${this.spaceApp.App?.AppName}] or [DomainId: ${this.spaceApp.DomainId} and SpaceName: ${this.spaceApp.SpaceName}]`
133+
)
122134
}
123135

124136
// AWS DescribeSpace API returns full details with property names like 'SpaceSettings'
@@ -199,7 +211,6 @@ export class SagemakerSpace {
199211
* Sets up user activity monitoring for SageMaker spaces
200212
*/
201213
export async function setupUserActivityMonitoring(extensionContext: vscode.ExtensionContext): Promise<void> {
202-
const logger = getLogger()
203214
logger.info('setupUserActivityMonitoring: Starting user activity monitoring setup')
204215

205216
const tmpDirectory = '/tmp/'

packages/core/src/shared/clients/sagemaker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ export class SagemakerClient extends ClientWrapper<SageMakerClient> {
126126
return this.makeRequest(DeleteAppCommand, request)
127127
}
128128

129-
public async getAppBySpace(domainId: string, spaceName: string): Promise<AppDetails | undefined> {
129+
public async listAppForSpace(domainId: string, spaceName: string): Promise<AppDetails | undefined> {
130130
const appsList = await this.listApps({ DomainIdEquals: domainId, SpaceNameEquals: spaceName })
131131
.flatten()
132132
.promise()
133-
return appsList[0]
133+
return appsList[0] // At most one App for one SagemakerSpace
134134
}
135135

136136
public async startSpace(spaceName: string, domainId: string) {

packages/core/src/test/awsService/sagemaker/sagemakerSpace.test.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('SagemakerSpace', function () {
6363

6464
mockClient.describeSpace.resolves(mockDescribeSpaceResponse)
6565
mockClient.describeApp.resolves(mockDescribeAppResponse)
66-
mockClient.getAppBySpace.resolves(mockDescribeAppResponse)
66+
mockClient.listAppForSpace.resolves(mockDescribeAppResponse)
6767

6868
const space = new SagemakerSpace(mockClient as any, 'us-east-1', mockSpaceApp)
6969
const updateSpaceSpy = sinon.spy(space, 'updateSpace')
@@ -126,5 +126,37 @@ describe('SagemakerSpace', function () {
126126
assert.strictEqual(updateSpaceArgs.OwnershipSettingsSummary, undefined)
127127
assert.strictEqual(updateSpaceArgs.SpaceSharingSettingsSummary, undefined)
128128
})
129+
130+
it('should use listAppForSpace when AppName is not available', async function () {
131+
const mockDescribeSpaceResponse = {
132+
SpaceName: 'test-space',
133+
Status: 'InService',
134+
DomainId: 'test-domain',
135+
$metadata: { requestId: 'test-request-id' },
136+
}
137+
138+
const mockAppFromList = {
139+
AppName: 'listed-app',
140+
Status: 'InService',
141+
$metadata: { requestId: 'test-request-id' },
142+
}
143+
144+
mockClient.describeSpace.resolves(mockDescribeSpaceResponse)
145+
mockClient.listAppForSpace.resolves(mockAppFromList)
146+
147+
// Create space without App.AppName
148+
const spaceWithoutAppName: SagemakerSpaceApp = {
149+
...mockSpaceApp,
150+
App: undefined,
151+
}
152+
153+
const space = new SagemakerSpace(mockClient as any, 'us-east-1', spaceWithoutAppName)
154+
await space.updateSpaceAppStatus()
155+
156+
// Verify listAppForSpace was called instead of describeApp
157+
assert.ok(mockClient.listAppForSpace.calledOnce)
158+
assert.ok(mockClient.listAppForSpace.calledWith('test-domain', 'test-space'))
159+
assert.ok(mockClient.describeApp.notCalled)
160+
})
129161
})
130162
})

packages/core/src/test/shared/clients/sagemakerClient.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,41 @@ describe('SagemakerClient.listSpaceApps', function () {
173173
})
174174
})
175175

176+
describe('SagemakerClient.listAppForSpace', function () {
177+
const region = 'test-region'
178+
let client: SagemakerClient
179+
let listAppsStub: sinon.SinonStub
180+
181+
beforeEach(function () {
182+
client = new SagemakerClient(region)
183+
listAppsStub = sinon.stub(client, 'listApps')
184+
})
185+
186+
afterEach(function () {
187+
sinon.restore()
188+
})
189+
190+
it('returns first app for given domain and space', async function () {
191+
const appDetails: AppDetails[] = [
192+
{ AppName: 'app1', DomainId: 'domain1', SpaceName: 'space1', AppType: AppType.CodeEditor },
193+
]
194+
listAppsStub.returns(intoCollection([appDetails]))
195+
196+
const result = await client.listAppForSpace('domain1', 'space1')
197+
198+
assert.strictEqual(result?.AppName, 'app1')
199+
sinon.assert.calledWith(listAppsStub, { DomainIdEquals: 'domain1', SpaceNameEquals: 'space1' })
200+
})
201+
202+
it('returns undefined when no apps found', async function () {
203+
listAppsStub.returns(intoCollection([[]]))
204+
205+
const result = await client.listAppForSpace('domain1', 'space1')
206+
207+
assert.strictEqual(result, undefined)
208+
})
209+
})
210+
176211
describe('SagemakerClient.waitForAppInService', function () {
177212
const region = 'test-region'
178213
let client: SagemakerClient

0 commit comments

Comments
 (0)