@@ -7,6 +7,7 @@ class MockDockerService: DockerServiceProtocol {
77 var lastContainerName : String ?
88 var lastImageName : String ?
99 var executedScripts : [ String ] = [ ]
10+ var shellErrorsByCommandSubstring : [ String : Error ] = [ : ]
1011
1112 // 호환성을 위한 계산 속성
1213 var executedScript : String ? {
@@ -20,11 +21,17 @@ class MockDockerService: DockerServiceProtocol {
2021 }
2122
2223 func executeShell( container: String , script: String ) throws -> String {
24+ if let match = shellErrorsByCommandSubstring. first ( where: { script. contains ( $0. key) } ) {
25+ throw match. value
26+ }
2327 executedScripts. append ( script)
2428 return " mock shell output "
2529 }
2630
2731 func executeShellStreaming( container: String , script: String , onOutput: @escaping ( String ) -> Void ) throws -> String {
32+ if let match = shellErrorsByCommandSubstring. first ( where: { script. contains ( $0. key) } ) {
33+ throw match. value
34+ }
2835 executedScripts. append ( script)
2936 let output = " mock shell output "
3037 onOutput ( output)
@@ -57,9 +64,11 @@ final class ContainerOrchestratorTests: XCTestCase {
5764 override func setUp( ) {
5865 super. setUp ( )
5966 testStoreURL = FileManager . default. temporaryDirectory. appendingPathComponent ( " orchestrator_test.json " )
67+ AppLogStore . shared. clear ( )
6068 }
6169
6270 override func tearDown( ) {
71+ AppLogStore . shared. clear ( )
6372 try ? FileManager . default. removeItem ( at: testStoreURL)
6473 super. tearDown ( )
6574 }
@@ -100,4 +109,38 @@ final class ContainerOrchestratorTests: XCTestCase {
100109 let sessions = try sessionManager. loadSessions ( )
101110 XCTAssertEqual ( sessions. count, 1 )
102111 }
112+
113+ func testStartSessionLogsGitInstallFailureAndContinues( ) async throws {
114+ // Given
115+ let mockDocker = MockDockerService ( )
116+ mockDocker. shellErrorsByCommandSubstring [ " apk add --no-cache git " ] = NSError (
117+ domain: " docker " ,
118+ code: 1 ,
119+ userInfo: [ NSLocalizedDescriptionKey: " apk failed: temporary network error " ]
120+ )
121+ let sessionManager = SessionManager ( storeURL: testStoreURL)
122+ let orchestrator = ContainerOrchestrator (
123+ dockerService: mockDocker,
124+ sessionManager: sessionManager
125+ )
126+
127+ let repo = Repository (
128+ id: 1 ,
129+ name: " test-repo " ,
130+ fullName: " user/test-repo " ,
131+ isPrivate: false ,
132+ htmlURL: URL ( string: " https://github.com/user/test-repo " ) !,
133+ cloneURL: URL ( string: " https://github.com/user/test-repo.git " ) !
134+ )
135+
136+ // When
137+ let session = try await orchestrator. startSession ( repo: repo, token: " ghp_test_token " )
138+
139+ // Then
140+ XCTAssertEqual ( session. repoURL, repo. cloneURL)
141+ let logs = AppLogStore . shared. recentEntries ( )
142+ XCTAssertTrue ( logs. contains { entry in
143+ entry. contains ( " ContainerOrchestrator git install failed " ) && entry. contains ( " apk failed " )
144+ } )
145+ }
103146}
0 commit comments