Skip to content

Commit f6d0ff5

Browse files
committed
Throw fingerprint write errors
Per review feedback, reverting part of the changes introduced in #3928.
1 parent fc9ab55 commit f6d0ff5

File tree

3 files changed

+90
-9
lines changed

3 files changed

+90
-9
lines changed

Sources/PackageRegistry/RegistryClient.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,16 @@ public final class RegistryClient {
432432
switch storageResult {
433433
case .success:
434434
completion(.success(checksum))
435+
case .failure(PackageFingerprintStorageError.conflict(_, let existing)):
436+
switch self.fingerprintCheckingMode {
437+
case .strict:
438+
completion(.failure(RegistryError.checksumChanged(latest: checksum, previous: existing.value)))
439+
case .warn:
440+
observabilityScope.emit(warning: "The checksum \(checksum) from \(registry.url.absoluteString) does not match previously recorded value \(existing.value) from \(String(describing: existing.origin.url?.absoluteString))")
441+
completion(.success(checksum))
442+
}
435443
case .failure(let error):
436-
// Don't throw write errors
437-
observabilityScope.emit(warning: "Failed to save checksum '\(checksum) from \(registry.url) to fingerprints storage: \(error)")
438-
completion(.success(checksum))
444+
completion(.failure(error))
439445
}
440446
}
441447
} else {

Sources/Workspace/SourceControlPackageContainer.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,14 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri
185185
callback: $0
186186
)
187187
}
188-
} catch {
189-
observabilityScope.emit(warning: "Failed to save revision '\(revision.identifier) from \(sourceControlURL) to fingerprints storage: \(error)")
188+
} catch PackageFingerprintStorageError.conflict(_, let existing) {
189+
let message = "Revision \(revision.identifier) for \(self.package) version \(version) does not match previously recorded value \(existing.value) from \(String(describing: existing.origin.url?.absoluteString))"
190+
switch self.fingerprintCheckingMode {
191+
case .strict:
192+
throw StringError(message)
193+
case .warn:
194+
observabilityScope.emit(warning: message)
195+
}
190196
}
191197
} catch {
192198
self.observabilityScope.emit(error: "Failed to get source control fingerprint for \(self.package) version \(version) from storage: \(error)")

Tests/PackageRegistryTests/RegistryClientTests.swift

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,74 @@ final class RegistryClientTests: XCTestCase {
346346
var configuration = RegistryConfiguration()
347347
configuration.defaultRegistry = Registry(url: URL(string: registryURL)!)
348348

349+
let fingerprintStorage = MockPackageFingerprintStorage([
350+
identity: [
351+
version: [.registry: Fingerprint(origin: .registry(URL(string: registryURL)!), value: "non-matching checksum")],
352+
],
353+
])
354+
let registryClient = makeRegistryClient(configuration: configuration,
355+
httpClient: httpClient,
356+
fingerprintStorage: fingerprintStorage,
357+
fingerprintCheckingMode: .strict)
358+
359+
XCTAssertThrowsError(try registryClient.fetchSourceArchiveChecksum(package: identity, version: version)) { error in
360+
guard case RegistryError.checksumChanged = error else {
361+
return XCTFail("Expected RegistryError.checksumChanged, got \(error)")
362+
}
363+
}
364+
}
365+
366+
func testFetchSourceArchiveChecksum_storageConflict_fingerprintChecking_warn() throws {
367+
let registryURL = "https://packages.example.com"
368+
let identity = PackageIdentity.plain("mona.LinkedList")
369+
let (scope, name) = identity.scopeAndName!
370+
let version = Version("1.1.1")
371+
let metadataURL = URL(string: "\(registryURL)/\(scope)/\(name)/\(version)")!
372+
let checksum = "a2ac54cf25fbc1ad0028f03f0aa4b96833b83bb05a14e510892bb27dea4dc812"
373+
374+
let handler: HTTPClient.Handler = { request, _, completion in
375+
switch (request.method, request.url) {
376+
case (.get, metadataURL):
377+
XCTAssertEqual(request.headers.get("Accept").first, "application/vnd.swift.registry.v1+json")
378+
379+
let data = """
380+
{
381+
"id": "mona.LinkedList",
382+
"version": "1.1.1",
383+
"resources": [
384+
{
385+
"name": "source-archive",
386+
"type": "application/zip",
387+
"checksum": "\(checksum)"
388+
}
389+
],
390+
"metadata": {
391+
"description": "One thing links to another."
392+
}
393+
}
394+
""".data(using: .utf8)!
395+
396+
completion(.success(.init(
397+
statusCode: 200,
398+
headers: .init([
399+
.init(name: "Content-Length", value: "\(data.count)"),
400+
.init(name: "Content-Type", value: "application/json"),
401+
.init(name: "Content-Version", value: "1"),
402+
]),
403+
body: data
404+
)))
405+
default:
406+
completion(.failure(StringError("method and url should match")))
407+
}
408+
}
409+
410+
var httpClient = HTTPClient(handler: handler)
411+
httpClient.configuration.circuitBreakerStrategy = .none
412+
httpClient.configuration.retryStrategy = .none
413+
414+
var configuration = RegistryConfiguration()
415+
configuration.defaultRegistry = Registry(url: URL(string: registryURL)!)
416+
349417
let storedChecksum = "non-matching checksum"
350418
let fingerprintStorage = MockPackageFingerprintStorage([
351419
identity: [
@@ -355,21 +423,22 @@ final class RegistryClientTests: XCTestCase {
355423
let registryClient = makeRegistryClient(configuration: configuration,
356424
httpClient: httpClient,
357425
fingerprintStorage: fingerprintStorage,
358-
fingerprintCheckingMode: .strict)
426+
fingerprintCheckingMode: .warn)
359427

360428
let observability = ObservabilitySystem.makeForTesting()
361429

362-
// The checksum differs from that in storage, but we don't throw write errors
430+
// The checksum differs from that in storage, but error is not thrown
431+
// because fingerprintCheckingMode=.warn
363432
let checksumResponse = try registryClient.fetchSourceArchiveChecksum(
364433
package: identity,
365434
version: version,
366435
observabilityScope: observability.topScope
367436
)
368437
XCTAssertEqual(checksum, checksumResponse)
369438

370-
// There should be a warning though
439+
// But there should be a warning
371440
testDiagnostics(observability.diagnostics) { result in
372-
result.check(diagnostic: .contains("different from previously recorded value"), severity: .warning)
441+
result.check(diagnostic: .contains("does not match previously recorded value"), severity: .warning)
373442
}
374443

375444
// Storage should NOT be updated

0 commit comments

Comments
 (0)