Skip to content

Commit c65aec2

Browse files
committed
added unit test covering state transitions.
1 parent e5425e6 commit c65aec2

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import assert from 'assert'
7+
import sinon from 'sinon'
8+
import { PrepareCodeGenState, ConversationNotStartedState } from '../../../amazonqFeatureDev/session/sessionState'
9+
import { createMessenger } from '../utils'
10+
import { FeatureDevClient } from '../../../amazonqFeatureDev/client/featureDev'
11+
import { Session } from '../../../amazonqFeatureDev'
12+
import { createSessionConfig } from '../../../amazonq/commons/session/sessionConfigFactory'
13+
import { Uri } from 'vscode'
14+
15+
/**
16+
* Describes the test suite for the Session State Journey.
17+
* This suite tests various aspects of session state transitions and error handling.
18+
*/
19+
describe('Session State Flow', () => {
20+
const conversationId = 'conversation-id'
21+
const uploadId = 'upload-id'
22+
const tabId = 'tab-id'
23+
const scheme = 'testScheme'
24+
let session: Session
25+
let featureDevClient: FeatureDevClient
26+
27+
beforeEach(async () => {
28+
featureDevClient = sinon.createStubInstance(FeatureDevClient)
29+
featureDevClient.createConversation = sinon.stub().resolves(conversationId)
30+
featureDevClient.createUploadUrl = sinon.stub().resolves({
31+
uploadId: uploadId,
32+
uploadUrl: 'http://test-upload-url',
33+
$response: {} as any,
34+
})
35+
36+
const messenger = createMessenger()
37+
const sessionConfig = await createSessionConfig(scheme)
38+
39+
session = new Session(sessionConfig, messenger, tabId, undefined, featureDevClient)
40+
sinon.stub(session, 'conversationId').get(() => conversationId)
41+
sinon.stub(session, 'uploadId').get(() => uploadId)
42+
})
43+
44+
afterEach(() => {
45+
sinon.restore()
46+
})
47+
48+
describe('SessionState', () => {
49+
/**
50+
* Tests the correct state journey of a session.
51+
* This test case verifies that the session follows the expected state transitions:
52+
* 1. Starts in ConversationNotStartedState
53+
* 2. Transitions to PrepareCodeGenState after preloader
54+
* 3. Remains in PrepareCodeGenState after sending a message
55+
*/
56+
it('should follow the correct state flow', async () => {
57+
assert.ok(session.state instanceof ConversationNotStartedState)
58+
59+
await session.preloader('Initial message')
60+
61+
assert.ok(session.state instanceof PrepareCodeGenState)
62+
63+
const interactStub = sinon.stub(PrepareCodeGenState.prototype, 'interact').resolves({
64+
interaction: { content: 'Test message' },
65+
nextState: new PrepareCodeGenState(
66+
{
67+
conversationId: conversationId,
68+
uploadId: uploadId,
69+
workspaceRoots: [],
70+
workspaceFolders: [
71+
{
72+
uri: Uri.parse('file:///test/workspace'),
73+
name: '',
74+
index: 0,
75+
},
76+
],
77+
proxyClient: featureDevClient,
78+
},
79+
[],
80+
[],
81+
[],
82+
tabId,
83+
0
84+
),
85+
})
86+
87+
await session.send('Test message')
88+
const prep = session.state as PrepareCodeGenState
89+
90+
assert.ok(interactStub.calledOnce)
91+
assert.ok(prep instanceof PrepareCodeGenState)
92+
assert.ok((featureDevClient.createConversation as sinon.SinonStub).calledOnce)
93+
})
94+
95+
/**
96+
* Tests the handling of errors during sending a message in the session.
97+
* This test case simulates an error during the interaction process and verifies that the session
98+
* correctly handles the error by rejecting the promise and keeping the state in PrepareCodeGenState.
99+
*/
100+
it('should handle errors during send', async () => {
101+
await session.preloader('Initial message')
102+
assert.ok(session.state instanceof PrepareCodeGenState)
103+
104+
const interactStub = sinon
105+
.stub(PrepareCodeGenState.prototype, 'interact')
106+
.rejects(new Error('Interaction failed'))
107+
108+
await assert.rejects(session.send('Test message'), {
109+
message: 'Interaction failed',
110+
})
111+
112+
assert.ok(interactStub.calledOnce)
113+
assert.ok(session.state instanceof PrepareCodeGenState)
114+
})
115+
116+
/**
117+
* Handles timeout during state transition in a session.
118+
* This test case simulates a scenario where a state transition takes longer than expected,
119+
* and ensures that the system handles the timeout appropriately.
120+
*/
121+
it('should handle timeout during state transition', async () => {
122+
await session.preloader('Initial message')
123+
assert.ok(session.state instanceof PrepareCodeGenState)
124+
125+
const interactStub = sinon.stub(PrepareCodeGenState.prototype, 'interact').callsFake(() => {
126+
return new Promise((resolve) => {
127+
setTimeout(() => {
128+
resolve({
129+
interaction: { content: 'Test message' },
130+
nextState: new PrepareCodeGenState(
131+
{
132+
conversationId: conversationId,
133+
uploadId: uploadId,
134+
workspaceRoots: [],
135+
workspaceFolders: [
136+
{
137+
uri: Uri.parse('file:///test/workspace'),
138+
name: '',
139+
index: 0,
140+
},
141+
],
142+
proxyClient: featureDevClient,
143+
},
144+
[],
145+
[],
146+
[],
147+
tabId,
148+
0
149+
),
150+
})
151+
}, 5000) // 5 second delay
152+
})
153+
})
154+
155+
const timeoutPromise = new Promise((_, reject) => {
156+
setTimeout(() => reject(new Error('Timeout')), 1000) // 1 second timeout
157+
})
158+
159+
await assert.rejects(Promise.race([session.send('Test message'), timeoutPromise]), {
160+
message: 'Timeout',
161+
})
162+
163+
assert.ok(interactStub.calledOnce)
164+
assert.ok(session.state instanceof PrepareCodeGenState)
165+
})
166+
})
167+
})

0 commit comments

Comments
 (0)