Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix version 3.0 beta build #691

Merged
merged 60 commits into from
May 3, 2023
Merged

Conversation

cbaker6
Copy link
Contributor

@cbaker6 cbaker6 commented Apr 7, 2023

  • Fix all tests to run on latest version of Xcode provided by GitHub Actions (Xcode 14.2 on macOS 12)
  • Make store in OCKDailyPageViewController.swift public readable, commit: 38be8ce
  • Fix app crash caused by OCKCDPostalAddress init, commit: 863a5e8
  • Minor doc nits like: careKitStore->careStore commit: 4bf2d81
  • Fix broken watchOS build. There are currently some files that shouldn't build for watchOS
  • Run CI on iOS and watchOS to prevent breaking PR's on watchOS
  • Align all IPHONEOS_DEPLOYMENT_TARGET to 14
  • Align all WATCHOS_DEPLOYMENT_TARGET to 7.0
  • Fix CareKitFHIR project to build/test on watchOS
  • Fix broken testcases
  • Make any new commits cancel previous running actions on PR
  • Bump AsyncAlgorithms to 0.1.0
  • Add .spi.yml for properly building on Swift Package Index. Swift Package Index is the successor of SwiftPM Library and sponsored by Apple
  • Let SPI build docs as well. SPI will automatically build docs from the main branch along with any regular/beta release allowing all versions of docs to be captured and visited at anytime
  • Add SPI badges:
    image

Note1: The watchOS platform should appear after this PR is merged to the main as the added .spi.yml tells Swift Package Index what scheme to use for building watch.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Apr 7, 2023

@gavirawson-apple This is ready for review, let me know if you want me to make any adjustments.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Apr 7, 2023

@gavirawson-apple It looks like there are a couple files missing that SPM can see, but prevents testing. These files are currently not part of the Xcode build which is why it succeeds:

  • TestCoreDataQueryPublisher.swift - this is in the repo, but not in the Xcode project. Currently can't build with it because it's missing the types below
  • CoreDataSource, QueryPublisher

@cbaker6
Copy link
Contributor Author

cbaker6 commented Apr 7, 2023

I've also tested these changes locally in Xcode 14.3 and fix all errors/warnings.

@cbaker6 cbaker6 closed this Apr 9, 2023
@cbaker6 cbaker6 closed this Apr 13, 2023
@cbaker6 cbaker6 reopened this Apr 13, 2023
@cbaker6 cbaker6 changed the title Fix CI for latest version Fix version 3.0 beta build Apr 13, 2023
@cbaker6 cbaker6 closed this Apr 13, 2023
@cbaker6 cbaker6 reopened this Apr 13, 2023
@cbaker6
Copy link
Contributor Author

cbaker6 commented Apr 13, 2023

I think the CI for this PR needs approval to run.

You can track the working build in my local PR: cbaker6#8

Comment on lines 20 to 22
exclude:
- destination: 'platform=watchOS\ Simulator,OS=9.1,name=Apple\ Watch\ Series\ 5\ \(40mm\)'
scheme: 'CareKitUI'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

add this back

Comment on lines +5 to +9
platform: ios
- platform: ios
scheme: "CareKit"
- platform: watchos
scheme: "CareKit"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

add macOS

@@ -88,7 +88,7 @@ public struct OCKScheduleElement: Codable, Equatable {
}
}

private let calendar: Calendar
private static var calendar = Calendar.current
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Change to static computed property

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove file

