fix(server): storage usage should be float rather than int (#4275)

This commit is contained in:
LongYinan
2023-09-07 22:15:33 -07:00
committed by GitHub
parent 0bc3d9ebf5
commit aa025b0d46
5 changed files with 127 additions and 19 deletions

View File

@@ -101,7 +101,7 @@ export class InvitationWorkspaceType {
@ObjectType() @ObjectType()
export class WorkspaceBlobSizes { export class WorkspaceBlobSizes {
@Field(() => Int) @Field(() => Float)
size!: number; size!: number;
} }

View File

@@ -124,7 +124,7 @@ type InvitationWorkspaceType {
} }
type WorkspaceBlobSizes { type WorkspaceBlobSizes {
size: Int! size: Float!
} }
type InvitationType { type InvitationType {

View File

@@ -6,7 +6,7 @@ import type { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { hashSync } from '@node-rs/argon2'; import { hashSync } from '@node-rs/argon2';
import { User } from '@prisma/client'; import { User } from '@prisma/client';
import test from 'ava'; import ava, { TestFn } from 'ava';
import { Express } from 'express'; import { Express } from 'express';
// @ts-expect-error graphql-upload is not typed // @ts-expect-error graphql-upload is not typed
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs'; import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
@@ -17,7 +17,9 @@ import { PrismaService } from '../prisma/service';
const gql = '/graphql'; const gql = '/graphql';
let app: INestApplication; const test = ava as TestFn<{
app: INestApplication;
}>;
class FakePrisma { class FakePrisma {
fakeUser: User = { fakeUser: User = {
@@ -46,33 +48,33 @@ class FakePrisma {
} }
} }
test.beforeEach(async () => { test.beforeEach(async t => {
const module = await Test.createTestingModule({ const module = await Test.createTestingModule({
imports: [AppModule], imports: [AppModule],
}) })
.overrideProvider(PrismaService) .overrideProvider(PrismaService)
.useClass(FakePrisma) .useClass(FakePrisma)
.compile(); .compile();
app = module.createNestApplication({ t.context.app = module.createNestApplication({
cors: true, cors: true,
bodyParser: true, bodyParser: true,
}); });
app.use( t.context.app.use(
graphqlUploadExpress({ graphqlUploadExpress({
maxFileSize: 10 * 1024 * 1024, maxFileSize: 10 * 1024 * 1024,
maxFiles: 5, maxFiles: 5,
}) })
); );
await app.init(); await t.context.app.init();
}); });
test.afterEach(async () => { test.afterEach(async t => {
await app.close(); await t.context.app.close();
}); });
test('should init app', async t => { test('should init app', async t => {
t.is(typeof app, 'object'); t.is(typeof t.context.app, 'object');
await request(app.getHttpServer()) await request(t.context.app.getHttpServer())
.post(gql) .post(gql)
.send({ .send({
query: ` query: `
@@ -83,9 +85,9 @@ test('should init app', async t => {
}) })
.expect(400); .expect(400);
const { token } = await createToken(app); const { token } = await createToken(t.context.app);
await request(app.getHttpServer()) await request(t.context.app.getHttpServer())
.post(gql) .post(gql)
.auth(token, { type: 'bearer' }) .auth(token, { type: 'bearer' })
.send({ .send({
@@ -102,8 +104,8 @@ test('should init app', async t => {
}); });
test('should find default user', async t => { test('should find default user', async t => {
const { token } = await createToken(app); const { token } = await createToken(t.context.app);
await request(app.getHttpServer()) await request(t.context.app.getHttpServer())
.post(gql) .post(gql)
.auth(token, { type: 'bearer' }) .auth(token, { type: 'bearer' })
.send({ .send({
@@ -123,14 +125,14 @@ test('should find default user', async t => {
}); });
test('should be able to upload avatar', async t => { test('should be able to upload avatar', async t => {
const { token, id } = await createToken(app); const { token, id } = await createToken(t.context.app);
const png = await Transformer.fromRgbaPixels( const png = await Transformer.fromRgbaPixels(
Buffer.alloc(400 * 400 * 4).fill(255), Buffer.alloc(400 * 400 * 4).fill(255),
400, 400,
400 400
).png(); ).png();
await request(app.getHttpServer()) await request(t.context.app.getHttpServer())
.post(gql) .post(gql)
.auth(token, { type: 'bearer' }) .auth(token, { type: 'bearer' })
.field( .field(

View File

@@ -1,6 +1,9 @@
import { randomUUID } from 'node:crypto';
import type { INestApplication } from '@nestjs/common'; import type { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { PrismaClient } from '@prisma/client'; import { hashSync } from '@node-rs/argon2';
import { PrismaClient, User } from '@prisma/client';
// @ts-expect-error graphql-upload is not typed // @ts-expect-error graphql-upload is not typed
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs'; import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
import request from 'supertest'; import request from 'supertest';
@@ -498,6 +501,33 @@ async function getInviteInfo(
return res.body.data.getInviteInfo; return res.body.data.getInviteInfo;
} }
export class FakePrisma {
fakeUser: User = {
id: randomUUID(),
name: 'Alex Yang',
avatarUrl: '',
email: 'alex.yang@example.org',
password: hashSync('123456'),
emailVerified: new Date(),
createdAt: new Date(),
};
get user() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const prisma = this;
return {
async findFirst() {
return prisma.fakeUser;
},
async findUnique() {
return this.findFirst();
},
async update() {
return this.findFirst();
},
};
}
}
export { export {
acceptInvite, acceptInvite,
acceptInviteById, acceptInviteById,

View File

@@ -0,0 +1,76 @@
import type { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import ava, { TestFn } from 'ava';
import { stub } from 'sinon';
import { AppModule } from '../app';
import { UsersService } from '../modules/users';
import { PermissionService } from '../modules/workspaces/permission';
import { WorkspaceResolver } from '../modules/workspaces/resolver';
import { PrismaService } from '../prisma';
import { StorageProvide } from '../storage';
import { FakePrisma } from './utils';
class FakePermission {
async tryCheck() {
return true;
}
async getWorkspaceOwner() {
return {
user: new FakePrisma().fakeUser,
};
}
}
const fakeUserService = {
getStorageQuotaById: stub(),
};
const test = ava as TestFn<{
app: INestApplication;
resolver: WorkspaceResolver;
}>;
test.beforeEach(async t => {
const module = await Test.createTestingModule({
imports: [AppModule],
})
.overrideProvider(PrismaService)
.useValue({
userWorkspacePermission: {
async findMany() {
return [];
},
},
})
.overrideProvider(PermissionService)
.useClass(FakePermission)
.overrideProvider(UsersService)
.useValue(fakeUserService)
.overrideProvider(StorageProvide)
.useValue({
blobsSize() {
return 1024 * 10;
},
})
.compile();
t.context.app = module.createNestApplication();
t.context.resolver = t.context.app.get(WorkspaceResolver);
await t.context.app.init();
});
test.afterEach(async t => {
await t.context.app.close();
});
test('should get blob size limit', async t => {
const { resolver } = t.context;
fakeUserService.getStorageQuotaById.returns(
Promise.resolve(100 * 1024 * 1024 * 1024)
);
const res = await resolver.checkBlobSize(new FakePrisma().fakeUser, '', 100);
t.not(res, false);
// @ts-expect-error
t.is(typeof res.size, 'number');
fakeUserService.getStorageQuotaById.reset();
});