test(server): utils (#10028)
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import test from 'ava';
|
||||
import request from 'supertest';
|
||||
|
||||
import { AppModule } from '../../app.module';
|
||||
import { WorkspaceFeatureModel } from '../../models';
|
||||
import {
|
||||
collectAllBlobSizes,
|
||||
@@ -10,7 +8,6 @@ import {
|
||||
getWorkspaceBlobsSize,
|
||||
listBlobs,
|
||||
setBlob,
|
||||
signUp,
|
||||
TestingApp,
|
||||
} from '../utils';
|
||||
|
||||
@@ -27,11 +24,7 @@ let app: TestingApp;
|
||||
let model: WorkspaceFeatureModel;
|
||||
|
||||
test.before(async () => {
|
||||
const { app: testApp } = await createTestingApp({
|
||||
imports: [AppModule],
|
||||
});
|
||||
|
||||
app = testApp;
|
||||
app = await createTestingApp();
|
||||
model = app.get(WorkspaceFeatureModel);
|
||||
});
|
||||
|
||||
@@ -44,117 +37,113 @@ test.after.always(async () => {
|
||||
});
|
||||
|
||||
test('should set blobs', async t => {
|
||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace = await createWorkspace(app, u1.token.token);
|
||||
const workspace = await createWorkspace(app);
|
||||
|
||||
const buffer1 = Buffer.from([0, 0]);
|
||||
const hash1 = await setBlob(app, u1.token.token, workspace.id, buffer1);
|
||||
const hash1 = await setBlob(app, workspace.id, buffer1);
|
||||
const buffer2 = Buffer.from([0, 1]);
|
||||
const hash2 = await setBlob(app, u1.token.token, workspace.id, buffer2);
|
||||
const hash2 = await setBlob(app, workspace.id, buffer2);
|
||||
|
||||
const server = app.getHttpServer();
|
||||
|
||||
const response1 = await request(server)
|
||||
.get(`/api/workspaces/${workspace.id}/blobs/${hash1}`)
|
||||
.auth(u1.token.token, { type: 'bearer' })
|
||||
const response1 = await app
|
||||
.GET(`/api/workspaces/${workspace.id}/blobs/${hash1}`)
|
||||
.buffer();
|
||||
|
||||
t.deepEqual(response1.body, buffer1, 'failed to get blob');
|
||||
|
||||
const response2 = await request(server)
|
||||
.get(`/api/workspaces/${workspace.id}/blobs/${hash2}`)
|
||||
.auth(u1.token.token, { type: 'bearer' })
|
||||
const response2 = await app
|
||||
.GET(`/api/workspaces/${workspace.id}/blobs/${hash2}`)
|
||||
.buffer();
|
||||
|
||||
t.deepEqual(response2.body, buffer2, 'failed to get blob');
|
||||
});
|
||||
|
||||
test('should list blobs', async t => {
|
||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace = await createWorkspace(app, u1.token.token);
|
||||
const blobs = await listBlobs(app, u1.token.token, workspace.id);
|
||||
const workspace = await createWorkspace(app);
|
||||
const blobs = await listBlobs(app, workspace.id);
|
||||
t.is(blobs.length, 0, 'failed to list blobs');
|
||||
|
||||
const buffer1 = Buffer.from([0, 0]);
|
||||
const hash1 = await setBlob(app, u1.token.token, workspace.id, buffer1);
|
||||
const hash1 = await setBlob(app, workspace.id, buffer1);
|
||||
const buffer2 = Buffer.from([0, 1]);
|
||||
const hash2 = await setBlob(app, u1.token.token, workspace.id, buffer2);
|
||||
const hash2 = await setBlob(app, workspace.id, buffer2);
|
||||
|
||||
const ret = await listBlobs(app, u1.token.token, workspace.id);
|
||||
const ret = await listBlobs(app, workspace.id);
|
||||
t.is(ret.length, 2, 'failed to list blobs');
|
||||
// list blob result is not ordered
|
||||
t.deepEqual(ret.sort(), [hash1, hash2].sort());
|
||||
});
|
||||
|
||||
test('should calc blobs size', async t => {
|
||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace = await createWorkspace(app, u1.token.token);
|
||||
const workspace = await createWorkspace(app);
|
||||
|
||||
const buffer1 = Buffer.from([0, 0]);
|
||||
await setBlob(app, u1.token.token, workspace.id, buffer1);
|
||||
await setBlob(app, workspace.id, buffer1);
|
||||
const buffer2 = Buffer.from([0, 1]);
|
||||
await setBlob(app, u1.token.token, workspace.id, buffer2);
|
||||
await setBlob(app, workspace.id, buffer2);
|
||||
|
||||
const size = await getWorkspaceBlobsSize(app, u1.token.token, workspace.id);
|
||||
const size = await getWorkspaceBlobsSize(app, workspace.id);
|
||||
t.is(size, 4, 'failed to collect blob sizes');
|
||||
});
|
||||
|
||||
test('should calc all blobs size', async t => {
|
||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace1 = await createWorkspace(app, u1.token.token);
|
||||
const workspace1 = await createWorkspace(app);
|
||||
|
||||
const buffer1 = Buffer.from([0, 0]);
|
||||
await setBlob(app, u1.token.token, workspace1.id, buffer1);
|
||||
await setBlob(app, workspace1.id, buffer1);
|
||||
const buffer2 = Buffer.from([0, 1]);
|
||||
await setBlob(app, u1.token.token, workspace1.id, buffer2);
|
||||
await setBlob(app, workspace1.id, buffer2);
|
||||
|
||||
const workspace2 = await createWorkspace(app, u1.token.token);
|
||||
const workspace2 = await createWorkspace(app);
|
||||
|
||||
const buffer3 = Buffer.from([0, 0]);
|
||||
await setBlob(app, u1.token.token, workspace2.id, buffer3);
|
||||
await setBlob(app, workspace2.id, buffer3);
|
||||
const buffer4 = Buffer.from([0, 1]);
|
||||
await setBlob(app, u1.token.token, workspace2.id, buffer4);
|
||||
await setBlob(app, workspace2.id, buffer4);
|
||||
|
||||
const size = await collectAllBlobSizes(app, u1.token.token);
|
||||
const size = await collectAllBlobSizes(app);
|
||||
t.is(size, 8, 'failed to collect all blob sizes');
|
||||
});
|
||||
|
||||
test('should reject blob exceeded limit', async t => {
|
||||
const u1 = await signUp(app, 'darksky', 'darksky@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace1 = await createWorkspace(app, u1.token.token);
|
||||
const workspace1 = await createWorkspace(app);
|
||||
await model.add(workspace1.id, 'team_plan_v1', 'test', RESTRICTED_QUOTA);
|
||||
|
||||
const buffer1 = Buffer.from(
|
||||
Array.from({ length: RESTRICTED_QUOTA.blobLimit + 1 }, () => 0)
|
||||
);
|
||||
await t.throwsAsync(setBlob(app, u1.token.token, workspace1.id, buffer1));
|
||||
await t.throwsAsync(setBlob(app, workspace1.id, buffer1));
|
||||
});
|
||||
|
||||
test('should reject blob exceeded quota', async t => {
|
||||
const u1 = await signUp(app, 'darksky', 'darksky@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace = await createWorkspace(app, u1.token.token);
|
||||
const workspace = await createWorkspace(app);
|
||||
await model.add(workspace.id, 'team_plan_v1', 'test', RESTRICTED_QUOTA);
|
||||
|
||||
const buffer = Buffer.from(Array.from({ length: OneMB }, () => 0));
|
||||
|
||||
await t.notThrowsAsync(setBlob(app, u1.token.token, workspace.id, buffer));
|
||||
await t.throwsAsync(setBlob(app, u1.token.token, workspace.id, buffer));
|
||||
await t.notThrowsAsync(setBlob(app, workspace.id, buffer));
|
||||
await t.throwsAsync(setBlob(app, workspace.id, buffer));
|
||||
});
|
||||
|
||||
test('should accept blob even storage out of quota if workspace has unlimited feature', async t => {
|
||||
const u1 = await signUp(app, 'darksky', 'darksky@affine.pro', '1');
|
||||
await app.signup('u1@affine.pro');
|
||||
|
||||
const workspace = await createWorkspace(app, u1.token.token);
|
||||
const workspace = await createWorkspace(app);
|
||||
await model.add(workspace.id, 'team_plan_v1', 'test', RESTRICTED_QUOTA);
|
||||
await model.add(workspace.id, 'unlimited_workspace', 'test');
|
||||
|
||||
const buffer = Buffer.from(Array.from({ length: OneMB }, () => 0));
|
||||
await t.notThrowsAsync(setBlob(app, u1.token.token, workspace.id, buffer));
|
||||
await t.notThrowsAsync(setBlob(app, u1.token.token, workspace.id, buffer));
|
||||
await t.notThrowsAsync(setBlob(app, workspace.id, buffer));
|
||||
await t.notThrowsAsync(setBlob(app, workspace.id, buffer));
|
||||
});
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
import { Readable } from 'node:stream';
|
||||
|
||||
import { HttpStatus, INestApplication } from '@nestjs/common';
|
||||
import { HttpStatus } from '@nestjs/common';
|
||||
import { PrismaClient, WorkspaceMemberStatus } from '@prisma/client';
|
||||
import ava, { TestFn } from 'ava';
|
||||
import Sinon from 'sinon';
|
||||
import request from 'supertest';
|
||||
|
||||
import { AppModule } from '../../app.module';
|
||||
import { CurrentUser } from '../../core/auth';
|
||||
import { AuthService } from '../../core/auth/service';
|
||||
import { PgWorkspaceDocStorageAdapter } from '../../core/doc';
|
||||
import { WorkspaceBlobStorage } from '../../core/storage';
|
||||
import { createTestingApp, internalSignIn } from '../utils';
|
||||
import { createTestingApp, TestingApp, TestUser } from '../utils';
|
||||
|
||||
const test = ava as TestFn<{
|
||||
u1: CurrentUser;
|
||||
db: PrismaClient;
|
||||
app: INestApplication;
|
||||
app: TestingApp;
|
||||
u1: TestUser;
|
||||
storage: Sinon.SinonStubbedInstance<WorkspaceBlobStorage>;
|
||||
workspace: Sinon.SinonStubbedInstance<PgWorkspaceDocStorageAdapter>;
|
||||
}>;
|
||||
|
||||
test.before(async t => {
|
||||
const { app } = await createTestingApp({
|
||||
imports: [AppModule],
|
||||
const app = await createTestingApp({
|
||||
tapModule: m => {
|
||||
m.overrideProvider(WorkspaceBlobStorage)
|
||||
.useValue(Sinon.createStubInstance(WorkspaceBlobStorage))
|
||||
@@ -32,10 +27,9 @@ test.before(async t => {
|
||||
},
|
||||
});
|
||||
|
||||
const auth = app.get(AuthService);
|
||||
t.context.u1 = await auth.signUp('u1@affine.pro', '1');
|
||||
const db = app.get(PrismaClient);
|
||||
|
||||
t.context.u1 = await app.signup('u1@affine.pro');
|
||||
t.context.db = db;
|
||||
t.context.app = app;
|
||||
t.context.storage = app.get(WorkspaceBlobStorage);
|
||||
@@ -109,23 +103,19 @@ function blob() {
|
||||
|
||||
// blob
|
||||
test('should be able to get blob from public workspace', async t => {
|
||||
const { app, u1, storage } = t.context;
|
||||
const { app, storage } = t.context;
|
||||
|
||||
// no authenticated user
|
||||
storage.get.resolves(blob());
|
||||
let res = await request(t.context.app.getHttpServer()).get(
|
||||
'/api/workspaces/public/blobs/test'
|
||||
);
|
||||
let res = await app.GET('/api/workspaces/public/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('content-type'), 'text/plain');
|
||||
t.is(res.text, 'blob');
|
||||
|
||||
// authenticated user
|
||||
const cookie = await internalSignIn(app, u1.id);
|
||||
res = await request(t.context.app.getHttpServer())
|
||||
.get('/api/workspaces/public/blobs/test')
|
||||
.set('Cookie', cookie);
|
||||
await app.login(t.context.u1);
|
||||
res = await app.GET('/api/workspaces/public/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('content-type'), 'text/plain');
|
||||
@@ -133,23 +123,19 @@ test('should be able to get blob from public workspace', async t => {
|
||||
});
|
||||
|
||||
test('should be able to get private workspace with public pages', async t => {
|
||||
const { app, u1, storage } = t.context;
|
||||
const { app, storage } = t.context;
|
||||
|
||||
// no authenticated user
|
||||
storage.get.resolves(blob());
|
||||
let res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/private/blobs/test'
|
||||
);
|
||||
let res = await app.GET('/api/workspaces/private/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('content-type'), 'text/plain');
|
||||
t.is(res.text, 'blob');
|
||||
|
||||
// authenticated user
|
||||
const cookie = await internalSignIn(app, u1.id);
|
||||
res = await request(app.getHttpServer())
|
||||
.get('/api/workspaces/private/blobs/test')
|
||||
.set('cookie', cookie);
|
||||
await app.login(t.context.u1);
|
||||
res = await app.GET('/api/workspaces/private/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('content-type'), 'text/plain');
|
||||
@@ -157,29 +143,24 @@ test('should be able to get private workspace with public pages', async t => {
|
||||
});
|
||||
|
||||
test('should not be able to get private workspace with no public pages', async t => {
|
||||
const { app, u1 } = t.context;
|
||||
const { app } = t.context;
|
||||
|
||||
let res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/totally-private/blobs/test'
|
||||
);
|
||||
let res = await app.GET('/api/workspaces/totally-private/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.FORBIDDEN);
|
||||
|
||||
res = await request(app.getHttpServer())
|
||||
.get('/api/workspaces/totally-private/blobs/test')
|
||||
.set('cookie', await internalSignIn(app, u1.id));
|
||||
res = await app.GET('/api/workspaces/totally-private/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.FORBIDDEN);
|
||||
});
|
||||
|
||||
test('should be able to get permission granted workspace', async t => {
|
||||
const { app, u1, db, storage } = t.context;
|
||||
const { app, db, storage } = t.context;
|
||||
|
||||
const cookie = await internalSignIn(app, u1.id);
|
||||
await db.workspaceUserPermission.create({
|
||||
data: {
|
||||
workspaceId: 'totally-private',
|
||||
userId: u1.id,
|
||||
userId: t.context.u1.id,
|
||||
type: 1,
|
||||
accepted: true,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
@@ -187,9 +168,8 @@ test('should be able to get permission granted workspace', async t => {
|
||||
});
|
||||
|
||||
storage.get.resolves(blob());
|
||||
const res = await request(app.getHttpServer())
|
||||
.get('/api/workspaces/totally-private/blobs/test')
|
||||
.set('Cookie', cookie);
|
||||
await app.login(t.context.u1);
|
||||
const res = await app.GET('/api/workspaces/totally-private/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.text, 'blob');
|
||||
@@ -200,9 +180,7 @@ test('should return 404 if blob not found', async t => {
|
||||
|
||||
// @ts-expect-error mock
|
||||
storage.get.resolves({ body: null });
|
||||
const res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/public/blobs/test'
|
||||
);
|
||||
const res = await app.GET('/api/workspaces/public/blobs/test');
|
||||
|
||||
t.is(res.status, HttpStatus.NOT_FOUND);
|
||||
});
|
||||
@@ -210,17 +188,14 @@ test('should return 404 if blob not found', async t => {
|
||||
// doc
|
||||
// NOTE: permission checking of doc api is the same with blob api, skip except one
|
||||
test('should not be able to get private workspace with private page', async t => {
|
||||
const { app, u1 } = t.context;
|
||||
const { app } = t.context;
|
||||
|
||||
let res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/private/docs/private-page'
|
||||
);
|
||||
let res = await app.GET('/api/workspaces/private/docs/private-page');
|
||||
|
||||
t.is(res.status, HttpStatus.FORBIDDEN);
|
||||
|
||||
res = await request(app.getHttpServer())
|
||||
.get('/api/workspaces/private/docs/private-page')
|
||||
.set('cookie', await internalSignIn(app, u1.id));
|
||||
await app.login(t.context.u1);
|
||||
res = await app.GET('/api/workspaces/private/docs/private-page');
|
||||
|
||||
t.is(res.status, HttpStatus.FORBIDDEN);
|
||||
});
|
||||
@@ -235,9 +210,7 @@ test('should be able to get doc', async t => {
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
const res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/private/docs/public'
|
||||
);
|
||||
const res = await app.GET('/api/workspaces/private/docs/public');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('content-type'), 'application/octet-stream');
|
||||
@@ -254,9 +227,7 @@ test('should be able to change page publish mode', async t => {
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
let res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/private/docs/public'
|
||||
);
|
||||
let res = await app.GET('/api/workspaces/private/docs/public');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('publish-mode'), 'page');
|
||||
@@ -266,9 +237,7 @@ test('should be able to change page publish mode', async t => {
|
||||
data: { mode: 1 },
|
||||
});
|
||||
|
||||
res = await request(app.getHttpServer()).get(
|
||||
'/api/workspaces/private/docs/public'
|
||||
);
|
||||
res = await app.GET('/api/workspaces/private/docs/public');
|
||||
|
||||
t.is(res.status, HttpStatus.OK);
|
||||
t.is(res.get('publish-mode'), 'edgeless');
|
||||
|
||||
Reference in New Issue
Block a user