Skip to content

Conversation

@JZDesign
Copy link
Contributor

@JZDesign JZDesign commented Dec 8, 2025

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-android and hybrids

Motivation

resolves #5912

Description

Replaces the user defaults cache with a file cache to prevent crashes on watchOS (and probably TVOS)

@JZDesign JZDesign changed the title First pass–replace user defaults with file cache UserDefaults Crash Fix Dec 8, 2025
@JZDesign JZDesign marked this pull request as ready for review December 10, 2025 17:57
@JZDesign JZDesign requested a review from a team as a code owner December 10, 2025 17:57
@JZDesign JZDesign added the pr:fix A bug fix label Dec 10, 2025
static func cacheKey(for request: URLRequest) -> String? {
return request.url?.absoluteString
static func cacheKey(for request: URLRequest) -> CacheKey? {
return (request.url?.absoluteString.asData.md5String).map(ETagManager.CacheKey.init)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using ://some-text/some-path in the file system is not a good idea

Copy link
Member

@ajpallares ajpallares left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the implementation looks mostly good. However, I have some comments about improving the code and also about tests, which I think have some issues because of the MockSimpleCache's implementation

Comment on lines +20 to +21
var workingCacheDirectory: URL?
var workingDocsDirectory: URL?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these two needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache sets the working directory once when used by the consumer. This is used to test that the clear happens at the working directory.

Comment on lines 36 to 46
func testETagIsEmptyIfThereIsNoETagSavedForThatRequestWithDifferentURL() throws {
let request1 = URLRequest(url: Self.testURL)
let request2 = URLRequest(url: Self.testURL2)

try self.mockStoredETagResponse(for: request1)
// Request2 will also try to load, stub a failure for it
mockCache.stubLoadFile(with: .failure(SampleError()))

let header = self.eTagManager.eTagHeader(for: request2, withSignatureVerification: false)
expect(header[ETagManager.eTagRequestHeader.rawValue]) == ""
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these tests are very useful now using the MockSimpleCache. Probably the issue is in the MockSimpleCache implementation, which is not associating the stored data to keys, but storing data by index.

  • If we change the order of the mocks, the test fails
// Request2 will also try to load, stub a failure for it
mockCache.stubLoadFile(with: .failure(SampleError()))

try self.mockStoredETagResponse(for: request1)

Even more "wrong", if we only check in the test for the eTag header of request1, the test fails

func testETagIsEmptyIfThereIsNoETagSavedForThatRequestWithDifferentURL() throws {
    let request1 = URLRequest(url: Self.testURL)
    let request2 = URLRequest(url: Self.testURL2)

    try self.mockStoredETagResponse(for: request1)
    // Request2 will also try to load, stub a failure for it
    mockCache.stubLoadFile(with: .failure(SampleError()))

    let header1 = self.eTagManager.eTagHeader(for: request1, withSignatureVerification: false)
    XCTAssertEqual(header1[ETagManager.eTagRequestHeader.rawValue], Self.testETag)
}

Copy link
Contributor Author

@JZDesign JZDesign Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was too involved in other things to give this much attention yesterday. I started in on this today. Again, great feedback, thank you.

I've created a tailored mock for this use case. One of the reasons I had avoided it was the md5 conversions and needing to have the exact right storage URL to look it up. But you're right, these tests would have been easily breakable with the index based version.

@JZDesign JZDesign requested a review from ajpallares December 12, 2025 15:54
@JZDesign
Copy link
Contributor Author

@RCGitBot please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Crash on watchOS when storing etags in UserDefaults

3 participants