mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-17 07:50:31 +00:00
remove ApiBasedRepository.ts and tests
This commit is contained in:
@@ -2,5 +2,4 @@ import { GetterRepository } from "./repositories/GetterRepository";
|
|||||||
|
|
||||||
export interface ServerContext {
|
export interface ServerContext {
|
||||||
repository: GetterRepository;
|
repository: GetterRepository;
|
||||||
apiBasedRepository: GetterRepository;
|
|
||||||
}
|
}
|
||||||
11
src/index.ts
11
src/index.ts
@@ -2,11 +2,9 @@ import { readFileSync } from "fs";
|
|||||||
import { ApolloServer } from "@apollo/server";
|
import { ApolloServer } from "@apollo/server";
|
||||||
import { startStandaloneServer } from "@apollo/server/standalone";
|
import { startStandaloneServer } from "@apollo/server/standalone";
|
||||||
import { resolvers } from "./resolvers";
|
import { resolvers } from "./resolvers";
|
||||||
import { loadTestData } from "./loaders/loadTestData";
|
|
||||||
import { ServerContext } from "./ServerContext";
|
import { ServerContext } from "./ServerContext";
|
||||||
import { UnoptimizedInMemoryRepository } from "./repositories/UnoptimizedInMemoryRepository";
|
import { UnoptimizedInMemoryRepository } from "./repositories/UnoptimizedInMemoryRepository";
|
||||||
import { RepositoryDataLoader } from "./loaders/RepositoryDataLoader";
|
import { RepositoryDataLoader } from "./loaders/RepositoryDataLoader";
|
||||||
import { ApiBasedRepository } from "./repositories/ApiBasedRepository";
|
|
||||||
|
|
||||||
const typeDefs = readFileSync("./schema.graphqls", "utf8");
|
const typeDefs = readFileSync("./schema.graphqls", "utf8");
|
||||||
|
|
||||||
@@ -25,14 +23,6 @@ async function main() {
|
|||||||
);
|
);
|
||||||
await repositoryDataUpdater.start();
|
await repositoryDataUpdater.start();
|
||||||
|
|
||||||
// TODO: Migrate all logic over to this repository
|
|
||||||
const apiBasedRepository = new ApiBasedRepository();
|
|
||||||
|
|
||||||
const systemIds = ["263"];
|
|
||||||
await Promise.all(systemIds.map(async (systemId) => {
|
|
||||||
await apiBasedRepository.seedCacheForSystemId(systemId);
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { url } = await startStandaloneServer(server, {
|
const { url } = await startStandaloneServer(server, {
|
||||||
listen: {
|
listen: {
|
||||||
port: process.env.PORT ? parseInt(process.env.PORT) : 4000,
|
port: process.env.PORT ? parseInt(process.env.PORT) : 4000,
|
||||||
@@ -40,7 +30,6 @@ async function main() {
|
|||||||
context: async ({ req, res }) => {
|
context: async ({ req, res }) => {
|
||||||
return {
|
return {
|
||||||
repository,
|
repository,
|
||||||
apiBasedRepository,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,387 +0,0 @@
|
|||||||
import { GetterRepository } from "./GetterRepository";
|
|
||||||
import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
|
|
||||||
|
|
||||||
const baseUrl = "https://passiogo.com/mapGetData.php"
|
|
||||||
|
|
||||||
// TODO: implement TTL functionality
|
|
||||||
// TODO: add TTL values to everything
|
|
||||||
// TODO: remove RepositoryDataLoader and UnoptimizedInMemoryRepository
|
|
||||||
// TODO: make milliseconds (TTL) required on everything
|
|
||||||
// TODO: extract cache into its own class
|
|
||||||
|
|
||||||
export interface ApiBasedRepositoryCache {
|
|
||||||
etasForShuttleId?: {
|
|
||||||
[shuttleId: string]: IEta[],
|
|
||||||
},
|
|
||||||
etasForStopId?: {
|
|
||||||
[stopId: string]: IEta[],
|
|
||||||
},
|
|
||||||
stopsBySystemId?: {
|
|
||||||
[systemId: string]: IStop[],
|
|
||||||
},
|
|
||||||
stopByStopId?: {
|
|
||||||
[stopId: string]: IStop,
|
|
||||||
},
|
|
||||||
shuttleByShuttleId?: {
|
|
||||||
[shuttleId: string]: IShuttle,
|
|
||||||
},
|
|
||||||
shuttlesBySystemId?: {
|
|
||||||
[systemId: string]: IShuttle[],
|
|
||||||
},
|
|
||||||
// To speed things up, implement caches for other data later
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ApiBasedRepositoryMillisecondTTLs {
|
|
||||||
etasForShuttleId?: number,
|
|
||||||
etasForStopId?: number,
|
|
||||||
shuttleByShuttleId?: number,
|
|
||||||
shuttlesBySystemId?: number,
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyCache: ApiBasedRepositoryCache = {
|
|
||||||
etasForShuttleId: {},
|
|
||||||
etasForStopId: {},
|
|
||||||
shuttleByShuttleId: {},
|
|
||||||
shuttlesBySystemId: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultTtls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
etasForShuttleId: 10000,
|
|
||||||
etasForStopId: 10000,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ApiBasedRepository implements GetterRepository {
|
|
||||||
private cache: ApiBasedRepositoryCache;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
initialCache: ApiBasedRepositoryCache | undefined = emptyCache,
|
|
||||||
private ttls: ApiBasedRepositoryMillisecondTTLs = defaultTtls,
|
|
||||||
) {
|
|
||||||
this.cache = initialCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Seed the initial data in the cache, so data can be updated
|
|
||||||
* given the correct ID.
|
|
||||||
* Alternatively, pass in an `initialCache` with existing data
|
|
||||||
* (useful for testing).
|
|
||||||
* @param systemId
|
|
||||||
*/
|
|
||||||
public async seedCacheForSystemId(systemId: string): Promise<void> {
|
|
||||||
await this.updateShuttlesForSystemIfTTL(systemId);
|
|
||||||
await this.updateEtasForSystemIfTTL(systemId);
|
|
||||||
await this.updateStopsForSystemIdIfTTL(systemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getEtaForShuttleAndStopId(shuttleId: string, stopId: string): Promise<IEta | null> {
|
|
||||||
const shuttle = await this.getShuttleById(shuttleId);
|
|
||||||
const systemId = shuttle?.systemId;
|
|
||||||
if (!systemId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
await this.updateEtasForSystemIfTTL(systemId);
|
|
||||||
|
|
||||||
if (this.cache?.etasForStopId && this.cache.etasForStopId[stopId]) {
|
|
||||||
const etas = this.cache.etasForStopId[stopId];
|
|
||||||
const foundEta = etas.find((eta) => eta.shuttleId === shuttleId);
|
|
||||||
if (foundEta) {
|
|
||||||
return foundEta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getEtasForShuttleId(shuttleId: string): Promise<IEta[]> {
|
|
||||||
const shuttle = await this.getShuttleById(shuttleId);
|
|
||||||
const systemId = shuttle?.systemId;
|
|
||||||
if (!systemId) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
await this.updateEtasForSystemIfTTL(systemId);
|
|
||||||
|
|
||||||
if (!this.cache?.etasForShuttleId || !this.cache.etasForShuttleId[shuttleId]) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.cache.etasForShuttleId[shuttleId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getEtasForStopId(stopId: string): Promise<IEta[]> {
|
|
||||||
const stop = await this.getStopById(stopId);
|
|
||||||
const systemId = stop?.systemId;
|
|
||||||
if (!systemId) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
await this.updateEtasForSystemIfTTL(systemId);
|
|
||||||
|
|
||||||
if (!this.cache?.etasForStopId || !this.cache.etasForStopId[stopId]) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.cache.etasForStopId[stopId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async updateEtasForSystemIfTTL(systemId: string) {
|
|
||||||
// TODO: check if TTL
|
|
||||||
try {
|
|
||||||
const stops = await this.getStopsBySystemId(systemId);
|
|
||||||
await Promise.all(stops.map(async (stop) => {
|
|
||||||
const params = {
|
|
||||||
eta: "3",
|
|
||||||
stopIds: stop.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
const query = new URLSearchParams(params).toString();
|
|
||||||
const response = await fetch(`${baseUrl}?${query}`, {
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
const json = await response.json();
|
|
||||||
|
|
||||||
if (json.ETAs && json.ETAs[stop.id]) {
|
|
||||||
if (!this.cache.etasForStopId) {
|
|
||||||
this.cache.etasForStopId = {};
|
|
||||||
}
|
|
||||||
this.cache.etasForStopId[stop.id] = [];
|
|
||||||
|
|
||||||
// This is technically incorrect, the entire shuttle cache
|
|
||||||
// should not be reset like this
|
|
||||||
// TODO: restore normal cache behavior
|
|
||||||
this.cache.etasForShuttleId = {};
|
|
||||||
|
|
||||||
// Continue with the parsing
|
|
||||||
json.ETAs[stop.id].forEach((jsonEta: any) => {
|
|
||||||
// Update cache
|
|
||||||
if (!this.cache.etasForStopId) {
|
|
||||||
this.cache.etasForStopId = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.cache.etasForShuttleId) {
|
|
||||||
this.cache.etasForShuttleId = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: create cache abstraction to deal with possibly undefined properties
|
|
||||||
|
|
||||||
const shuttleId: string = jsonEta.busId;
|
|
||||||
if (!this.cache.etasForShuttleId[shuttleId]) {
|
|
||||||
this.cache.etasForShuttleId[shuttleId] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const eta: IEta = {
|
|
||||||
secondsRemaining: jsonEta.secondsSpent,
|
|
||||||
shuttleId: `${shuttleId}`,
|
|
||||||
stopId: stop.id,
|
|
||||||
millisecondsSinceEpoch: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.cache.etasForStopId[stop.id].push(eta);
|
|
||||||
this.cache.etasForShuttleId[shuttleId].push(eta);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: migrate rest of logic over to this class
|
|
||||||
public async getOrderedStopByRouteAndStopId(routeId: string, stopId: string): Promise<| null> {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getOrderedStopsByRouteId(routeId: string): Promise<[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getOrderedStopsByStopId(stopId: string): Promise<[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getRouteById(routeId: string): Promise<| null> {
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getRoutesBySystemId(systemId: string): Promise<[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getShuttleById(shuttleId: string): Promise<IShuttle | null> {
|
|
||||||
if (!this.cache.shuttleByShuttleId) return null;
|
|
||||||
let shuttle = this.cache.shuttleByShuttleId[shuttleId];
|
|
||||||
if (!shuttle) return null;
|
|
||||||
|
|
||||||
// Call getShuttlesBySystemId to update the data if not TTL
|
|
||||||
await this.updateShuttlesForSystemIfTTL(shuttle.systemId);
|
|
||||||
|
|
||||||
shuttle = this.cache.shuttleByShuttleId[shuttleId];
|
|
||||||
if (!shuttle) return null;
|
|
||||||
return shuttle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getShuttlesByRouteId(routeId: string): Promise<[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getShuttlesBySystemId(systemId: string): Promise<IShuttle[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async updateShuttlesForSystemIfTTL(systemId: string) {
|
|
||||||
// TODO: check if TTL
|
|
||||||
try {
|
|
||||||
// TODO: update shuttlesByRouteId
|
|
||||||
// Update shuttleByShuttleId, shuttlesBySystemId
|
|
||||||
const params = {
|
|
||||||
getBuses: "2"
|
|
||||||
};
|
|
||||||
|
|
||||||
const formDataJsonObject = {
|
|
||||||
"s0": systemId,
|
|
||||||
"sA": "1"
|
|
||||||
};
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.set("json", JSON.stringify(formDataJsonObject));
|
|
||||||
|
|
||||||
const query = new URLSearchParams(params).toString();
|
|
||||||
const response = await fetch(`${baseUrl}?${query}`, {
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
const json = await response.json();
|
|
||||||
|
|
||||||
if (json.buses && json.buses["-1"] === undefined) {
|
|
||||||
const jsonBuses = Object.values(json.buses).map((busesArr: any) => {
|
|
||||||
return busesArr[0];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store shuttles by system, with the additional side effect that
|
|
||||||
// shuttleByShuttleId is updated
|
|
||||||
const shuttles = await Promise.all(jsonBuses.map(async (jsonBus: any) => {
|
|
||||||
const constructedShuttle: IShuttle = {
|
|
||||||
name: jsonBus.bus,
|
|
||||||
coordinates: {
|
|
||||||
latitude: parseFloat(jsonBus.latitude),
|
|
||||||
longitude: parseFloat(jsonBus.longitude),
|
|
||||||
},
|
|
||||||
routeId: jsonBus.routeId,
|
|
||||||
systemId: systemId,
|
|
||||||
id: `${jsonBus.busId}`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.cache.shuttleByShuttleId) {
|
|
||||||
this.cache.shuttleByShuttleId[jsonBus.busId] = constructedShuttle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return constructedShuttle;
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (this.cache.shuttlesBySystemId) {
|
|
||||||
this.cache.shuttlesBySystemId[systemId] = shuttles;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn(`No shuttle data available for system ID ${systemId} and JSON output
|
|
||||||
${json}`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getStopById(stopId: string): Promise<IStop | null> {
|
|
||||||
if (!this.cache.stopByStopId) return null;
|
|
||||||
const oldStop = this.cache.stopByStopId[stopId];
|
|
||||||
if (!oldStop) return null;
|
|
||||||
|
|
||||||
await this.updateStopsForSystemIdIfTTL(oldStop.systemId);
|
|
||||||
|
|
||||||
const newStop = this.cache.stopByStopId[stopId];
|
|
||||||
if (!newStop) return null;
|
|
||||||
|
|
||||||
return newStop;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getStopsBySystemId(systemId: string): Promise<IStop[]> {
|
|
||||||
await this.updateStopsForSystemIdIfTTL(systemId);
|
|
||||||
|
|
||||||
if (!this.cache.stopsBySystemId || !this.cache.stopsBySystemId[systemId]) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return this.cache.stopsBySystemId[systemId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async updateStopsForSystemIdIfTTL(systemId: string) {
|
|
||||||
// TODO: check if TTL
|
|
||||||
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
getStops: "2",
|
|
||||||
};
|
|
||||||
|
|
||||||
const formDataJsonObject = {
|
|
||||||
"s0": systemId,
|
|
||||||
"sA": 1
|
|
||||||
};
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.set("json", JSON.stringify(formDataJsonObject));
|
|
||||||
|
|
||||||
const query = new URLSearchParams(params).toString();
|
|
||||||
const response = await fetch(`${baseUrl}?${query}`, {
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
const json = await response.json();
|
|
||||||
|
|
||||||
// TODO: update polyline data
|
|
||||||
// TODO: update ordered stop data
|
|
||||||
|
|
||||||
if (json.stops) {
|
|
||||||
const jsonStops = Object.values(json.stops);
|
|
||||||
|
|
||||||
// TODO: restore normal cache behavior
|
|
||||||
this.cache.stopsBySystemId = {};
|
|
||||||
this.cache.stopByStopId = {};
|
|
||||||
|
|
||||||
await Promise.all(jsonStops.map(async (stop: any) => {
|
|
||||||
const constructedStop: IStop = {
|
|
||||||
name: stop.name,
|
|
||||||
id: stop.id,
|
|
||||||
systemId: systemId,
|
|
||||||
coordinates: {
|
|
||||||
latitude: parseFloat(stop.latitude),
|
|
||||||
longitude: parseFloat(stop.longitude),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!this.cache.stopsBySystemId) {
|
|
||||||
this.cache.stopsBySystemId = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.cache.stopsBySystemId[systemId]) {
|
|
||||||
this.cache.stopsBySystemId[systemId] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cache.stopsBySystemId[systemId].push(constructedStop);
|
|
||||||
|
|
||||||
if (!this.cache.stopByStopId) {
|
|
||||||
this.cache.stopByStopId = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cache.stopByStopId[constructedStop.id] = constructedStop;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getSystemById(systemId: string): Promise<ISystem| null> {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getSystems(): Promise<[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,422 +0,0 @@
|
|||||||
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
|
|
||||||
import {
|
|
||||||
ApiBasedRepository,
|
|
||||||
ApiBasedRepositoryCache,
|
|
||||||
ApiBasedRepositoryMillisecondTTLs
|
|
||||||
} from "../../src/repositories/ApiBasedRepository";
|
|
||||||
import { IEta, IShuttle, IStop } from "../../src/entities/entities";
|
|
||||||
import { genericEtaDataByStopId } from "../jsonSnapshots/genericEtaDataBySystemId";
|
|
||||||
import { genericShuttleDataBySystemId } from "../jsonSnapshots/genericShuttleDataBySystemId";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the global fetch function to return a specific object.
|
|
||||||
* @param obj
|
|
||||||
*/
|
|
||||||
function updateGlobalFetchMockJson(obj: any) {
|
|
||||||
// @ts-ignore
|
|
||||||
global.fetch = jest.fn(() => {
|
|
||||||
return Promise.resolve({
|
|
||||||
json: () => Promise.resolve(obj)
|
|
||||||
})
|
|
||||||
}) as jest.Mock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the global fetch function mock's JSON to return an empty object.
|
|
||||||
* @param obj
|
|
||||||
*/
|
|
||||||
function resetGlobalFetchMockJson() {
|
|
||||||
updateGlobalFetchMockJson({})
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
resetGlobalFetchMockJson();
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
describe("getEtaForShuttleAndStopId", () => {
|
|
||||||
test("getEtaForShuttleAndStopId returns correct ETA data", async () => {
|
|
||||||
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
||||||
|
|
||||||
const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
etasForStopId: {
|
|
||||||
"177666": [
|
|
||||||
{
|
|
||||||
secondsRemaining: 587,
|
|
||||||
shuttleId: "5577",
|
|
||||||
stopId: "177666",
|
|
||||||
millisecondsSinceEpoch: Date.now(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
secondsRemaining: 226,
|
|
||||||
shuttleId: "9909",
|
|
||||||
stopId: "177666",
|
|
||||||
millisecondsSinceEpoch: Date.now(),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const repository = new ApiBasedRepository(initialCache);
|
|
||||||
|
|
||||||
repository.getShuttleById = jest.fn(async () => {
|
|
||||||
const shuttle: IShuttle = {
|
|
||||||
id: "5577",
|
|
||||||
name: "08",
|
|
||||||
coordinates: {
|
|
||||||
latitude: 33.7933406,
|
|
||||||
longitude: -117.8539321,
|
|
||||||
},
|
|
||||||
routeId: "53966",
|
|
||||||
systemId: "1",
|
|
||||||
};
|
|
||||||
return shuttle;
|
|
||||||
});
|
|
||||||
|
|
||||||
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await repository.getEtaForShuttleAndStopId("5577", "177666");
|
|
||||||
|
|
||||||
expect(result?.secondsRemaining).toEqual(587);
|
|
||||||
expect(result?.millisecondsSinceEpoch).toBeDefined();
|
|
||||||
expect(result?.shuttleId).toEqual("5577");
|
|
||||||
expect(result?.stopId).toEqual("177666");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getEtaForShuttleAndStopId returns null if API call is invalid and cache is empty", async () => {
|
|
||||||
const repository = new ApiBasedRepository();
|
|
||||||
const result = await repository.getEtaForShuttleAndStopId("5577", "177666");
|
|
||||||
|
|
||||||
expect(result).toEqual(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getEtasForShuttleId", () => {
|
|
||||||
test("getEtasForShuttleId returns correct ETA data", async () => {
|
|
||||||
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
||||||
|
|
||||||
const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
etasForStopId: {},
|
|
||||||
etasForShuttleId: {
|
|
||||||
"5577": [
|
|
||||||
{
|
|
||||||
secondsRemaining: 587,
|
|
||||||
shuttleId: "5577",
|
|
||||||
stopId: "177666",
|
|
||||||
millisecondsSinceEpoch: Date.now(),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
etasForShuttleId: 100000,
|
|
||||||
etasForStopId: 100000,
|
|
||||||
};
|
|
||||||
|
|
||||||
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
||||||
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
||||||
});
|
|
||||||
repository.getShuttleById = jest.fn(async () => {
|
|
||||||
const shuttle: IShuttle = {
|
|
||||||
id: "5577",
|
|
||||||
name: "08",
|
|
||||||
coordinates: {
|
|
||||||
latitude: 33.7933406,
|
|
||||||
longitude: -117.8539321,
|
|
||||||
},
|
|
||||||
routeId: "53966",
|
|
||||||
systemId: "1",
|
|
||||||
};
|
|
||||||
return shuttle;
|
|
||||||
});
|
|
||||||
const result = await repository.getEtasForShuttleId("5577");
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
expect(result).toEqual(initialCache.etasForShuttleId["5577"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getEtasForShuttleId returns empty array if no data available", async () => {
|
|
||||||
const repository = new ApiBasedRepository();
|
|
||||||
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
||||||
});
|
|
||||||
const result = await repository.getEtasForShuttleId("5577");
|
|
||||||
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getEtasForStopId", () => {
|
|
||||||
test("getEtasForStopId returns correct ETA data", async () => {
|
|
||||||
// Because I'm testing updateEtasForSystemIfTTL separately,
|
|
||||||
// stub it out here
|
|
||||||
|
|
||||||
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
||||||
|
|
||||||
const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
etasForStopId: {
|
|
||||||
"177666": [
|
|
||||||
{
|
|
||||||
secondsRemaining: 587,
|
|
||||||
shuttleId: "5577",
|
|
||||||
stopId: "177666",
|
|
||||||
millisecondsSinceEpoch: Date.now(),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
etasForShuttleId: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
etasForShuttleId: 100000,
|
|
||||||
etasForStopId: 100000,
|
|
||||||
};
|
|
||||||
|
|
||||||
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
||||||
repository.getStopById = jest.fn(async () => {
|
|
||||||
const stop: IStop = {
|
|
||||||
name: "Chapman Court",
|
|
||||||
systemId: "1",
|
|
||||||
id: "177666",
|
|
||||||
coordinates: {
|
|
||||||
latitude: 33.796796,
|
|
||||||
longitude: -117.889293
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return stop;
|
|
||||||
});
|
|
||||||
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
||||||
});
|
|
||||||
const result = await repository.getEtasForStopId("177666");
|
|
||||||
|
|
||||||
expect(result).toEqual(initialCache.etasForStopId!["177666"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getEtasForStopId returns empty array if no data available", async () => {
|
|
||||||
const repository = new ApiBasedRepository();
|
|
||||||
repository.updateEtasForSystemIfTTL = jest.fn(async () => {
|
|
||||||
});
|
|
||||||
const result = await repository.getEtasForShuttleId("5577");
|
|
||||||
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("updateEtasForSystemIfTTL", () => {
|
|
||||||
// test("updateEtasForSystemIfTTL does nothing if data is not TTL", async () => {
|
|
||||||
// updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
||||||
//
|
|
||||||
// // If ETA data is not TTL, then don't do anything
|
|
||||||
// const expectedEta: IEta = {
|
|
||||||
// secondsRemaining: 587,
|
|
||||||
// shuttleId: "5577",
|
|
||||||
// stopId: "177666",
|
|
||||||
// millisecondsSinceEpoch: Date.now() - 1000,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
// etasForShuttleId: {
|
|
||||||
// "5577": [
|
|
||||||
// expectedEta,
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// etasForStopId: {
|
|
||||||
// "177666": [
|
|
||||||
// expectedEta,
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// stopsBySystemId: {
|
|
||||||
// "1": [
|
|
||||||
// {
|
|
||||||
// systemId: "1",
|
|
||||||
// millisecondsSinceEpoch: Date.now() - 1000,
|
|
||||||
// name: "Chapman Court",
|
|
||||||
// id: "177666",
|
|
||||||
// coordinates: {
|
|
||||||
// latitude: 33.796796,
|
|
||||||
// longitude: -117.889293
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
// etasForShuttleId: 100000,
|
|
||||||
// etasForStopId: 100000,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const repository = new ApiBasedRepository(initialCache, ttls);
|
|
||||||
// await repository.updateEtasForSystemIfTTL("1");
|
|
||||||
//
|
|
||||||
// const updatedResult = await repository.getEtaForShuttleAndStopId(
|
|
||||||
// "5577",
|
|
||||||
// "177666",
|
|
||||||
// );
|
|
||||||
// expect(updatedResult?.millisecondsSinceEpoch).toEqual(expectedEta.millisecondsSinceEpoch);
|
|
||||||
// });
|
|
||||||
|
|
||||||
test("updateEtasForSystemIfTTL updates all ETA data if data is TTL", async () => {
|
|
||||||
updateGlobalFetchMockJson(genericEtaDataByStopId);
|
|
||||||
|
|
||||||
const sampleStop: IStop = {
|
|
||||||
name: "Chapman Court",
|
|
||||||
systemId: "1",
|
|
||||||
id: "177666",
|
|
||||||
coordinates: {
|
|
||||||
latitude: 33.796796,
|
|
||||||
longitude: -117.889293
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const repository = new ApiBasedRepository();
|
|
||||||
repository.getStopsBySystemId = jest.fn(async () => {
|
|
||||||
return [
|
|
||||||
sampleStop
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
repository.getStopById = jest.fn(async () => {
|
|
||||||
return sampleStop;
|
|
||||||
});
|
|
||||||
|
|
||||||
await repository.updateEtasForSystemIfTTL("1");
|
|
||||||
|
|
||||||
const updatedResult = await repository.getEtasForStopId("177666");
|
|
||||||
expect(updatedResult.length).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getShuttleById", () => {
|
|
||||||
test("getShuttleById returns null if unseeded cache", async () => {
|
|
||||||
updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
||||||
|
|
||||||
const initialCache: ApiBasedRepositoryCache = {};
|
|
||||||
const repository = new ApiBasedRepository(initialCache);
|
|
||||||
|
|
||||||
const shuttle = await repository.getShuttleById("5577");
|
|
||||||
expect(shuttle).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getShuttleById returns data if present", async () => {
|
|
||||||
updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
||||||
|
|
||||||
const initialCacheShuttle = {
|
|
||||||
coordinates: {
|
|
||||||
latitude: 33.7917818,
|
|
||||||
longitude: -117.8589646,
|
|
||||||
},
|
|
||||||
name: "08",
|
|
||||||
routeId: "53966",
|
|
||||||
systemId: "1",
|
|
||||||
id: "5577",
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
shuttleByShuttleId: {
|
|
||||||
"5577": initialCacheShuttle
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
shuttleByShuttleId: 1000,
|
|
||||||
};
|
|
||||||
|
|
||||||
const repository = new ApiBasedRepository(initialCache, ttls);
|
|
||||||
repository.updateStopsForSystemIdIfTTL = jest.fn(async () => {
|
|
||||||
})
|
|
||||||
|
|
||||||
const shuttle = await repository.getShuttleById("5577");
|
|
||||||
expect(shuttle).toEqual(initialCacheShuttle);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: enable when implemented
|
|
||||||
// describe("getShuttlesBySystemId", () => {
|
|
||||||
// test("getShuttlesBySystemId returns old data if not expired", async () => {
|
|
||||||
// updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
||||||
//
|
|
||||||
// const initialCacheShuttle = {
|
|
||||||
// coordinates: {
|
|
||||||
// latitude: 33.791781,
|
|
||||||
// longitude: -117.8589646,
|
|
||||||
// },
|
|
||||||
// name: "08",
|
|
||||||
// routeId: "53966",
|
|
||||||
// systemId: "1",
|
|
||||||
// id: "5577",
|
|
||||||
// millisecondsSinceEpoch: Date.now() - 1000,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
// shuttlesBySystemId: {
|
|
||||||
// "1": [
|
|
||||||
// initialCacheShuttle,
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// shuttleByShuttleId: {
|
|
||||||
// "5577": initialCacheShuttle,
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
// shuttleByShuttleId: 100000,
|
|
||||||
// shuttlesBySystemId: 100000,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const repository = new ApiBasedRepository(initialCache, ttls);
|
|
||||||
// const shuttles = await repository.getShuttlesBySystemId("1");
|
|
||||||
// expect(shuttles.length).toEqual(1);
|
|
||||||
// expect(shuttles[0].id).toEqual(initialCacheShuttle.id);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// test("getShuttlesBySystemId returns fresh data if expired", async () => {
|
|
||||||
// updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
||||||
//
|
|
||||||
// // TODO: move construction of shuttle into method
|
|
||||||
// const initialCacheShuttle = {
|
|
||||||
// coordinates: {
|
|
||||||
// latitude: 33.791781,
|
|
||||||
// longitude: -117.8589646,
|
|
||||||
// },
|
|
||||||
// name: "08",
|
|
||||||
// routeId: "53966",
|
|
||||||
// systemId: "1",
|
|
||||||
// id: "5577",
|
|
||||||
// millisecondsSinceEpoch: Date.now() - 100000,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const initialCache: ApiBasedRepositoryCache = {
|
|
||||||
// shuttlesBySystemId: {
|
|
||||||
// "1": [
|
|
||||||
// initialCacheShuttle,
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// shuttleByShuttleId: {
|
|
||||||
// "5577": initialCacheShuttle,
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const ttls: ApiBasedRepositoryMillisecondTTLs = {
|
|
||||||
// shuttleByShuttleId: 1000,
|
|
||||||
// shuttlesBySystemId: 1000,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const repository = new ApiBasedRepository(initialCache, ttls);
|
|
||||||
// const shuttles = await repository.getShuttlesBySystemId("1");
|
|
||||||
//
|
|
||||||
// expect(shuttles.length).toEqual(1);
|
|
||||||
// expect(shuttles[0].id).toEqual("5577");
|
|
||||||
// expect(shuttles[0].millisecondsSinceEpoch).not.toEqual(initialCacheShuttle.millisecondsSinceEpoch);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// test("getShuttlesBySystemId returns fresh data if no seeded data", async () => {
|
|
||||||
// updateGlobalFetchMockJson(genericShuttleDataBySystemId);
|
|
||||||
//
|
|
||||||
// const repository = new ApiBasedRepository();
|
|
||||||
// const shuttles = await repository.getShuttlesBySystemId("1");
|
|
||||||
//
|
|
||||||
// expect(shuttles.length).toEqual(1);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
Reference in New Issue
Block a user