da34cfe6c9
This pull request introduces a set of Node.js scripts for performing A/B comparison of websteps and webconnectivity as described in https://github.com/ooni/probe/issues/1805. Rather than using Jafar, I ended up using `miniooni`'s `--censor` command line flag introduced in [v3.12.0-alpha.1](https://github.com/ooni/probe-cli/releases/tag/v3.12.0-alpha.1). The main reason for doing so is that it's simpler to run tests without requiring root access and Linux _and_ Docker (e.g., I did not develop part of this diff using Linux). Additionally, I choose to use Node.js rather than extending the existing Python framework for QA, because I found Node.js easier when working with JSON data.
197 lines
7.3 KiB
JavaScript
197 lines
7.3 KiB
JavaScript
// This file contains code for analysing results.
|
|
|
|
import { type } from "os"
|
|
|
|
// checkAnnotations checks whether we have annotations.
|
|
function checkAnnotations(report) {
|
|
let result = true
|
|
|
|
const isObject = typeof (report.annotations) === "object"
|
|
console.log(`checking whether annotations is an object... ${isObject}`)
|
|
result = result && isObject
|
|
|
|
const hasArchitecture = typeof (report.annotations.architecture) === "string"
|
|
console.log(`checking whether annotations contains architecture... ${hasArchitecture}`)
|
|
result = result && hasArchitecture
|
|
|
|
const hasEngineName = typeof (report.annotations.engine_name) === "string"
|
|
console.log(`checking whether annotations contains engine_name... ${hasEngineName}`)
|
|
result = result && hasEngineName
|
|
|
|
const hasEngineVersion = typeof (report.annotations.engine_version) === "string"
|
|
console.log(`checking whether annotations contains engine_version... ${hasEngineVersion}`)
|
|
result = result && hasEngineVersion
|
|
|
|
const hasPlatform = typeof (report.annotations.platform) === "string"
|
|
console.log(`checking whether annotations contains platform... ${hasPlatform}`)
|
|
result = result && hasPlatform
|
|
|
|
return result
|
|
}
|
|
|
|
// checkDataFormatVersion checks whether we have data_format_version.
|
|
function checkDataFormatVersion(report) {
|
|
const result = report.data_format_version === "0.2.0"
|
|
console.log(`checking whether we have the right data format version... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkExtensions ensures that extensions exists and has the right type.
|
|
function checkExtensions(report) {
|
|
const result = typeof (report.extensions) === "object"
|
|
console.log(`checking whether report.extensions is an object... ${result}`)
|
|
// Quirk: some experiments (e.g. web_connectivity) don't include
|
|
// an extensions object, and we don't want to fail here.
|
|
return true
|
|
}
|
|
|
|
// checkInput ensures that the input is correct.
|
|
function checkInput(testCase, report) {
|
|
const result = testCase.input === report.input
|
|
console.log(`checking whether input is correct... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkExperimentName ensures that the experimentName is correctly
|
|
// set in the output report file.
|
|
function checkExperimentName(name, report) {
|
|
const result = report.test_name === name
|
|
console.log(`checking whether the experiment name is correct... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkStartTime ensures that a given start time is in the correct format.
|
|
function checkStartTime(report, key) {
|
|
const value = report[key]
|
|
let result = typeof (value) === "string"
|
|
console.log(`checking whether ${key} is a string... ${result}`)
|
|
result = result && value.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/) !== null
|
|
console.log(`checking whether ${key} matches the date regexp... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkASN ensures that an ASN field is correct.
|
|
function checkASN(report, key) {
|
|
const value = report[key]
|
|
let result = typeof (value) === "string"
|
|
console.log(`checking whether ${key} is a string... ${result}`)
|
|
result = result && value.match(/^AS[0-9]+$/) !== null
|
|
console.log(`checking whether ${key} matches the ASN regexp... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkProbeCC ensures that the probe_cc field is correct.
|
|
function checkProbeCC(report) {
|
|
const value = report["probe_cc"]
|
|
let result = typeof (value) === "string"
|
|
console.log(`checking whether probe_cc is a string... ${result}`)
|
|
result = result && value.match(/^[A-Z]{2}$/) !== null
|
|
console.log(`checking whether probe_cc matches the CC regexp... ${result}`)
|
|
return result
|
|
|
|
}
|
|
|
|
// checkProbeIP ensures that the probe_ip field is correct.
|
|
function checkProbeIP(report) {
|
|
const result = report.probe_ip === "127.0.0.1"
|
|
console.log(`checking whether probe_ip is correct... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkReportID ensures that the report_id field is correct.
|
|
function checkReportID(report) {
|
|
const result = report.report_id === "" // note: we don't submit
|
|
console.log(`checking whether report_id is correct... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkString ensures that a field is a string.
|
|
function checkString(report, key) {
|
|
const value = report[key]
|
|
const result = typeof(value) === "string"
|
|
console.log(`checking whether ${key} is a string... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkNetworkName ensures that an xxx_network_name field is correct.
|
|
function checkNetworkName(report, key) {
|
|
return checkString(report, key)
|
|
}
|
|
|
|
// checkResolverIP ensures that the resolver_ip field is correct.
|
|
function checkResolverIP(report) {
|
|
return checkString(report, "resolver_ip")
|
|
}
|
|
|
|
// checkSoftwareName ensures that the software_name field is correct.
|
|
function checkSoftwareName(report) {
|
|
return checkString(report, "software_name")
|
|
}
|
|
|
|
// checkSoftwareVersion ensures that the software_version field is correct.
|
|
function checkSoftwareVersion(report) {
|
|
return checkString(report, "software_version")
|
|
}
|
|
|
|
// checkTestRuntime ensures that the test_runtime field is correct.
|
|
function checkTestRuntime(report) {
|
|
const result = typeof(report.test_runtime) === "number"
|
|
console.log(`checking whether test_runtime is a number... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkTestVersion ensures that the test_version field is correct.
|
|
function checkTestVersion(report) {
|
|
return checkString(report, "test_version")
|
|
}
|
|
|
|
// checkTestKeys ensures that test_keys is an object.
|
|
function checkTestKeys(report) {
|
|
const result = typeof(report.test_keys) === "object"
|
|
console.log(`checking whether test_keys is an object... ${result}`)
|
|
return result
|
|
}
|
|
|
|
// checkMeasurement is a function that invokes a standard set of checks
|
|
// to validate the top-level test keys of a result.
|
|
//
|
|
// This function helps to implement per-experiment checkers.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// - testCase is the current test case
|
|
//
|
|
// - name is the name of the current experiment
|
|
//
|
|
// - report is the JSON measurement
|
|
//
|
|
// - extraChecks is the optional callback to perform extra checks
|
|
// that takes in input the report's test keys.
|
|
export function checkMeasurement(testCase, name, report, extraChecks) {
|
|
let result = true
|
|
result = result && checkAnnotations(report)
|
|
result = result && checkDataFormatVersion(report)
|
|
result = result && checkExtensions(report)
|
|
result = result && checkInput(testCase, report)
|
|
result = result && checkStartTime(report, "measurement_start_time")
|
|
result = result && checkASN(report, "probe_asn")
|
|
result = result && checkProbeCC(report)
|
|
result = result && checkProbeIP(report)
|
|
result = result && checkNetworkName(report, "probe_network_name")
|
|
result = result && checkReportID(report)
|
|
result = result && checkASN(report, "resolver_asn")
|
|
result = result && checkResolverIP(report)
|
|
result = result && checkNetworkName(report, "resolver_network_name")
|
|
result = result && checkSoftwareName(report)
|
|
result = result && checkSoftwareVersion(report)
|
|
result = result && checkExperimentName(name, report)
|
|
result = result && checkTestRuntime(report)
|
|
result = result && checkStartTime(report, "test_start_time")
|
|
result = result && checkTestVersion(report)
|
|
result = result && checkTestKeys(report)
|
|
if (typeof extraChecks === "function") {
|
|
result = result && extraChecks(report.test_keys)
|
|
}
|
|
return result
|
|
}
|