Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita172337

Browse files
committed
chore: add file sync daemon tests
1 parent968fa7b commita172337

File tree

9 files changed

+262
-52
lines changed

9 files changed

+262
-52
lines changed

‎Coder-Desktop/Coder-Desktop/Coder_DesktopApp.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
5151
#elseif arch(x86_64)
5252
letmutagenBinary="mutagen-darwin-amd64"
5353
#endif
54-
fileSyncDaemon=MutagenDaemon(
54+
letfileSyncDaemon=MutagenDaemon(
5555
mutagenPath:Bundle.main.url(forResource: mutagenBinary, withExtension:nil)
5656
)
57+
Task{
58+
await fileSyncDaemon.tryStart()
59+
}
60+
self.fileSyncDaemon= fileSyncDaemon
5761
}
5862

5963
func applicationDidFinishLaunching(_:Notification){

‎Coder-Desktop/Coder-Desktop/Preview Content/PreviewFileSync.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class PreviewFileSync: FileSyncDaemon {
2020
state=.stopped
2121
}
2222

23-
func createSession(localPath _:String, agentHost _:String, remotePath _:String)asyncthrows(DaemonError){}
23+
func createSession(arg _:CreateSyncSessionRequest)asyncthrows(DaemonError){}
2424

2525
func deleteSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
2626

‎Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,6 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
175175
defer{ loading=false}
176176
dothrows(DaemonError){
177177
tryawait fileSync.deleteSessions(ids:[selection!])
178-
if fileSync.sessionState.isEmpty{
179-
// Last session was deleted, stop the daemon
180-
await fileSync.stop()
181-
}
182178
} catch{
183179
actionError= error
184180
}

‎Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,10 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View {
9999
tryawait fileSync.deleteSessions(ids:[existingSession.id])
100100
}
101101
tryawait fileSync.createSession(
102-
localPath: localPath,
103-
agentHost: workspace.primaryHost!,
104-
remotePath: remotePath
102+
arg:.init(
103+
alpha:.init(path: localPath, protocolKind:.local),
104+
beta:.init(path: remotePath, protocolKind:.ssh(host: workspace.primaryHost!))
105+
)
105106
)
106107
} catch{
107108
createError= error
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
@testableimport Coder_Desktop
2+
import Foundation
3+
import GRPC
4+
import NIO
5+
import Subprocess
6+
import Testing
7+
import VPNLib
8+
import XCTest
9+
10+
@MainActor
11+
@Suite(.timeLimit(.minutes(1)))
12+
classFileSyncDaemonTests{
13+
lettempDir:URL
14+
letmutagenBinary:URL
15+
letmutagenDataDirectory:URL
16+
letmutagenAlphaDirectory:URL
17+
letmutagenBetaDirectory:URL
18+
19+
init()throws{
20+
tempDir=FileManager.default.makeTempDir()!
21+
#if arch(arm64)
22+
letbinaryName="mutagen-darwin-arm64"
23+
#elseif arch(x86_64)
24+
letbinaryName="mutagen-darwin-amd64"
25+
#endif
26+
mutagenBinary=Bundle.main.url(forResource: binaryName, withExtension:nil)!
27+
mutagenDataDirectory= tempDir.appending(path:"mutagen")
28+
mutagenAlphaDirectory= tempDir.appending(path:"alpha")
29+
tryFileManager.default.createDirectory(at: mutagenAlphaDirectory, withIntermediateDirectories:true)
30+
mutagenBetaDirectory= tempDir.appending(path:"beta")
31+
tryFileManager.default.createDirectory(at: mutagenBetaDirectory, withIntermediateDirectories:true)
32+
}
33+
34+
deinit{
35+
try?FileManager.default.removeItem(at: tempDir)
36+
}
37+
38+
privatefunc statesEqual(_ first:DaemonState, _ second:DaemonState)->Bool{
39+
switch(first, second){
40+
case(.stopped,.stopped):
41+
true
42+
case(.running,.running):
43+
true
44+
case(.unavailable,.unavailable):
45+
true
46+
default:
47+
false
48+
}
49+
}
50+
51+
@Test
52+
func fullSync()asyncthrows{
53+
letdaemon=MutagenDaemon(mutagenPath: mutagenBinary, mutagenDataDirectory: mutagenDataDirectory)
54+
#expect(statesEqual(daemon.state,.stopped))
55+
#expect(daemon.sessionState.count==0)
56+
57+
// The daemon won't start until we create a session
58+
await daemon.tryStart()
59+
#expect(statesEqual(daemon.state,.stopped))
60+
#expect(daemon.sessionState.count==0)
61+
62+
tryawait daemon.createSession(
63+
arg:.init(
64+
alpha:.init(
65+
path: mutagenAlphaDirectory.path(),
66+
protocolKind:.local
67+
),
68+
beta:.init(
69+
path: mutagenBetaDirectory.path(),
70+
protocolKind:.local
71+
)
72+
)
73+
)
74+
75+
// Daemon should have started itself
76+
#expect(statesEqual(daemon.state,.running))
77+
#expect(daemon.sessionState.count==1)
78+
79+
// Write a file to Alpha
80+
letalphaFile= mutagenAlphaDirectory.appendingPathComponent("test.txt")
81+
try"Hello, World!".write(to: alphaFile, atomically:true, encoding:.utf8)
82+
try #expect(
83+
awaiteventually(timeout:.seconds(5), interval:.milliseconds(100)){@MainActorin
84+
returntryFileManager.default.fileExists(
85+
atPath:self.mutagenBetaDirectory.appending(path:"test.txt").path()
86+
)
87+
})
88+
89+
tryawait daemon.deleteSessions(ids: daemon.sessionState.map(\.id))
90+
#expect(daemon.sessionState.count==0)
91+
// Daemon should have stopped itself once all sessions are deleted
92+
#expect(statesEqual(daemon.state,.stopped))
93+
}
94+
95+
@Test
96+
func autoStopStart()asyncthrows{
97+
letdaemon=MutagenDaemon(mutagenPath: mutagenBinary, mutagenDataDirectory: mutagenDataDirectory)
98+
#expect(statesEqual(daemon.state,.stopped))
99+
#expect(daemon.sessionState.count==0)
100+
101+
tryawait daemon.createSession(
102+
arg:.init(
103+
alpha:.init(
104+
path: mutagenAlphaDirectory.path(),
105+
protocolKind:.local
106+
),
107+
beta:.init(
108+
path: mutagenBetaDirectory.path(),
109+
protocolKind:.local
110+
)
111+
)
112+
)
113+
114+
tryawait daemon.createSession(
115+
arg:.init(
116+
alpha:.init(
117+
path: mutagenAlphaDirectory.path(),
118+
protocolKind:.local
119+
),
120+
beta:.init(
121+
path: mutagenBetaDirectory.path(),
122+
protocolKind:.local
123+
)
124+
)
125+
)
126+
127+
#expect(statesEqual(daemon.state,.running))
128+
#expect(daemon.sessionState.count==2)
129+
130+
tryawait daemon.deleteSessions(ids:[daemon.sessionState[0].id])
131+
#expect(daemon.sessionState.count==1)
132+
#expect(statesEqual(daemon.state,.running))
133+
134+
tryawait daemon.deleteSessions(ids:[daemon.sessionState[0].id])
135+
#expect(daemon.sessionState.count==0)
136+
#expect(statesEqual(daemon.state,.stopped))
137+
}
138+
139+
@Test
140+
func orphaned()asyncthrows{
141+
letdaemon1=MutagenDaemon(mutagenPath: mutagenBinary, mutagenDataDirectory: mutagenDataDirectory)
142+
await daemon1.refreshSessions()
143+
tryawait daemon1.createSession(arg:
144+
.init(
145+
alpha:.init(
146+
path: mutagenAlphaDirectory.path(),
147+
protocolKind:.local
148+
),
149+
beta:.init(
150+
path: mutagenBetaDirectory.path(),
151+
protocolKind:.local
152+
)
153+
)
154+
)
155+
#expect(statesEqual(daemon1.state,.running))
156+
#expect(daemon1.sessionState.count==1)
157+
158+
letdaemon2=MutagenDaemon(mutagenPath: mutagenBinary, mutagenDataDirectory: mutagenDataDirectory)
159+
await daemon2.tryStart()
160+
#expect(statesEqual(daemon2.state,.running))
161+
162+
// Daemon 2 should have killed daemon 1, causing it to fail
163+
#expect(daemon1.state.isFailed)
164+
}
165+
}

‎Coder-Desktop/Coder-DesktopTests/Util.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class MockFileSyncDaemon: FileSyncDaemon {
4747
[]
4848
}
4949

50-
func createSession(localPath _:String, agentHost _:String, remotePath _:String)asyncthrows(DaemonError){}
50+
func createSession(arg _:CreateSyncSessionRequest)asyncthrows(DaemonError){}
5151

5252
func pauseSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
5353

@@ -82,3 +82,18 @@ public func eventually(
8282
}
8383
returnfalse
8484
}
85+
86+
extensionFileManager{
87+
func makeTempDir()->URL?{
88+
lettempDirectory=FileManager.default.temporaryDirectory
89+
letdirectoryName=String(Int.random(in:0..<1_000_000))
90+
letdirectoryURL= tempDirectory.appendingPathComponent(directoryName)
91+
92+
do{
93+
tryFileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories:true)
94+
return directoryURL
95+
}catch{
96+
returnnil
97+
}
98+
}
99+
}

‎Coder-Desktop/VPNLib/FileSync/FileSyncDaemon.swift

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public protocol FileSyncDaemon: ObservableObject {
1414
func tryStart()async
1515
func stop()async
1616
func refreshSessions()async
17-
func createSession(localPath:String, agentHost:String, remotePath:String)asyncthrows(DaemonError)
17+
func createSession(arg:CreateSyncSessionRequest)asyncthrows(DaemonError)
1818
func deleteSessions(ids:[String])asyncthrows(DaemonError)
1919
func pauseSessions(ids:[String])asyncthrows(DaemonError)
2020
func resumeSessions(ids:[String])asyncthrows(DaemonError)
@@ -76,21 +76,6 @@ public class MutagenDaemon: FileSyncDaemon {
7676
state=.unavailable
7777
return
7878
}
79-
80-
// If there are sync sessions, the daemon should be running
81-
Task{
82-
dothrows(DaemonError){
83-
tryawaitstart()
84-
} catch{
85-
state=.failed(error)
86-
return
87-
}
88-
awaitrefreshSessions()
89-
if sessionState.isEmpty{
90-
logger.info("No sync sessions found on startup, stopping daemon")
91-
awaitstop()
92-
}
93-
}
9479
}
9580

9681
publicfunc tryStart()async{
@@ -99,6 +84,12 @@ public class MutagenDaemon: FileSyncDaemon {
9984
tryawaitstart()
10085
} catch{
10186
state=.failed(error)
87+
return
88+
}
89+
awaitrefreshSessions()
90+
if sessionState.isEmpty{
91+
logger.info("No sync sessions found on startup, stopping daemon")
92+
awaitstop()
10293
}
10394
}
10495

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp