11import { describe , expect , it , beforeEach , afterEach , spyOn } from "bun:test" ;
22import * as runtimeHelpers from "@/node/utils/runtime/helpers" ;
33import { SSHRuntime , computeBaseRepoPath } from "./SSHRuntime" ;
4+ import { buildRemoteProjectLayout , getRemoteWorkspacePath } from "./remoteProjectLayout" ;
45import { createSSHTransport } from "./transports" ;
56
67/**
@@ -149,10 +150,8 @@ describe("SSHRuntime base repo config normalization", () => {
149150} ) ;
150151
151152describe ( "SSHRuntime.createWorkspace" , ( ) => {
152- it ( "uses directoryName for the workspace path while preparing the remote parent directory" , async ( ) => {
153- const config = { host : "example.com" , srcBaseDir : "/home/user/src" } ;
154- const runtime = new SSHRuntime ( config , createSSHTransport ( config , false ) ) ;
155- const execSpy = spyOn ( runtime , "exec" ) . mockResolvedValue ( {
153+ function createExecStream ( exitCode = 0 ) {
154+ return {
156155 stdout : new ReadableStream < Uint8Array > ( {
157156 start ( controller ) {
158157 controller . close ( ) ;
@@ -164,18 +163,29 @@ describe("SSHRuntime.createWorkspace", () => {
164163 } ,
165164 } ) ,
166165 stdin : new WritableStream < Uint8Array > ( ) ,
167- exitCode : Promise . resolve ( 0 ) ,
166+ exitCode : Promise . resolve ( exitCode ) ,
168167 duration : Promise . resolve ( 0 ) ,
169- } ) ;
170- const readFileSpy = spyOn ( runtime , "readFile" ) . mockReturnValue (
171- new ReadableStream < Uint8Array > ( {
172- start ( controller ) {
173- controller . error ( new Error ( "missing branch map" ) ) ;
174- } ,
175- } )
168+ } ;
169+ }
170+
171+ it ( "uses directoryName for the workspace path while preparing the remote parent directory" , async ( ) => {
172+ const config = { host : "example.com" , srcBaseDir : "/home/user/src" } ;
173+ const runtime = new SSHRuntime ( config , createSSHTransport ( config , false ) ) ;
174+ const expectedLayout = buildRemoteProjectLayout ( config . srcBaseDir , "/projects/demo" ) ;
175+ const expectedWorkspacePath = getRemoteWorkspacePath ( expectedLayout , "review-slot" ) ;
176+ const execSpy = spyOn ( runtime , "exec" ) . mockImplementation ( ( ) =>
177+ Promise . resolve ( createExecStream ( ) )
178+ ) ;
179+ const readFileSpy = spyOn ( runtime , "readFile" ) . mockImplementation (
180+ ( ) =>
181+ new ReadableStream < Uint8Array > ( {
182+ start ( controller ) {
183+ controller . error ( new Error ( "missing branch metadata" ) ) ;
184+ } ,
185+ } )
176186 ) ;
177- const writeFileSpy = spyOn ( runtime , "writeFile" ) . mockReturnValue (
178- new WritableStream < Uint8Array > ( )
187+ const writeFileSpy = spyOn ( runtime , "writeFile" ) . mockImplementation (
188+ ( ) => new WritableStream < Uint8Array > ( )
179189 ) ;
180190
181191 try {
@@ -194,13 +204,16 @@ describe("SSHRuntime.createWorkspace", () => {
194204
195205 expect ( result ) . toEqual ( {
196206 success : true ,
197- workspacePath : "/home/user/src/demo/review-slot" ,
198- } ) ;
199- expect ( execSpy ) . toHaveBeenCalledWith ( 'mkdir -p "/home/user/src/demo"' , {
200- cwd : "/tmp" ,
201- timeout : 10 ,
202- abortSignal : undefined ,
207+ workspacePath : expectedWorkspacePath ,
203208 } ) ;
209+ expect ( execSpy ) . toHaveBeenCalledWith (
210+ `mkdir -p ${ JSON . stringify ( expectedLayout . projectRoot ) } ` ,
211+ {
212+ cwd : "/tmp" ,
213+ timeout : 10 ,
214+ abortSignal : undefined ,
215+ }
216+ ) ;
204217 } finally {
205218 execSpy . mockRestore ( ) ;
206219 readFileSpy . mockRestore ( ) ;
@@ -223,6 +236,8 @@ describe("SSHRuntime.deleteWorkspace", () => {
223236 it ( "deletes the mapped workspace branch instead of the current remote checkout" , async ( ) => {
224237 const config = { host : "example.com" , srcBaseDir : "/home/user/src" } ;
225238 const runtime = new SSHRuntime ( config , createSSHTransport ( config , false ) ) ;
239+ const expectedLayout = buildRemoteProjectLayout ( config . srcBaseDir , "/projects/demo" ) ;
240+ const expectedDeletedPath = getRemoteWorkspacePath ( expectedLayout , "review-slot" ) ;
226241 const execSpy = spyOn ( runtime , "exec" ) . mockImplementation ( ( command ) => {
227242 if ( command . includes ( "git diff --quiet" ) || command . includes ( "test -d" ) ) {
228243 return Promise . resolve ( createExecStream ( 0 ) ) ;
@@ -232,13 +247,14 @@ describe("SSHRuntime.deleteWorkspace", () => {
232247 }
233248 throw new Error ( `Unexpected exec command: ${ command } ` ) ;
234249 } ) ;
235- const readFileSpy = spyOn ( runtime , "readFile" ) . mockReturnValue (
236- new ReadableStream < Uint8Array > ( {
237- start ( controller ) {
238- controller . enqueue ( new TextEncoder ( ) . encode ( '{"review-slot":"feature-branch"}\n' ) ) ;
239- controller . close ( ) ;
240- } ,
241- } )
250+ const readFileSpy = spyOn ( runtime , "readFile" ) . mockImplementation (
251+ ( ) =>
252+ new ReadableStream < Uint8Array > ( {
253+ start ( controller ) {
254+ controller . enqueue ( new TextEncoder ( ) . encode ( '{"review-slot":"feature-branch"}\n' ) ) ;
255+ controller . close ( ) ;
256+ } ,
257+ } )
242258 ) ;
243259 const execBufferedSpy = spyOn ( runtimeHelpers , "execBuffered" ) . mockImplementation (
244260 ( _runtime , command ) => {
@@ -261,7 +277,7 @@ describe("SSHRuntime.deleteWorkspace", () => {
261277 const result = await runtime . deleteWorkspace ( "/projects/demo" , "review-slot" , true ) ;
262278 expect ( result ) . toEqual ( {
263279 success : true ,
264- deletedPath : "/home/user/src/demo/review-slot" ,
280+ deletedPath : expectedDeletedPath ,
265281 } ) ;
266282 } finally {
267283 execSpy . mockRestore ( ) ;
@@ -396,14 +412,16 @@ describe("SSHRuntime.resolvePath", () => {
396412} ) ;
397413describe ( "computeBaseRepoPath" , ( ) => {
398414 it ( "computes the correct bare repo path" , ( ) => {
399- // computeBaseRepoPath uses getProjectName (basename) to compute:
400- // <srcBaseDir>/<projectName>/.mux-base.git
415+ const layout = buildRemoteProjectLayout ( "~/mux" , "/Users/me/code/my-project" ) ;
401416 const result = computeBaseRepoPath ( "~/mux" , "/Users/me/code/my-project" ) ;
402- expect ( result ) . toBe ( "~/mux/my-project/.mux-base.git" ) ;
417+ expect ( result ) . toBe ( layout . baseRepoPath ) ;
418+ expect ( result ) . toMatch ( / ^ ~ \/ m u x \/ m y - p r o j e c t - [ a - f 0 - 9 ] { 12 } \/ \. m u x - b a s e \. g i t $ / ) ;
403419 } ) ;
404420
405421 it ( "handles absolute srcBaseDir" , ( ) => {
422+ const layout = buildRemoteProjectLayout ( "/home/user/src" , "/code/repo" ) ;
406423 const result = computeBaseRepoPath ( "/home/user/src" , "/code/repo" ) ;
407- expect ( result ) . toBe ( "/home/user/src/repo/.mux-base.git" ) ;
424+ expect ( result ) . toBe ( layout . baseRepoPath ) ;
425+ expect ( result ) . toMatch ( / ^ \/ h o m e \/ u s e r \/ s r c \/ r e p o - [ a - f 0 - 9 ] { 12 } \/ \. m u x - b a s e \. g i t $ / ) ;
408426 } ) ;
409427} ) ;
0 commit comments