From 7b2e671d337e58c4317c1057a1b0f1b0420d8985 Mon Sep 17 00:00:00 2001 From: Nader Date: Thu, 3 Oct 2024 09:27:36 +1000 Subject: [PATCH 01/17] datasource upload, nonfunctional upload --- webapp/src/test/account.ts | 10 +++---- webapp/src/test/datasources.ts | 43 +++++++++++++++++++++++++++++ webapp/src/test/fileUpload.txt | 1 + webapp/src/test/integration.test.ts | 1 + webapp/src/test/logout.ts | 4 +-- webapp/src/test/models.ts | 8 +++--- webapp/src/test/teams.ts | 12 ++++---- 7 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 webapp/src/test/datasources.ts create mode 100644 webapp/src/test/fileUpload.txt diff --git a/webapp/src/test/account.ts b/webapp/src/test/account.ts index 401b2875..3fe9f71d 100644 --- a/webapp/src/test/account.ts +++ b/webapp/src/test/account.ts @@ -43,7 +43,7 @@ beforeAll(async () => { describe('account tests', () => { - test('register new accounts', async () => { + test.only('register new accounts', async () => { let response = await fetch(`${process.env.WEBAPP_TEST_BASE_URL}/forms/account/register`, { method: 'POST', headers: { @@ -94,7 +94,7 @@ describe('account tests', () => { await db.db().collection('accounts').deleteMany({ email: accountDetails.account3_email }); //delete these accounts so we can stress test logins in the next test }, 60 * SECONDS); //extended timeout due to multiple account creations - test('stress test registration with many accounts', async () => { + test.only('stress test registration with many accounts', async () => { const accounts = [ { name: accountDetails.account1_name, email: accountDetails.account1_email, password: accountDetails.account1_password }, { name: accountDetails.account2_name, email: accountDetails.account2_email, password: accountDetails.account2_password }, @@ -131,7 +131,7 @@ describe('account tests', () => { //TODO: refactor this to do it with a loop - test('login as new users - 11 logins', async () => { + test.only('login as new users - 11 logins', async () => { let response = await fetch(`${process.env.WEBAPP_TEST_BASE_URL}/forms/account/login`, { method: 'POST', headers: { @@ -300,7 +300,7 @@ describe('account tests', () => { }, 60 * SECONDS); // extended timeout due to multiple account logins - test('get account', async () => { + test.only('get account', async () => { const url = `${process.env.WEBAPP_TEST_BASE_URL}/account.json`; const accounts = [ { email: accountDetails.account1_email, sessionCookie: sessionCookie1 }, @@ -353,7 +353,7 @@ describe('account tests', () => { //test with valid token?? //sets the role to prevent redirects to onboarding in further tests - test('set role - onboarding', async () => { + test.only('set role - onboarding', async () => { const accounts = [ accountDetails.account1_email, accountDetails.account2_email, diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts new file mode 100644 index 00000000..e775730c --- /dev/null +++ b/webapp/src/test/datasources.ts @@ -0,0 +1,43 @@ +import { afterAll, beforeAll, describe, expect, test } from '@jest/globals'; +import * as db from '../db/index'; +import { addTeam, getTeamById, getTeamWithMembers } from '../db/team'; +import { getAccountByEmail, setStripeCustomerId, setStripePlan } from '../db/account'; +import { SubscriptionPlan } from '../lib/struct/billing'; +import { getInitialData, makeFetch, fetchTypes, accountDetails, setInitialData, updateAllAccountCsrf } from './helpers'; +import dotenv from 'dotenv'; +import { URLSearchParams } from 'url'; +import toObjectId from '../lib/misc/toobjectid'; +import { ModelList, ModelType } from '../lib/struct/model'; +import { ShareLinkTypes } from '../lib/struct/sharelink'; +import { getToolsByTeam } from "../db/tool"; +import { TeamRoles } from "../lib/permissions/roles" +import {Retriever} from '../lib/struct/tool'; +//look in components/DropZone to see how the multipart form is created and how the file is uploaded +//use Fast Embed to reduce token usage for us and to also +//use a self hosted runner in git to automate the tests into the PR process +beforeAll(()=>{ +}) + +describe("Datasource Tests", () => { + + test.only("Upload a file", async ()=>{ + const account1Object = await getInitialData(accountDetails.account1_email); + const formData = new FormData(); + const fs = require('fs'); + + formData.set('resourceSlug', account1Object.resourceSlug as string); + // formData.set('modelId', ) need to create a valid embedding model and get that modelId + formData.set('datasourceDescription', "File Upload Test Datasource"); + formData.set('name', "TestSource"); + formData.set('retriever', Retriever.RAW as string); + formData.set('_csrf', account1Object.csrfToken as string); + + fs.readFile('./fileUpload.txt', async (err, data) => { + if(err){ + throw err; + }; + const file = data; + console.log(file); + }) + }) +}); \ No newline at end of file diff --git a/webapp/src/test/fileUpload.txt b/webapp/src/test/fileUpload.txt new file mode 100644 index 00000000..b8d9b25c --- /dev/null +++ b/webapp/src/test/fileUpload.txt @@ -0,0 +1 @@ +Simon Says: "1+1 actually equals 4 :D" \ No newline at end of file diff --git a/webapp/src/test/integration.test.ts b/webapp/src/test/integration.test.ts index f2d27859..b969a310 100644 --- a/webapp/src/test/integration.test.ts +++ b/webapp/src/test/integration.test.ts @@ -2,5 +2,6 @@ import './account'; import './pages'; import './teams'; import './models'; +import './datasources'; import './logout'; //this MUST be last \ No newline at end of file diff --git a/webapp/src/test/logout.ts b/webapp/src/test/logout.ts index 7a194461..720928a8 100644 --- a/webapp/src/test/logout.ts +++ b/webapp/src/test/logout.ts @@ -40,7 +40,7 @@ afterAll(async () => { describe("log out and wrap up tests", ()=>{ - test('log out', async () => { + test.only('log out', async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account1_email ); @@ -57,7 +57,7 @@ describe("log out and wrap up tests", ()=>{ expect(response.status).toBe(200); }); - test('cant get account with invalidated session cookie', async () => { + test.only('cant get account with invalidated session cookie', async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account1_email ); diff --git a/webapp/src/test/models.ts b/webapp/src/test/models.ts index 668fe089..7d511348 100644 --- a/webapp/src/test/models.ts +++ b/webapp/src/test/models.ts @@ -58,7 +58,7 @@ describe('Model Tests', () => { expect(addModelResponseJson?.error).toBeDefined(); }); - test("Test valid models with the FREE plan", async () => { + test.only("Test valid models with the FREE plan", async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); @@ -86,7 +86,7 @@ describe('Model Tests', () => { - test("Test valid embedding models with the FREE plan", async () => { + test.only("Test valid embedding models with the FREE plan", async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); @@ -186,7 +186,7 @@ describe('Model Tests', () => { expect(addModelResponseJson?.error).toBeDefined(); }) - test("Test valid models with PRO plan", async () => { + test.only("Test valid models with PRO plan", async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); @@ -216,7 +216,7 @@ describe('Model Tests', () => { //switch the plan to TEAMS, test adding valid models that are off limits for FREE and for PRO and add custom models - test("Test all models with TEAMS plan", async ()=> { + test.only("Test all models with TEAMS plan", async ()=> { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); diff --git a/webapp/src/test/teams.ts b/webapp/src/test/teams.ts index 6b7236f7..0efa52cd 100644 --- a/webapp/src/test/teams.ts +++ b/webapp/src/test/teams.ts @@ -33,7 +33,7 @@ describe('team tests', () => { }); //when debugging or creating tests, mark this test as ".only" to ensure a second team is created, this team is used in future. - test('add new team with correct stripe permissions', async () => { + test.only('add new team with correct stripe permissions', async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account1_email ); @@ -62,7 +62,7 @@ describe('team tests', () => { }); - test('Inviting existing account to team', async () => { + test.only('Inviting existing account to team', async () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account1_email ); @@ -116,7 +116,7 @@ describe('team tests', () => { expect(responseJson?.team?.members.length).toBe(3); }); - test('testing TEAM_MEMBER permissions', async () => { + test.only('testing TEAM_MEMBER permissions', async () => { const account1Object = await getInitialData( //account1 is the ORG_ADMIN accountDetails.account1_email @@ -193,7 +193,7 @@ describe('team tests', () => { expect(addAgentResponse?._id).toBeDefined(); }); - test('testing TEAM_ADMIN permissions', async () => { + test.only('testing TEAM_ADMIN permissions', async () => { const account1Object = await getInitialData(accountDetails.account1_email); const account2Object = await getInitialData(accountDetails.account2_email); const account3Object = await getInitialData(accountDetails.account3_email); @@ -248,7 +248,7 @@ describe('team tests', () => { // const responseJson = await response.json(); }); - test('removing TEAM_ADMIN from team, reinviting them again as a TEAM_MEMBER and testing permissions', async () => { + test.only('removing TEAM_ADMIN from team, reinviting them again as a TEAM_MEMBER and testing permissions', async () => { const account1Object = await getInitialData(accountDetails.account1_email); const account2Object = await getInitialData(accountDetails.account2_email); const account3Object = await getInitialData(accountDetails.account3_email); @@ -310,7 +310,7 @@ describe('team tests', () => { expect(responseJson?.error).toBe("Missing permission \"Add Team Member\"");//make sure it's a permissions error and not a stripe error etc... }); - test('cant add more than 10 members to TEAMS subscriptions plan', async () => { + test.only('cant add more than 10 members to TEAMS subscriptions plan', async () => { const { resourceSlug } = await getInitialData(accountDetails.account1_email); const url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/team/invite`; const accounts = [ From d50ede7cfeee3e3c196e58d51a696e6dcff45d4c Mon Sep 17 00:00:00 2001 From: NaderRNA Date: Thu, 3 Oct 2024 10:06:30 +1000 Subject: [PATCH 02/17] file successfully uploads, test not completed --- webapp/src/sync-server/ecosystem.config.js | 2 +- webapp/src/test/datasources.ts | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/webapp/src/sync-server/ecosystem.config.js b/webapp/src/sync-server/ecosystem.config.js index 094aa949..88602a9c 100644 --- a/webapp/src/sync-server/ecosystem.config.js +++ b/webapp/src/sync-server/ecosystem.config.js @@ -18,7 +18,7 @@ module.exports = { DEBUG: 'sync-server:main', DEBUG_COLORS: true } - }, + } // { // script: 'npm run dev:sync-worker', // watch: true, diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts index e775730c..2d6bd1fd 100644 --- a/webapp/src/test/datasources.ts +++ b/webapp/src/test/datasources.ts @@ -12,6 +12,8 @@ import { ShareLinkTypes } from '../lib/struct/sharelink'; import { getToolsByTeam } from "../db/tool"; import { TeamRoles } from "../lib/permissions/roles" import {Retriever} from '../lib/struct/tool'; +import path from 'path'; +import { defaultChunkingOptions } from '../lib/misc/defaultchunkingoptions'; //look in components/DropZone to see how the multipart form is created and how the file is uploaded //use Fast Embed to reduce token usage for us and to also //use a self hosted runner in git to automate the tests into the PR process @@ -24,6 +26,7 @@ describe("Datasource Tests", () => { const account1Object = await getInitialData(accountDetails.account1_email); const formData = new FormData(); const fs = require('fs'); + const chunkingConfig = defaultChunkingOptions formData.set('resourceSlug', account1Object.resourceSlug as string); // formData.set('modelId', ) need to create a valid embedding model and get that modelId @@ -31,13 +34,16 @@ describe("Datasource Tests", () => { formData.set('name', "TestSource"); formData.set('retriever', Retriever.RAW as string); formData.set('_csrf', account1Object.csrfToken as string); + const filepath = path.resolve(__dirname, 'fileUpload.txt'); + const file = fs.readFileSync(filepath); - fs.readFile('./fileUpload.txt', async (err, data) => { - if(err){ - throw err; - }; - const file = data; - console.log(file); - }) + formData.append('file', new Blob([file]), 'uploadTest.txt') + Object.entries(chunkingConfig).forEach(([key, value]) => { + if (value != null) { + formData.set(key, value as string); + } + }); + + let url = `${process.env.WEBAPP_TEST_URL}/${account1Object.resourceSlug}/forms/datasource/upload` }) }); \ No newline at end of file From 8bdca7b4452cbc22e40ca70b6a97068e5b717f20 Mon Sep 17 00:00:00 2001 From: Nader Date: Thu, 3 Oct 2024 11:26:03 +1000 Subject: [PATCH 03/17] package-lock.json changes --- webapp/package-lock.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index d671f42d..842a465c 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -99,6 +99,7 @@ "socket.io-client": "^4.7.2", "stripe": "^14.25.0", "tailwind-merge": "^2.4.0", + "tailwind-scrollbar": "^3.1.0", "tsconfig-paths": "^4.2.0", "uuid": "^9.0.1" }, @@ -109,7 +110,6 @@ "@types/react": "^18.2.22", "jest": "^29.7.0", "postcss": "^8.4.30", - "tailwind-scrollbar": "^3.1.0", "tailwindcss": "^3.3.3", "ts-jest": "^29.2.4", "ts-node": "^10.9.1", @@ -19752,7 +19752,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.1.0.tgz", "integrity": "sha512-pmrtDIZeHyu2idTejfV59SbaJyvp1VRjYxAjZBH0jnyrPRo6HL1kD5Glz8VPagasqr6oAx6M05+Tuw429Z8jxg==", - "dev": true, "engines": { "node": ">=12.13.0" }, From a93a8905df477d963434651d01225d026cc786ef Mon Sep 17 00:00:00 2001 From: Nader Date: Thu, 3 Oct 2024 13:13:40 +1000 Subject: [PATCH 04/17] successful file upload test, adding agent tests --- .../src/lib/middleware/auth/checksession.ts | 2 +- .../src/lib/middleware/auth/fetchsession.ts | 3 +- webapp/src/test/agents.ts | 56 +++++++++++++++++++ webapp/src/test/datasources.ts | 54 +++++++++++++++++- 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 webapp/src/test/agents.ts diff --git a/webapp/src/lib/middleware/auth/checksession.ts b/webapp/src/lib/middleware/auth/checksession.ts index 35fd4517..9e8c917d 100644 --- a/webapp/src/lib/middleware/auth/checksession.ts +++ b/webapp/src/lib/middleware/auth/checksession.ts @@ -4,7 +4,7 @@ import { dynamicResponse } from '@dr'; export default function checkSession(req, res, next) { if (!res.locals.account?._id && !res.locals.isAgentBackend) { - // console.log("checkSession, reslocals: ", res.locals); + console.log("checkSession, reslocals: ", res.locals); if (res.locals.isSocket) { return res?.locals?.socket?.disconnect(); } else { diff --git a/webapp/src/lib/middleware/auth/fetchsession.ts b/webapp/src/lib/middleware/auth/fetchsession.ts index 33261f6b..63fe273f 100644 --- a/webapp/src/lib/middleware/auth/fetchsession.ts +++ b/webapp/src/lib/middleware/auth/fetchsession.ts @@ -7,6 +7,7 @@ const log = debug('webapp:session'); export default async function fetchSession(req, res, next) { // log('req.session:', req.session); if (req.session && (req.session.accountId || req.session.passport?.user)) { + log("req.session.account", req.session.accountId); let account: Account; if (req.session.accountId) { account = await getAccountById(req.session.accountId); @@ -14,7 +15,7 @@ export default async function fetchSession(req, res, next) { const { oauthId, provider } = req.session.passport?.user; account = await getAccountByOAuthOrEmail(oauthId, provider, null); } - // log('account:', account); + log('account:', account); if (account) { res.locals.account = { _id: account._id.toString(), diff --git a/webapp/src/test/agents.ts b/webapp/src/test/agents.ts new file mode 100644 index 00000000..23b68de3 --- /dev/null +++ b/webapp/src/test/agents.ts @@ -0,0 +1,56 @@ +import { afterAll, beforeAll, describe, expect, test } from '@jest/globals'; +import * as db from '../db/index'; +import { addTeam, getTeamById, getTeamWithMembers } from '../db/team'; +import { getAccountByEmail, setStripeCustomerId, setStripePlan } from '../db/account'; +import { SubscriptionPlan } from '../lib/struct/billing'; +import { getInitialData, makeFetch, fetchTypes, accountDetails, setInitialData, updateAllAccountCsrf } from './helpers'; +import dotenv from 'dotenv'; +import { URLSearchParams } from 'url'; +import toObjectId from '../lib/misc/toobjectid'; +import { ModelList, ModelType } from '../lib/struct/model'; +import { ShareLinkTypes } from '../lib/struct/sharelink'; +import { getToolsByTeam } from "../db/tool"; +import { TeamRoles } from "../lib/permissions/roles" +import {Retriever} from '../lib/struct/tool'; +import path from 'path'; +import { defaultChunkingOptions } from '../lib/misc/defaultchunkingoptions'; + + +beforeAll(()=>{ + updateAllAccountCsrf(); +}) + +describe("Agents Tests", () => { + test.only("Add an agent", async ()=>{ + + }); + + test.only("Update an agent", async ()=>{ + + }); + + test.only("Can't add agent without permissions", async ()=>{ + + }); + + test.only("Can't edit agent without permissions", async ()=>{ + + }); + + test.only("Add an agent with invalid body", async ()=>{ + + }); + + test.only("Edit an agent with invalid body", async ()=>{ + + }); + + test.only("Add multiple agents", async ()=>{ + + }); + + test.only("Get agents (agents.json)", async ()=>{ + + }); + +}) \ No newline at end of file diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts index 2d6bd1fd..129d09cf 100644 --- a/webapp/src/test/datasources.ts +++ b/webapp/src/test/datasources.ts @@ -18,18 +18,47 @@ import { defaultChunkingOptions } from '../lib/misc/defaultchunkingoptions'; //use Fast Embed to reduce token usage for us and to also //use a self hosted runner in git to automate the tests into the PR process beforeAll(()=>{ + updateAllAccountCsrf(); }) describe("Datasource Tests", () => { test.only("Upload a file", async ()=>{ const account1Object = await getInitialData(accountDetails.account1_email); + //create model to be used for embedding + let url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/add`; + let config = { + model: 'fast-bge-small-en', + api_key: 'abcdefg' + } + let body = { + name: 'testModel1', + model: 'fast-bge-small-en', + config: config, + type: ModelType.FASTEMBED + }; + + let response = await makeFetch( + url, + fetchTypes.POST, + accountDetails.account1_email, + body + ); + + expect(response.status).toBe(200); + + let responseJson = await response.json(); + + expect(responseJson?._id).toBeDefined(); + + const modelId = responseJson?._id; + const formData = new FormData(); const fs = require('fs'); const chunkingConfig = defaultChunkingOptions formData.set('resourceSlug', account1Object.resourceSlug as string); - // formData.set('modelId', ) need to create a valid embedding model and get that modelId + formData.set('modelId', modelId as string); formData.set('datasourceDescription', "File Upload Test Datasource"); formData.set('name', "TestSource"); formData.set('retriever', Retriever.RAW as string); @@ -44,6 +73,27 @@ describe("Datasource Tests", () => { } }); - let url = `${process.env.WEBAPP_TEST_URL}/${account1Object.resourceSlug}/forms/datasource/upload` + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/datasource/upload`; + + response = await fetch(url, { + headers: { + cookie : account1Object.sessionCookie + }, + method: 'POST', + body: formData + }) + + expect(response.status).toBe(200); + + responseJson = await response.json(); + + console.log(responseJson); + + expect(responseJson?.datasourceId).toBeDefined(); + }); + + + test.only("Make Connection", async () => {//make a connection with airbyte + }) }); \ No newline at end of file From 195f8a15683c49716581dbf8f12901e2234b2f0f Mon Sep 17 00:00:00 2001 From: Nader Date: Thu, 3 Oct 2024 13:16:32 +1000 Subject: [PATCH 05/17] lint --- webapp/src/lib/middleware/auth/checksession.ts | 2 +- webapp/src/lib/middleware/auth/fetchsession.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/lib/middleware/auth/checksession.ts b/webapp/src/lib/middleware/auth/checksession.ts index 9e8c917d..32e23d79 100644 --- a/webapp/src/lib/middleware/auth/checksession.ts +++ b/webapp/src/lib/middleware/auth/checksession.ts @@ -4,7 +4,7 @@ import { dynamicResponse } from '@dr'; export default function checkSession(req, res, next) { if (!res.locals.account?._id && !res.locals.isAgentBackend) { - console.log("checkSession, reslocals: ", res.locals); + console.log('checkSession, reslocals: ', res.locals); if (res.locals.isSocket) { return res?.locals?.socket?.disconnect(); } else { diff --git a/webapp/src/lib/middleware/auth/fetchsession.ts b/webapp/src/lib/middleware/auth/fetchsession.ts index 63fe273f..55e05ee3 100644 --- a/webapp/src/lib/middleware/auth/fetchsession.ts +++ b/webapp/src/lib/middleware/auth/fetchsession.ts @@ -7,7 +7,7 @@ const log = debug('webapp:session'); export default async function fetchSession(req, res, next) { // log('req.session:', req.session); if (req.session && (req.session.accountId || req.session.passport?.user)) { - log("req.session.account", req.session.accountId); + log('req.session.account', req.session.accountId); let account: Account; if (req.session.accountId) { account = await getAccountById(req.session.accountId); From 51d423e5a6fe27bbf42bc6ea683b919fd22e3fa7 Mon Sep 17 00:00:00 2001 From: Nader Date: Thu, 3 Oct 2024 14:22:50 +1000 Subject: [PATCH 06/17] wip --- webapp/src/test/agents.ts | 9 +++++++-- webapp/src/test/datasources.ts | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/webapp/src/test/agents.ts b/webapp/src/test/agents.ts index 23b68de3..fb98e50d 100644 --- a/webapp/src/test/agents.ts +++ b/webapp/src/test/agents.ts @@ -22,7 +22,12 @@ beforeAll(()=>{ describe("Agents Tests", () => { test.only("Add an agent", async ()=>{ - + const account1Object = await getInitialData(accountDetails.account1_email); + + const teamTools = await getToolsByTeam(account1Object.resourceSlug); + const toolIds = teamTools.map(tool => (tool._id)) + + console.log(toolIds); }); test.only("Update an agent", async ()=>{ @@ -52,5 +57,5 @@ describe("Agents Tests", () => { test.only("Get agents (agents.json)", async ()=>{ }); - + }) \ No newline at end of file diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts index 129d09cf..ad244abc 100644 --- a/webapp/src/test/datasources.ts +++ b/webapp/src/test/datasources.ts @@ -83,6 +83,7 @@ describe("Datasource Tests", () => { body: formData }) + console.log(response); expect(response.status).toBe(200); responseJson = await response.json(); From f404bad8693bc5803be40928b104b938809411d2 Mon Sep 17 00:00:00 2001 From: NaderRNA Date: Fri, 4 Oct 2024 15:55:59 +1000 Subject: [PATCH 07/17] modifying all tests to delete any objects created within the test to keep db clean --- webapp/.env.example | 2 + webapp/src/test/agents.ts | 147 +++++++++++++++++++++- webapp/src/test/datasources.ts | 34 +++++- webapp/src/test/helpers.ts | 5 + webapp/src/test/integration.test.ts | 1 + webapp/src/test/logout.ts | 2 +- webapp/src/test/models.ts | 182 +++++++++++++++++++++++++--- webapp/src/test/teams.ts | 25 +++- 8 files changed, 364 insertions(+), 34 deletions(-) diff --git a/webapp/.env.example b/webapp/.env.example index 5c637fda..1fc05a6d 100644 --- a/webapp/.env.example +++ b/webapp/.env.example @@ -56,6 +56,8 @@ STRIPE_ADDON_USERS_PRODUCT_ID= STRIPE_ADDON_STORAGE_PRODUCT_ID= STRIPE_WEBHOOK_SECRET= STRIPE_ACCOUNT_SECRET= +SKIP_EMAIL= +SKIP_STRIPE= NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= WEBAPP_TEST_BASE_URL=http://localhost:3000 NEXT_PUBLIC_LOCAL_UNSTRUCTURED=1 diff --git a/webapp/src/test/agents.ts b/webapp/src/test/agents.ts index fb98e50d..61124c32 100644 --- a/webapp/src/test/agents.ts +++ b/webapp/src/test/agents.ts @@ -21,28 +21,163 @@ beforeAll(()=>{ }) describe("Agents Tests", () => { - test.only("Add an agent", async ()=>{ + test.only("Can't add agent with empty modelid", async ()=>{ const account1Object = await getInitialData(accountDetails.account1_email); const teamTools = await getToolsByTeam(account1Object.resourceSlug); const toolIds = teamTools.map(tool => (tool._id)) - console.log(toolIds); + let body, url, response, responseJson; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/add` + body = { + toolIds, + name: "AddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId: '', //emptymodelId + } + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); + expect(response.status).toBe(400); }); - test.only("Update an agent", async ()=>{ + test.only("Can't add agent with invalid modelid", async ()=>{ + const account1Object = await getInitialData(accountDetails.account1_email); + + const teamTools = await getToolsByTeam(account1Object.resourceSlug); + const toolIds = teamTools.map(tool => (tool._id)) + let body, url, response, responseJson; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/add` + body = { + toolIds, + name: "AddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId: 'aaaaaaaaaaaaaaaaaaaaaaaa', //this modelId doesn't exist + } + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); + expect(response.status).toBe(400); }); - test.only("Can't add agent without permissions", async ()=>{ + test.only("add with valid modelId", async ()=>{ + const account1Object = await getInitialData(accountDetails.account1_email); + let body, url, response, responseJson; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/add`; + body = { + name: 'testModel1', + model: 'gpt-4o', + config: { + model: 'gpt-4o', + api_key: 'abcdefg' + }, + type: ModelType.OPENAI + }; + + const addModelResponse = await makeFetch( + url, + fetchTypes.POST, + accountDetails.account1_email, + body + ); + + expect(addModelResponse.status).toBe(200); + responseJson = await addModelResponse.json(); + expect(responseJson?._id).toBeDefined(); + const modelId = responseJson._id; //the added item ID of the model + + const teamTools = await getToolsByTeam(account1Object.resourceSlug); + const toolIds = teamTools.map(tool => (tool._id)) + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/add` + body = { + toolIds, + name: "AddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId + } + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); + expect(response.status).toBe(200); //successfully add model + responseJson = await response.json(); + expect(responseJson?._id).toBeDefined(); //make sure that the 200 response isn't a redirect to login or any other response than a success for adding agent + + //clean up tests by removing agent and model that were added + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/${responseJson._id}`; + body={ + agentId: responseJson._id + }; + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); + expect(response.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/${modelId}`; + body = { + modelId + } + + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); + expect(response.status).toBe(200); }); - test.only("Can't edit agent without permissions", async ()=>{ + test.only("can't add agent with invalid permissions", async ()=>{ + const account1Object = await getInitialData(accountDetails.account1_email); + let body, url, response, responseJson; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/add`; + body = { + name: 'testModel1', + model: 'gpt-4o', + config: { + model: 'gpt-4o', + api_key: 'abcdefg' + }, + type: ModelType.OPENAI + }; + + const addModelResponse = await makeFetch( + url, + fetchTypes.POST, + accountDetails.account1_email, + body + ); + + expect(addModelResponse.status).toBe(200); + responseJson = await addModelResponse.json(); + expect(responseJson?._id).toBeDefined(); + const modelId = responseJson._id; //the added item ID of the model + + const teamTools = await getToolsByTeam(account1Object.resourceSlug); + const toolIds = teamTools.map(tool => (tool._id)) + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/add` + body = { + toolIds, + name: "AddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId + } + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); + expect(response.status).toBe(200); //successfully add model + responseJson = await response.json(); + expect(responseJson?._id).toBeDefined(); //make sure that the 200 response isn't a redirect to login or any other response than a success for adding agent + }); + + test.only("Update an agent", async ()=>{ + + }); + + test.only("Can't add agent without permissions", async ()=>{ }); - test.only("Add an agent with invalid body", async ()=>{ + test.only("Can't edit agent without permissions", async ()=>{ }); diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts index ad244abc..b39d7fe4 100644 --- a/webapp/src/test/datasources.ts +++ b/webapp/src/test/datasources.ts @@ -3,7 +3,7 @@ import * as db from '../db/index'; import { addTeam, getTeamById, getTeamWithMembers } from '../db/team'; import { getAccountByEmail, setStripeCustomerId, setStripePlan } from '../db/account'; import { SubscriptionPlan } from '../lib/struct/billing'; -import { getInitialData, makeFetch, fetchTypes, accountDetails, setInitialData, updateAllAccountCsrf } from './helpers'; +import { getInitialData, makeFetch, fetchTypes, accountDetails, setInitialData, updateAllAccountCsrf, wait } from './helpers'; import dotenv from 'dotenv'; import { URLSearchParams } from 'url'; import toObjectId from '../lib/misc/toobjectid'; @@ -21,17 +21,20 @@ beforeAll(()=>{ updateAllAccountCsrf(); }) +const SECONDS = 1000; + describe("Datasource Tests", () => { test.only("Upload a file", async ()=>{ const account1Object = await getInitialData(accountDetails.account1_email); //create model to be used for embedding + let body; let url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/add`; let config = { model: 'fast-bge-small-en', api_key: 'abcdefg' } - let body = { + body = { name: 'testModel1', model: 'fast-bge-small-en', config: config, @@ -83,15 +86,36 @@ describe("Datasource Tests", () => { body: formData }) - console.log(response); expect(response.status).toBe(200); responseJson = await response.json(); - console.log(responseJson); expect(responseJson?.datasourceId).toBeDefined(); - }); + const datasourceId = responseJson.datasourceId; + + // //TODO: find a better way to wait for embedding to be completed + // let ready=false; + // while(!ready){ + // url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/datasource/${datasourceId}.json` + // response = await makeFetch(url, fetchTypes.GET, accountDetails.account1_email); + // responseJson = await response.json(); + // if(responseJson?.status === "ready"){ + // ready = true; + // break; + // } + // else{ + // wait(1 * SECONDS); //wait 1 second if the datasource isn't ready + // } + // }; + //once the datasource is classed as ready then delete it to clean up the db and the vector-db + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/datasource/${datasourceId}`; + body={ + datasourceId + }; + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); + expect(response.status).toBe(200); + }, 60 * SECONDS); test.only("Make Connection", async () => {//make a connection with airbyte diff --git a/webapp/src/test/helpers.ts b/webapp/src/test/helpers.ts index 40360893..a27bb242 100644 --- a/webapp/src/test/helpers.ts +++ b/webapp/src/test/helpers.ts @@ -1,5 +1,6 @@ let accountInformationMap: Map = new Map(); +let objectIds: string[]; export enum fetchTypes { POST = 'POST', GET = 'GET', @@ -90,4 +91,8 @@ export async function updateAllAccountCsrf() { const { sessionCookie } = await getInitialData(accountDetails[accountStr]); setInitialData(accountDetails[accountStr], { accountData: accountJson, sessionCookie }); }; +} + +export async function wait(ms: number) { + return new Promise( resolve => setTimeout(resolve, ms) ); } \ No newline at end of file diff --git a/webapp/src/test/integration.test.ts b/webapp/src/test/integration.test.ts index b969a310..c95a4837 100644 --- a/webapp/src/test/integration.test.ts +++ b/webapp/src/test/integration.test.ts @@ -3,5 +3,6 @@ import './pages'; import './teams'; import './models'; import './datasources'; +import './agents'; import './logout'; //this MUST be last \ No newline at end of file diff --git a/webapp/src/test/logout.ts b/webapp/src/test/logout.ts index 720928a8..453f15a1 100644 --- a/webapp/src/test/logout.ts +++ b/webapp/src/test/logout.ts @@ -34,7 +34,7 @@ afterAll(async () => { accountDetails.account11_email ] } - }); + }); await db.client().close(); }); diff --git a/webapp/src/test/models.ts b/webapp/src/test/models.ts index 7d511348..ac5e77f1 100644 --- a/webapp/src/test/models.ts +++ b/webapp/src/test/models.ts @@ -3,7 +3,7 @@ import * as db from '../db/index'; import { addTeam, getTeamById, getTeamWithMembers } from '../db/team'; import { getAccountByEmail, setStripeCustomerId, setStripePlan } from '../db/account'; import { SubscriptionPlan } from '../lib/struct/billing'; -import { getInitialData, makeFetch, fetchTypes, accountDetails, setInitialData, updateAllAccountCsrf } from './helpers'; +import { getInitialData, makeFetch, fetchTypes, accountDetails, setInitialData, updateAllAccountCsrf} from './helpers'; import dotenv from 'dotenv'; import { URLSearchParams } from 'url'; import toObjectId from '../lib/misc/toobjectid'; @@ -62,9 +62,10 @@ describe('Model Tests', () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); + let body; let url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; - let body = { + body = { name: 'testModel1', model: 'gpt-4o', config: { @@ -82,6 +83,16 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + const addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson?._id).toBeDefined(); + + //clean up db with model delete + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + } + let response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(response.status).toBe(200); }); @@ -90,9 +101,10 @@ describe('Model Tests', () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); + let addModelResponseJson, body, addModelResponse, url, deleteModelResponse; - let url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; - let body = { + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1-FREE-EMBED', model: 'text-embedding-3-small', config: { @@ -102,7 +114,7 @@ describe('Model Tests', () => { type: ModelType.OPENAI }; - let addModelResponse = await makeFetch( + addModelResponse = await makeFetch( url, fetchTypes.POST, accountDetails.account3_email, @@ -110,6 +122,20 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson?._id).toBeDefined(); + + //clean up after test + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + + body = { name: 'testModel2-FREE-EMBED', model: 'text-embedding-3-large', @@ -128,6 +154,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson?._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel3-FREE-EMBED', model: 'text-embedding-ada-002', @@ -146,6 +183,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson?._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + }); @@ -160,10 +208,10 @@ describe('Model Tests', () => { const plan = SubscriptionPlan.PRO; setStripeCustomerId(initialData?.accountData?.account?._id, stripeCustomerId); setStripePlan(stripeCustomerId, plan); + let url, body, addModelResponse, addModelResponseJson; - - let url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; - let body = { + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1', model: 'gemini-1.5-pro', config: { @@ -173,13 +221,13 @@ describe('Model Tests', () => { type: ModelType.GOOGLE_AI }; - const addModelResponse = await makeFetch( + addModelResponse = await makeFetch( url, fetchTypes.POST, accountDetails.account3_email, body ); - const addModelResponseJson = await addModelResponse.json(); + addModelResponseJson = await addModelResponse.json(); expect(addModelResponse.status).toBe(403); @@ -190,10 +238,11 @@ describe('Model Tests', () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); + let addModelResponseJson, addModelResponse, url, body, deleteModelResponse; - let url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; - let body = { + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1', model: 'claude-3-5-sonnet-20240620', config: { @@ -203,7 +252,7 @@ describe('Model Tests', () => { type: ModelType.ANTHROPIC }; - const addModelResponse = await makeFetch( + addModelResponse = await makeFetch( url, fetchTypes.POST, accountDetails.account3_email, @@ -212,6 +261,17 @@ describe('Model Tests', () => { expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + }); @@ -220,7 +280,7 @@ describe('Model Tests', () => { const { initialData, sessionCookie, resourceSlug, csrfToken } = await getInitialData( accountDetails.account3_email ); - + let addModelResponseJson, url, body, addModelResponse, deleteModelResponse; //set org to pro plan const stripeCustomerId = initialData?.accountData?.account?.stripe?.stripeCustomerId || ""; const plan = SubscriptionPlan.TEAMS; @@ -228,19 +288,19 @@ describe('Model Tests', () => { setStripePlan(stripeCustomerId, plan); - let url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; let config = { model: 'gpt-4o-mini', api_key: 'abcdefg' } - let body = { + body = { name: 'testModel1', model: 'gpt-4o-mini', config: config, type: ModelType.OPENAI }; - let addModelResponse = await makeFetch( + addModelResponse = await makeFetch( url, fetchTypes.POST, accountDetails.account3_email, @@ -248,6 +308,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + config = { model: 'fast-bge-small-en', api_key: 'abcdefg' @@ -267,6 +338,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + let ollamaConfig = { model: 'llama2', api_key: 'abcdefg', @@ -287,6 +369,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1', model: 'claude-3-5-sonnet-20240620', @@ -305,6 +398,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + const groqConfig = { groq_api_key: 'abcdegs', model: 'llama3-70b-8192' @@ -325,6 +429,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1', model: 'gemini-1.5-pro', @@ -347,6 +462,17 @@ describe('Model Tests', () => { body ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1', model: 'gemini-1.5-pro', @@ -365,6 +491,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + body = { name: 'testModel1', model: 'gpt-4o-mini', @@ -388,6 +525,17 @@ describe('Model Tests', () => { ); expect(addModelResponse.status).toBe(200); + addModelResponseJson = await addModelResponse.json(); + expect(addModelResponseJson._id).toBeDefined(); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/${addModelResponseJson._id}`; + body = { + modelId: addModelResponseJson._id + }; + deleteModelResponse = await makeFetch(url, fetchTypes.DELETE, accountDetails.account3_email, body); + expect(deleteModelResponse.status).toBe(200); + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/model/add`; + }) diff --git a/webapp/src/test/teams.ts b/webapp/src/test/teams.ts index 0efa52cd..7850acb8 100644 --- a/webapp/src/test/teams.ts +++ b/webapp/src/test/teams.ts @@ -40,10 +40,8 @@ describe('team tests', () => { const stripeCustomerId = 'sk_12345'; //testing flags set stripe customer ID to null, need to set it to set the plan const plan = SubscriptionPlan.TEAMS; - setStripeCustomerId(initialData?.accountData?.account?._id, stripeCustomerId); - setStripePlan(stripeCustomerId, plan); - - const newAccount = await getAccountByEmail(accountDetails.account1_email); + await setStripeCustomerId(initialData?.accountData?.account?._id, stripeCustomerId); + await setStripePlan(stripeCustomerId, plan); const url = `${process.env.WEBAPP_TEST_BASE_URL}/${resourceSlug}/forms/team/add`; const body = { @@ -54,6 +52,7 @@ describe('team tests', () => { const response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); const responseJson = await response.json(); + console.log(responseJson); expect(response.status).toBe(200); expect(responseJson?._id).toBeDefined(); expect(responseJson?.orgId).toBeDefined(); @@ -191,6 +190,23 @@ describe('team tests', () => { const addAgentResponse = await response.json(); expect(addAgentResponse?.redirect).toBeDefined(); expect(addAgentResponse?._id).toBeDefined(); + + + //clean up the db by deleting all the added elements + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/${addAgentResponse._id}`; + body={ + agentId: addAgentResponse._id + } + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); + expect(response.status).toBe(200); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/${addModelResponseJson._id}`; + body={ + modelId: addModelResponseJson._id + } + response= await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); + expect(response.status).toBe(200); + }); test.only('testing TEAM_ADMIN permissions', async () => { @@ -340,6 +356,5 @@ describe('team tests', () => { } } - const teamMembers = await getTeamWithMembers(resourceSlug); }); }); From 1174085407a5368df2f7af388b9ecde4b0e1dff4 Mon Sep 17 00:00:00 2001 From: Nader Date: Tue, 8 Oct 2024 12:46:00 +1100 Subject: [PATCH 08/17] modifying .env.example to work with integration tests, including script to set the .env to be the same as .env.example to ensure clean run --- setemptyenv.sh | 37 +++++++++++++++++++++++++++ webapp/.env.example | 4 +-- webapp/src/test/agents.ts | 53 +++++++++++++++++++++++++++++++++++++++ webapp/src/test/teams.ts | 1 - 4 files changed, 92 insertions(+), 3 deletions(-) create mode 100755 setemptyenv.sh diff --git a/setemptyenv.sh b/setemptyenv.sh new file mode 100755 index 00000000..e0f0316a --- /dev/null +++ b/setemptyenv.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + + +# Function to copy .env.example to .env +copy_env_example() { + # Check if .env.example exists + if [ ! -f ".env.example" ]; then + echo ".env.example file does not exist." + exit 1 + fi + + # Copy contents of .env.example to .env + cp .env.example .env + echo ".env file has been created with the contents of .env.example." +} + +# Navigate to the ./webapp directory +cd ./webapp || { + echo "Failed to navigate to ./webapp. Directory does not exist."; + exit 1; +} + +copy_env_example + +cd ../agent-backend || { + echo "Failed to navigate to ../agent-backend. Directory may not exist"; + exit 1; +} + +copy_env_example + +cd ../vector-db-proxy || { + echo "Failed to navigate to ../vector-db-proxy. Directory may not exist"; + exit 1; +} + +copy_env_example \ No newline at end of file diff --git a/webapp/.env.example b/webapp/.env.example index 1fc05a6d..a96a38bf 100644 --- a/webapp/.env.example +++ b/webapp/.env.example @@ -56,8 +56,8 @@ STRIPE_ADDON_USERS_PRODUCT_ID= STRIPE_ADDON_STORAGE_PRODUCT_ID= STRIPE_WEBHOOK_SECRET= STRIPE_ACCOUNT_SECRET= -SKIP_EMAIL= -SKIP_STRIPE= +SKIP_EMAIL=1 +SKIP_STRIPE=1 NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= WEBAPP_TEST_BASE_URL=http://localhost:3000 NEXT_PUBLIC_LOCAL_UNSTRUCTURED=1 diff --git a/webapp/src/test/agents.ts b/webapp/src/test/agents.ts index 61124c32..cc134444 100644 --- a/webapp/src/test/agents.ts +++ b/webapp/src/test/agents.ts @@ -174,6 +174,59 @@ describe("Agents Tests", () => { }); test.only("Can't add agent without permissions", async ()=>{ + const account1Object = await getInitialData(accountDetails.account1_email); + const account11Object = await getInitialData(accountDetails.account11_email); + let body, url, response, responseJson; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/add`; + body = { + name: 'testModel1', + model: 'gpt-4o', + config: { + model: 'gpt-4o', + api_key: 'abcdefg' + }, + type: ModelType.OPENAI + }; + + const addModelResponse = await makeFetch( + url, + fetchTypes.POST, + accountDetails.account1_email, + body + ); + + expect(addModelResponse.status).toBe(200); + responseJson = await addModelResponse.json(); + expect(responseJson?._id).toBeDefined(); + const modelId = responseJson._id; //the added item ID of the model + + const teamTools = await getToolsByTeam(account1Object.resourceSlug); + const toolIds = teamTools.map(tool => (tool._id)) + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/add` + body = { + toolIds, + name: "AddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId + } + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account11_email, body); //account 11 doesn't have permissions to add an agent to this team, recall teams tests, 10 members are invited (10 total in the team), 11 can't be invited due to subscription restrictions + responseJson = await response.json(); + expect(response.status).toBe(200); //This is a successful redirect to the welcome page NOT a successful creation of the agent + expect(responseJson?.redirect).toBe('/welcome?noaccess=true'); //redirects to the welcome page to gracefully handle invalid permission + + //clean up tests by removing agent and model that were added + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/${modelId}`; + body = { + modelId + } + + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); //delete the model from earlier + expect(response.status).toBe(200); }); diff --git a/webapp/src/test/teams.ts b/webapp/src/test/teams.ts index 7850acb8..489a7762 100644 --- a/webapp/src/test/teams.ts +++ b/webapp/src/test/teams.ts @@ -52,7 +52,6 @@ describe('team tests', () => { const response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); const responseJson = await response.json(); - console.log(responseJson); expect(response.status).toBe(200); expect(responseJson?._id).toBeDefined(); expect(responseJson?.orgId).toBeDefined(); From 86e530166b9a025743c537a7f5eef036c0bc050c Mon Sep 17 00:00:00 2001 From: NaderRNA Date: Tue, 8 Oct 2024 13:04:44 +1100 Subject: [PATCH 09/17] Create webapp-integration-tests.yml --- .../workflows/webapp-integration-tests.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/webapp-integration-tests.yml diff --git a/.github/workflows/webapp-integration-tests.yml b/.github/workflows/webapp-integration-tests.yml new file mode 100644 index 00000000..6cd3f1e9 --- /dev/null +++ b/.github/workflows/webapp-integration-tests.yml @@ -0,0 +1,37 @@ + +name: Run Webapp Integration Tests + +on: + pull_request: + branches: [ "more-integration-tests" ] + +jobs: + integration-tests: + name: Build and install dependencies + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Set environment variables + run: ./setemptyenv.sh + + - name: Install webapp dependencies + working-directory: ./webapp + run: npm install + + - name: run ./install.sh + run: ./install.sh + + - name: Run integration tests + working-directory: ./webapp + run: npm run test:integration From 01c65380d92a4294e08790a54211c560c24a4544 Mon Sep 17 00:00:00 2001 From: NaderRNA Date: Tue, 8 Oct 2024 13:13:27 +1100 Subject: [PATCH 10/17] Update webapp-integration-tests.yml --- .github/workflows/webapp-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webapp-integration-tests.yml b/.github/workflows/webapp-integration-tests.yml index 6cd3f1e9..c607d83e 100644 --- a/.github/workflows/webapp-integration-tests.yml +++ b/.github/workflows/webapp-integration-tests.yml @@ -3,7 +3,7 @@ name: Run Webapp Integration Tests on: pull_request: - branches: [ "more-integration-tests" ] + branches: [ "develop" ] jobs: integration-tests: From 98a0a6db073d8f43ed38d93d481ddd96778a7010 Mon Sep 17 00:00:00 2001 From: Nader Date: Tue, 8 Oct 2024 13:15:55 +1100 Subject: [PATCH 11/17] adding .env.example to vector-db-proxy --- vector-db-proxy/.env.example | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 vector-db-proxy/.env.example diff --git a/vector-db-proxy/.env.example b/vector-db-proxy/.env.example new file mode 100644 index 00000000..435e511c --- /dev/null +++ b/vector-db-proxy/.env.example @@ -0,0 +1,21 @@ +HOST=0.0.0.0 +PORT=9001 +MONGO_URI=mongodb://docker_mongo:27017 +MONGO_DB_NAME=test +RABBITMQ_HOST=docker_rabbitmq +RABBITMQ_PORT=5672 +RABBITMQ_STREAM=streaming +RABBITMQ_EXCHANGE=agentcloud +RABBITMQ_ROUTING_KEY=key +RABBITMQ_USERNAME=guest +RABBITMQ_PASSWORD=guest +QDRANT_URI=http://qdrant:6334 +QDRANT_HOST=http://qdrant +QDRANT_PORT=6334 +REDIS_HOST=docker_redis +REDIS_PORT=6379 +WEBAPP_HOST=webapp_next +THREAD_PERCENTAGE_UTILISATION=0.8 +USE_GPU=false +LOGGING_LEVEL=warn +UNSTRUCTURED_API_URL=http://unstructured-api:9500/general/v0/general \ No newline at end of file From 935d1821b38675fd0d0123956b5cf70808a6bc9e Mon Sep 17 00:00:00 2001 From: Nader Date: Tue, 8 Oct 2024 13:33:33 +1100 Subject: [PATCH 12/17] fixing terminal issue in github action --- .github/workflows/webapp-integration-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/webapp-integration-tests.yml b/.github/workflows/webapp-integration-tests.yml index c607d83e..6b692f52 100644 --- a/.github/workflows/webapp-integration-tests.yml +++ b/.github/workflows/webapp-integration-tests.yml @@ -9,6 +9,8 @@ jobs: integration-tests: name: Build and install dependencies runs-on: ubuntu-latest + env: + TERM: xterm permissions: contents: read security-events: write From e91a8349b5d6a9831b5f7605075601205e04b7d3 Mon Sep 17 00:00:00 2001 From: Nader Date: Tue, 8 Oct 2024 13:45:52 +1100 Subject: [PATCH 13/17] adding firefox support to action --- .../workflows/webapp-integration-tests.yml | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/webapp-integration-tests.yml b/.github/workflows/webapp-integration-tests.yml index 6b692f52..5ec0606e 100644 --- a/.github/workflows/webapp-integration-tests.yml +++ b/.github/workflows/webapp-integration-tests.yml @@ -7,8 +7,11 @@ on: jobs: integration-tests: - name: Build and install dependencies + name: Build app and run integration tests runs-on: ubuntu-latest + strategy: + matrix: + firefox: [ '84.0', 'devedition-84.0b1', 'latest-beta', 'latest-devedition', 'latest-nightly', 'latest-esr', 'latest' ] env: TERM: xterm permissions: @@ -18,6 +21,15 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + + - name: Setup firefox + id: setup-firefox + uses: browser-actions/setup-firefox@v1 + with: + firefox-version: ${{ matrix.firefox }} + - run: | + echo Installed firefox versions: ${{ steps.setup-firefox.outputs.firefox-version }} + ${{ steps.setup-firefox.outputs.firefox-path }} --version - name: Set up Node.js uses: actions/setup-node@v4 @@ -30,10 +42,3 @@ jobs: - name: Install webapp dependencies working-directory: ./webapp run: npm install - - - name: run ./install.sh - run: ./install.sh - - - name: Run integration tests - working-directory: ./webapp - run: npm run test:integration From f4d29d93dd1748b2feab59563c524aae92d3d5a0 Mon Sep 17 00:00:00 2001 From: Nader Date: Tue, 8 Oct 2024 13:49:41 +1100 Subject: [PATCH 14/17] adding install.sh back into the action --- .github/workflows/webapp-integration-tests.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/webapp-integration-tests.yml b/.github/workflows/webapp-integration-tests.yml index 5ec0606e..002e11a1 100644 --- a/.github/workflows/webapp-integration-tests.yml +++ b/.github/workflows/webapp-integration-tests.yml @@ -25,11 +25,6 @@ jobs: - name: Setup firefox id: setup-firefox uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ matrix.firefox }} - - run: | - echo Installed firefox versions: ${{ steps.setup-firefox.outputs.firefox-version }} - ${{ steps.setup-firefox.outputs.firefox-path }} --version - name: Set up Node.js uses: actions/setup-node@v4 @@ -42,3 +37,10 @@ jobs: - name: Install webapp dependencies working-directory: ./webapp run: npm install + + - name: run ./install.sh + run: ./install.sh + + - name: run integration tests + working-directory: ./webapp + run: npm run test:integration \ No newline at end of file From 42b1169f4787c41d6d1bdc6e2287be509e1da9e1 Mon Sep 17 00:00:00 2001 From: Nader Date: Tue, 8 Oct 2024 14:25:58 +1100 Subject: [PATCH 15/17] fixing dockercompose issues --- .github/workflows/webapp-integration-tests.yml | 3 --- docker-compose.yml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/webapp-integration-tests.yml b/.github/workflows/webapp-integration-tests.yml index 002e11a1..c0dfa984 100644 --- a/.github/workflows/webapp-integration-tests.yml +++ b/.github/workflows/webapp-integration-tests.yml @@ -9,9 +9,6 @@ jobs: integration-tests: name: Build app and run integration tests runs-on: ubuntu-latest - strategy: - matrix: - firefox: [ '84.0', 'devedition-84.0b1', 'latest-beta', 'latest-devedition', 'latest-nightly', 'latest-esr', 'latest' ] env: TERM: xterm permissions: diff --git a/docker-compose.yml b/docker-compose.yml index ca5afdfb..05e8165f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: container_name: unstructured-api environment: - PORT=9500 - image: localhost:5000/unstructured-api + image: localhost:9500/unstructured-api docker_rabbitmq: image: rabbitmq:3.13.1-management From 44a4e47e3f4bc744277ca6057fcb67955db209c9 Mon Sep 17 00:00:00 2001 From: NaderRNA Date: Fri, 11 Oct 2024 09:06:29 +1100 Subject: [PATCH 16/17] slightly modifying test file before merging develop into this branch --- webapp/src/test/datasources.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts index b39d7fe4..551f6c77 100644 --- a/webapp/src/test/datasources.ts +++ b/webapp/src/test/datasources.ts @@ -117,6 +117,14 @@ describe("Datasource Tests", () => { expect(response.status).toBe(200); }, 60 * SECONDS); + //AIRBYTE TESTS + //get connections.json + + //getSpecification + + //getJobsList + + //getDatasourceSchema test.only("Make Connection", async () => {//make a connection with airbyte From 4a5ddb6528b4d8b858c9390ae5a82e29bbba0e7f Mon Sep 17 00:00:00 2001 From: NaderRNA Date: Fri, 11 Oct 2024 11:08:11 +1100 Subject: [PATCH 17/17] adding another agent test --- webapp/src/test/agents.ts | 78 ++++++++++++++++++++++++++++++++++ webapp/src/test/datasources.ts | 4 +- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/webapp/src/test/agents.ts b/webapp/src/test/agents.ts index cc134444..cceea407 100644 --- a/webapp/src/test/agents.ts +++ b/webapp/src/test/agents.ts @@ -231,6 +231,84 @@ describe("Agents Tests", () => { }); test.only("Can't edit agent without permissions", async ()=>{ + const account1Object = await getInitialData(accountDetails.account1_email); + const account11Object = await getInitialData(accountDetails.account11_email); + let body, url, response, responseJson; + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/add`; + body = { + name: 'testModel1', + model: 'gpt-4o', + config: { + model: 'gpt-4o', + api_key: 'abcdefg' + }, + type: ModelType.OPENAI + }; + + const addModelResponse = await makeFetch( + url, + fetchTypes.POST, + accountDetails.account1_email, + body + ); + + expect(addModelResponse.status).toBe(200); + responseJson = await addModelResponse.json(); + expect(responseJson?._id).toBeDefined(); + const modelId = responseJson._id; //the added item ID of the model + + const teamTools = await getToolsByTeam(account1Object.resourceSlug); + const toolIds = teamTools.map(tool => (tool._id)) + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/add` + body = { + toolIds, + name: "AddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId + } + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account1_email, body); //account 11 doesn't have permissions to add an agent to this team, recall teams tests, 10 members are invited (10 total in the team), 11 can't be invited due to subscription restrictions + responseJson = await response.json(); + expect(response.status).toBe(200); //This is a successful redirect to the welcome page NOT a successful creation of the agent + expect(responseJson?._id).toBeDefined(); + + const addedAgentId = responseJson?._id; + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/${addedAgentId}/edit`; + body = { + toolIds, + name: "editedAddBasicAgent", + role: "AddBasicAgent", + goal: "AddBasicAgent", + backstory: "AddBasicAgent", + modelId + }; + + response = await makeFetch(url, fetchTypes.POST, accountDetails.account11_email, body); + responseJson = await response.json(); + expect(response.status).toBe(200); //this is a successful redirect to the welcome page + expect(responseJson?.redirect).toBe('/welcome?noaccess=true'); //ensure redirect path is correct + + //clean up tests by removing agent and model that were added + + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/model/${modelId}`; + body = { + modelId + } + + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); //delete the model from earlier + expect(response.status).toBe(200); + url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/forms/agent/${addedAgentId}`; + body = { + agentId: addedAgentId + } + + response = await makeFetch(url, fetchTypes.DELETE, accountDetails.account1_email, body); //delete the model from earlier + responseJson = await response.json(); + expect(response.status).toBe(200); }); diff --git a/webapp/src/test/datasources.ts b/webapp/src/test/datasources.ts index 551f6c77..3a2cf586 100644 --- a/webapp/src/test/datasources.ts +++ b/webapp/src/test/datasources.ts @@ -108,6 +108,8 @@ describe("Datasource Tests", () => { // wait(1 * SECONDS); //wait 1 second if the datasource isn't ready // } // }; + + //once the datasource is classed as ready then delete it to clean up the db and the vector-db url = `${process.env.WEBAPP_TEST_BASE_URL}/${account1Object.resourceSlug}/datasource/${datasourceId}`; body={ @@ -126,7 +128,7 @@ describe("Datasource Tests", () => { //getDatasourceSchema - test.only("Make Connection", async () => {//make a connection with airbyte + test.only("Make Connection", async () => {//make a connection with airbyte, connection credentials will probably have to be set in .env }) }); \ No newline at end of file