@@ -57,8 +56,7 @@ class TestColorExtension: XCTestCase {

func testClamping() {
let start = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
let lightened = start.lightened(10)
let lightened = start.lightened(1)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has a pre-condition where the argument passed to lightened has to be <=1. For some reason it hasn't been failing on the iOS tests, but the watchOS tests caught the error.

Copy link
Contributor Author

@cbaker6 cbaker6 Apr 20, 2023

Choose a reason for hiding this comment

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

I found the issue. The reason was TestColorExtension wasn't included in the XCTest scheme so it never ran when the CI tests the Xcode project. I noticed the issue in SPM after #691 (comment) since SPM auto detects test files instead of depending on the project scheme.

The update to include the test is here: 225341b

@@ -4,7 +4,7 @@ import PackageDescription
let package = Package(
name: "CareKit",
defaultLocalization: "en",
platforms: [.iOS(.v13), .macOS(.v10_15), .watchOS(.v6)],
platforms: [.iOS(.v14), .macOS(.v11), .watchOS(.v7)],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bumps to minimum iOS 14 along with counterparts so SPM matches the Xcode Project.

name: "CareKitUITests",
dependencies: ["CareKitUI"],
path: "CareKitUI/CareKitUITests",
exclude: ["Info.plist", "CareKitUI.xctestplan"]),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test target was missing from SPM so CareKitUITests weren't showing up when the project was opened with Package.swift

@cbaker6
Copy link
Contributor Author

cbaker6 commented Apr 20, 2023

@gavirawson-apple this is ready for review. You can see the passing tests in the CI here: cbaker6#8

The CI should begin running against this repo once it's approved

// 8. Lock in the changes. If this fails, all
// merged changes will be rolled back and
// we'll need to try again later.
try self.context.save()
Copy link
Contributor Author

@cbaker6 cbaker6 Apr 22, 2023

Choose a reason for hiding this comment

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

This bug wasn't easy to find, but was introduced with the changes in #553. The issue is with the last increment to the knowledge vector is never saved in context, causing data to be lost when saving OCK objects using a CareKit card or other view because it doesn't have the most up-to-date clock value.

The fix is just to save after the increment and probably have a heuristic that mentions a save should always occur after an increment at some point before exiting the respective block of code.

The current test cases don't catch this issue because they are testing the stores directly as oppose to using the CareKit cards to save the outcomes.

The example case to replicate the issue is below:

  1. Setup Device1 to connect to a OCKRemoteServer
  2. Add tasks
  3. Save an outcome using a CareKit card and sync Device1 to the OCKRemoteServer
  4. Bring a new Device2 online and sync it to the OCKRemoteServer. Device2 will now reflect everything on Device1
  5. Delete the saved outcome using a CareKit card on Device2. This will trigger a pullRevision, but notice during pushRevisions no new revision records will be found because the CareKit didn't have the correct Knowledge Vector clock value because it wasn't saved in context. Causing Device1 to never receive the deleted outcome, forcing the devices out-of-sync

I've tested the updates using my sample and using OCKWatchConnectivityPeer. Before the fix I was able to get the iPhone and watch out-of-sync. After the updates, the devices remained synchronized.

Copy link
Contributor Author

@cbaker6 cbaker6 Apr 22, 2023

Choose a reason for hiding this comment

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

This can also be done after push revisions is complete, but I'm not sure if it's actually better and requires extra code:

// 4. Detect and resolve any conflicts that exist. The store
    //    is a CRDT, so there aren't any conflicts at the data
    //    layer, but we want to resolve concurrent changes.
    self.resolveConflicts { error in

        self.context.perform {
            do {
                // 5. Lock in the changes. If this fails, all
                //    merged changes will be rolled back and
                //    we'll need to try again later.
                try self.context.save()

                // 6. Local revisions will now include any patches
                //    that were applied during conflict resolution.
                let localKnowledge = self.context.knowledgeVector

                let localRevisions = try self.computeRevisions(
                    since: remoteKnowledge
                )

                // 7. Bump knowledge vector to indicate that any
                //    objects created beyond this point in time
                //    are considered unknown to the peer.
                self.context.knowledgeVector.increment(
                    clockFor: self.context.clockID
                )

                // 8. Push conflict resolutions + local changes to remote
                remote.pushRevisions(
                    deviceRevisions: localRevisions,
                    deviceKnowledge: localKnowledge) { error in

                    if let error = error {
                        os_log("Failed to push revision. %{private}@",
                               log: .store, type: .error, error as NSError)
                    }
                    
                    self.context.perform {
                        do {
                            // 9. Lock in the changes. If this fails, all
                            //    merged changes will be rolled back and
                            //    we'll need to try again later.
                            try self.context.save()
                        } catch {
                            self.context.rollback()
                            completion(error)
                            return
                        }

                        // 10. The sync is still considered successful
                        //    even if the remote doesn't accept the
                        //    push. The next time we sync with it, it
                        //    will still have the same knowledge
                        //    vector, which means the proper diff will
                        //    be generated.
                        completion(nil)
                    }
                }
            } catch {
                self.context.rollback()
                completion(error)
            }
        }
    }

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice catch!

Copy link
Collaborator

@gavirawson-apple gavirawson-apple left a comment

Choose a reason for hiding this comment

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

Looks amazing Corey, I just have one minor suggestion to consider before we merge away.

CareKitStore/CareKitStore/Structs/OCKScheduleElement.swift Outdated Show resolved Hide resolved
Co-authored-by: Gavi Rawson <51756298+gavirawson-apple@users.noreply.github.com>
@cbaker6
Copy link
Contributor Author

cbaker6 commented Apr 28, 2023

@gavirawson-apple let me know if you need anything else from me on this PR

@gavirawson-apple
Copy link
Collaborator

Thanks Corey, everything is set here. We're just going through some process on our end.

@gavirawson-apple gavirawson-apple merged commit 2f2af4e into carekit-apple:main May 3, 2023
@cbaker6 cbaker6 deleted the fixCI branch June 8, 2023 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants