Skip to content

Commit

Permalink
Add Origins page Traffic Portal v2 (#7881)
Browse files Browse the repository at this point in the history
* [WIP] Add Origins

* add origin, coordinate service; update origin list/detail

* fix unit tests

* add missing @returns annotations

* add test get multiple coordinates/origins

* add test case delete existing origins

* fix test delete origin
  • Loading branch information
ntheanh201 authored Feb 7, 2024
1 parent 1bae48e commit b7f5774
Show file tree
Hide file tree
Showing 18 changed files with 1,707 additions and 1 deletion.
117 changes: 117 additions & 0 deletions experimental/traffic-portal/src/app/api/coordinate.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* @license Apache-2.0
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
HttpClientTestingModule,
HttpTestingController,
} from "@angular/common/http/testing";
import { TestBed } from "@angular/core/testing";

import { CoordinateService } from "./coordinate.service";

describe("CoordinateService", () => {
let service: CoordinateService;
let httpTestingController: HttpTestingController;
const coordinate = {
id: 1,
lastUpdated: new Date(),
latitude: 1.0,
longitude: -1.0,
name: "test_coordinate",
};

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [CoordinateService],
});
service = TestBed.inject(CoordinateService);
httpTestingController = TestBed.inject(HttpTestingController);
});

it("should be created", () => {
expect(service).toBeTruthy();
});

it("gets multiple Coordinates", async () => {
const responseP = service.getCoordinates();
const req = httpTestingController.expectOne(
`/api/${service.apiVersion}/coordinates`
);
expect(req.request.method).toBe("GET");
expect(req.request.params.keys().length).toBe(0);
req.flush({ response: [coordinate] });
await expectAsync(responseP).toBeResolvedTo([coordinate]);
});

it("gets a single Coordinate by ID", async () => {
const responseP = service.getCoordinates(coordinate.id);
const req = httpTestingController.expectOne(
(r) => r.url === `/api/${service.apiVersion}/coordinates`
);
expect(req.request.method).toBe("GET");
expect(req.request.params.keys().length).toBe(1);
expect(req.request.params.get("id")).toBe(String(coordinate.id));
req.flush({ response: [coordinate] });
await expectAsync(responseP).toBeResolvedTo(coordinate);
});

it("gets a single Coordinate by name", async () => {
const responseP = service.getCoordinates(coordinate.name);
const req = httpTestingController.expectOne(
(r) => r.url === `/api/${service.apiVersion}/coordinates`
);
expect(req.request.method).toBe("GET");
expect(req.request.params.keys().length).toBe(1);
expect(req.request.params.get("name")).toBe(coordinate.name);
req.flush({ response: [coordinate] });
await expectAsync(responseP).toBeResolvedTo(coordinate);
});

it("sends requests for multiple coordinates by ID", async () => {
const responseParams = service.getCoordinates(coordinate.id);
const req = httpTestingController.expectOne(
(r) => r.url === `/api/${service.apiVersion}/coordinates`
);
expect(req.request.method).toBe("GET");
expect(req.request.params.keys().length).toBe(1);
expect(req.request.params.get("id")).toBe(String(coordinate.id));
const data = {
response: [
{
id: 1,
lastUpdated: new Date(),
latitude: 1.0,
longitude: -1.0,
name: "test_coordinate1",
},
{
id: 1,
lastUpdated: new Date(),
latitude: 1.0,
longitude: -1.0,
name: "test_coordinate2",
},
],
};
req.flush(data);
await expectAsync(responseParams).toBeRejectedWithError(
`Traffic Ops responded with 2 Coordinates by identifier ${coordinate.id}`
);
});

afterEach(() => {
httpTestingController.verify();
});
});
85 changes: 85 additions & 0 deletions experimental/traffic-portal/src/app/api/coordinate.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import type { ResponseCoordinate } from "trafficops-types";

import { APIService } from "./base-api.service";

/**
* CoordinateService exposes API functionality relating to Coordinates.
*/
@Injectable()
export class CoordinateService extends APIService {
/**
* Gets a specific Coordinate from Traffic Ops.
*
* @param idOrName Either the integral, unique identifier (number) or name
* (string) of the Coordinate to be returned.
* @returns The requested Coordinate.
*/
public async getCoordinates(
idOrName: number | string
): Promise<ResponseCoordinate>;
/**
* Gets Coordinates from Traffic Ops.
*
* @returns An Array of all Coordinates from Traffic Ops.
*/
public async getCoordinates(): Promise<Array<ResponseCoordinate>>;

/**
* Gets one or all Coordinates from Traffic Ops.
*
* @param idOrName Optionally the integral, unique identifier (number) or
* name (string) of a single Coordinate to be returned.
* @returns The requested Coordinate(s).
*/
public async getCoordinates(
idOrName?: number | string
): Promise<ResponseCoordinate | Array<ResponseCoordinate>> {
const path = "coordinates";
if (idOrName !== undefined) {
let params;
switch (typeof idOrName) {
case "string":
params = { name: idOrName };
break;
case "number":
params = { id: idOrName };
}
const r = await this.get<[ResponseCoordinate]>(
path,
undefined,
params
).toPromise();
if (r.length !== 1) {
throw new Error(
`Traffic Ops responded with ${r.length} Coordinates by identifier ${idOrName}`
);
}
return r[0];
}
return this.get<Array<ResponseCoordinate>>(path).toPromise();
}

/**
* Injects the Angular HTTP client service into the parent constructor.
*
* @param http The Angular HTTP client service.
*/
constructor(http: HttpClient) {
super(http);
}
}
6 changes: 6 additions & 0 deletions experimental/traffic-portal/src/app/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import { ChangeLogsService } from "src/app/api/change-logs.service";

import { CacheGroupService } from "./cache-group.service";
import { CDNService } from "./cdn.service";
import { CoordinateService } from "./coordinate.service";
import { DeliveryServiceService } from "./delivery-service.service";
import { InvalidationJobService } from "./invalidation-job.service";
import { MiscAPIsService } from "./misc-apis.service";
import { OriginService } from "./origin.service";
import { PhysicalLocationService } from "./physical-location.service";
import { ProfileService } from "./profile.service";
import { ServerService } from "./server.service";
Expand All @@ -42,6 +44,8 @@ export * from "./server.service";
export * from "./topology.service";
export * from "./type.service";
export * from "./user.service";
export * from "./origin.service";
export * from "./coordinate.service";

/**
* The API Module contains all logic used to access the Traffic Ops API.
Expand All @@ -64,6 +68,8 @@ export * from "./user.service";
TopologyService,
TypeService,
UserService,
OriginService,
CoordinateService,
]
})
export class APIModule { }
Loading

0 comments on commit b7f5774

Please sign in to comment.