mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-06-27 16:10:30 +08:00
Merge pull request #342 from jack-michaud/jm/contract-tests-for-website
refactor + test: add OasstApiClient in website with tests
This commit is contained in:
@@ -15,6 +15,9 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- run: cd oasst-shared && pip install -e .
|
||||
|
||||
@@ -22,9 +25,14 @@ jobs:
|
||||
|
||||
- run: cd backend && pip install -r requirements.txt
|
||||
|
||||
- run: cd website && npm install
|
||||
|
||||
- run: ./scripts/backend-development/start-mock-server.sh
|
||||
|
||||
- name: Run contract tests
|
||||
- name: Run Python OasstApiClient contract tests
|
||||
run: ./scripts/oasst-shared-development/test.sh
|
||||
|
||||
- name: Run JavaScript OasstApiClient contract tests
|
||||
run: ./scripts/frontend-development/run-contract-test.sh
|
||||
|
||||
- run: ./scripts/backend-development/stop-mock-server.sh
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||
|
||||
# switch to website directory
|
||||
pushd "$parent_path/../../website"
|
||||
|
||||
set -xe
|
||||
|
||||
npm run cypress:run:contract
|
||||
|
||||
popd
|
||||
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
// No baseUrl here, because we don't need it for contract testing
|
||||
baseUrl: null,
|
||||
specPattern: "cypress/contract/*.cy.{ts,js}",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import OasstApiClient from "src/lib/oasst_api_client";
|
||||
|
||||
describe("Contract test for Oasst API", function () {
|
||||
// Assumes this is running the mock server.
|
||||
const oasstApiClient = new OasstApiClient("http://localhost:8080", "test");
|
||||
|
||||
it("can fetch a task", async () => {
|
||||
expect(
|
||||
await oasstApiClient.fetchTask("random", {
|
||||
sub: "test",
|
||||
name: "test",
|
||||
email: "test",
|
||||
})
|
||||
).to.be.not.null;
|
||||
});
|
||||
|
||||
it("can ack a task", async () => {
|
||||
const task = await oasstApiClient.fetchTask("random", {
|
||||
sub: "test",
|
||||
name: "test",
|
||||
email: "test",
|
||||
});
|
||||
expect(await oasstApiClient.ackTask(task.id, "321")).to.be.null;
|
||||
});
|
||||
|
||||
// TODO(#354): Add test for 204
|
||||
// TODO(#354): Add test for parsing >=300, throwing an OasstError
|
||||
// TODO(#354): Add test for parsing >=300, throwing a generic error
|
||||
});
|
||||
@@ -12,6 +12,7 @@
|
||||
"build-storybook": "build-storybook",
|
||||
"cypress": "cypress open",
|
||||
"cypress:run": "cypress run",
|
||||
"cypress:run:contract": "cypress run --config-file ./cypress.config.contract.js",
|
||||
"cypress:image-baseline": "cypress-image-diff -u",
|
||||
"fix:lint": "eslint --fix src/ --ext .js,.jsx,.ts,.tsx",
|
||||
"fix:format": "prettier --write ./src",
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { JWT } from "next-auth/jwt";
|
||||
|
||||
class OasstError {
|
||||
message: string;
|
||||
errorCode: number;
|
||||
httpStatusCode: number;
|
||||
|
||||
constructor(message: string, errorCode: number, httpStatusCode: number) {
|
||||
this.message = message;
|
||||
this.errorCode = errorCode;
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
}
|
||||
}
|
||||
|
||||
export default class OasstApiClient {
|
||||
constructor(private readonly oasstApiUrl: string, private readonly oasstApiKey: string) {}
|
||||
|
||||
private async post(path: string, body: any): Promise<any> {
|
||||
const resp = await fetch(`${this.oasstApiUrl}${path}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-API-Key": this.oasstApiKey,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (resp.status == 204) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (resp.status >= 300) {
|
||||
const errorText = await resp.text();
|
||||
try {
|
||||
const error = JSON.parse(errorText);
|
||||
throw new OasstError(error.message, error.error_code, resp.status);
|
||||
} catch (e) {
|
||||
throw new OasstError(errorText, 0, resp.status);
|
||||
}
|
||||
}
|
||||
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
// TODO return a strongly typed Task?
|
||||
// This method is used to store a task in RegisteredTask.task.
|
||||
// This is a raw Json type, so we can't use it to strongly type the task.
|
||||
async fetchTask(taskType: string, userToken: JWT): Promise<any> {
|
||||
return this.post("/api/v1/tasks/", {
|
||||
type: taskType,
|
||||
user: {
|
||||
id: userToken.sub,
|
||||
display_name: userToken.name || userToken.email,
|
||||
auth_method: "local",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async ackTask(taskId: string, messageId: string): Promise<void> {
|
||||
return this.post(`/api/v1/tasks/${taskId}/ack`, {
|
||||
message_id: messageId,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getToken } from "next-auth/jwt";
|
||||
import OasstApiClient from "src/lib/oasst_api_client";
|
||||
import prisma from "src/lib/prismadb";
|
||||
|
||||
/**
|
||||
@@ -20,25 +21,10 @@ const handler = async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const oasstApiClient = new OasstApiClient(process.env.FASTAPI_URL, process.env.FASTAPI_KEY);
|
||||
|
||||
// Fetch the new task.
|
||||
//
|
||||
// This needs to be refactored into an easier to use library.
|
||||
const taskRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/tasks/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: task_type,
|
||||
user: {
|
||||
id: token.sub,
|
||||
display_name: token.name || token.email,
|
||||
auth_method: "local",
|
||||
},
|
||||
}),
|
||||
});
|
||||
const task = await taskRes.json();
|
||||
const task = await oasstApiClient.fetchTask(task_type, token);
|
||||
|
||||
// Store the task and link it to the user..
|
||||
const registeredTask = await prisma.registeredTask.create({
|
||||
@@ -53,16 +39,7 @@ const handler = async (req, res) => {
|
||||
});
|
||||
|
||||
// Update the backend with our Task ID
|
||||
await fetch(`${process.env.FASTAPI_URL}/api/v1/tasks/${task.id}/ack`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message_id: registeredTask.id,
|
||||
}),
|
||||
});
|
||||
await oasstApiClient.ackTask(task.id, registeredTask.id);
|
||||
|
||||
// Send the results to the client.
|
||||
res.status(200).json(registeredTask);
|
||||
|
||||
@@ -36,6 +36,7 @@ const handler = async (req, res) => {
|
||||
|
||||
// Send the interaction to the Task Backend. This automatically fetches the
|
||||
// next task in the sequence (or the done task).
|
||||
// TODO(#353): Move this into OasstApiClient.
|
||||
const interactionRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/tasks/interaction`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
||||
Reference in New Issue
Block a user