Skip to content

Commit 08f816a

Browse files
feat: Add Backend.exists, Backend.fromName, Backend.isHealthy, and Backend.prototype.toName (#523)
Co-authored-by: Trevor Elliott <[email protected]>
1 parent ad0dfd8 commit 08f816a

File tree

9 files changed

+857
-249
lines changed

9 files changed

+857
-249
lines changed

integration-tests/js-compute/fixtures/app/src/dynamic-backend.js

Lines changed: 293 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Backend } from 'fastly:backend';
22
import { CacheOverride } from 'fastly:cache-override';
33
import { allowDynamicBackends } from "fastly:experimental";
44
import { pass, assert, assertDoesNotThrow, assertThrows, assertRejects, assertResolves } from "./assertions.js";
5-
import { routes } from "./routes.js";
5+
import { isRunningLocally, routes } from "./routes.js";
66

77
/// The backend name is already in use.
88

@@ -61,7 +61,7 @@ import { routes } from "./routes.js";
6161
{
6262
routes.set("/backend/interface", async () => {
6363
let actual = Reflect.ownKeys(Backend)
64-
let expected = ["prototype", "length", "name"]
64+
let expected = ["prototype", "exists", "fromName", "health", "length", "name"]
6565
let error = assert(actual, expected, `Reflect.ownKeys(Backend)`)
6666
if (error) { return error }
6767

@@ -75,6 +75,60 @@ import { routes } from "./routes.js";
7575
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend, 'prototype')`)
7676
if (error) { return error }
7777

78+
actual = Reflect.getOwnPropertyDescriptor(Backend, 'exists')
79+
expected = {
80+
"value": Backend.exists,
81+
"writable": true,
82+
"enumerable": true,
83+
"configurable": true
84+
}
85+
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend, 'exists')`)
86+
if (error) { return error }
87+
88+
error = assert(typeof Backend.exists, 'function', `typeof Backend.exists`)
89+
if (error) { return error }
90+
91+
error = assert(Backend.exists.length, 1, `Backend.exists.length`)
92+
if (error) { return error }
93+
error = assert(Backend.exists.name, "exists", `Backend.exists.name`)
94+
if (error) { return error }
95+
96+
actual = Reflect.getOwnPropertyDescriptor(Backend, 'fromName')
97+
expected = {
98+
"value": Backend.fromName,
99+
"writable": true,
100+
"enumerable": true,
101+
"configurable": true
102+
}
103+
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend, 'fromName')`)
104+
if (error) { return error }
105+
106+
error = assert(typeof Backend.fromName, 'function', `typeof Backend.fromName`)
107+
if (error) { return error }
108+
109+
error = assert(Backend.fromName.length, 1, `Backend.fromName.length`)
110+
if (error) { return error }
111+
error = assert(Backend.fromName.name, "fromName", `Backend.fromName.name`)
112+
if (error) { return error }
113+
114+
actual = Reflect.getOwnPropertyDescriptor(Backend, 'health')
115+
expected = {
116+
"value": Backend.health,
117+
"writable": true,
118+
"enumerable": true,
119+
"configurable": true
120+
}
121+
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend, 'health')`)
122+
if (error) { return error }
123+
124+
error = assert(typeof Backend.health, 'function', `typeof Backend.health`)
125+
if (error) { return error }
126+
127+
error = assert(Backend.health.length, 1, `Backend.health.length`)
128+
if (error) { return error }
129+
error = assert(Backend.health.name, "health", `Backend.health.name`)
130+
if (error) { return error }
131+
78132
actual = Reflect.getOwnPropertyDescriptor(Backend, 'length')
79133
expected = {
80134
"value": 1,
@@ -96,7 +150,7 @@ import { routes } from "./routes.js";
96150
if (error) { return error }
97151

98152
actual = Reflect.ownKeys(Backend.prototype)
99-
expected = ["constructor", "toString"]
153+
expected = ["constructor", "toString", "toName"]
100154
error = assert(actual, expected, `Reflect.ownKeys(Backend.prototype)`)
101155
if (error) { return error }
102156

@@ -114,6 +168,8 @@ import { routes } from "./routes.js";
114168
if (error) { return error }
115169
error = assert(typeof Backend.prototype.toString, 'function', `typeof Backend.prototype.toString`)
116170
if (error) { return error }
171+
error = assert(typeof Backend.prototype.toName, 'function', `typeof Backend.prototype.toName`)
172+
if (error) { return error }
117173

118174
actual = Reflect.getOwnPropertyDescriptor(Backend.prototype.constructor, 'length')
119175
expected = {
@@ -155,6 +211,26 @@ import { routes } from "./routes.js";
155211
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend.prototype.toString, 'name')`)
156212
if (error) { return error }
157213

214+
actual = Reflect.getOwnPropertyDescriptor(Backend.prototype.toName, 'length')
215+
expected = {
216+
"value": 0,
217+
"writable": false,
218+
"enumerable": false,
219+
"configurable": true
220+
}
221+
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend.prototype.toName, 'length')`)
222+
if (error) { return error }
223+
224+
actual = Reflect.getOwnPropertyDescriptor(Backend.prototype.toName, 'name')
225+
expected = {
226+
"value": "toName",
227+
"writable": false,
228+
"enumerable": false,
229+
"configurable": true
230+
}
231+
error = assert(actual, expected, `Reflect.getOwnPropertyDescriptor(Backend.prototype.toName, 'name')`)
232+
if (error) { return error }
233+
158234
return pass('ok')
159235
});
160236

