-
Notifications
You must be signed in to change notification settings - Fork 7
feat(sync): RN-1680: Sync tests #6597
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
base: rn-1717-test-four
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @chris-bes, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the synchronization capabilities by introducing a dedicated Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a comprehensive suite of tests for the sync functionality, significantly improving the robustness of the CentralSyncManager. The new tests cover pull, push, session management, and the sync lookup table logic, which is a valuable addition. The changes also include minor refactorings and additions to support this testing effort, such as a test hook for pausing snapshots and enabling the avoidRepull feature by default. My review focuses on enhancing type safety within the new test files by replacing the use of any with more specific types, which will improve maintainability and code clarity.
packages/sync-server/src/__tests__/CentralSyncManager.pull.test.ts
Outdated
Show resolved
Hide resolved
| import { waitForPushComplete, waitForSession } from '../testUtilities/waitForSync'; | ||
|
|
||
| describe('CentralSyncManager.push', () => { | ||
| let models: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/sync-server/src/__tests__/CentralSyncManager.push.test.ts
Outdated
Show resolved
Hide resolved
packages/sync-server/src/__tests__/CentralSyncManager.session.test.ts
Outdated
Show resolved
Hide resolved
packages/sync-server/src/__tests__/CentralSyncManager.session.test.ts
Outdated
Show resolved
Hide resolved
packages/sync-server/src/__tests__/CentralSyncManager.syncLookup.test.ts
Outdated
Show resolved
Hide resolved
jaskfla
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Buncha small optional details, but nothing to complain about. Looking great overall—happy for you to pick and choose which comments need addressing and merge without re-review ✅
Thanks for sorting this out 🙏
| * @param {number} tick | ||
| */ | ||
| async markAsStartedAt(id, tick) { | ||
| await this.updateById(id, { started_at_tick: tick }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small stylistic thing, but could be nice to be explicit that we’re throwing away the return value
| await this.updateById(id, { started_at_tick: tick }); | |
| void (await this.updateById(id, { started_at_tick: tick })); |
| "start-verbose": "LOG_LEVEL=debug yarn run start-dev", | ||
| "setup-test": "yarn workspace @tupaia/database run setup-test-database", | ||
| "test": "yarn run package:test" | ||
| "test": "yarn run package:test:serial" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only usage of :serial, right? Maybe clearer just to call jest --runInBand here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve had a quick squiz and it seems like the --maxWorkers=50% we set in the global script is Jest’s default anyway
Simpler to just remove --maxWorkers=50% from the global script. Here, call yarn run package:test --runInBand and let Yarn forward the argument
| const POLICY = { | ||
| DL: [BES_ADMIN_PERMISSION_GROUP, 'Admin'], | ||
| KI: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Admin'], | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const POLICY = { | |
| DL: [BES_ADMIN_PERMISSION_GROUP, 'Admin'], | |
| KI: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Admin'], | |
| }; | |
| const POLICY = { | |
| DL: [BES_ADMIN_PERMISSION_GROUP, 'Admin'], | |
| KI: [TUPAIA_ADMIN_PANEL_PERMISSION_GROUP, 'Admin'], | |
| } as const; |
Ditto with SYNC_CONFIG in CentralSyncManager.syncLookup.test.ts
| ); | ||
| }); | ||
|
|
||
| it("excludes inserted records from another sync session when the current' session's snapshot transaction already started", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| it("excludes inserted records from another sync session when the current' session's snapshot transaction already started", async () => { | |
| it('excludes inserted records from another sync session when the current session’s snapshot transaction already started', async () => { |
| recordId: userAccount4.id, | ||
| data: await userAccount4.getData(), | ||
| }, | ||
| ] as SyncSnapshotAttributes[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly dangerous cast? Looks like the array elements are missing a couple properties that SyncSnapshotAttributes requires
Happy to overlook this in test environment, though—your call 🙂
|
|
||
| describe('startSession', () => { | ||
| it('creates a new session', async () => { | ||
| const centralSyncManager = new CentralSyncManager(models); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional: could declare let centralSyncManager: CentralSyncManager in a higher scope and do centralSyncManager = new CentralSyncManager(models) in the beforeEach phase
| record_id: expect.anything(), | ||
| record_type: model.databaseRecord, | ||
| project_ids: expect.anything(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth being stricter here?
| record_id: expect.anything(), | |
| record_type: model.databaseRecord, | |
| project_ids: expect.anything(), | |
| record_id: expect.stringMatcing(/^[a-f\d]{24}$/), | |
| record_type: model.databaseRecord, | |
| project_ids: expect.arrayOf(expect.stringMatching(/^[a-f\d]{24}$/)); |
expect.any(String) also works as a middle ground, but matching the pattern feels right there
(.anything() appears a few times in this test suite, but I won’t repeat this comment)
| lookupTable: { | ||
| perModelUpdateTimeoutMs: 1_000_000, | ||
| avoidRepull: false, | ||
| avoidRepull: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double checking this was an intentional change?
| // @ts-expect-error - central-server createApp is a JS file without types | ||
| import { createApp } from '../../../central-server/src/createApp'; | ||
|
|
||
| const models = getTestModels() as ModelRegistry & { user: any }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const models = getTestModels() as ModelRegistry & { user: any }; | |
| const models = getTestModels() as SyncServerModelRegistry; |
(Remember to update imports)
| let ready = false; | ||
| while (!ready) { | ||
| ready = await centralSyncManager.checkSessionReady(sessionId); | ||
| await sleep(100); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of those rare instances where do…while makes sense!
Honestly not fussed about changing; I like the readability of the ready variable. This is mostly just a reminder that do loops exist in JS 😆
| let ready = false; | |
| while (!ready) { | |
| ready = await centralSyncManager.checkSessionReady(sessionId); | |
| await sleep(100); | |
| } | |
| do { | |
| await sleep(100); | |
| } while (!(await centralSyncManager.checkSessionReady(sessionId))) |
55e4843 to
2600161
Compare
| record_type: 'user_account', | ||
| updated_at_sync_tick: expectedTick.toString(), | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test assertion never validates record data
The forEach callback doesn't receive any parameters (uses () instead of (record)), and expect.objectContaining({...}) by itself creates a matcher but never actually asserts anything. The matcher needs to be used with expect(record).toEqual(...) or similar. This test will always pass regardless of the actual data in userAccountLookupData, effectively making it useless for verifying the updated_at_sync_tick values.
|
|
||
| await centralSyncManager.connectToSession(sessionId); | ||
|
|
||
| expect(() => centralSyncManager.connectToSession(sessionId)).not.toThrow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test uses synchronous assertion on async function
The test uses expect(() => connectToSession(...)).not.toThrow() on an async function, but .toThrow() only catches synchronous throws, not Promise rejections. Since connectToSession is async, this assertion will always pass even if the function returns a rejected Promise. The correct pattern is await expect(...).resolves.toBeDefined() as used elsewhere (e.g., line 189 uses the async-aware .rejects.toThrow()).
| lookupTable: { | ||
| perModelUpdateTimeoutMs: 1_000_000, | ||
| avoidRepull: false, | ||
| avoidRepull: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default config change in test-focused PR
The default value for avoidRepull in DEFAULT_CONFIG was changed from false to true. This changes production behavior in a PR that's titled as "Sync tests" and should only be adding tests. A reviewer in the discussion explicitly asked "Double checking this was an intentional change?" suggesting this may have been accidentally included. This behavioral change affects how sync data is handled for devices and could impact production sync behavior if not intentional.
# Conflicts: # packages/sync/src/utils/index.ts
Changes: