| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #!/usr/bin/env node
- /**
- * Checks collections for potential issues with batchedUpdate missing
- * entries at the start of the collection.
- */
- import assert from 'node:assert/strict'
- import { describe, it, before, after } from 'node:test'
- import { db, connectionPromise } from '../lib/mongodb.mjs'
- /**
- * Finds IDs where the natural order and _id sorted order differ.
- * This identifies records that might have been moved or updated in a way
- * that affected their storage position in MongoDB.
- */
- async function findDivergentRecords(coll) {
- const [firstNatural, firstSorted] = await Promise.all([
- db[coll].find().limit(1).next(),
- db[coll].find().sort({ _id: 1 }).limit(1).next(),
- ])
- if (!firstNatural || !firstSorted || firstNatural._id.equals(firstSorted._id))
- return []
- const [minId, maxId] =
- firstNatural._id.toString() < firstSorted._id.toString()
- ? [firstNatural._id, firstSorted._id]
- : [firstSorted._id, firstNatural._id]
- const found = await db[coll]
- .find({ _id: { $gte: minId, $lte: maxId } })
- .toArray()
- return found
- }
- describe('Batched update audit', async () => {
- let client
- before(async () => {
- client = await connectionPromise
- })
- after(async () => {
- if (client) await client.close()
- })
- describe('users collection', async () => {
- const records = await findDivergentRecords('users')
- if (records.length === 0) {
- it('no divergent records found', () => assert.ok(true))
- } else {
- for (const record of records) {
- describe(`Record: ${record._id}`, () => {
- // tools/migrations/20210726083523_convert_confirmedAt_strings_to_dates.mjs
- // any confirmedAt field must be a date
- it('confirmedAt is a Date object in email records', () => {
- record.emails?.forEach(emailObj => {
- if ('confirmedAt' in emailObj) {
- assert.ok(emailObj.confirmedAt instanceof Date)
- }
- })
- })
- // tools/migrations/20210726083523_convert_split_tests_assigned_at_strings_to_dates.mjs
- // each split test entry has a date in the assignedAt field if set
- it('splitTests entry assignedAt fields are Date objects', () => {
- // splitTests is stored as an object keyed by test name
- Object.values(record.splitTests || {}).forEach(test => {
- if (test.assignedAt) assert.ok(test.assignedAt instanceof Date)
- })
- })
- // tools/migrations/20220826104236_disable_alpha_beta_program.mjs
- // should be strictly false, but allow undefined for simplicity
- it('alpha/beta program are disabled', () => {
- assert.ok(
- record.alphaProgram === false || record.alphaProgram === undefined
- )
- assert.ok(
- record.betaProgram === false || record.betaProgram === undefined
- )
- })
- // tools/migrations/20220913125500_migrate_auditLog_to_collections.mjs
- it('obsolete auditLog field is not present', () => {
- assert.equal(record.auditLog, undefined)
- })
- // tools/migrations/20230124092607_clear_old_2fa_setup.mjs
- it('obsolete 2fa field is not present', () => {
- assert.equal(record.twoFactorAuthentication, undefined)
- })
- // tools/migrations/20240618125145_cleanup_user_features_templates.mjs
- // unsets features.templates
- it('features does not contain a templates field', () => {
- assert.equal(
- record.features?.templates,
- undefined,
- `features ${JSON.stringify(record.features)}`
- )
- })
- // tools/migrations/20240713110905_emails_reversed_hostname.mjs
- it('reversedHostname matches reversed email domain', () => {
- record.emails.forEach((emailObj, index) => {
- if (emailObj.email) {
- const expected = emailObj.email
- .split('@')[1]
- .split('')
- .reverse()
- .join('')
- assert.equal(
- emailObj.reversedHostname,
- expected,
- `Email ${index} mismatch`
- )
- }
- })
- })
- })
- }
- }
- })
- describe('subscriptions collection', async () => {
- const records = await findDivergentRecords('subscriptions')
- if (records.length === 0) {
- it('no divergent records found', () => assert.ok(true))
- } else {
- for (const record of records) {
- describe(`Record: ${record._id}`, () => {
- // tools/migrations/20230110140452_rename_recurly_cached_status.mjs
- // renames recurly to recurlyStatus
- it('recurly field does not exist', () =>
- assert.equal(record.recurly, undefined))
- // tools/migrations/20230207134844_group_invite_emails_to_lowercase.mjs
- // changes array entries to lowercase
- it('teamInvites emails are lowercase', () => {
- record.teamInvites?.forEach(invite => {
- if (invite.email)
- assert.equal(invite.email, invite.email.toLowerCase())
- })
- })
- // tools/migrations/20230928092537_backfill_subscriptions_managed_users_feature_flag.mjs
- // unsets features.managedUsers if $ne:true
- // Note this is superseded by the 20241111133330_remove_null_managed_users_sso_from_subscriptions.mjs below
- it('features.managedUsers is either true or null', () => {
- const managedUsers = record.features?.managedUsers
- assert.ok(
- managedUsers === true || managedUsers === null,
- 'features.managedUsers must be either true or null'
- )
- })
- // tools/migrations/20231030160030_managed_users_enabled.mjs
- // sets managedUsersEnabled to true when groupPolicy exists
- it('managedUsersEnabled is true if groupPolicy exists', () => {
- if ('groupPolicy' in record) {
- assert(record.managedUsersEnabled === true)
- }
- })
- // tools/migrations/20241111133330_remove_null_managed_users_sso_from_subscriptions.mjs
- it('features.managedUsers is true if set', () => {
- if (record.features && 'managedUsers' in record.features) {
- assert.strictEqual(
- record.features.managedUsers,
- true,
- 'features.managedUsers must be true when set'
- )
- }
- })
- // also in tools/migrations/20241111133330_remove_null_managed_users_sso_from_subscriptions.mjs
- it('features.groupSSO is true if set', () => {
- if (record.features && 'groupSSO' in record.features) {
- assert.strictEqual(
- record.features.groupSSO,
- true,
- 'features.groupSSO must be true when set'
- )
- }
- })
- })
- }
- }
- })
- })
|