@@ -1291,6 +1367,220 @@ import { routes } from "./routes.js";
12911367
});
12921368
}
12931369
}
1370+
1371+
// exists
1372+
{
1373+
routes.set("/backend/exists/called-as-constructor-function", async () => {
1374+
let error = assertThrows(() => {
1375+
new Backend.exists()
1376+
}, TypeError, `Backend.exists is not a constructor`)
1377+
if (error) { return error }
1378+
return pass('ok')
1379+
});
1380+
routes.set("/backend/exists/empty-parameter", async () => {
1381+
let error = assertThrows(() => {
1382+
Backend.exists()
1383+
}, TypeError, `Backend.exists: At least 1 argument required, but only 0 passed`)
1384+
if (error) { return error }
1385+
return pass('ok')
1386+
});
1387+
// https://tc39.es/ecma262/#sec-tostring
1388+
routes.set("/backend/exists/parameter-calls-7.1.17-ToString", async () => {
1389+
let sentinel;
1390+
const test = () => {
1391+
sentinel = Symbol();
1392+
const name = {
1393+
toString() {
1394+
throw sentinel;
1395+
}
1396+
}
1397+
Backend.exists(name)
1398+
}
1399+
let error = assertThrows(test)
1400+
if (error) { return error }
1401+
try {
1402+
test()
1403+
} catch (thrownError) {
1404+
let error = assert(thrownError, sentinel, 'thrownError === sentinel')
1405+
if (error) { return error }
1406+
}
1407+
error = assertThrows(() => Backend.exists(Symbol()), TypeError, `can't convert symbol to string`)
1408+
if (error) { return error }
1409+
return pass('ok')
1410+
});
1411+
1412+
routes.set("/backend/exists/parameter-invalid", async () => {
1413+
// null
1414+
let error = assertThrows(() => Backend.exists(null), TypeError)
1415+
if (error) { return error }
1416+
// undefined
1417+
error = assertThrows(() => Backend.exists(undefined), TypeError)
1418+
if (error) { return error }
1419+
// .length > 254
1420+
error = assertThrows(() => Backend.exists('a'.repeat(255)), TypeError)
1421+
if (error) { return error }
1422+
// .length == 0
1423+
error = assertThrows(() => Backend.exists(''), TypeError)
1424+
if (error) { return error }
1425+
return pass('ok')
1426+
});
1427+
routes.set("/backend/exists/happy-path-backend-exists", async () => {
1428+
let error = assert(Backend.exists('TheOrigin'), true, `Backend.exists('TheOrigin')`)
1429+
if (error) { return error }
1430+
return pass('ok')
1431+
});
1432+
routes.set("/backend/exists/happy-path-backend-does-not-exist", async () => {
1433+
let error = assert(Backend.exists('meow'), false, `Backend.exists('meow')`)
1434+
if (error) { return error }
1435+
return pass('ok')
1436+
});
1437+
}
1438+
1439+
// fromName
1440+
{
1441+
routes.set("/backend/fromName/called-as-constructor-function", async () => {
1442+
let error = assertThrows(() => {
1443+
new Backend.fromName()
1444+
}, TypeError, `Backend.fromName is not a constructor`)
1445+
if (error) { return error }
1446+
return pass('ok')
1447+
});
1448+
routes.set("/backend/fromName/empty-parameter", async () => {
1449+
let error = assertThrows(() => {
1450+
Backend.fromName()
1451+
}, TypeError, `Backend.fromName: At least 1 argument required, but only 0 passed`)
1452+
if (error) { return error }
1453+
return pass('ok')
1454+
});
1455+
// https://tc39.es/ecma262/#sec-tostring
1456+
routes.set("/backend/fromName/parameter-calls-7.1.17-ToString", async () => {
1457+
let sentinel;
1458+
const test = () => {
1459+
sentinel = Symbol();
1460+
const name = {
1461+
toString() {
1462+
throw sentinel;
1463+
}
1464+
}
1465+
Backend.fromName(name)
1466+
}
1467+
let error = assertThrows(test)
1468+
if (error) { return error }
1469+
try {
1470+
test()
1471+
} catch (thrownError) {
1472+
let error = assert(thrownError, sentinel, 'thrownError === sentinel')
1473+
if (error) { return error }
1474+
}
1475+
error = assertThrows(() => Backend.fromName(Symbol()), TypeError, `can't convert symbol to string`)
1476+
if (error) { return error }
1477+
return pass('ok')
1478+
});
1479+
1480+
routes.set("/backend/fromName/parameter-invalid", async () => {
1481+
// null
1482+
let error = assertThrows(() => Backend.fromName(null), TypeError)
1483+
if (error) { return error }
1484+
// undefined
1485+
error = assertThrows(() => Backend.fromName(undefined), TypeError)
1486+
if (error) { return error }
1487+
// .length > 254
1488+
error = assertThrows(() => Backend.fromName('a'.repeat(255)), TypeError)
1489+
if (error) { return error }
1490+
// .length == 0
1491+
error = assertThrows(() => Backend.fromName(''), TypeError)
1492+
if (error) { return error }
1493+
return pass('ok')
1494+
});
1495+
routes.set("/backend/fromName/happy-path-backend-exists", async () => {
1496+
allowDynamicBackends(false);
1497+
let error = assert(Backend.fromName('TheOrigin') instanceof Backend, true, `Backend.fromName('TheOrigin') instanceof Backend`)
1498+
if (error) { return error }
1499+
1500+
error = await assertResolves(() => fetch('https://http-me.glitch.me/headers', {
1501+
backend: Backend.fromName('TheOrigin'),
1502+
}));
1503+
if (error) { return error }
1504+
1505+
return pass('ok')
1506+
});
1507+
routes.set("/backend/fromName/happy-path-backend-does-not-exist", async () => {
1508+
let error = assertThrows(() => Backend.fromName('meow'), Error, "Backend.fromName: backend named 'meow' does not exist")
1509+
if (error) { return error }
1510+
return pass('ok')
1511+
});
1512+
}
1513+
1514+
// health
1515+
{
1516+
routes.set("/backend/health/called-as-constructor-function", async () => {
1517+
let error = assertThrows(() => {
1518+
new Backend.health()
1519+
}, TypeError, `Backend.health is not a constructor`)
1520+
if (error) { return error }
1521+
return pass('ok')
1522+
});
1523+
routes.set("/backend/health/empty-parameter", async () => {
1524+
let error = assertThrows(() => {
1525+
Backend.health()
1526+
}, TypeError, `Backend.health: At least 1 argument required, but only 0 passed`)
1527+
if (error) { return error }
1528+
return pass('ok')
1529+
});
1530+
// https://tc39.es/ecma262/#sec-tostring
1531+
routes.set("/backend/health/parameter-calls-7.1.17-ToString", async () => {
1532+
let sentinel;
1533+
const test = () => {
1534+
sentinel = Symbol();
1535+
const name = {
1536+
toString() {
1537+
throw sentinel;
1538+
}
1539+
}
1540+
Backend.health(name)
1541+
}
1542+
let error = assertThrows(test)
1543+
if (error) { return error }
1544+
try {
1545+
test()
1546+
} catch (thrownError) {
1547+
let error = assert(thrownError, sentinel, 'thrownError === sentinel')
1548+
if (error) { return error }
1549+
}
1550+
error = assertThrows(() => Backend.health(Symbol()), TypeError, `can't convert symbol to string`)
1551+
if (error) { return error }
1552+
return pass('ok')
1553+
});
1554+
1555+
routes.set("/backend/health/parameter-invalid", async () => {
1556+
// null
1557+
let error = assertThrows(() => Backend.health(null), TypeError)
1558+
if (error) { return error }
1559+
// undefined
1560+
error = assertThrows(() => Backend.health(undefined), TypeError)
1561+
if (error) { return error }
1562+
// .length > 254
1563+
error = assertThrows(() => Backend.health('a'.repeat(255)), TypeError)
1564+
if (error) { return error }
1565+
// .length == 0
1566+
error = assertThrows(() => Backend.health(''), TypeError)
1567+
if (error) { return error }
1568+
return pass('ok')
1569+
});
1570+
routes.set("/backend/health/happy-path-backend-exists", async () => {
1571+
let error = assert(typeof Backend.health('TheOrigin'), 'string', "typeof Backend.health('TheOrigin')");
1572+
if (error) { return error }
1573+
error = assert(Backend.health('TheOrigin'), 'unknown', "Backend.health('TheOrigin')");
1574+
if (error) { return error }
1575+
1576+
return pass('ok')
1577+
});
1578+
routes.set("/backend/health/happy-path-backend-does-not-exist", async () => {
1579+
let error = assertThrows(() => Backend.health('meow'), Error, "Backend.health: backend named 'meow' does not exist")
1580+
if (error) { return error }
1581+
return pass('ok')
1582+
});
1583+
}
12941584
}
12951585

12961586
function createValidHttpMeBackend() {

0 commit comments

Comments
 (0)