Skip to content

Commit 4497913

Browse files
committed
Fix registry download with symlinks in root
1 parent 2096cff commit 4497913

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

Tests/PackageRegistryTests/RegistryClientTests.swift

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2957,6 +2957,137 @@ fileprivate var availabilityURL = URL("\(registryURL)/availability")
29572957
return false
29582958
}
29592959
}
2960+
2961+
@Test func downloadSourceArchiveWithSymlinks() async throws {
2962+
let checksumAlgorithm: HashAlgorithm = MockHashAlgorithm()
2963+
let checksum = checksumAlgorithm.hash(emptyZipFile).hexadecimalRepresentation
2964+
2965+
let handler: HTTPClient.Implementation = { request, _ in
2966+
switch (request.kind, request.method, request.url) {
2967+
case (.generic, .get, metadataURL):
2968+
let data = """
2969+
{
2970+
"id": "\(identity)",
2971+
"version": "\(version)",
2972+
"resources": [
2973+
{
2974+
"name": "source-archive",
2975+
"type": "application/zip",
2976+
"checksum": "\(checksum)"
2977+
}
2978+
],
2979+
"metadata": {
2980+
"author": {
2981+
"name": "Test Author"
2982+
},
2983+
"description": "Test package with symlinks"
2984+
}
2985+
}
2986+
""".data(using: .utf8)!
2987+
2988+
return .init(
2989+
statusCode: 200,
2990+
headers: .init([
2991+
.init(name: "Content-Length", value: "\(data.count)"),
2992+
.init(name: "Content-Type", value: "application/json"),
2993+
.init(name: "Content-Version", value: "1"),
2994+
]),
2995+
body: data
2996+
)
2997+
case (.download(let fileSystem, let path), .get, downloadURL):
2998+
#expect(request.headers.get("Accept").first == "application/vnd.swift.registry.v1+zip")
2999+
3000+
let data = Data(emptyZipFile.contents)
3001+
try! fileSystem.writeFileContents(path, data: data)
3002+
3003+
return .init(
3004+
statusCode: 200,
3005+
headers: .init([
3006+
.init(name: "Content-Length", value: "\(data.count)"),
3007+
.init(name: "Content-Type", value: "application/zip"),
3008+
.init(name: "Content-Version", value: "1"),
3009+
.init(
3010+
name: "Content-Disposition",
3011+
value: "attachment; filename=\"\(identity)-\(version).zip\""
3012+
),
3013+
.init(
3014+
name: "Digest",
3015+
value: "sha-256=bc6c9a5d2f2226cfa1ef4fad8344b10e1cc2e82960f468f70d9ed696d26b3283"
3016+
),
3017+
]),
3018+
body: nil
3019+
)
3020+
default:
3021+
throw StringError("method and url should match")
3022+
}
3023+
}
3024+
3025+
let httpClient = HTTPClient(implementation: handler)
3026+
var configuration = RegistryConfiguration()
3027+
configuration.defaultRegistry = Registry(url: registryURL, supportsAvailability: false)
3028+
configuration.security = .testDefault
3029+
3030+
let fileSystem = localFileSystem
3031+
let tmpDir = try fileSystem.tempDirectory.appending(component: UUID().uuidString)
3032+
try fileSystem.createDirectory(tmpDir, recursive: true)
3033+
defer {
3034+
try? fileSystem.removeFileTree(tmpDir)
3035+
}
3036+
3037+
let registryClient = RegistryClient(
3038+
configuration: configuration,
3039+
fingerprintStorage: .none,
3040+
fingerprintCheckingMode: .strict,
3041+
skipSignatureValidation: false,
3042+
signingEntityStorage: .none,
3043+
signingEntityCheckingMode: .strict,
3044+
customHTTPClient: httpClient,
3045+
customArchiverProvider: { fileSystem in
3046+
MockArchiver(handler: { _, from, to, callback in
3047+
let data = try fileSystem.readFileContents(from)
3048+
#expect(data == emptyZipFile)
3049+
3050+
let packagePath = to.appending(component: "package")
3051+
try fileSystem.createDirectory(packagePath, recursive: true)
3052+
3053+
let targetFile = packagePath.appending(component: "AFile.swift")
3054+
try fileSystem.writeFileContents(targetFile, string: "// Target file content\n")
3055+
3056+
let symlink = packagePath.appending(component: "ZLinkToFile.swift")
3057+
try fileSystem.createSymbolicLink(symlink, pointingAt: targetFile, relative: true)
3058+
3059+
// Also create Package.swift
3060+
try fileSystem.writeFileContents(packagePath.appending(component: "Package.swift"), string: "// Package manifest\n")
3061+
3062+
callback(.success(()))
3063+
})
3064+
},
3065+
delegate: .none,
3066+
checksumAlgorithm: checksumAlgorithm
3067+
)
3068+
3069+
let path = tmpDir.appending(component: "\(identity)-\(version)")
3070+
3071+
try await registryClient.downloadSourceArchive(
3072+
package: identity,
3073+
version: version,
3074+
fileSystem: fileSystem,
3075+
destinationPath: path
3076+
)
3077+
3078+
let contents = try fileSystem.getDirectoryContents(path).sorted()
3079+
#expect(contents.contains("AFile.swift"), "Regular file AFile.swift should exist")
3080+
#expect(contents.contains("ZLinkToFile.swift"), "Symlink ZLinkToFile.swift should exist")
3081+
#expect(contents.contains("Package.swift"), "Package.swift should exist")
3082+
#expect(contents.contains(RegistryReleaseMetadataStorage.fileName), "Metadata file should exist")
3083+
3084+
let symlinkPath = path.appending(component: "ZLinkToFile.swift")
3085+
let regularFilePath = path.appending(component: "AFile.swift")
3086+
3087+
let regularFileContent: String = try fileSystem.readFileContents(regularFilePath)
3088+
let symlinkContent: String = try fileSystem.readFileContents(symlinkPath)
3089+
#expect(symlinkContent == regularFileContent, "Symlink should have same content as target file")
3090+
}
29603091
}
29613092

29623093
@Suite("Lookup Identities") struct LookupIdentities {

0 commit comments

Comments
 (0)