|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors |
| 5 | +// Copyright (c) 2021-2023 Apple Inc. and the Swift project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See http://swift.org/LICENSE.txt for license information
|
@@ -247,6 +247,86 @@ final class RegistryClientTests: XCTestCase {
|
247 | 247 | XCTAssertEqual(parsedToolsVersion, .v4)
|
248 | 248 | }
|
249 | 249 | }
|
| 250 | + |
| 251 | + func testGetManifestContent_optionalContentVersion() throws { |
| 252 | + let registryURL = "https://packages.example.com" |
| 253 | + let identity = PackageIdentity.plain("mona.LinkedList") |
| 254 | + let (scope, name) = identity.scopeAndName! |
| 255 | + let version = Version("1.1.1") |
| 256 | + let manifestURL = URL(string: "\(registryURL)/\(scope)/\(name)/\(version)/Package.swift")! |
| 257 | + |
| 258 | + let handler: HTTPClient.Handler = { request, _, completion in |
| 259 | + var components = URLComponents(url: request.url, resolvingAgainstBaseURL: false)! |
| 260 | + let toolsVersion = components.queryItems?.first { $0.name == "swift-version" } |
| 261 | + .flatMap { ToolsVersion(string: $0.value!) } ?? ToolsVersion.current |
| 262 | + // remove query |
| 263 | + components.query = nil |
| 264 | + let urlWithoutQuery = components.url |
| 265 | + switch (request.method, urlWithoutQuery) { |
| 266 | + case (.get, manifestURL): |
| 267 | + XCTAssertEqual(request.headers.get("Accept").first, "application/vnd.swift.registry.v1+swift") |
| 268 | + |
| 269 | + let data = """ |
| 270 | + // swift-tools-version:\(toolsVersion) |
| 271 | +
|
| 272 | + import PackageDescription |
| 273 | +
|
| 274 | + let package = Package() |
| 275 | + """.data(using: .utf8)! |
| 276 | + |
| 277 | + completion(.success(.init( |
| 278 | + statusCode: 200, |
| 279 | + headers: .init([ |
| 280 | + .init(name: "Content-Length", value: "\(data.count)"), |
| 281 | + .init(name: "Content-Type", value: "text/x-swift"), |
| 282 | + // Omit `Content-Version` header |
| 283 | + ]), |
| 284 | + body: data |
| 285 | + ))) |
| 286 | + default: |
| 287 | + completion(.failure(StringError("method and url should match"))) |
| 288 | + } |
| 289 | + } |
| 290 | + |
| 291 | + var httpClient = HTTPClient(handler: handler) |
| 292 | + httpClient.configuration.circuitBreakerStrategy = .none |
| 293 | + httpClient.configuration.retryStrategy = .none |
| 294 | + |
| 295 | + var configuration = RegistryConfiguration() |
| 296 | + configuration.defaultRegistry = Registry(url: URL(string: registryURL)!) |
| 297 | + |
| 298 | + let registryClient = makeRegistryClient(configuration: configuration, httpClient: httpClient) |
| 299 | + |
| 300 | + do { |
| 301 | + let manifest = try registryClient.getManifestContent( |
| 302 | + package: identity, |
| 303 | + version: version, |
| 304 | + customToolsVersion: nil |
| 305 | + ) |
| 306 | + let parsedToolsVersion = try ToolsVersionParser.parse(utf8String: manifest) |
| 307 | + XCTAssertEqual(parsedToolsVersion, .current) |
| 308 | + } |
| 309 | + |
| 310 | + do { |
| 311 | + let manifest = try registryClient.getManifestContent( |
| 312 | + package: identity, |
| 313 | + version: version, |
| 314 | + customToolsVersion: .v5_3 |
| 315 | + ) |
| 316 | + let parsedToolsVersion = try ToolsVersionParser.parse(utf8String: manifest) |
| 317 | + XCTAssertEqual(parsedToolsVersion, .v5_3) |
| 318 | + } |
| 319 | + |
| 320 | + do { |
| 321 | + let manifest = try registryClient.getManifestContent( |
| 322 | + package: identity, |
| 323 | + version: version, |
| 324 | + customToolsVersion: .v4 |
| 325 | + ) |
| 326 | + let parsedToolsVersion = try ToolsVersionParser.parse(utf8String: manifest) |
| 327 | + XCTAssertEqual(parsedToolsVersion, .v4) |
| 328 | + } |
| 329 | + } |
250 | 330 |
|
251 | 331 | func testFetchSourceArchiveChecksum() throws {
|
252 | 332 | let registryURL = "https://packages.example.com"
|
@@ -858,6 +938,115 @@ final class RegistryClientTests: XCTestCase {
|
858 | 938 | XCTAssertEqual(registryURL, fingerprint.origin.url?.absoluteString)
|
859 | 939 | XCTAssertEqual(checksum, fingerprint.value)
|
860 | 940 | }
|
| 941 | + |
| 942 | + func testDownloadSourceArchive_optionalContentVersion() throws { |
| 943 | + let registryURL = "https://packages.example.com" |
| 944 | + let identity = PackageIdentity.plain("mona.LinkedList") |
| 945 | + let (scope, name) = identity.scopeAndName! |
| 946 | + let version = Version("1.1.1") |
| 947 | + let downloadURL = URL(string: "\(registryURL)/\(scope)/\(name)/\(version).zip")! |
| 948 | + let metadataURL = URL(string: "\(registryURL)/\(scope)/\(name)/\(version)")! |
| 949 | + |
| 950 | + let checksumAlgorithm: HashAlgorithm = SHA256() |
| 951 | + let checksum = checksumAlgorithm.hash(emptyZipFile).hexadecimalRepresentation |
| 952 | + |
| 953 | + let handler: HTTPClient.Handler = { request, _, completion in |
| 954 | + switch (request.kind, request.method, request.url) { |
| 955 | + case (.download(let fileSystem, let path), .get, downloadURL): |
| 956 | + XCTAssertEqual(request.headers.get("Accept").first, "application/vnd.swift.registry.v1+zip") |
| 957 | + |
| 958 | + let data = Data(emptyZipFile.contents) |
| 959 | + try! fileSystem.writeFileContents(path, data: data) |
| 960 | + |
| 961 | + completion(.success(.init( |
| 962 | + statusCode: 200, |
| 963 | + headers: .init([ |
| 964 | + .init(name: "Content-Length", value: "\(data.count)"), |
| 965 | + .init(name: "Content-Type", value: "application/zip"), |
| 966 | + // Omit `Content-Version` header |
| 967 | + .init(name: "Content-Disposition", value: #"attachment; filename="LinkedList-1.1.1.zip""#), |
| 968 | + .init( |
| 969 | + name: "Digest", |
| 970 | + value: "sha-256=bc6c9a5d2f2226cfa1ef4fad8344b10e1cc2e82960f468f70d9ed696d26b3283" |
| 971 | + ), |
| 972 | + ]), |
| 973 | + body: nil |
| 974 | + ))) |
| 975 | + // `downloadSourceArchive` calls this API to fetch checksum |
| 976 | + case (.generic, .get, metadataURL): |
| 977 | + XCTAssertEqual(request.headers.get("Accept").first, "application/vnd.swift.registry.v1+json") |
| 978 | + |
| 979 | + let data = """ |
| 980 | + { |
| 981 | + "id": "mona.LinkedList", |
| 982 | + "version": "1.1.1", |
| 983 | + "resources": [ |
| 984 | + { |
| 985 | + "name": "source-archive", |
| 986 | + "type": "application/zip", |
| 987 | + "checksum": "\(checksum)" |
| 988 | + } |
| 989 | + ], |
| 990 | + "metadata": { |
| 991 | + "description": "One thing links to another." |
| 992 | + } |
| 993 | + } |
| 994 | + """.data(using: .utf8)! |
| 995 | + |
| 996 | + completion(.success(.init( |
| 997 | + statusCode: 200, |
| 998 | + headers: .init([ |
| 999 | + .init(name: "Content-Length", value: "\(data.count)"), |
| 1000 | + .init(name: "Content-Type", value: "application/json"), |
| 1001 | + .init(name: "Content-Version", value: "1"), |
| 1002 | + ]), |
| 1003 | + body: data |
| 1004 | + ))) |
| 1005 | + default: |
| 1006 | + completion(.failure(StringError("method and url should match"))) |
| 1007 | + } |
| 1008 | + } |
| 1009 | + |
| 1010 | + var httpClient = HTTPClient(handler: handler) |
| 1011 | + httpClient.configuration.circuitBreakerStrategy = .none |
| 1012 | + httpClient.configuration.retryStrategy = .none |
| 1013 | + |
| 1014 | + var configuration = RegistryConfiguration() |
| 1015 | + configuration.defaultRegistry = Registry(url: URL(string: registryURL)!) |
| 1016 | + |
| 1017 | + let fingerprintStorage = MockPackageFingerprintStorage() |
| 1018 | + let registryClient = RegistryClient( |
| 1019 | + configuration: configuration, |
| 1020 | + fingerprintStorage: fingerprintStorage, |
| 1021 | + fingerprintCheckingMode: .strict, |
| 1022 | + customHTTPClient: httpClient, |
| 1023 | + customArchiverProvider: { fileSystem in |
| 1024 | + MockArchiver(handler: { _, from, to, callback in |
| 1025 | + let data = try fileSystem.readFileContents(from) |
| 1026 | + XCTAssertEqual(data, emptyZipFile) |
| 1027 | + |
| 1028 | + let packagePath = to.appending(component: "package") |
| 1029 | + try fileSystem.createDirectory(packagePath, recursive: true) |
| 1030 | + try fileSystem.writeFileContents(packagePath.appending(component: "Package.swift"), string: "") |
| 1031 | + callback(.success(())) |
| 1032 | + }) |
| 1033 | + } |
| 1034 | + ) |
| 1035 | + |
| 1036 | + let fileSystem = InMemoryFileSystem() |
| 1037 | + let path = AbsolutePath(path: "/LinkedList-1.1.1") |
| 1038 | + |
| 1039 | + try registryClient.downloadSourceArchive( |
| 1040 | + package: identity, |
| 1041 | + version: version, |
| 1042 | + fileSystem: fileSystem, |
| 1043 | + destinationPath: path, |
| 1044 | + checksumAlgorithm: checksumAlgorithm |
| 1045 | + ) |
| 1046 | + |
| 1047 | + let contents = try fileSystem.getDirectoryContents(path) |
| 1048 | + XCTAssertEqual(contents, ["Package.swift"]) |
| 1049 | + } |
861 | 1050 |
|
862 | 1051 | func testLookupIdentities() throws {
|
863 | 1052 | let registryURL = "https://packages.example.com"
|
|
0 commit comments