From 444364b63c0d5f2d7e5e00815a831713856713c2 Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Fri, 31 Jan 2025 08:22:11 -0500 Subject: [PATCH] test: Add entry query function tests (#8534) --- app/queries/servers/entry.test.ts | 237 ++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 app/queries/servers/entry.test.ts diff --git a/app/queries/servers/entry.test.ts b/app/queries/servers/entry.test.ts new file mode 100644 index 000000000..60032fbd1 --- /dev/null +++ b/app/queries/servers/entry.test.ts @@ -0,0 +1,237 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {CATEGORIES_TO_KEEP} from '@constants/preferences'; +import DatabaseManager from '@database/manager'; + +import {prepareEntryModels, prepareEntryModelsForDeletion, truncateCrtRelatedTables} from './entry'; + +import type {MyChannelsRequest} from '@actions/remote/channel'; +import type {MyPreferencesRequest} from '@actions/remote/preference'; +import type {MyTeamsRequest} from '@actions/remote/team'; +import type {MyUserRequest} from '@actions/remote/user'; +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type {Database} from '@nozbe/watermelondb'; +import type PreferenceModel from '@typings/database/models/servers/preference'; + +describe('Entry Queries', () => { + const serverUrl = 'entry.test.com'; + let database: Database; + let operator: ServerDataOperator; + + beforeEach(async () => { + await DatabaseManager.init([serverUrl]); + const serverDatabaseAndOperator = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + database = serverDatabaseAndOperator.database; + operator = serverDatabaseAndOperator.operator; + }); + + afterEach(async () => { + await DatabaseManager.destroyServerDatabase(serverUrl); + }); + + describe('prepareEntryModels', () => { + it('should prepare models with team data', async () => { + const teamData: MyTeamsRequest = { + teams: [{ + id: 'team1', + name: 'team1', + }] as Team[], + memberships: [{ + team_id: 'team1', + user_id: 'user1', + roles: 'team_user', + }] as TeamMembership[], + }; + + const promises = await prepareEntryModels({ + operator, + teamData, + }); + + expect(promises.length).toBe(3); + const results = await Promise.all(promises); + expect(results[0].length).toBeGreaterThan(0); + }); + + it('should prepare models with channel data', async () => { + const chData: MyChannelsRequest = { + channels: [{ + id: 'channel1', + name: 'channel1', + team_id: 'team1', + }] as Channel[], + memberships: [{ + channel_id: 'channel1', + user_id: 'user1', + roles: 'channel_user', + }] as ChannelMembership[], + categories: [{ + id: 'category1', + team_id: 'team1', + type: 'custom', + channel_ids: ['channel1'], + }] as CategoryWithChannels[], + }; + + const promises = await prepareEntryModels({ + operator, + chData, + }); + + expect(promises.length).toBe(6); + const results = await Promise.all(promises); + expect(results[0].length).toBeGreaterThan(0); + }); + + it('should prepare models with preference data', async () => { + const prefData: MyPreferencesRequest = { + preferences: [{ + category: CATEGORIES_TO_KEEP.ADVANCED_SETTINGS, + name: 'test', + user_id: 'user1', + value: 'test', + }], + }; + + const promises = await prepareEntryModels({ + operator, + prefData, + }); + + expect(promises.length).toBe(1); + const results = await Promise.all(promises); + expect(results[0].length).toBeGreaterThan(0); + expect((results[0][0] as PreferenceModel).name).toBe('test'); + }); + + it('should prepare models with user data', async () => { + const meData: MyUserRequest = { + user: { + id: 'user1', + username: 'user1', + roles: '', + } as UserProfile, + }; + + const promises = await prepareEntryModels({ + operator, + meData, + }); + + expect(promises.length).toBe(1); + const results = await Promise.all(promises); + expect(results[0].length).toBe(1); + expect(results[0][0].id).toBe('user1'); + }); + }); + + describe('prepareEntryModelsForDeletion', () => { + it('should prepare models for deletion with team data', async () => { + const mockTeam = { + id: 'team1', + name: 'team1', + } as Team; + + await operator.handleTeam({ + teams: [mockTeam], + prepareRecordsOnly: false, + }); + + await operator.handleMyTeam({ + myTeams: [{ + id: 'team1', + roles: 'team_user', + }], + prepareRecordsOnly: false, + }); + + const teamData: MyTeamsRequest = { + teams: [mockTeam], + memberships: [{ + team_id: 'team2', // Different team ID triggers deletion of team1 + user_id: 'user1', + roles: 'team_user', + delete_at: 0, + }] as TeamMembership[], + }; + + const promises = await prepareEntryModelsForDeletion({ + operator, + teamData, + }); + + expect(promises.length).toBeGreaterThan(0); + const results = await Promise.all(promises); + expect(results[0].length).toBeGreaterThan(0); + }); + + it('should prepare models for deletion with channel data', async () => { + await operator.handleChannel({ + channels: [{ + id: 'channel1', + name: 'channel1', + team_id: 'team1', + }] as Channel[], + prepareRecordsOnly: false, + }); + + const chData: MyChannelsRequest = { + channels: [{ + id: 'channel2', // Different channel triggers deletion of channel1 + name: 'channel2', + team_id: 'team1', + }] as Channel[], + memberships: [{ + channel_id: 'channel2', + user_id: 'user1', + roles: 'channel_user', + }] as ChannelMembership[], + }; + + const promises = await prepareEntryModelsForDeletion({ + operator, + chData, + }); + + expect(promises.length).toBeGreaterThan(0); + const results = await Promise.all(promises); + expect(results[0].length).toBeGreaterThan(0); + }); + }); + + describe('truncateCrtRelatedTables', () => { + it('should handle errors in development mode', async () => { + // Mock __DEV__ to true + const originalDev = __DEV__; + (global as any).__DEV__ = true; + + // Mock database.write to throw error + jest.spyOn(database, 'write').mockImplementation(() => { + throw new Error('Test error'); + }); + + await expect(truncateCrtRelatedTables(serverUrl)).rejects.toThrow('Test error'); + + // Restore __DEV__ + (global as any).__DEV__ = originalDev; + }); + + it('should handle errors in production mode', async () => { + // Mock __DEV__ to false + const originalDev = __DEV__; + (global as any).__DEV__ = false; + + // Mock database.write to throw error + jest.spyOn(database, 'write').mockImplementation(() => { + throw new Error('Test error'); + }); + + const result = await truncateCrtRelatedTables(serverUrl); + expect(result.error).toBeTruthy(); + + // Restore __DEV__ + (global as any).__DEV__ = originalDev; + }); + }); +});