Skip to content

Commit

Permalink
TestCasesforGet & POST and DELETE for ticket
Browse files Browse the repository at this point in the history
  • Loading branch information
EthM370 committed Dec 20, 2024
1 parent 079d4ff commit 8000c22
Show file tree
Hide file tree
Showing 3 changed files with 275 additions and 23 deletions.
142 changes: 119 additions & 23 deletions src/routes/paidEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import {
QueryCommand,
ScanCommand,
ConditionalCheckFailedException,
PutItemCommand,
DeleteItemCommand,
} from "@aws-sdk/client-dynamodb";
import { genericConfig } from "../config.js";
import { unmarshall } from "@aws-sdk/util-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
import { DatabaseFetchError } from "../errors/index.js";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { AppRoles } from "../roles.js";

const dynamoclient = new DynamoDBClient({
region: genericConfig.AwsRegion,
Expand All @@ -28,22 +31,28 @@ type EventUpdateRequest = {
Body: { attribute: string; value: string };
};

/*const updateJsonSchema = zodToJsonSchema(
z.object({
event_id: z.number(),
event_name: z.string(),
eventCost: z.record(z.number()),
eventDetails: z.optional(z.string()),
eventImage: z.optional(z.string()),
eventProps: z.record(z.string(), z.string()),
event_capacity: z.number(),
event_sales_active_utc: z.string(),
event_time: z.number(),
member_price: z.optional(z.string()),
nonmember_price: z.optional(z.string()),
tickets_sold: z.number()
})
)*/
type EventDeleteRequest = {
Params: { id: string };
Querystring: undefined;
Body: undefined;
};

export const postTicketSchema = z.object({
event_id: z.string(),
event_name: z.string(),
eventCost: z.record(z.number()),
eventDetails: z.optional(z.string()),
eventImage: z.optional(z.string()),
eventProps: z.optional(z.record(z.string(), z.string())),
event_capacity: z.number(),
event_sales_active_utc: z.string(),
event_time: z.number(),
member_price: z.optional(z.string()),
nonmember_price: z.optional(z.string()),
tickets_sold: z.number(),
});

type TicketPostSchema = z.infer<typeof postTicketSchema>;

const responseJsonSchema = zodToJsonSchema(
z.object({
Expand Down Expand Up @@ -214,20 +223,18 @@ const paidEventsPlugin: FastifyPluginAsync = async (fastify, _options) => {
});
} catch (e: unknown) {
if (e instanceof Error) {
request.log.error("Failed to get from DynamoDB: " + e.toString());
request.log.error("Failed to update to DynamoDB: " + e.toString());
}
if (e instanceof ConditionalCheckFailedException) {
request.log.error("Attribute does not exist");
}
throw new DatabaseFetchError({
message: "Failed to get event from Dynamo table.",
message: "Failed to update event in Dynamo table.",
});
}
},
);

//Multiple attribute udpates...

fastify.put<EventUpdateRequest>(
"/merchEvents/:id",
{
Expand Down Expand Up @@ -274,13 +281,102 @@ const paidEventsPlugin: FastifyPluginAsync = async (fastify, _options) => {
});
} catch (e: unknown) {
if (e instanceof Error) {
request.log.error("Failed to get from DynamoDB: " + e.toString());
request.log.error("Failed to update to DynamoDB: " + e.toString());
}
if (e instanceof ConditionalCheckFailedException) {
request.log.error("Attribute does not exist");
}
throw new DatabaseFetchError({
message: "Failed to get event from Dynamo table.",
message: "Failed to update event in Dynamo table.",
});
}
},
);

fastify.post<{ Body: TicketPostSchema }>(
"/ticketEvents",
{
schema: {
response: { 200: responseJsonSchema },
},
preValidation: async (request, reply) => {
await fastify.zodValidateBody(request, reply, postTicketSchema);
},
/*onRequest: async (request, reply) => {
await fastify.authorize(request, reply, [AppRoles.EVENTS_MANAGER]);
},*/ //validation taken off
},
async (request: FastifyRequest<{ Body: TicketPostSchema }>, reply) => {
const id = request.body.event_id;
try {
//Verify if event_id already exists
const response = await dynamoclient.send(
new QueryCommand({
TableName: genericConfig.TicketMetadataTableName,
KeyConditionExpression: "event_id = :id",
ExpressionAttributeValues: {
":id": { S: id },
},
}),
);
if (response.Items?.length != 0) {
throw new Error("Event_id already exists");
}
const entry = {
...request.body,
};
await dynamoclient.send(
new PutItemCommand({
TableName: genericConfig.TicketMetadataTableName,
Item: marshall(entry),
}),
);
reply.send({
id: id,
resource: `/api/v1/paidEvents/ticketEvents/${id}`,
});
} catch (e: unknown) {
if (e instanceof Error) {
request.log.error("Failed to post to DynamoDB: " + e.toString());
}
throw new DatabaseFetchError({
message: "Failed to post event to Dynamo table.",
});
}
},
);

fastify.delete<EventDeleteRequest>(
"/ticketEvents/:id",
{
schema: {
response: { 200: responseJsonSchema },
},
onRequest: async (request, reply) => {
await fastify.authorize(request, reply, [AppRoles.EVENTS_MANAGER]);
}, //auth
},
async (request: FastifyRequest<EventDeleteRequest>, reply) => {
const id = request.params.id;
try {
await dynamoclient.send(
new DeleteItemCommand({
TableName: genericConfig.TicketMetadataTableName,
Key: {
event_id: { S: id },
},
}),
);
reply.send({
id: id,
resource: `/api/v1/paidEvents/ticketEvents/${id}`,
});
} catch (e: unknown) {
if (e instanceof Error) {
request.log.error("Failed to delete from DynamoDB: " + e.toString());
}
throw new DatabaseFetchError({
message: "Failed to delete event from Dynamo table.",
});
}
},
Expand Down
77 changes: 77 additions & 0 deletions tests/unit/mockPaidEventData.testdata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { unmarshall } from "@aws-sdk/util-dynamodb";

const dynamoTableData = [
{
event_id: {
S: "test_barcrawl",
},
eventCost: {
M: {
others: {
N: "100",
},
paid: {
N: "0",
},
},
},
eventDetails: {
S: "Join ACM",
},
eventImage: {
S: "img/test.png",
},
eventProps: {
M: {
end: {
N: "",
},
host: {
S: "",
},
location: {
S: "",
},
},
},
event_capacity: {
N: "130",
},
event_name: {
S: "ACM Fall 2023 Bar Crawl",
},
event_sales_active_utc: {
N: "0",
},
event_time: {
N: "1699578000",
},
member_price: {
S: "price_1O6zHhDiGOXU9RuSvlrcIfOv",
},
nonmember_price: {
S: "price_1O6zHhDiGOXU9RuSvlrcIfOv",
},
tickets_sold: {
N: "0",
},
},
];

const dynamoTableDataUnmarshalled = dynamoTableData.map((x: any) => {
const temp = unmarshall(x);
return temp;
});

const dynamoTableDataUnmarshalledUpcomingOnly = dynamoTableData
.map((x: any) => {
const temp = unmarshall(x);
return temp;
})
.filter((x: any) => x.title != "Event in the past.");

export {
dynamoTableData,
dynamoTableDataUnmarshalled,
dynamoTableDataUnmarshalledUpcomingOnly,
};
79 changes: 79 additions & 0 deletions tests/unit/paidEvents.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { afterAll, expect, test, beforeEach, vi } from "vitest";
import {
ScanCommand,
DynamoDBClient,
QueryCommand,
} from "@aws-sdk/client-dynamodb";
import { mockClient } from "aws-sdk-client-mock";
import init from "../../src/index.js";
import {
dynamoTableData,
dynamoTableDataUnmarshalled,
} from "./mockPaidEventData.testdata.js";
import { secretObject } from "./secret.testdata.js";

const ddbMock = mockClient(DynamoDBClient);
const jwt_secret = secretObject["jwt_key"];
vi.stubEnv("JwtSigningKey", jwt_secret);

const app = await init();
test("Test paidEvents up", async () => {
const response = await app.inject({
method: "GET",
url: "/api/v1/paidEvents",
});
expect(response.statusCode).toBe(200);
const responseDataJson = await response.json();
expect(responseDataJson).toEqual({ Status: "Up" });
});

test("Test paidEvents get ticketEvents", async () => {
ddbMock.on(ScanCommand).resolves({
Items: dynamoTableData as any,
});
const response = await app.inject({
method: "GET",
url: "/api/v1/paidEvents/ticketEvents",
});
expect(response.statusCode).toBe(200);
const responseDataJson = await response.json();
expect(responseDataJson).toEqual(dynamoTableDataUnmarshalled);
});

test("Test paidEvents get ticketEvents by id", async () => {
ddbMock.on(QueryCommand).resolves({
Items: dynamoTableData as any,
});
const response = await app.inject({
method: "GET",
url: "/api/v1/paidEvents/ticketEvents/test_barcrawl",
});
expect(response.statusCode).toBe(200);
const responseDataJson = await response.json();
expect(responseDataJson).toEqual(dynamoTableDataUnmarshalled[0]); //[0] since unmarshalled gives an array
});

test("Test dynamodb error handling", async () => {
ddbMock.onAnyCommand().rejects("Nope");
const response = await app.inject({
method: "GET",
url: "/api/v1/paidEvents/ticketEvents",
});
expect(response.statusCode).toBe(500);
const responseDataJson = await response.json();
expect(responseDataJson).toEqual({
error: true,
name: "DatabaseFetchError",
id: 106,
message: "Failed to get events from Dynamo table.",
});
});

afterAll(async () => {
await app.close();
vi.useRealTimers();
});
beforeEach(() => {
ddbMock.reset();
vi.useFakeTimers();
});

0 comments on commit 8000c22

Please sign in to comment.