From bde3daae084e52c9ee7758fe08996d5bd118fd09 Mon Sep 17 00:00:00 2001 From: Marcus Schiesser <mail@marcusschiesser.de> Date: Tue, 1 Oct 2024 11:50:21 +0700 Subject: [PATCH] reorganize e2e tests (split Python and TS) (#329) --------- Co-authored-by: leehuwuj <leehuwuj@gmail.com> --- .github/workflows/e2e.yml | 79 ++++++++++++- .../resolve_dependencies.spec.ts} | 8 +- e2e/resolve_ts_dependencies.spec.ts | 102 ----------------- e2e/{ => shared}/extractor_template.spec.ts | 9 +- e2e/{ => shared}/multiagent_template.spec.ts | 4 +- e2e/{ => shared}/streaming_template.spec.ts | 4 +- e2e/typescript/resolve_dependencies.spec.ts | 106 ++++++++++++++++++ package.json | 2 + .../src/controllers/chat-upload.controller.ts | 6 + 9 files changed, 198 insertions(+), 122 deletions(-) rename e2e/{resolve_python_dependencies.spec.ts => python/resolve_dependencies.spec.ts} (92%) delete mode 100644 e2e/resolve_ts_dependencies.spec.ts rename e2e/{ => shared}/extractor_template.spec.ts (89%) rename e2e/{ => shared}/multiagent_template.spec.ts (96%) rename e2e/{ => shared}/streaming_template.spec.ts (97%) create mode 100644 e2e/typescript/resolve_dependencies.spec.ts diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 332b025b..d99890a6 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -9,8 +9,75 @@ env: POETRY_VERSION: "1.6.1" jobs: - e2e: - name: create-llama + e2e-python: + name: python + timeout-minutes: 60 + strategy: + fail-fast: true + matrix: + node-version: [20] + python-version: ["3.11"] + os: [macos-latest, windows-latest, ubuntu-22.04] + frameworks: ["fastapi"] + datasources: ["--no-files", "--example-file"] + defaults: + run: + shell: bash + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Set up python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: ${{ env.POETRY_VERSION }} + + - uses: pnpm/action-setup@v3 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: "pnpm" + + - name: Install dependencies + run: pnpm install + + - name: Install Playwright Browsers + run: pnpm exec playwright install --with-deps + working-directory: . + + - name: Build create-llama + run: pnpm run build + working-directory: . + + - name: Install + run: pnpm run pack-install + working-directory: . + + - name: Run Playwright tests for Python + run: pnpm run e2e:python + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + LLAMA_CLOUD_API_KEY: ${{ secrets.LLAMA_CLOUD_API_KEY }} + FRAMEWORK: ${{ matrix.frameworks }} + DATASOURCE: ${{ matrix.datasources }} + working-directory: . + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report-python + path: ./playwright-report/ + retention-days: 30 + + e2e-typescript: + name: typescript timeout-minutes: 60 strategy: fail-fast: true @@ -18,7 +85,7 @@ jobs: node-version: [18, 20] python-version: ["3.11"] os: [macos-latest, windows-latest, ubuntu-22.04] - frameworks: ["nextjs", "express", "fastapi"] + frameworks: ["nextjs", "express"] datasources: ["--no-files", "--example-file"] defaults: run: @@ -60,8 +127,8 @@ jobs: run: pnpm run pack-install working-directory: . - - name: Run Playwright tests - run: pnpm run e2e + - name: Run Playwright tests for TypeScript + run: pnpm run e2e:typescript env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} LLAMA_CLOUD_API_KEY: ${{ secrets.LLAMA_CLOUD_API_KEY }} @@ -72,6 +139,6 @@ jobs: - uses: actions/upload-artifact@v3 if: always() with: - name: playwright-report + name: playwright-report-typescript path: ./playwright-report/ retention-days: 30 diff --git a/e2e/resolve_python_dependencies.spec.ts b/e2e/python/resolve_dependencies.spec.ts similarity index 92% rename from e2e/resolve_python_dependencies.spec.ts rename to e2e/python/resolve_dependencies.spec.ts index b678a107..96864ac0 100644 --- a/e2e/resolve_python_dependencies.spec.ts +++ b/e2e/python/resolve_dependencies.spec.ts @@ -3,8 +3,8 @@ import { exec } from "child_process"; import fs from "fs"; import path from "path"; import util from "util"; -import { TemplateFramework, TemplateVectorDB } from "../helpers/types"; -import { createTestDir, runCreateLlama } from "./utils"; +import { TemplateFramework, TemplateVectorDB } from "../../helpers/types"; +import { createTestDir, runCreateLlama } from "../utils"; const execAsync = util.promisify(exec); @@ -16,8 +16,6 @@ const dataSource: string = process.env.DATASOURCE : "--example-file"; if ( - templateFramework == "fastapi" && // test is only relevant for fastapi - process.version.startsWith("v20.") && // XXX: Only run for Node.js version 20 (CI matrix will trigger other versions) dataSource === "--example-file" // XXX: this test provides its own data source - only trigger it on one data source (usually the CI matrix will trigger multiple data sources) ) { // vectorDBs, tools, and data source combinations to test @@ -56,7 +54,7 @@ if ( const result = await runCreateLlama({ cwd, templateType: "streaming", - templateFramework: "fastapi", + templateFramework, dataSource, vectorDb, port: 3000, // port diff --git a/e2e/resolve_ts_dependencies.spec.ts b/e2e/resolve_ts_dependencies.spec.ts deleted file mode 100644 index 7e775303..00000000 --- a/e2e/resolve_ts_dependencies.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { expect, test } from "@playwright/test"; -import { exec } from "child_process"; -import fs from "fs"; -import path from "path"; -import util from "util"; -import { TemplateFramework, TemplateVectorDB } from "../helpers/types"; -import { createTestDir, runCreateLlama } from "./utils"; - -const execAsync = util.promisify(exec); - -const templateFramework: TemplateFramework = process.env.FRAMEWORK - ? (process.env.FRAMEWORK as TemplateFramework) - : "nextjs"; -const dataSource: string = process.env.DATASOURCE - ? process.env.DATASOURCE - : "--example-file"; - -if ( - templateFramework == "nextjs" || - templateFramework == "express" // test is only relevant for TS projects -) { - const llamaParseOptions = [true, false]; - // vectorDBs combinations to test - const vectorDbs: TemplateVectorDB[] = [ - "mongo", - "pg", - "qdrant", - "pinecone", - "milvus", - "astra", - "chroma", - "llamacloud", - "weaviate", - ]; - - test.describe("Test resolve TS dependencies", () => { - for (const llamaParseOpt of llamaParseOptions) { - for (const vectorDb of vectorDbs) { - const optionDescription = `vectorDb: ${vectorDb}, dataSource: ${dataSource}, llamaParse: ${llamaParseOpt}`; - - test(`options: ${optionDescription}`, async () => { - const cwd = await createTestDir(); - - const result = await runCreateLlama({ - cwd: cwd, - templateType: "streaming", - templateFramework: templateFramework, - dataSource: dataSource, - vectorDb: vectorDb, - port: 3000, - externalPort: 8000, - postInstallAction: "none", - templateUI: undefined, - appType: templateFramework === "nextjs" ? "" : "--no-frontend", - llamaCloudProjectName: undefined, - llamaCloudIndexName: undefined, - tools: undefined, - useLlamaParse: llamaParseOpt, - }); - const name = result.projectName; - - // Check if the app folder exists - const appDir = path.join(cwd, name); - const dirExists = fs.existsSync(appDir); - expect(dirExists).toBeTruthy(); - - // Install dependencies using pnpm - try { - const { stderr: installStderr } = await execAsync( - "pnpm install --prefer-offline", - { - cwd: appDir, - }, - ); - expect(installStderr).toBeFalsy(); - } catch (error) { - console.error("Error installing dependencies:", error); - throw error; - } - - // Run tsc type check and capture the output - try { - const { stdout, stderr } = await execAsync( - "pnpm exec tsc -b --diagnostics", - { - cwd: appDir, - }, - ); - // Check if there's any error output - expect(stderr).toBeFalsy(); - - // Log the stdout for debugging purposes - console.log("TypeScript type-check output:", stdout); - } catch (error) { - console.error("Error running tsc:", error); - throw error; - } - }); - } - } - }); -} diff --git a/e2e/extractor_template.spec.ts b/e2e/shared/extractor_template.spec.ts similarity index 89% rename from e2e/extractor_template.spec.ts rename to e2e/shared/extractor_template.spec.ts index 0818e7c7..643fc6dd 100644 --- a/e2e/extractor_template.spec.ts +++ b/e2e/shared/extractor_template.spec.ts @@ -3,8 +3,8 @@ import { expect, test } from "@playwright/test"; import { ChildProcess } from "child_process"; import fs from "fs"; import path from "path"; -import { TemplateFramework } from "../helpers"; -import { createTestDir, runCreateLlama } from "./utils"; +import { TemplateFramework } from "../../helpers"; +import { createTestDir, runCreateLlama } from "../utils"; const templateFramework: TemplateFramework = process.env.FRAMEWORK ? (process.env.FRAMEWORK as TemplateFramework) @@ -16,9 +16,8 @@ const dataSource: string = process.env.DATASOURCE // The extractor template currently only works with FastAPI and files (and not on Windows) if ( process.platform !== "win32" && - templateFramework !== "nextjs" && - templateFramework !== "express" && - dataSource !== "--no-files" + templateFramework === "fastapi" && + dataSource === "--example-file" ) { test.describe("Test extractor template", async () => { let frontendPort: number; diff --git a/e2e/multiagent_template.spec.ts b/e2e/shared/multiagent_template.spec.ts similarity index 96% rename from e2e/multiagent_template.spec.ts rename to e2e/shared/multiagent_template.spec.ts index 061c8a47..d76d320c 100644 --- a/e2e/multiagent_template.spec.ts +++ b/e2e/shared/multiagent_template.spec.ts @@ -7,8 +7,8 @@ import type { TemplateFramework, TemplatePostInstallAction, TemplateUI, -} from "../helpers"; -import { createTestDir, runCreateLlama, type AppType } from "./utils"; +} from "../../helpers"; +import { createTestDir, runCreateLlama, type AppType } from "../utils"; const templateFramework: TemplateFramework = process.env.FRAMEWORK ? (process.env.FRAMEWORK as TemplateFramework) diff --git a/e2e/streaming_template.spec.ts b/e2e/shared/streaming_template.spec.ts similarity index 97% rename from e2e/streaming_template.spec.ts rename to e2e/shared/streaming_template.spec.ts index 53eb2318..74c7eb4e 100644 --- a/e2e/streaming_template.spec.ts +++ b/e2e/shared/streaming_template.spec.ts @@ -7,8 +7,8 @@ import type { TemplateFramework, TemplatePostInstallAction, TemplateUI, -} from "../helpers"; -import { createTestDir, runCreateLlama, type AppType } from "./utils"; +} from "../../helpers"; +import { createTestDir, runCreateLlama, type AppType } from "../utils"; const templateFramework: TemplateFramework = process.env.FRAMEWORK ? (process.env.FRAMEWORK as TemplateFramework) diff --git a/e2e/typescript/resolve_dependencies.spec.ts b/e2e/typescript/resolve_dependencies.spec.ts new file mode 100644 index 00000000..9ae8aa7a --- /dev/null +++ b/e2e/typescript/resolve_dependencies.spec.ts @@ -0,0 +1,106 @@ +import { expect, test } from "@playwright/test"; +import { exec } from "child_process"; +import fs from "fs"; +import path from "path"; +import util from "util"; +import { TemplateFramework, TemplateVectorDB } from "../../helpers/types"; +import { createTestDir, runCreateLlama } from "../utils"; + +const execAsync = util.promisify(exec); + +const templateFramework: TemplateFramework = process.env.FRAMEWORK + ? (process.env.FRAMEWORK as TemplateFramework) + : "nextjs"; +const dataSource: string = process.env.DATASOURCE + ? process.env.DATASOURCE + : "--example-file"; + +// vectorDBs combinations to test +const vectorDbs: TemplateVectorDB[] = [ + "mongo", + "pg", + "qdrant", + "pinecone", + "milvus", + "astra", + "chroma", + "llamacloud", + "weaviate", +]; + +test.describe("Test resolve TS dependencies", () => { + // Test vector DBs without LlamaParse + for (const vectorDb of vectorDbs) { + const optionDescription = `vectorDb: ${vectorDb}, dataSource: ${dataSource}`; + + test(`Vector DB test - ${optionDescription}`, async () => { + await runTest(vectorDb, false); + }); + } + + // Test LlamaParse with vectorDB 'none' + test(`LlamaParse test - vectorDb: none, dataSource: ${dataSource}, llamaParse: true`, async () => { + await runTest("none", true); + }); + + async function runTest( + vectorDb: TemplateVectorDB | "none", + useLlamaParse: boolean, + ) { + const cwd = await createTestDir(); + + const result = await runCreateLlama({ + cwd: cwd, + templateType: "streaming", + templateFramework: templateFramework, + dataSource: dataSource, + vectorDb: vectorDb, + port: 3000, + externalPort: 8000, + postInstallAction: "none", + templateUI: undefined, + appType: templateFramework === "nextjs" ? "" : "--no-frontend", + llamaCloudProjectName: undefined, + llamaCloudIndexName: undefined, + tools: undefined, + useLlamaParse: useLlamaParse, + }); + const name = result.projectName; + + // Check if the app folder exists + const appDir = path.join(cwd, name); + const dirExists = fs.existsSync(appDir); + expect(dirExists).toBeTruthy(); + + // Install dependencies using pnpm + try { + const { stderr: installStderr } = await execAsync( + "pnpm install --prefer-offline", + { + cwd: appDir, + }, + ); + } catch (error) { + console.error("Error installing dependencies:", error); + throw error; + } + + // Run tsc type check and capture the output + try { + const { stdout, stderr } = await execAsync( + "pnpm exec tsc -b --diagnostics", + { + cwd: appDir, + }, + ); + // Check if there's any error output + expect(stderr).toBeFalsy(); + + // Log the stdout for debugging purposes + console.log("TypeScript type-check output:", stdout); + } catch (error) { + console.error("Error running tsc:", error); + throw error; + } + } +}); diff --git a/package.json b/package.json index 7491f095..3a98d6f8 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "clean": "rimraf --glob ./dist ./templates/**/__pycache__ ./templates/**/node_modules ./templates/**/poetry.lock", "dev": "ncc build ./index.ts -w -o dist/", "e2e": "playwright test", + "e2e:python": "playwright test e2e/shared e2e/python", + "e2e:typescript": "playwright test e2e/shared e2e/typescript", "format": "prettier --ignore-unknown --cache --check .", "format:write": "prettier --ignore-unknown --write .", "lint": "eslint . --ignore-pattern dist --ignore-pattern e2e/cache", diff --git a/templates/types/streaming/express/src/controllers/chat-upload.controller.ts b/templates/types/streaming/express/src/controllers/chat-upload.controller.ts index 0bd5b431..70dfa2fe 100644 --- a/templates/types/streaming/express/src/controllers/chat-upload.controller.ts +++ b/templates/types/streaming/express/src/controllers/chat-upload.controller.ts @@ -14,5 +14,11 @@ export const chatUpload = async (req: Request, res: Response) => { }); } const index = await getDataSource(params); + if (!index) { + return res.status(500).json({ + error: + "StorageContext is empty - call 'npm run generate' to generate the storage first", + }); + } return res.status(200).json(await uploadDocument(index, filename, base64)); }; -- GitLab