diff --git a/frontend/src/ResultsRow.js b/frontend/src/ResultsRow.js
index b14116f..969cc34 100644
--- a/frontend/src/ResultsRow.js
+++ b/frontend/src/ResultsRow.js
@@ -1,5 +1,100 @@
import {h, Component} from 'preact'
+function renderSuccess(server = '') {
+ return (
+
+ {server.toUpperCase()}
+
+ )
+}
+
+function renderError(server = '', text, details) {
+ return (
+
+
{server.toUpperCase()}
+ {text && (
{text}
)}
+
{details}
+
+ )
+}
+
+function renderStatus(endpoint) {
+ const servers = Object.entries(endpoint.servers)
+ const broken = servers.filter(([,{status}]) => status >= 400)
+
+ if(broken.length === 0) {
+ return renderSuccess();
+ }
+
+ return servers.map(
+ ([server, {status, error}]) => (
+ status < 400 ? renderSuccess(server) : renderError(server, status, error || 'Unknown error')
+ )
+ )
+}
+
+function renderSchema(endpoint) {
+ const servers = Object.entries(endpoint.servers)
+
+ if(servers.every(([, {schemaValid}]) => schemaValid === undefined)) {
+ return ('—')
+ }
+
+ const broken = servers.filter(([,{schemaValid}]) => !schemaValid)
+
+ if(broken.length === 0) {
+ return renderSuccess()
+ }
+
+ const firstServer = servers[0][1];
+ const sameError = servers.every(
+ ([, {schemaValid, schemaChanges}]) =>
+ schemaValid === firstServer.schemaValid &&
+ schemaChanges === firstServer.schemaChanges
+ )
+
+ if(sameError) {
+ return renderError('', null, ({firstServer.schemaChanges}))
+ }
+
+ return servers.map(
+ ([server, {schemaValid, schemaChanges}]) => (
+ schemaValid ? renderSuccess(server) : renderError(server, null, ({schemaChanges}))
+ )
+ )
+}
+
+function renderSnapshot(endpoint) {
+ const servers = Object.entries(endpoint.servers)
+
+ if(servers.every(([, {snapshotValid}]) => snapshotValid === undefined)) {
+ return ('—')
+ }
+
+ const broken = servers.filter(([,{snapshotValid}]) => !snapshotValid)
+
+ if(broken.length === 0) {
+ return renderSuccess();
+ }
+
+ const firstServer = servers[0][1];
+ const sameError = servers.every(
+ ([, {snapshotValid, snapshotChanges}]) =>
+ snapshotValid === firstServer.snapshotValid &&
+ snapshotChanges === firstServer.snapshotChanges
+ )
+
+ if(sameError) {
+ return renderError('', null, ({firstServer.snapshotChanges}))
+ }
+
+ return servers.map(
+ ([server, {snapshotValid, snapshotChanges}]) => (
+ snapshotValid ? renderSuccess(server) : renderError(server, null, ({snapshotChanges}))
+ )
+ )
+}
+
class ResultsRow extends Component {
render () {
const {data, className, onClick} = this.props
@@ -10,61 +105,29 @@ class ResultsRow extends Component {
{data.name}
- {data.status < 400 && (
-
- )}
-
- {data.status >= 400 && (
-
-
- {data.status}
- {data.error || 'Unknown error'}
-
- )}
+ {renderStatus(data)}
|
- {data.schemaValid === undefined && '—'}
-
- {data.schemaValid !== undefined && data.schemaValid && (
-
- )}
-
- {data.schemaValid !== undefined && !data.schemaValid && (
-
- )}
+ {renderSchema(data)}
|
- {data.snapshotValid === undefined && '—'}
-
- {data.snapshotValid !== undefined && data.snapshotValid && (
-
- )}
-
- {data.snapshotValid !== undefined && !data.snapshotValid && (
-
- )}
+ {renderSnapshot(data)}
|
- {data.duration <= 1500 && (
+ {data.servers.eu.duration <= 1500 && (
)}
- {data.duration > 1500 && data.duration <= 3000 && (
+ {data.servers.eu.duration > 1500 && data.servers.eu.duration <= 3000 && (
)}
- {data.duration > 3000 && (
+ {data.servers.eu.duration > 3000 && (
)}
- {data.duration !== 0 ? `${data.duration.toLocaleString()} ms` : ''}
+ {data.servers.eu.duration !== 0 ? `${data.servers.eu.duration.toLocaleString()} ms` : ''}
|
diff --git a/frontend/src/ResultsTable.js b/frontend/src/ResultsTable.js
index 52c00eb..edb9e7e 100644
--- a/frontend/src/ResultsTable.js
+++ b/frontend/src/ResultsTable.js
@@ -52,22 +52,19 @@ class ResultsTable extends Component {
const count = workingCount === results.data.length ? 'All' : workingCount
const text = `${prefix} ${count} endpoints fully operational 🎉`
- const averageDuration = Math.round(average(workingResults.map(x => x.duration)))
-
- const data = {
- name: text,
- status: 200,
- schemaValid: true,
- snapshotValid: true,
- duration: averageDuration
- }
+ const averageDuration = Math.round(average(workingResults.map(x => x.servers.eu.duration)))
return (
- this.setState({expanded: !this.state.expanded})}
- className='result-row--summary'
- />
+ this.setState({expanded: !this.state.expanded})} className="result-row--summary">
+ | {text} |
+ |
+ |
+ |
+
+
+ {averageDuration.toLocaleString()}ms
+ |
+
)
}
}
diff --git a/frontend/src/sideEffects.js b/frontend/src/sideEffects.js
index 3dbbf0f..88a1ec0 100644
--- a/frontend/src/sideEffects.js
+++ b/frontend/src/sideEffects.js
@@ -9,7 +9,7 @@ export async function getLatestTest () {
return endpoint
})
- result.data.sort((a, b) => b.duration - a.duration)
+ result.data.sort((a, b) => b.servers.eu.duration - a.servers.eu.duration)
result.data.sort((a, b) => b.severity - a.severity)
result.updated_at = new Date(result.updated_at)
@@ -18,21 +18,29 @@ export async function getLatestTest () {
}
function calculateSeverity (endpoint) {
- if (endpoint.status >= 400) {
- return 3
+ const severity = Object.values(endpoint.servers).map(
+ (server) => {
+ if (server.status >= 400) {
+ return 3
+ }
+
+ if (server.schemaValid === false || server.snapshotValid === false) {
+ return 2
+ }
+
+ return 0
+ }
+ ).reduce(
+ (total, severity) => total + severity, 0
+ )
+
+ if (endpoint.servers.eu.duration > 3000) {
+ return severity + 1
}
- if (endpoint.schemaValid === false || endpoint.snapshotValid === false) {
- return 2
+ if (endpoint.servers.eu.duration > 1500) {
+ return severity + 0.5
}
- if (endpoint.duration > 3000) {
- return 1
- }
-
- if (endpoint.duration > 1500) {
- return 0.5
- }
-
- return 0
+ return severity
}
diff --git a/worker/src/requestApi.js b/worker/src/requestApi.js
index af86440..0a64e39 100644
--- a/worker/src/requestApi.js
+++ b/worker/src/requestApi.js
@@ -1,11 +1,46 @@
const fetch = require('node-fetch')
+const { Agent } = require('https');
+
+const server = {
+ us: createApiAgent('34.226.105.80'),
+ eu: createApiAgent('52.58.154.210')
+};
+
+function createApiAgent (ip) {
+ // create new https agent
+ const agent = new Agent()
+
+ // save original createConnection function
+ const createConnection = agent.createConnection
+
+ // override createConnection
+ agent.createConnection = function(opts, callback) {
+ // set custom dns lookup resolving to either us or eu datacenter
+ opts.lookup = (_1, _2, cb) => cb(null, ip, 4)
+
+ // call original create connection call
+ return createConnection.call(agent, opts, callback)
+ }
+
+ return agent
+}
async function requestApi (url) {
+ return Promise.all(Object.entries(servers).map(
+ ([server, agent]) => [server, requestApiInternal(url, agent)]
+ )).then(
+ (servers) => servers.reduce(
+ (servers, [server, result]) => ({...servers, [server]: result}), {}
+ )
+ )
+}
+
+async function requestApiInternal (url, agent) {
const start = new Date().getTime()
let response = null
try {
- response = await fetch(url)
+ response = await fetch(url, { agent })
} catch (err) {}
const end = new Date().getTime()
diff --git a/worker/src/runTests.js b/worker/src/runTests.js
index 9b4049c..2e345eb 100644
--- a/worker/src/runTests.js
+++ b/worker/src/runTests.js
@@ -12,8 +12,15 @@ async function runTests () {
results.push(await testEndpoint(endpoints[i]))
}
- let possiblyBroken = results.filter(x => x.schemaValid === false || x.snapshotValid === false)
- let definitelyBroken = results.filter(x => x.status !== 200)
+ let possiblyBroken = results.filter(
+ (endpoint) => Object.values(endpoint.servers).some(
+ (server) => server.schemaValid === false || server.snapshotValid === false
+ )
+ )
+
+ let definitelyBroken = results.filter(
+ (endpoint) => Object.values(endpoint.servers).some((server) => server.status !== 200)
+ )
if (definitelyBroken.length > 0) {
console.log(`❗ ERROR: ${definitelyBroken.length} API endpoint(s)`)
diff --git a/worker/src/testEndpoint.js b/worker/src/testEndpoint.js
index f47afbe..216bfea 100644
--- a/worker/src/testEndpoint.js
+++ b/worker/src/testEndpoint.js
@@ -5,27 +5,20 @@ const matchSnapshot = require('./matchSnapshot')
async function testEndpoint (endpoint) {
const url = generateUrl(endpoint.url)
- const {duration, response} = await requestApi(url)
+ const requests = await requestApi(url)
- const error = response.status >= 400 && response.content && response.content.text
-
- let result = {
+ return {
url,
name: endpoint.name,
- status: response.status,
- duration,
- error
- }
-
- if (result.status !== 200) {
- return result
+ servers: Object.entries(requests)
+ .reduce((a, [server, {response: {status, content}, duration }]) => ({
+ ...a, [server]: {
+ status, duration,
+ ...(endpoint.matchSchema ? matchSchema(endpoint, content) : {}),
+ ...(endpoint.matchSnapshot ? matchSnapshot(endpoint, content) : {})
+ }
+ }), [])
}
-
- return Object.assign(
- result,
- endpoint.matchSchema ? matchSchema(endpoint, response.content) : {},
- endpoint.matchSnapshot ? matchSnapshot(endpoint, response.content) : {}
- )
}
module.exports = testEndpoint