Path: blob/main/components/gitpod-db/src/user-db.spec.db.ts
2497 views
/**1* Copyright (c) 2020 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import * as chai from "chai";7const expect = chai.expect;8import { suite, test, timeout } from "@testdeck/mocha";910import { GitpodTokenType, Identity, Workspace, WorkspaceInstance } from "@gitpod/gitpod-protocol";11import { testContainer } from "./test-container";12import { DBIdentity } from "./typeorm/entity/db-identity";13import { TypeORMUserDBImpl } from "./typeorm/user-db-impl";14import { TypeORMWorkspaceDBImpl } from "./typeorm/workspace-db-impl";15import { TypeORM } from "./typeorm/typeorm";16import { resetDB } from "./test/reset-db";1718const _IDENTITY1: Identity = {19authProviderId: "GitHub",20authId: "1234",21authName: "gero",22deleted: false,23lastSigninTime: undefined,24primaryEmail: undefined,25readonly: false,26};27const _IDENTITY2: Identity = {28authProviderId: "GitHub",29authId: "4321",30authName: "gero",31deleted: false,32lastSigninTime: undefined,33primaryEmail: undefined,34readonly: false,35};36const WRONG_ID = "123"; // no uuid3738@suite39class UserDBSpec {40db = testContainer.get<TypeORMUserDBImpl>(TypeORMUserDBImpl);4142wsDb = testContainer.get<TypeORMWorkspaceDBImpl>(TypeORMWorkspaceDBImpl);4344async before() {45await this.wipeRepos();46}4748async after() {49await this.wipeRepos();50}5152async wipeRepos() {53const typeorm = testContainer.get<TypeORM>(TypeORM);54await resetDB(typeorm);55}5657// Copy to avoid pollution58get IDENTITY1() {59return Object.assign({}, _IDENTITY1);60}61get IDENTITY2() {62return Object.assign({}, _IDENTITY2);63}6465@test(timeout(10000))66public async createUserAndFindById() {67let user = await this.db.newUser();68user.identities.push(this.IDENTITY1);69user = await this.db.storeUser(user);7071const dbResult = await this.db.findUserById(user.id);72// We use 'user' as reference, so clean it73// @ts-ignore74user.identities.forEach((i) => delete (i as DBIdentity).user);75expect(dbResult).to.deep.include(user);76}7778@test(timeout(10000))79public async createUserAndNotFindByWrongId() {80let user = await this.db.newUser();81user.identities.push(this.IDENTITY2);82user = await this.db.storeUser(user);83expect(await this.db.findUserById(WRONG_ID)).to.be.undefined;84}8586@test(timeout(10000))87public async createUserAndFindByIdentity() {88let user = await this.db.newUser();89user.identities.push(this.IDENTITY1);90user = await this.db.storeUser(user);9192const dbResult = await this.db.findUserByIdentity(this.IDENTITY1);93// We use 'user' as reference, so clean it94// @ts-ignore95user.identities.forEach((i) => delete (i as DBIdentity).user);96expect(dbResult).to.deep.include(user);97}9899@test(timeout(10000))100public async findUserById() {101const user = await this.db.newUser();102user.identities.push(this.IDENTITY1);103await this.db.storeUser(user);104105const foundUser = await this.db.findUserById(user.id);106expect(foundUser!.id).to.eq(user.id);107}108109@test(timeout(10000))110public async findUserById_undefined() {111const user = await this.db.newUser();112user.identities.push(this.IDENTITY1);113await this.db.storeUser(user);114115try {116await this.db.findUserById(undefined!);117expect.fail("Should have failed");118} catch (error) {119expect(error.code).to.eq(400);120}121try {122await this.db.findUserById("");123expect.fail("Should have failed");124} catch (error) {125expect(error.code).to.eq(400);126}127}128129@test(timeout(10000))130public async findUsersByEmail_multiple_users_identities() {131let user1 = await this.db.newUser();132user1.name = "Old";133user1.identities.push(TestData.ID1);134user1.identities.push(TestData.ID2);135user1.identities.push(TestData.ID3);136user1 = await this.db.storeUser(user1);137138await this.wsDb.store({139...TestData.DEFAULT_WS,140id: "1",141creationTime: new Date().toISOString(),142ownerId: user1.id,143});144await this.wsDb.storeInstance({145...TestData.DEFAULT_WSI,146workspaceId: "1",147id: "11",148creationTime: new Date().toISOString(),149});150151// ensure that the second user's last modified is definitely after first one's152await new Promise((resolve) => setTimeout(resolve, 100));153154let user2 = await this.db.newUser();155user2.name = "New";156user2.identities.push(TestData.ID4);157user2.identities.push(TestData.ID5);158user2 = await this.db.storeUser(user2);159160await this.wsDb.store({161...TestData.DEFAULT_WS,162id: "2",163creationTime: new Date().toISOString(),164ownerId: user2.id,165});166await this.wsDb.storeInstance({167...TestData.DEFAULT_WSI,168workspaceId: "2",169id: "22",170creationTime: new Date().toISOString(),171});172173const dbResult = await this.db.findUsersByEmail(TestData.primaryEmail);174175expect(dbResult).to.be.an("array");176expect(dbResult).to.be.have.length(2);177expect(dbResult[0].name).to.be.eq("New");178expect(dbResult[1].name).to.be.eq("Old");179}180181@test(timeout(10000))182public async findUserByIdentity_after_moving_identity() {183let user1 = await this.db.newUser();184user1.name = "ABC";185user1.identities.push(TestData.ID1);186user1.identities.push(TestData.ID2);187user1 = await this.db.storeUser(user1);188189let user2 = await this.db.newUser();190user2.name = "XYZ";191user2.identities.push(TestData.ID3);192user2 = await this.db.storeUser(user2);193user2.identities.push(TestData.ID2);194user2 = await this.db.storeUser(user2);195196const r2 = await this.db.findUserByIdentity(TestData.ID1);197expect(r2).to.be.not.undefined;198expect(r2!.identities).to.have.length(1);199200const r1 = await this.db.findUserByIdentity(TestData.ID2);201expect(r1).to.be.not.undefined;202expect(r1!.name).to.be.eq("XYZ");203}204205@test(timeout(10000))206public async findOrgOwnedUser_by_email() {207let orgUser1 = await this.db.newUser();208orgUser1.organizationId = "org1";209orgUser1.name = "Tester";210orgUser1.identities.push({211authId: "123",212authName: "Tester",213authProviderId: "oauth2-client-id",214primaryEmail: "[email protected]",215});216orgUser1 = await this.db.storeUser(orgUser1);217218const result = await this.db.findOrgOwnedUser("org1", "[email protected]");219expect(result, "organizational user should be found").not.to.be.undefined;220expect(result!.identities, "should find a single identity").to.have.length(1);221222const result2 = await this.db.findOrgOwnedUser("org1", "[email protected]");223expect(result2, "no user should be found").to.be.undefined;224}225226@test(timeout(10000))227public async findTokenAndOwner() {228let user1 = await this.db.newUser();229user1.name = "ABC";230user1.identities.push(TestData.ID1);231user1.identities.push(TestData.ID2);232user1 = await this.db.storeUser(user1);233234await this.db.storeGitpodToken({235tokenHash: "tokenhash",236created: new Date().toISOString(),237scopes: ["read-only"],238type: GitpodTokenType.API_AUTH_TOKEN,239userId: user1.id,240});241const result = await this.db.findUserByGitpodToken("tokenhash");242expect(result).to.not.be.undefined;243expect(result?.user.id).to.eq(user1.id);244expect(result?.token.userId).to.eq(user1.id);245}246247@test(timeout(10000))248public async findGitpodTokenOfUser() {249let user1 = await this.db.newUser();250user1.name = "ABC";251user1.identities.push(TestData.ID1);252user1.identities.push(TestData.ID2);253user1 = await this.db.storeUser(user1);254255const token = {256tokenHash: "tokenhash",257created: new Date().toISOString(),258scopes: ["read-only"],259type: GitpodTokenType.API_AUTH_TOKEN,260userId: user1.id,261};262await this.db.storeGitpodToken(token);263const result = await this.db.findGitpodTokensOfUser(user1.id, token.tokenHash);264expect(result).to.not.be.undefined;265expect(result?.userId).to.eq(user1.id);266expect(result?.tokenHash).to.eq(token.tokenHash);267}268269@test(timeout(10000))270public async findAllGitpodTokensOfUser() {271let user1 = await this.db.newUser();272user1.name = "ABC";273user1.identities.push(TestData.ID1);274user1.identities.push(TestData.ID2);275user1 = await this.db.storeUser(user1);276277const token = {278tokenHash: "tokenhash",279created: new Date().toISOString(),280scopes: ["read-only"],281type: GitpodTokenType.API_AUTH_TOKEN,282userId: user1.id,283};284await this.db.storeGitpodToken(token);285const token2 = {286tokenHash: "tokenhash2",287created: new Date().toISOString(),288scopes: ["read-only"],289type: GitpodTokenType.API_AUTH_TOKEN,290userId: user1.id,291};292await this.db.storeGitpodToken(token2);293const result = await this.db.findAllGitpodTokensOfUser(user1.id);294expect(result).to.not.be.undefined;295expect(result.length).to.eq(2);296expect(result.some((t) => t.tokenHash === token.tokenHash)).to.be.true;297expect(result.some((t) => t.tokenHash === token2.tokenHash)).to.be.true;298}299300@test(timeout(10000))301public async findUserIdsNotYetMigratedToFgaVersion() {302let user1 = await this.db.newUser();303user1.name = "ABC";304user1.fgaRelationshipsVersion = 0;305user1 = await this.db.storeUser(user1);306307let user2 = await this.db.newUser();308user2.name = "ABC2";309user2.fgaRelationshipsVersion = 1;310user2 = await this.db.storeUser(user2);311312let user3 = await this.db.newUser();313user3.name = "ABC3";314user3.fgaRelationshipsVersion = 0;315user3 = await this.db.storeUser(user3);316317const result = await this.db.findUserIdsNotYetMigratedToFgaVersion(1, 10);318expect(result).to.not.be.undefined;319expect(result.length).to.eq(2);320expect(result.some((id) => id === user1.id)).to.be.true;321expect(result.some((id) => id === user2.id)).to.be.false;322expect(result.some((id) => id === user3.id)).to.be.true;323324const result2 = await this.db.findUserIdsNotYetMigratedToFgaVersion(1, 1);325expect(result2).to.not.be.undefined;326expect(result2.length).to.eq(1);327328const result3 = await this.db.findUserIdsNotYetMigratedToFgaVersion(2, 10);329expect(result3).to.not.be.undefined;330expect(result3.length).to.eq(3);331}332}333334namespace TestData {335export const primaryEmail = "[email protected]";336const DEFAULT: Identity = {337authProviderId: "Public-GitHub",338primaryEmail,339authId: "1234",340authName: "Foo Bar",341deleted: false,342readonly: false,343};344export const organizationId: string = "org1";345export const ID1: Identity = { ...DEFAULT, authId: "2345" };346export const ID2: Identity = { ...DEFAULT, authId: "3456", authProviderId: "Public-GitLab" };347export const ID3: Identity = { ...DEFAULT, authId: "4567", authProviderId: "ACME" };348export const ID4: Identity = { ...DEFAULT, authId: "5678" };349export const ID5: Identity = { ...DEFAULT, authId: "6789", authProviderId: "ACME" };350export const DEFAULT_WS: Workspace = {351id: "1",352type: "regular",353creationTime: new Date().toISOString(),354config: {355ports: [],356image: "",357tasks: [],358},359organizationId,360context: { title: "example" },361contextURL: "example.org",362description: "blabla",363ownerId: "12345",364};365export const DEFAULT_WSI: WorkspaceInstance = {366workspaceId: DEFAULT_WS.id,367id: "123",368ideUrl: "example.org",369region: "unknown",370workspaceImage: "abc.io/test/image:123",371creationTime: new Date().toISOString(),372startedTime: undefined,373deployedTime: undefined,374stoppedTime: undefined,375status: {376version: 1,377phase: "preparing",378conditions: {},379},380configuration: {381theiaVersion: "unknown",382ideImage: "unknown",383},384deleted: false,385};386}387388module.exports = new UserDBSpec();389390391