import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; import { InMemoryParkingRepository, PARKING_LOGGING_INTERVAL_MS, ParkingStructureID } from "../../src/repositories/InMemoryParkingRepository"; import { IParkingStructure, IParkingStructureTimestampRecord } from "../../src/entities/ParkingRepositoryEntities"; import { CircularQueue } from "../../src/types/CircularQueue"; import { ParkingStructureCountOptions } from "../../src/repositories/ParkingGetterRepository"; import { ParkingGetterSetterRepository } from "../../src/repositories/ParkingGetterSetterRepository"; import { RedisParkingRepository } from "../../src/repositories/RedisParkingRepository"; interface RepositoryHolder { name: string; factory(): Promise; teardown(): Promise; } class InMemoryParkingRepositoryHolder implements RepositoryHolder { name = 'InMemoryParkingRepository'; factory = async () => { return new InMemoryParkingRepository(); }; teardown = async () => {}; } class RedisParkingRepositoryHolder implements RepositoryHolder { repo: RedisParkingRepository | undefined; name = 'RedisParkingRepository'; factory = async () => { this.repo = new RedisParkingRepository(); await this.repo.connect(); return this.repo; }; teardown = async () => { if (this.repo) { await this.repo.clearAllData(); await this.repo.disconnect(); } }; } const repositoryImplementations = [ // new InMemoryParkingRepositoryHolder(), new RedisParkingRepositoryHolder(), ]; describe.each(repositoryImplementations)('$name', (holder) => { let repository: ParkingGetterSetterRepository; const testStructure: IParkingStructure = { coordinates: { latitude: 33.794795, longitude: -117.850807, }, spotsAvailable: 0, id: "1", name: "Anderson Parking Structure", capacity: 100, address: "300 E Walnut Ave, Orange, CA 92867", updatedTime: new Date(), }; beforeEach(async () => { repository = await holder.factory(); jest.useRealTimers(); }); afterEach(async () => { await holder.teardown(); }); describe("addOrUpdateParkingStructure", () => { it("should add a new parking structure", async () => { await repository.addOrUpdateParkingStructure(testStructure); const result = await repository.getParkingStructureById(testStructure.id); expect(result).toEqual(testStructure); }); it("should update existing parking structure", async () => { await repository.addOrUpdateParkingStructure(testStructure); const updatedStructure = { ...testStructure, name: "Updated Garage" }; await repository.addOrUpdateParkingStructure(updatedStructure); const result = await repository.getParkingStructureById(testStructure.id); expect(result).toEqual(updatedStructure); }); }); describe("removeParkingStructureIfExists", () => { it("should remove existing parking structure and return it", async () => { await repository.addOrUpdateParkingStructure(testStructure); const removed = await repository.removeParkingStructureIfExists(testStructure.id); expect(removed).toEqual(testStructure); const result = await repository.getParkingStructureById(testStructure.id); expect(result).toBeNull(); }); it("should return null when removing non-existent structure", async () => { const result = await repository.removeParkingStructureIfExists("non-existent"); expect(result).toBeNull(); }); }); describe("clearParkingStructureData", () => { it("should remove all parking structures", async () => { const structures = [ testStructure, { ...testStructure, id: "test-id-2", name: "Second Garage" } ]; for (const structure of structures) { await repository.addOrUpdateParkingStructure(structure); } await repository.clearParkingStructureData(); const result = await repository.getParkingStructures(); expect(result).toHaveLength(0); }); }); describe("getParkingStructures", () => { it("should return empty array when no structures exist", async () => { const result = await repository.getParkingStructures(); expect(result).toEqual([]); }); it("should return all added structures", async () => { const structures = [ testStructure, { ...testStructure, id: "test-id-2", name: "Second Garage" } ]; for (const structure of structures) { await repository.addOrUpdateParkingStructure(structure); } const result = await repository.getParkingStructures(); expect(result).toHaveLength(2); expect(result).toEqual(expect.arrayContaining(structures)); }); }); describe("getParkingStructureById", () => { it("should return null for non-existent structure", async () => { const result = await repository.getParkingStructureById("non-existent"); expect(result).toBeNull(); }); it("should return structure by id", async () => { await repository.addOrUpdateParkingStructure(testStructure); const result = await repository.getParkingStructureById(testStructure.id); expect(result).toEqual(testStructure); }); }); describe("getHistoricalAveragesOfParkingStructureCounts", () => { it("should return empty array for non-existent structure or no data", async () => { const options: ParkingStructureCountOptions = { startUnixEpochMs: 1000, endUnixEpochMs: 2000, intervalMs: 500 }; // Non-existent structure expect(await repository.getHistoricalAveragesOfParkingStructureCounts("non-existent", options)).toEqual([]); // Structure with no historical data await repository.addOrUpdateParkingStructure(testStructure); expect(await repository.getHistoricalAveragesOfParkingStructureCounts(testStructure.id, options)).toEqual([]); }); // it("should calculate averages for intervals with manual historical data", async () => { // await repository.addOrUpdateParkingStructure(testStructure); // // const now = Date.now(); // jest.useFakeTimers().setSystemTime(now); // // const updates = [ // { ...testStructure, spotsAvailable: 80, updatedTime: new Date(now + 1000) }, // { ...testStructure, spotsAvailable: 70, updatedTime: new Date(now + 2000) }, // ]; // // for (let i = 0; i < updates.length; i++) { // jest.setSystemTime(now + (i + 1) * PARKING_LOGGING_INTERVAL_MS + 100); // await repository.addOrUpdateParkingStructure(updates[i]); // } // // const options: ParkingStructureCountOptions = { // startUnixEpochMs: now, // endUnixEpochMs: now + 4000000, // Large range to capture all data // intervalMs: 1000000 // }; // // const result = await repository.getHistoricalAveragesOfParkingStructureCounts(testStructure.id, options); // // // Should have at least some historical data // expect(result.length).toBeGreaterThan(0); // if (result.length > 0) { // expect(result[0]).toHaveProperty('fromUnixEpochMs'); // expect(result[0]).toHaveProperty('toUnixEpochMs'); // expect(result[0]).toHaveProperty('averageSpotsAvailable'); // expect(typeof result[0].averageSpotsAvailable).toBe('number'); // } // }); }); });