44 */
55
66import * as sinon from 'sinon'
7- import * as FakeTimers from '@sinonjs/fake-timers'
87import * as vscode from 'vscode'
98
109import assert from 'assert'
1110import { clearDocument , closeSession , tailLogGroup } from '../../../../awsService/cloudWatchLogs/commands/tailLogGroup'
12- import { LiveTailSessionLogEvent , StartLiveTailResponseStream } from '@aws-sdk/client-cloudwatch-logs'
11+ import { StartLiveTailResponseStream } from '@aws-sdk/client-cloudwatch-logs'
1312import { LiveTailSessionRegistry } from '../../../../awsService/cloudWatchLogs/registry/liveTailSessionRegistry'
1413import { LiveTailSession } from '../../../../awsService/cloudWatchLogs/registry/liveTailSession'
15- import { asyncGenerator } from '../../../../shared/utilities/collectionUtils'
1614import {
1715 TailLogGroupWizard ,
1816 TailLogGroupWizardResponse ,
1917} from '../../../../awsService/cloudWatchLogs/wizard/tailLogGroupWizard'
2018import { getTestWindow } from '../../../shared/vscode/window'
2119import { CloudWatchLogsSettings , uriToKey } from '../../../../awsService/cloudWatchLogs/cloudWatchLogsUtils'
22- import { installFakeClock } from '../../../testUtil'
23- import { DefaultAwsContext , ToolkitError } from '../../../../shared'
20+ import { DefaultAwsContext , ToolkitError , waitUntil } from '../../../../shared'
2421import { LiveTailCodeLensProvider } from '../../../../awsService/cloudWatchLogs/document/liveTailCodeLensProvider'
2522
2623describe ( 'TailLogGroup' , function ( ) {
@@ -39,23 +36,12 @@ describe('TailLogGroup', function () {
3936 let cloudwatchSettingsSpy : sinon . SinonSpy
4037 let wizardSpy : sinon . SinonSpy
4138
42- let clock : FakeTimers . InstalledClock
43-
44- before ( function ( ) {
45- clock = installFakeClock ( )
46- } )
47-
4839 beforeEach ( function ( ) {
49- clock . reset ( )
5040 sandbox = sinon . createSandbox ( )
5141 registry = new LiveTailSessionRegistry ( )
5242 codeLensProvider = new LiveTailCodeLensProvider ( registry )
5343 } )
5444
55- after ( function ( ) {
56- clock . uninstall ( )
57- } )
58-
5945 afterEach ( function ( ) {
6046 sandbox . restore ( )
6147 } )
@@ -64,47 +50,46 @@ describe('TailLogGroup', function () {
6450 sandbox . stub ( DefaultAwsContext . prototype , 'getCredentialAccountId' ) . returns ( testAwsAccountId )
6551 sandbox . stub ( DefaultAwsContext . prototype , 'getCredentials' ) . returns ( Promise . resolve ( testAwsCredentials ) )
6652
67- wizardSpy = sandbox . stub ( TailLogGroupWizard . prototype , 'run' ) . callsFake ( async function ( ) {
68- return getTestWizardResponse ( )
69- } )
70- const testMessage2 = `${ testMessage } -2`
71- const testMessage3 = `${ testMessage } -3`
53+ const startTimestamp = 1732276800000 // 11-22-2024 12:00:00PM GMT
54+ const updateFrames : StartLiveTailResponseStream [ ] = [
55+ getSessionUpdateFrame ( false , `${ testMessage } -1` , startTimestamp + 1000 ) ,
56+ getSessionUpdateFrame ( false , `${ testMessage } -2` , startTimestamp + 2000 ) ,
57+ getSessionUpdateFrame ( false , `${ testMessage } -3` , startTimestamp + 3000 ) ,
58+ ]
59+ //Returns the configured update frames and then indefinitely blocks.
60+ //This keeps the stream 'open', simulating an open network stream waiting for new events.
61+ //If the stream were to close, the event listeners in the TailLogGroup command would dispose,
62+ //breaking the 'closes tab closes session' assertions this test makes.
63+ async function * generator ( ) : AsyncIterable < StartLiveTailResponseStream > {
64+ for ( const frame of updateFrames ) {
65+ yield frame
66+ }
67+ await new Promise ( ( ) => { } )
68+ }
69+
7270 startLiveTailSessionSpy = sandbox
7371 . stub ( LiveTailSession . prototype , 'startLiveTailSession' )
74- . callsFake ( async function ( ) {
75- return getTestResponseStream ( [
76- {
77- message : testMessage ,
78- timestamp : 876830400000 ,
79- } ,
80- {
81- message : testMessage2 ,
82- timestamp : 876830402000 ,
83- } ,
84- {
85- message : testMessage3 ,
86- timestamp : 876830403000 ,
87- } ,
88- ] )
89- } )
72+ . returns ( Promise . resolve ( generator ( ) ) )
9073 stopLiveTailSessionSpy = sandbox
9174 . stub ( LiveTailSession . prototype , 'stopLiveTailSession' )
9275 . callsFake ( async function ( ) {
9376 return
9477 } )
95-
78+ wizardSpy = sandbox . stub ( TailLogGroupWizard . prototype , 'run' ) . callsFake ( async function ( ) {
79+ return getTestWizardResponse ( )
80+ } )
9681 //Set maxLines to 1.
9782 cloudwatchSettingsSpy = sandbox . stub ( CloudWatchLogsSettings . prototype , 'get' ) . callsFake ( ( ) => {
9883 return 1
9984 } )
100- await tailLogGroup ( registry , testSource , codeLensProvider , {
85+
86+ //The mock stream doesn't 'close', causing tailLogGroup to not return. If we `await`, it will never resolve.
87+ //Run it in the background and use waitUntil to poll its state.
88+ void tailLogGroup ( registry , testSource , codeLensProvider , {
10189 groupName : testLogGroup ,
10290 regionName : testRegion ,
10391 } )
104- assert . strictEqual ( wizardSpy . calledOnce , true )
105- assert . strictEqual ( cloudwatchSettingsSpy . calledOnce , true )
106- assert . strictEqual ( startLiveTailSessionSpy . calledOnce , true )
107- assert . strictEqual ( registry . size , 1 )
92+ await waitUntil ( async ( ) => registry . size !== 0 , { interval : 100 , timeout : 1000 } )
10893
10994 //registry is asserted to have only one entry, so this is assumed to be the session that was
11095 //started in this test.
@@ -113,13 +98,24 @@ describe('TailLogGroup', function () {
11398 if ( sessionUri === undefined ) {
11499 throw Error
115100 }
116- const document = getTestWindow ( ) . activeTextEditor ?. document
101+
102+ assert . strictEqual ( wizardSpy . calledOnce , true )
103+ assert . strictEqual ( cloudwatchSettingsSpy . calledOnce , true )
104+ assert . strictEqual ( startLiveTailSessionSpy . calledOnce , true )
105+ assert . strictEqual ( registry . size , 1 )
106+
107+ //Validate writing to the document.
108+ //MaxLines is set to 1, and "testMessage3" is the last event in the stream, its contents should be the only thing in the doc.
109+ const window = getTestWindow ( )
110+ const document = window . activeTextEditor ?. document
117111 assert . strictEqual ( sessionUri . toString ( ) , document ?. uri . toString ( ) )
118- //Test responseStream has 3 events, maxLines is set to 1. Only 3rd event should be in doc.
119- assert . strictEqual ( document ?. getText ( ) . trim ( ) , `12:00:03\t${ testMessage3 } ` )
112+ const doesDocumentContainExpectedContent = await waitUntil (
113+ async ( ) => document ?. getText ( ) . trim ( ) === `12:00:03\t${ testMessage } -3` ,
114+ { interval : 100 , timeout : 1000 }
115+ )
116+ assert . strictEqual ( doesDocumentContainExpectedContent , true )
120117
121118 //Test that closing all tabs the session's document is open in will cause the session to close
122- const window = getTestWindow ( )
123119 let tabs : vscode . Tab [ ] = [ ]
124120 window . tabGroups . all . forEach ( ( tabGroup ) => {
125121 tabs = tabs . concat ( getLiveTailSessionTabsFromTabGroup ( tabGroup , sessionUri ! ) )
@@ -159,7 +155,6 @@ describe('TailLogGroup', function () {
159155 closeSession ( session . uri , registry , testSource , codeLensProvider )
160156 assert . strictEqual ( 0 , registry . size )
161157 assert . strictEqual ( true , stopLiveTailSessionSpy . calledOnce )
162- assert . strictEqual ( 0 , clock . countTimers ( ) )
163158 } )
164159
165160 it ( 'clearDocument clears all text from document' , async function ( ) {
@@ -200,26 +195,23 @@ describe('TailLogGroup', function () {
200195 }
201196 }
202197
203- //Creates a test response stream. Each log event provided will be its own "frame" of the input stream.
204- function getTestResponseStream ( logEvents : LiveTailSessionLogEvent [ ] ) : AsyncIterable < StartLiveTailResponseStream > {
205- const sessionStartFrame : StartLiveTailResponseStream = {
206- sessionStart : {
207- logGroupIdentifiers : [ testLogGroup ] ,
198+ function getSessionUpdateFrame (
199+ isSampled : boolean ,
200+ message : string ,
201+ timestamp : number
202+ ) : StartLiveTailResponseStream {
203+ return {
204+ sessionUpdate : {
205+ sessionMetadata : {
206+ sampled : isSampled ,
207+ } ,
208+ sessionResults : [
209+ {
210+ message : message ,
211+ timestamp : timestamp ,
212+ } ,
213+ ] ,
208214 } ,
209- sessionUpdate : undefined ,
210215 }
211-
212- const updateFrames : StartLiveTailResponseStream [ ] = logEvents . map ( ( event ) => {
213- return {
214- sessionUpdate : {
215- sessionMetadata : {
216- sampled : false ,
217- } ,
218- sessionResults : [ event ] ,
219- } ,
220- }
221- } )
222-
223- return asyncGenerator ( [ sessionStartFrame , ...updateFrames ] )
224216 }
225217} )
0 commit comments