@@ -45,7 +45,8 @@ vi.mock("./headers");
4545vi . mock ( "./inbox" ) ;
4646vi . mock ( "./sshConfig" ) ;
4747vi . mock ( "./sshSupport" ) ;
48- vi . mock ( "./storage" ) ;
48+ // Don't mock storage - we'll create real instances in tests
49+ // vi.mock("./storage");
4950vi . mock ( "./util" ) ;
5051vi . mock ( "./workspaceMonitor" ) ;
5152vi . mock ( "fs/promises" ) ;
@@ -123,6 +124,7 @@ describe("remote", () => {
123124} ,
124125} as unknown as typeof vscode ;
125126
127+ // Storage import not needed here since we use mocks
126128mockStorage = {
127129getSessionTokenPath :vi . fn ( ) . mockReturnValue ( "/mock/session/path" ) ,
128130writeToCoderOutputChannel :vi . fn ( ) ,
@@ -1283,4 +1285,150 @@ describe("remote", () => {
12831285expect ( findProcess . default ) . toHaveBeenCalledWith ( "port" , 9999 ) ;
12841286} ) ;
12851287} ) ;
1288+
1289+ describe ( "Logger integration" , ( ) => {
1290+ it ( "should use Logger when set on Storage for logging messages" , async ( ) => {
1291+ // Import the factory function for creating logger with mock
1292+ const { createMockOutputChannelWithLogger} = await import (
1293+ "./test-helpers"
1294+ ) ;
1295+ const { mockOutputChannel, logger} = createMockOutputChannelWithLogger ( ) ;
1296+
1297+ // Create a real Storage instance with the mock output channel
1298+ const { Storage} = await import ( "./storage" ) ;
1299+ const realStorage = new Storage (
1300+ mockOutputChannel as never ,
1301+ { } as never ,
1302+ { } as never ,
1303+ { } as never ,
1304+ { } as never ,
1305+ ) ;
1306+
1307+ // Set the logger on storage
1308+ realStorage . setLogger ( logger ) ;
1309+
1310+ // Spy on storage methods we need
1311+ vi . spyOn ( realStorage , "getSessionTokenPath" ) . mockReturnValue (
1312+ "/mock/session/path" ,
1313+ ) ;
1314+ vi . spyOn ( realStorage , "migrateSessionToken" ) . mockResolvedValue ( undefined ) ;
1315+ vi . spyOn ( realStorage , "readCliConfig" ) . mockResolvedValue ( {
1316+ url :"https://test.coder.com" ,
1317+ token :"test-token" ,
1318+ } ) ;
1319+ vi . spyOn ( realStorage , "getRemoteSSHLogPath" ) . mockResolvedValue ( undefined ) ;
1320+ vi . spyOn ( realStorage , "fetchBinary" ) . mockResolvedValue ( "/path/to/coder" ) ;
1321+ vi . spyOn ( realStorage , "getNetworkInfoPath" ) . mockReturnValue (
1322+ "/mock/network/info" ,
1323+ ) ;
1324+ vi . spyOn ( realStorage , "getLogPath" ) . mockReturnValue ( "/mock/log/path" ) ;
1325+ vi . spyOn ( realStorage , "getHeaders" ) . mockResolvedValue ( { } ) ;
1326+
1327+ // Create remote with the real storage that has logger
1328+ remote = new Remote (
1329+ mockVscodeProposed ,
1330+ realStorage ,
1331+ mockCommands ,
1332+ vscode . ExtensionMode . Production ,
1333+ ) ;
1334+
1335+ // Mock parseRemoteAuthority to return valid parts
1336+ const { parseRemoteAuthority} = await import ( "./util" ) ;
1337+ vi . mocked ( parseRemoteAuthority ) . mockReturnValue ( {
1338+ host :"test.coder.com" ,
1339+ label :"test-label" ,
1340+ username :"test-user" ,
1341+ workspace :"test-workspace" ,
1342+ agent :undefined ,
1343+ } ) ;
1344+
1345+ // Storage config already mocked above
1346+
1347+ // Mock needToken to return false
1348+ const { needToken} = await import ( "./api" ) ;
1349+ vi . mocked ( needToken ) . mockReturnValue ( false ) ;
1350+
1351+ // Mock makeCoderSdk to return workspace not found to exit early
1352+ const mockWorkspaceRestClient = {
1353+ getBuildInfo :vi . fn ( ) . mockResolvedValue ( { version :"v0.15.0" } ) ,
1354+ getWorkspaceByOwnerAndName :vi . fn ( ) . mockRejectedValue ( {
1355+ isAxiosError :true ,
1356+ response :{ status :404 } ,
1357+ } ) ,
1358+ } as never ;
1359+ const { makeCoderSdk} = await import ( "./api" ) ;
1360+ vi . mocked ( makeCoderSdk ) . mockResolvedValue ( mockWorkspaceRestClient ) ;
1361+
1362+ // Mock cli.version
1363+ const cli = await import ( "./cliManager" ) ;
1364+ vi . mocked ( cli . version ) . mockResolvedValue ( "v0.15.0" ) ;
1365+
1366+ // Mock featureSetForVersion
1367+ const { featureSetForVersion} = await import ( "./featureSet" ) ;
1368+ vi . mocked ( featureSetForVersion ) . mockReturnValue ( {
1369+ vscodessh :true ,
1370+ } as never ) ;
1371+
1372+ // Mock user cancellation
1373+ const showInfoMessageSpy = mockVscodeProposed . window
1374+ . showInformationMessage as ReturnType < typeof vi . fn > ;
1375+ showInfoMessageSpy . mockResolvedValue ( undefined ) ;
1376+
1377+ // Mock closeRemote
1378+ vi . spyOn ( remote , "closeRemote" ) . mockResolvedValue ( ) ;
1379+
1380+ // Mock isAxiosError
1381+ const { isAxiosError} = await import ( "axios" ) ;
1382+ vi . mocked ( isAxiosError ) . mockReturnValue ( true ) ;
1383+
1384+ // Execute setup which should trigger logging
1385+ await remote . setup ( "coder-vscode--test-label--test-user--test-workspace" ) ;
1386+
1387+ // Verify that messages were logged through the Logger
1388+ const logs = logger . getLogs ( ) ;
1389+ expect ( logs . length ) . toBeGreaterThan ( 0 ) ;
1390+
1391+ // Verify specific log messages were created
1392+ const logMessages = logs . map ( ( log ) => log . message ) ;
1393+ expect ( logMessages ) . toContain (
1394+ "Setting up remote: test-user/test-workspace" ,
1395+ ) ;
1396+ expect ( logMessages ) . toContain (
1397+ "Using deployment URL: https://test.coder.com" ,
1398+ ) ;
1399+ expect ( logMessages ) . toContain ( "Using deployment label: test-label" ) ;
1400+ expect ( logMessages ) . toContain (
1401+ "Got build info: v0.15.0 vscodessh feature: true" ,
1402+ ) ;
1403+
1404+ // Verify messages were written to output channel with proper formatting
1405+ expect ( mockOutputChannel . appendLine ) . toHaveBeenCalledWith (
1406+ expect . stringMatching (
1407+ / \[ .* \] \[ I N F O \] S e t t i n g u p r e m o t e : t e s t - u s e r \/ t e s t - w o r k s p a c e / ,
1408+ ) ,
1409+ ) ;
1410+ } ) ;
1411+
1412+ it ( "should maintain backward compatibility with writeToCoderOutputChannel" , async ( ) => {
1413+ // Import the factory function for creating logger with mock
1414+ const { createMockOutputChannelWithLogger} = await import (
1415+ "./test-helpers"
1416+ ) ;
1417+ const { mockOutputChannel, logger} = createMockOutputChannelWithLogger ( ) ;
1418+
1419+ // Test backward compatibility method
1420+ logger . writeToCoderOutputChannel ( "Test backward compatibility" ) ;
1421+
1422+ // Verify it logs at INFO level
1423+ const logs = logger . getLogs ( ) ;
1424+ expect ( logs ) . toHaveLength ( 1 ) ;
1425+ expect ( logs [ 0 ] . level ) . toBe ( "INFO" ) ;
1426+ expect ( logs [ 0 ] . message ) . toBe ( "Test backward compatibility" ) ;
1427+
1428+ // Verify output format
1429+ expect ( mockOutputChannel . appendLine ) . toHaveBeenCalledWith (
1430+ expect . stringMatching ( / \[ .* \] \[ I N F O \] T e s t b a c k w a r d c o m p a t i b i l i t y / ) ,
1431+ ) ;
1432+ } ) ;
1433+ } ) ;
12861434} ) ;