Skip to content

Commit a9bac8b

Browse files
committed
Add unit tests
1 parent 3208551 commit a9bac8b

File tree

3 files changed

+747
-0
lines changed

3 files changed

+747
-0
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as sinon from 'sinon'
7+
import * as assert from 'assert'
8+
import { SagemakerDevSpaceNode } from '../../../../awsService/sagemaker/explorer/sagemakerDevSpaceNode'
9+
import { SagemakerHyperpodNode } from '../../../../awsService/sagemaker/explorer/sagemakerHyperpodNode'
10+
import { HyperpodDevSpace, HyperpodCluster, KubectlClient } from '../../../../shared/clients/kubectlClient'
11+
import { SagemakerClient } from '../../../../shared/clients/sagemaker'
12+
13+
describe('SagemakerDevSpaceNode', function () {
14+
let testNode: SagemakerDevSpaceNode
15+
let mockParent: SagemakerHyperpodNode
16+
let mockKubectlClient: sinon.SinonStubbedInstance<KubectlClient>
17+
let mockDevSpace: HyperpodDevSpace
18+
let mockHyperpodCluster: HyperpodCluster
19+
let mockSagemakerClient: sinon.SinonStubbedInstance<SagemakerClient>
20+
const testRegion = 'us-east-1'
21+
22+
beforeEach(function () {
23+
mockSagemakerClient = sinon.createStubInstance(SagemakerClient)
24+
mockParent = new SagemakerHyperpodNode(testRegion, mockSagemakerClient as any)
25+
mockKubectlClient = sinon.createStubInstance(KubectlClient)
26+
mockDevSpace = {
27+
name: 'test-space',
28+
namespace: 'test-namespace',
29+
cluster: 'test-cluster',
30+
group: 'sagemaker.aws.amazon.com',
31+
version: 'v1',
32+
plural: 'devspaces',
33+
status: 'Stopped',
34+
appType: 'jupyterlab',
35+
creator: 'test-user',
36+
accessType: 'Public',
37+
}
38+
mockHyperpodCluster = {
39+
clusterName: 'test-cluster',
40+
clusterArn: 'arn:aws:sagemaker:us-east-1:123456789012:cluster/test-cluster',
41+
status: 'InService',
42+
regionCode: testRegion,
43+
}
44+
45+
sinon.stub(mockParent, 'getKubectlClient').returns(mockKubectlClient as any)
46+
sinon.stub(mockParent, 'trackPendingNode').returns()
47+
48+
testNode = new SagemakerDevSpaceNode(mockParent, mockDevSpace, mockHyperpodCluster, testRegion)
49+
})
50+
51+
afterEach(function () {
52+
sinon.restore()
53+
})
54+
55+
describe('buildLabel', function () {
56+
it('should return formatted label with name and status', function () {
57+
const label = testNode.buildLabel()
58+
assert.strictEqual(label, 'test-space (Stopped)')
59+
})
60+
})
61+
62+
describe('buildDescription', function () {
63+
it('should return access type description', function () {
64+
const description = testNode.buildDescription()
65+
assert.strictEqual(description, 'Public space')
66+
})
67+
68+
it('should default to Public when accessType is undefined', function () {
69+
const newDevSpace = { ...mockDevSpace, accessType: 'Public' }
70+
const newNode = new SagemakerDevSpaceNode(mockParent, newDevSpace, mockHyperpodCluster, testRegion)
71+
const description = newNode.buildDescription()
72+
assert.strictEqual(description, 'Public space')
73+
})
74+
})
75+
76+
describe('getContext', function () {
77+
it('should return transitional context for Starting status', function () {
78+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Starting')
79+
const context = (testNode as any).getContext()
80+
assert.strictEqual(context, 'awsSagemakerHyperpodDevSpaceTransitionalNode')
81+
getStatusStub.restore()
82+
})
83+
84+
it('should return stopped context for Stopped status', function () {
85+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Stopped')
86+
const context = (testNode as any).getContext()
87+
assert.strictEqual(context, 'awsSagemakerHyperpodDevSpaceStoppedNode')
88+
getStatusStub.restore()
89+
})
90+
91+
it('should return running context for Running status', function () {
92+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Running')
93+
const context = (testNode as any).getContext()
94+
assert.strictEqual(context, 'awsSagemakerHyperpodDevSpaceRunningNode')
95+
getStatusStub.restore()
96+
})
97+
98+
it('should return error context for unknown status', function () {
99+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Unknown')
100+
const context = (testNode as any).getContext()
101+
assert.strictEqual(context, 'awsSagemakerHyperpodDevSpaceErrorNode')
102+
getStatusStub.restore()
103+
})
104+
})
105+
106+
describe('isPending', function () {
107+
it('should return false for Running status', function () {
108+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Running')
109+
assert.strictEqual(testNode.isPending(), false)
110+
getStatusStub.restore()
111+
})
112+
113+
it('should return false for Stopped status', function () {
114+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Stopped')
115+
assert.strictEqual(testNode.isPending(), false)
116+
getStatusStub.restore()
117+
})
118+
119+
it('should return true for Starting status', function () {
120+
const getStatusStub = sinon.stub(testNode, 'status').get(() => 'Starting')
121+
assert.strictEqual(testNode.isPending(), true)
122+
getStatusStub.restore()
123+
})
124+
})
125+
126+
describe('getDevSpaceKey', function () {
127+
it('should return formatted devspace key', function () {
128+
const key = testNode.getDevSpaceKey()
129+
assert.strictEqual(key, 'test-cluster-test-namespace-test-space')
130+
})
131+
})
132+
133+
describe('updateWorkspaceStatus', function () {
134+
it('should update status from kubectl client', async function () {
135+
mockKubectlClient.getHyperpodSpaceStatus.resolves('Running')
136+
137+
await testNode.updateWorkspaceStatus()
138+
139+
assert.strictEqual(testNode.status, 'Running')
140+
sinon.assert.calledOnce(mockKubectlClient.getHyperpodSpaceStatus)
141+
})
142+
143+
it('should handle errors gracefully', async function () {
144+
mockKubectlClient.getHyperpodSpaceStatus.rejects(new Error('API Error'))
145+
146+
await testNode.updateWorkspaceStatus()
147+
148+
// Should not throw, just log warning
149+
sinon.assert.calledOnce(mockKubectlClient.getHyperpodSpaceStatus)
150+
})
151+
})
152+
153+
describe('buildTooltip', function () {
154+
it('should format tooltip with all devspace details', function () {
155+
const tooltip = testNode.buildTooltip()
156+
157+
assert.ok(tooltip.includes('test-space'))
158+
assert.ok(tooltip.includes('test-namespace'))
159+
assert.ok(tooltip.includes('test-cluster'))
160+
assert.ok(tooltip.includes('test-user'))
161+
assert.ok(tooltip.includes('Hyperpod'))
162+
})
163+
})
164+
165+
describe('buildIconPath', function () {
166+
it('should return jupyter icon for jupyterlab app type', function () {
167+
testNode.devSpace.appType = 'jupyterlab'
168+
169+
const iconPath = testNode.buildIconPath()
170+
171+
assert.ok(iconPath !== undefined)
172+
})
173+
174+
it('should return code editor icon for code-editor app type', function () {
175+
testNode.devSpace.appType = 'code-editor'
176+
177+
const iconPath = testNode.buildIconPath()
178+
179+
assert.ok(iconPath !== undefined)
180+
})
181+
182+
it('should return undefined for unknown app types', function () {
183+
testNode.devSpace.appType = 'unknown-type'
184+
185+
const iconPath = testNode.buildIconPath()
186+
187+
assert.strictEqual(iconPath, undefined)
188+
})
189+
})
190+
191+
describe('updateWorkspace', function () {
192+
it('should update all node properties and track pending if needed', function () {
193+
const isPendingStub = sinon.stub(testNode, 'isPending').returns(true)
194+
195+
testNode.updateWorkspace()
196+
197+
// Should update properties
198+
assert.ok(testNode.label)
199+
assert.ok(testNode.description)
200+
assert.ok(testNode.tooltip)
201+
assert.ok(testNode.contextValue)
202+
203+
isPendingStub.restore()
204+
})
205+
})
206+
207+
describe('refreshNode', function () {
208+
it('should update status and refresh VS Code explorer', async function () {
209+
const updateStatusStub = sinon.stub(testNode, 'updateWorkspaceStatus').resolves()
210+
211+
await testNode.refreshNode()
212+
213+
sinon.assert.calledOnce(updateStatusStub)
214+
// Note: VS Code commands.executeCommand is mocked by the test framework
215+
216+
updateStatusStub.restore()
217+
})
218+
})
219+
})

0 commit comments

Comments
 (0)