Skip to content

Commit

Permalink
Merge pull request #75 from AbdulrhmanGoni/tests/huggingface-service-…
Browse files Browse the repository at this point in the history
…related-tests

Write some huggingface service related tests and refactor some files
  • Loading branch information
AbdulrhmanGoni authored Nov 4, 2024
2 parents 85dd804 + c6f8385 commit 4ee1da3
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 11 deletions.
3 changes: 2 additions & 1 deletion src/constants/operationsResultsMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ const operationsResultsMessages = {
"Your huggingface account was created successfully",
failedHuggingfaceAccountCreation: "Failed to create Your huggingface account",
failedHuggingfaceOAuthProcess:
"Huggingface OAuth callback failed to complate",
"Huggingface OAuth callback failed to complete",
noHuggingfaceAccount: "You don't have a linked huggingface account",
successullyDatasetUpload:
"The dataset has been uploaded to the repository successfully",
noLinkedDatasetRepository: "The dataset has no linked huggingface repository",
successfulDatasetSyncWithRepository:
"The Dataset has been synced with the repository successfully",
failedAccessTokenRefreshing: "Failed to refresh user's Huggingface access token"
};

export default operationsResultsMessages;
5 changes: 4 additions & 1 deletion src/middlewares/createDatasetRepositoryInputValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ const datasetRepositorySchema = validationSchema<CreateDatasetRepositoryInput>({

export default function createDatasetRepositoryInputValidator(request: Req) {
try {
request.json = datasetRepositorySchema.validate(request.json);
request.json = datasetRepositorySchema.validate({
name: request.json.name,
license: request.json.license
});
} catch (e: any) {
const validationErrors = e.errors as ValidationError["errors"];
return ErrorResponse({ validationErrors }, 403);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { CreateDatasetRepositoryInput } from "../../types/huggingface";
export default async function createDatasetRepository_service(
this: HuggingfaceService,
userId: string,
{ name, license = "mit" }: CreateDatasetRepositoryInput
{ name, license }: CreateDatasetRepositoryInput
) {
const {
isSuccess,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import DatasetsModel from "../../models/DatasetsModel";
import ServiceOperationResult from "../../utilities/ServiceOperationResult";
import { refreshAccessToken } from "./huggingFaceOAuthTokenRequests";
import operationsResultsMessages from "../../constants/operationsResultsMessages";

export default async function refreshHuggingfaceAccessToken_service(
userId: string,
Expand Down Expand Up @@ -34,6 +35,6 @@ export default async function refreshHuggingfaceAccessToken_service(
}

return ServiceOperationResult.failure(
"Failed to refresh user's Huggingface access token"
operationsResultsMessages.failedAccessTokenRefreshing
);
}
41 changes: 41 additions & 0 deletions tests/e2e/huggingface/createDatasetRepository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { expect, describe, it, afterAll, mock } from "bun:test";
import DatasetsModel from "../../../src/models/DatasetsModel";
import { fakeUserHuggingfaceAccount } from "../../fake-data/fakeUserHuggingfaceAccount";
import { request } from "../..";

const exampleDotCom = "https://example.com"

mock.module("@huggingface/hub", () => {
return {
createRepo: async () => ({
repoUrl: exampleDotCom
}),
};
});

const path = "huggingface/datasets";

describe(`POST /${path}`, () => {
it("Should complete creating huggingface dataset repository process successfully", async () => {
await DatasetsModel.create({
_id: process.env.TESTING_USER_ID,
huggingfaceAccount: fakeUserHuggingfaceAccount,
datasets: []
})

const { resBody, status } = await request.POST(path, {
name: "username",
license: "mit"
})

expect(status).toBe(200)
expect(resBody.data).toMatchObject({
repoUrl: exampleDotCom
})
});
});

afterAll(async () => {
mock.restore()
await DatasetsModel.deleteMany();
});
8 changes: 8 additions & 0 deletions tests/fake-data/fakeUserHuggingfaceAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const fakeUserHuggingfaceAccount = {
accessToken: "anyaccessToken",
accessTokenExpiresIn: new Date().getTime() + 946334,
refreshToken: "anyrefreshToken",
username: "anyname",
emailVerified: true,
}

54 changes: 54 additions & 0 deletions tests/integration/huggingface/createHuggingfaceAccount.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { describe, expect, it, afterAll, beforeAll, mock } from "bun:test";
import operationsResultsMessages from "../../../src/constants/operationsResultsMessages";
import DatasetsModel from "../../../src/models/DatasetsModel";
import databaseConnection from "../../../src/configurations/databaseConnection";
import huggingfaceService from "../../../src/services/huggingface";

mock.module("@huggingface/hub", () => {
return {
whoAmI: async () => ({
name: "username",
emailVerified: true
}),
};
});

beforeAll(async () => {
await databaseConnection();
});

describe("Test `createHuggingfaceAccount` service method", () => {

const userHuggingfaceAccountCredentials = {
accessTokenExpiresIn: 57478, // in seconds
hfAccessToken: "n@!*&edVryme573@55n",
hfRefreshToken: "kjbgv&B^#65jbN(*Y#@1hj"
}

it("Should fail to create the huggingface account for the user because the user is not existant", async () => {
const result = await huggingfaceService.createHuggingfaceAccount(
process.env.TESTING_USER_ID,
userHuggingfaceAccountCredentials
);

expect(result.isSuccess).toBeFalse();
expect(result.message).toBe(operationsResultsMessages.failedHuggingfaceAccountCreation);
});

it("Should create the huggingface account for the user", async () => {
await DatasetsModel.create({ _id: process.env.TESTING_USER_ID })

const result = await huggingfaceService.createHuggingfaceAccount(
process.env.TESTING_USER_ID,
userHuggingfaceAccountCredentials
);

expect(result.isSuccess).toBeTrue();
expect(result.result).toBe(operationsResultsMessages.successfulHuggingfaceAccountCreation);
});
});

afterAll(async () => {
mock.restore()
await DatasetsModel.deleteMany();
});
45 changes: 45 additions & 0 deletions tests/integration/huggingface/getHuggingfaceAccount.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, it, afterAll, beforeAll } from "bun:test";
import operationsResultsMessages from "../../../src/constants/operationsResultsMessages";
import DatasetsModel from "../../../src/models/DatasetsModel";
import databaseConnection from "../../../src/configurations/databaseConnection";
import huggingfaceService from "../../../src/services/huggingface";
import { fakeUserHuggingfaceAccount } from "../../fake-data/fakeUserHuggingfaceAccount";

beforeAll(async () => {
await databaseConnection();
});

describe("Test `getHuggingfaceAccount` service method", () => {
it("Should not return user's huggingface account because it is not existant", async () => {
const result = await huggingfaceService.getHuggingfaceAccount(
process.env.TESTING_USER_ID
);

expect(result.isSuccess).toBeTrue();
expect(result.message).toBe(operationsResultsMessages.noHuggingfaceAccount);
});

it("Should return user's huggingface account successfully", async () => {
await DatasetsModel.create({
_id: process.env.TESTING_USER_ID,
huggingfaceAccount: fakeUserHuggingfaceAccount
})

const result = await huggingfaceService.getHuggingfaceAccount(
process.env.TESTING_USER_ID
);

expect(result.isSuccess).toBeTrue();
expect(result.result).toMatchObject({
accessToken: fakeUserHuggingfaceAccount.accessToken,
accessTokenExpiresIn: expect.any(Date),
refreshToken: fakeUserHuggingfaceAccount.refreshToken,
username: fakeUserHuggingfaceAccount.username,
emailVerified: fakeUserHuggingfaceAccount.emailVerified,
});
});
});

afterAll(async () => {
await DatasetsModel.deleteMany();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { describe, expect, it, afterAll, beforeAll, mock } from "bun:test";
import databaseConnection from "../../../src/configurations/databaseConnection";
import huggingfaceService from "../../../src/services/huggingface";
import DatasetsModel from "../../../src/models/DatasetsModel";
import operationsResultsMessages from "../../../src/constants/operationsResultsMessages";
import { fakeUserHuggingfaceAccount } from "../../fake-data/fakeUserHuggingfaceAccount";

beforeAll(async () => {
await databaseConnection();
});

const originalFetch = global.fetch

describe("Test `refreshHuggingfaceAccessToken` service method", () => {
it('Should complete refreshing access token process successfully', async () => {
const mockFetch = mock(async () => {
const payload = {
access_token: "-p0__8dso$@pyv94wmm6@#7",
refresh_token: "gj%*dqvp082_+9-ym8nmhj",
expires_in: 46346
}
return new Response(JSON.stringify(payload), { status: 200 })
})

global.fetch = mockFetch

await DatasetsModel.create({
_id: process.env.TESTING_USER_ID,
huggingfaceAccount: fakeUserHuggingfaceAccount
})

const result = await huggingfaceService.refreshHuggingfaceAccessToken(
process.env.TESTING_USER_ID,
"f5@*)d#@dSjykgyk*&t84gCk"
);

expect(mockFetch).toHaveBeenCalled()
expect(result.isSuccess).toBeTrue();
expect(result.result).toMatchObject({
accessToken: expect.any(String),
accessTokenExpiresIn: expect.any(Date),
refreshToken: expect.any(String),
username: "anyname",
emailVerified: true,
});
});

it('Should catch and return an error because of failed external API request', async () => {
const mockFetch = mock(async () => {
return new Response("{}", { status: 400 })
})

global.fetch = mockFetch

const result = await huggingfaceService.refreshHuggingfaceAccessToken(
process.env.TESTING_USER_ID,
"f5@*)d#@dSjykgyk*&t84gCk"
);

expect(mockFetch).toHaveBeenCalled()
expect(result.isSuccess).toBeFalse();
expect(result.message).toBe(operationsResultsMessages.failedAccessTokenRefreshing);
});
});

afterAll(async () => {
global.fetch = originalFetch
await DatasetsModel.deleteMany();
});
14 changes: 7 additions & 7 deletions tests/lib/TestingRequest.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { Server } from "bun";

export default class TestingRequest {
constructor(private server: Server) {}
constructor(private server: Server) { }

async returnRespons(res: Response) {
async returnResponse(res: Response) {
return {
resBody: await res.json(),
status: res.status,
};
}

async GET(path: string) {
return fetch(`${this.server.url.origin}/${path}`).then(this.returnRespons);
return fetch(`${this.server.url.origin}/${path}`).then(this.returnResponse);
}

async POST(path: string, body: Record<string, any> | string) {
Expand All @@ -20,7 +20,7 @@ export default class TestingRequest {
method: "POST",
};
return fetch(`${this.server.url.origin}/${path}`, init).then(
this.returnRespons
this.returnResponse
);
}

Expand All @@ -29,7 +29,7 @@ export default class TestingRequest {
method: "DELETE",
};
return fetch(`${this.server.url.origin}/${path}`, init).then(
this.returnRespons
this.returnResponse
);
}

Expand All @@ -39,7 +39,7 @@ export default class TestingRequest {
method: "PATCH",
};
return fetch(`${this.server.url.origin}/${path}`, init).then(
this.returnRespons
this.returnResponse
);
}

Expand All @@ -49,7 +49,7 @@ export default class TestingRequest {
method: "PUT",
};
return fetch(`${this.server.url.origin}/${path}`, init).then(
this.returnRespons
this.returnResponse
);
}
}

0 comments on commit 4ee1da3

Please sign in to comment.