/** * Copyright (c) 2021 Gitpod GmbH. All rights reserved. * Licensed under the Gitpod Enterprise Source Code License, * See License.enterprise.txt in the project root folder. */ import { Subscription } from "@gitpod/gitpod-protocol/lib/accounting-protocol"; import * as chai from "chai"; import { suite, test, timeout } from "mocha-typescript"; import { QueryRunner } from "typeorm"; import { AccountingDB } from "./accounting-db"; import { oneMonthLater, rightAfter, rightBefore } from "@gitpod/gitpod-protocol/lib/util/timeutil"; import { DBAccountEntry } from "./typeorm/entity/db-account-entry"; import { TransactionalAccountingDBImpl } from "./typeorm/accounting-db-impl"; import { DBWorkspace } from "./typeorm/entity/db-workspace"; import { DBWorkspaceInstance } from "./typeorm/entity/db-workspace-instance"; import { DBSubscription } from "./typeorm/entity/db-subscription"; import { testContainer } from "./test-container"; import { TypeORM } from "./typeorm/typeorm"; const expect = chai.expect; @suite @timeout(5000) export class AccountingDBSpec { typeORM = testContainer.get(TypeORM); db: AccountingDB; queryRunner: QueryRunner; async before() { const connection = await this.typeORM.getConnection(); const manager = connection.manager; await manager.clear(DBAccountEntry); await manager.clear(DBSubscription); await manager.clear(DBWorkspaceInstance); await manager.clear(DBWorkspace); this.queryRunner = connection.createQueryRunner(); await this.queryRunner.connect(); await this.queryRunner.startTransaction(); this.db = new TransactionalAccountingDBImpl(this.queryRunner.manager); } async after() { this.queryRunner.rollbackTransaction(); } @test public async subscriptionFixedPeriod() { const now = new Date().toISOString(); const later = oneMonthLater(now, 31); const inBetween = new Date(0.5 * (new Date(now).getTime() + new Date(later).getTime())).toISOString(); const subscription = { userId: "Now open", startDate: now, endDate: later, amount: 1.01, planId: "test", }; await this.db.newSubscription(subscription); // date inclusion expectExactlyOne(await this.db.findActiveSubscriptions(now, now), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(now, inBetween), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(inBetween, later), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(now, later), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(rightBefore(later), rightBefore(later)), subscription); // date exclusion expect(await this.db.findActiveSubscriptions(later, later)).to.be.empty; expect(await this.db.findActiveSubscriptions(rightBefore(now), rightBefore(now))).to.be.empty; } @test public async subscriptionOpenEnd() { const now = new Date().toISOString(); const later = oneMonthLater(now, 31); const inBetween = new Date(0.5 * (new Date(now).getTime() + new Date(later).getTime())).toISOString(); const subscription = { userId: "Open ended", startDate: now, endDate: undefined, // open ended amount: 1.01, planId: "test", }; await this.db.newSubscription(subscription); // date inclusion expectExactlyOne(await this.db.findActiveSubscriptions(now, now), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(later, later), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(now, inBetween), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(inBetween, later), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(now, later), subscription); expectExactlyOne(await this.db.findActiveSubscriptions(rightAfter(later), rightAfter(later)), subscription); // date exclusion expect(await this.db.findActiveSubscriptions(rightBefore(now), rightBefore(now))).to.be.empty; } @test public async subscriptionUpdate() { const now = new Date().toISOString(); const later = oneMonthLater(now, 31); const subscription = { userId: "Open ended", startDate: now, endDate: undefined, // open ended amount: 1.01, planId: "test", }; const dbSubscription = await this.db.newSubscription(subscription); expectExactlyOne(await this.db.findActiveSubscriptions(now, rightAfter(later)), subscription); expect(await this.db.findActiveSubscriptions(rightBefore(now), rightBefore(now))).to.be.empty; Subscription.cancelSubscription(dbSubscription, later); await this.db.storeSubscription(dbSubscription); expect(await this.db.findActiveSubscriptions(rightAfter(later), rightAfter(later))).to.be.empty; await this.db.storeSubscription(dbSubscription); expect(await this.db.findActiveSubscriptions(rightAfter(later), rightAfter(later))).to.be.empty; } @test public async subscriptionsForUser() { const now = new Date().toISOString(); const later = oneMonthLater(now, 31); const subscription = { userId: "Open ended", startDate: now, endDate: undefined, // open ended amount: 1.01, planId: "test", }; let dbSubscription = await this.db.newSubscription(subscription); expectExactlyOne(await this.db.findActiveSubscriptionsForUser(subscription.userId, now), subscription); expect(await this.db.findActiveSubscriptionsForUser(subscription.userId, rightBefore(now))).to.be.an("array") .and.empty; expectExactlyOne(await this.db.findActiveSubscriptionsForUser(subscription.userId, later), subscription); Subscription.cancelSubscription(dbSubscription, later); await this.db.storeSubscription(dbSubscription); expectExactlyOne( await this.db.findActiveSubscriptionsForUser(subscription.userId, rightBefore(later)), dbSubscription, ); expect(await this.db.findActiveSubscriptionsForUser(subscription.userId, later)).to.be.an("array").and.empty; } } const expectExactlyOne = (result: T[], expectation: T) => { expect(result.length).to.be.equal(1); expect(result[0]).to.deep.include(expectation); }; module.exports = new AccountingDBSpec();