blob: 9895820c9287071f53139a141f9559a60ad250bc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 { hasProperty } from "./CommonUtils/utils";
/** Possible levels of TO Alerts */
export type AlertLevel = "success" | "info" | "warning" | "error";
/**
* Checks whether an object is a valid Alert level.
*
* @param s The object to check.
* @returns Whether or not `s` is an AlertLevel.
*/
export function isAlertLevel(s: unknown): s is AlertLevel {
if (typeof(s) !== "string") {
return false;
}
switch (s) {
case "success":
case "info":
case "warning":
case "error":
return true;
}
return false;
}
/** TO API Alerts */
export interface Alert {
level: AlertLevel;
text: string;
}
/**
* Checks whether an object is an Alert like the ones TO normally returns.
*
* @param a The object to check.
* @returns Whether or not `a` is an Alert.
*/
export function isAlert(a: unknown): a is Alert {
if (typeof(a) !== "object" || a === null) {
return false;
}
if (!hasProperty(a, "level") || !hasProperty(a, "text", "string")) {
return false;
}
return isAlertLevel(a.level);
}
/**
* Logs an alert to the appropriate console stream based on its `level`.
*
* @param a The Alert to log.
* @param prefix Optional prefix for the log message
*/
export function logAlert(a: Alert, prefix?: string): void {
let logfunc;
let pre = (prefix ?? "").trimStart();
switch (a.level) {
case "success":
logfunc = console.log;
pre = `SUCCESS: ${pre}`;
break;
case "info":
logfunc = console.info
pre = `INFO: ${pre}`;
break;
case "warning":
logfunc = console.warn
pre = `WARN: ${pre}`;
break;
case "error":
logfunc = console.error
pre = `ERROR: ${pre}`;
break;
}
logfunc(pre, a.text);
}
/** TestingConfig is the type of a testing configuration. */
export interface TestingConfig {
/** This is login information for a user with admin-level permissions. */
readonly login: {
readonly password: string;
readonly username: string;
};
/** The URL at which the Traffic Ops API can be accessed. */
readonly apiUrl: string;
/** The URL at which Traffic Portal is served - root path. */
readonly baseUrl: string;
/** Logging alert levels that are enabled. */
readonly alertLevels?: Array<AlertLevel>;
}
/**
* Checks if a passed object is a valid testing configuration.
*
* @param c The object to check.
* @returns `true`, always. When the check fails, it throws an error that
* explains why.
*/
export function isTestingConfig(c: unknown): c is TestingConfig {
if (typeof(c) !== "object") {
throw new Error(`testing configuration must be an object, not a '${typeof(c)}'`);
}
if (c === null) {
throw new Error("testing configuration must be an object, not 'null'");
}
if (!hasProperty(c, "login") || typeof(c.login) !== "object" || c.login === null) {
throw new Error("missing or invalid 'login' property");
}
if (!hasProperty(c.login, "password", "string") || !hasProperty(c.login, "username", "string")) {
throw new Error("'login' property has missing and/or invalid 'password' and/or 'username' property(ies)");
}
if (c.login.username === "" || c.login.password === "") {
throw new Error("neither 'login.username' nor 'login.password' may be blank");
}
if (!hasProperty(c, "apiUrl", "string")) {
throw new Error("missing or invalid 'apiUrl' property");
}
try {
new URL(c.apiUrl);
} catch (e) {
throw new Error(`'apiUrl' is not a valid URL: ${c.apiUrl}`);
}
let baseURL;
if (!hasProperty(c, "baseUrl", "string")) {
throw new Error("missing or invalid 'baseUrl' property");
}
try {
baseURL = new URL(c.baseUrl);
} catch (e) {
throw new Error(`'baseUrl' is not a valid URL: ${c.baseUrl}`);
}
if (baseURL.pathname !== "/") {
throw new Error("'baseUrl' must be a root path");
}
if (!hasProperty(c, "alertLevels")) {
return true;
}
if (!(c.alertLevels instanceof Array)) {
throw new Error("'alertLevels' must be an array");
}
if (!c.alertLevels.every(isAlertLevel)) {
throw new Error(`invalid alert levels: ${c.alertLevels}`);
}
return true;
}