@@ -10,6 +10,7 @@ import { DocPrepareCodeGenState } from '../../../amazonqDoc'
1010import { createMockSessionStateAction } from '../../amazonq/utils'
1111
1212import { createTestContext , setupTestHooks } from '../../amazonq/session/testSetup'
13+ const filesModule = require ( '../../../amazonq/util/files' )
1314
1415describe ( 'sessionStateDoc' , ( ) => {
1516 const context = createTestContext ( )
@@ -27,3 +28,179 @@ describe('sessionStateDoc', () => {
2728 } )
2829 } )
2930} )
31+
32+ describe ( 'CodeGenBase generateCode log file handling' , ( ) => {
33+ const RunCommandLogFileName = '.amazonq/dev/run_command.log'
34+
35+ const registerNewFilesStub = sinon . stub ( )
36+ registerNewFilesStub . callsFake ( ( fs : any , newFileContents : any [ ] ) => {
37+ return newFileContents
38+ } )
39+ const getDeletedFileInfosStub = sinon . stub ( )
40+ getDeletedFileInfosStub . callsFake ( ( fs : any , deletedFiles : any [ ] ) => {
41+ return [ ]
42+ } )
43+
44+ class TestCodeGen extends ( require ( '../../../amazonq/session/sessionState' ) as any ) . CodeGenBase {
45+ public generatedFiles : any [ ] = [ ]
46+ constructor ( config : any , tabID : string ) {
47+ super ( config , tabID )
48+ }
49+ protected handleProgress ( messenger : any , action : any , detail ?: string ) : void {
50+ // no-op
51+ }
52+ protected getScheme ( ) : string {
53+ return 'file'
54+ }
55+ protected getTimeoutErrorCode ( ) : string {
56+ return 'test_timeout'
57+ }
58+ protected handleGenerationComplete ( messenger : any , newFileInfo : any [ ] , action : any ) : void {
59+ this . generatedFiles = newFileInfo
60+ }
61+ protected handleError ( messenger : any , codegenResult : any ) : Error {
62+ throw new Error ( 'handleError called' )
63+ }
64+ }
65+
66+ let testConfig : any
67+ let fakeProxyClient : any
68+ let fsMock : any
69+ let telemetryMock : any
70+ let messengerMock : any
71+ let testAction : any
72+
73+ beforeEach ( ( ) => {
74+ fakeProxyClient = {
75+ getCodeGeneration : sinon . stub ( ) . resolves ( {
76+ codeGenerationStatus : { status : 'Complete' } ,
77+ codeGenerationRemainingIterationCount : 0 ,
78+ codeGenerationTotalIterationCount : 1 ,
79+ } ) ,
80+ exportResultArchive : sinon . stub ( ) ,
81+ }
82+
83+ testConfig = {
84+ conversationId : 'conv1' ,
85+ uploadId : 'upload1' ,
86+ workspaceRoots : [ '/workspace' ] ,
87+ proxyClient : fakeProxyClient ,
88+ }
89+
90+ fsMock = {
91+ stat : sinon . stub ( ) ,
92+ readFile : sinon . stub ( ) ,
93+ writeFile : sinon . stub ( ) ,
94+ }
95+
96+ telemetryMock = {
97+ setCodeGenerationResult : sinon . spy ( ) ,
98+ setNumberOfFilesGenerated : sinon . spy ( ) ,
99+ setAmazonqNumberOfReferences : sinon . spy ( ) ,
100+ setGenerateCodeIteration : sinon . spy ( ) ,
101+ setGenerateCodeLastInvocationTime : sinon . spy ( ) ,
102+ recordUserCodeGenerationTelemetry : sinon . spy ( ) ,
103+ }
104+
105+ messengerMock = {
106+ sendAnswer : sinon . spy ( ) ,
107+ }
108+
109+ testAction = {
110+ telemetry : telemetryMock ,
111+ fs : fsMock ,
112+ messenger : messengerMock ,
113+ uploadHistory : { } ,
114+ tokenSource : { token : { isCancellationRequested : false , onCancellationRequested : ( ) => { } } } ,
115+ }
116+ } )
117+
118+ afterEach ( ( ) => {
119+ sinon . restore ( )
120+ } )
121+
122+ it ( 'should append existing log file content to new log content and remove the log file entry when file exists' , async ( ) => {
123+ const logFileInfo = {
124+ name : RunCommandLogFileName ,
125+ content : 'newLog' ,
126+ }
127+ const otherFile = { name : 'other.ts' , content : 'other' }
128+
129+ fakeProxyClient . exportResultArchive . resolves ( {
130+ newFileContents : [ logFileInfo , otherFile ] ,
131+ deletedFiles : [ ] ,
132+ references : [ ] ,
133+ } )
134+
135+ fsMock . stat . resolves ( { } )
136+ fsMock . readFile . resolves ( Buffer . from ( 'existing' ) )
137+
138+ sinon . stub ( filesModule , 'registerNewFiles' ) . callsFake ( registerNewFilesStub )
139+ sinon . stub ( filesModule , 'getDeletedFileInfos' ) . callsFake ( getDeletedFileInfosStub )
140+
141+ const testCodeGen = new TestCodeGen ( testConfig , 'tab1' )
142+
143+ await testCodeGen . generateCode ( {
144+ messenger : messengerMock ,
145+ fs : fsMock ,
146+ codeGenerationId : 'codegen1' ,
147+ telemetry : telemetryMock ,
148+ workspaceFolders : { } ,
149+ action : testAction ,
150+ } )
151+
152+ const expectedFilePath = `${ testConfig . workspaceRoots [ 0 ] } /${ RunCommandLogFileName } `
153+ const fileUri = vscode . Uri . file ( expectedFilePath )
154+ sinon . assert . calledWith ( fsMock . stat , fileUri )
155+ sinon . assert . calledWith ( fsMock . readFile , fileUri )
156+
157+ assert . strictEqual ( logFileInfo . content , 'existingnewLog' )
158+ assert . deepStrictEqual ( testCodeGen . generatedFiles , [ otherFile ] )
159+
160+ sinon . restore ( )
161+ } )
162+
163+ it ( 'should create a new log file when log file does not exist' , async ( ) => {
164+ const logFileInfo = {
165+ name : RunCommandLogFileName ,
166+ content : 'newLog' ,
167+ }
168+ const otherFile = { name : 'other.ts' , content : 'other' }
169+
170+ fakeProxyClient . exportResultArchive . resolves ( {
171+ newFileContents : [ logFileInfo , otherFile ] ,
172+ deletedFiles : [ ] ,
173+ references : [ ] ,
174+ } )
175+
176+ fsMock . stat . rejects ( new Error ( 'Not found' ) )
177+ fsMock . writeFile . resolves ( )
178+
179+ sinon . stub ( filesModule , 'registerNewFiles' ) . callsFake ( registerNewFilesStub )
180+ sinon . stub ( filesModule , 'getDeletedFileInfos' ) . callsFake ( getDeletedFileInfosStub )
181+
182+ const testCodeGen = new TestCodeGen ( testConfig , 'tab1' )
183+
184+ await testCodeGen . generateCode ( {
185+ messenger : messengerMock ,
186+ fs : fsMock ,
187+ codeGenerationId : 'codegen2' ,
188+ telemetry : telemetryMock ,
189+ workspaceFolders : { } ,
190+ action : testAction ,
191+ } )
192+
193+ const expectedFilePath = `${ testConfig . workspaceRoots [ 0 ] } /${ RunCommandLogFileName } `
194+ const fileUri = vscode . Uri . file ( expectedFilePath )
195+ sinon . assert . calledWith ( fsMock . stat , fileUri )
196+ sinon . assert . calledWith ( fsMock . writeFile , fileUri , new TextEncoder ( ) . encode ( 'newLog' ) , {
197+ create : true ,
198+ overwrite : true ,
199+ } )
200+ sinon . assert . notCalled ( fsMock . readFile )
201+
202+ assert . deepStrictEqual ( testCodeGen . generatedFiles , [ otherFile ] )
203+
204+ sinon . restore ( )
205+ } )
206+ } )
0 commit comments