Add suitable TestCase architecture

This commit is contained in:
Paul Schaub 2023-07-17 16:43:35 +02:00
parent 71dcf000ef
commit dd1bbcd47f
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
39 changed files with 258 additions and 53 deletions

View File

@ -221,9 +221,13 @@ class WotCLI: Callable<Int> {
@JvmStatic
fun main(args: Array<String>): Unit = exitProcess(
CommandLine(WotCLI()).execute(*args)
execute(args)
)
fun execute(args: Array<String>): Int {
return CommandLine(WotCLI()).execute(*args)
}
@JvmStatic
val dateFormat: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd")
}

View File

@ -31,6 +31,8 @@ dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit5:$kotlinVersion"
testImplementation project(":pgpainless-wot-cli")
testFixturesImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testFixturesImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
testFixturesRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"

View File

@ -4,47 +4,17 @@
package org.sequoia_pgp.wot.suite
import org.bouncycastle.util.io.Streams
import org.sequoia_pgp.wot.vectors.BestViaRootVectors
import java.io.ByteArrayOutputStream
import java.io.File
import java.util.concurrent.TimeUnit
import kotlin.test.Test
import kotlin.test.assertEquals
class BestViaRoot : TestCase(BestViaRootVectors()) {
override val tempFilePrefix: String
get() = "best-via-root"
val sq_wot: Pair<String, Array<String>> = "/home/vanitas/Programmierung/sequoia-wot/target/release/sq-wot" to arrayOf()
val pgpainless_wot: Pair<String, Array<String>> = File(
File(System.getProperty("user.dir")).parentFile,
"pgpainless-wot-cli/build/install/pgpainless-wot-cli/bin/pgpainless-wot-cli"
).absolutePath to arrayOf("JAVA_HOME=${System.getProperty("java.home")}")
@Test
fun sq_wot() {
execute(sq_wot.first, sq_wot.second)
execute(pgpainless_wot.first, pgpainless_wot.second)
override fun arguments(): Array<String> {
val v = vectors as BestViaRootVectors
return arrayOf("--keyring", keyRingPath(), "-r", v.aliceFpr.toString(), "--full", "authenticate", v.targetFpr.toString(), v.targetUid)
}
override fun execute(executable: String, env: Array<String>) {
val keyRing = tempKeyRingFile.absolutePath
val v = vectors as BestViaRootVectors
val p = Runtime.getRuntime().exec(
"$executable --keyring=$keyRing -r ${v.aliceFpr} --full authenticate ${v.targetFpr} ${v.targetUid}",
env)
val output = p.inputStream.let {
val bOut = ByteArrayOutputStream()
Streams.pipeAll(it, bOut)
bOut.toString()
}
Streams.pipeAll(p.errorStream, System.err)
p.waitFor(5, TimeUnit.SECONDS)
assertEquals(0, p.exitValue())
assertEquals(
"""[✓] 2AB08C06FC795AC26673B23CAD561ABDCBEBFDF0 <target@example.org>: fully authenticated (100%)
override fun expectedOutput(): Pair<String, Int> {
return """[✓] 2AB08C06FC795AC26673B23CAD561ABDCBEBFDF0 <target@example.org>: fully authenticated (100%)
B95FF5B1D055D26F758FD4E3BF12C4D1D28FDFFB ("<alice@example.org>")
certified the following certificate on 2021-09-27 (expiry: 2026-09-27) as a fully trusted meta-introducer (depth: 10)
6A8B9EC7D0A1B297B5D4A7A1C048DFF96601D9BD ("<bob@example.org>")
@ -53,6 +23,6 @@ class BestViaRoot : TestCase(BestViaRootVectors()) {
certified the following binding on 2021-09-27 (expiry: 2026-09-27) as a fully trusted meta-introducer (depth: 10)
2AB08C06FC795AC26673B23CAD561ABDCBEBFDF0 "<target@example.org>"
""", output)
""" to 0
}
}

View File

@ -4,29 +4,53 @@
package org.sequoia_pgp.wot.suite
import org.bouncycastle.util.io.Streams
import org.junit.jupiter.api.Named
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import org.sequoia_pgp.wot.suite.harness.ExecutableHarness
import org.sequoia_pgp.wot.suite.harness.WotCLIHarness
import org.sequoia_pgp.wot.vectors.ArtifactVectors
import java.io.File
import java.nio.file.Files
import kotlin.io.path.outputStream
import kotlin.test.assertEquals
abstract class TestCase(val vectors: ArtifactVectors) {
abstract val tempFilePrefix: String
val tempFileSuffix = ".pgp"
interface ExecutionCallback {
fun execute(vectors: ArtifactVectors, arguments: Array<String>): Pair<String, Int>
}
val tempKeyRingFile: File
get() {
val path = Files.createTempFile(tempFilePrefix, tempFileSuffix)
@ParameterizedTest
@MethodSource("instances")
fun execute(callback: ExecutionCallback) {
val arguments = arguments()
val expectedOutput = expectedOutput()
val outputStream = path.outputStream()
Streams.pipeAll(vectors.keyRingInputStream(), outputStream)
outputStream.close()
val result = callback.execute(vectors, arguments)
assertEquals(expectedOutput.first, result.first)
assertEquals(expectedOutput.second, result.second)
}
val file = path.toFile()
file.deleteOnExit()
return file
abstract fun arguments(): Array<String>
abstract fun expectedOutput(): Pair<String, Int>
internal fun keyRingPath(): String =
vectors.tempKeyRingFile.absolutePath
companion object {
@JvmStatic
fun instances(): List<Arguments> {
return buildList {
// pgpainless-wot-cli
add(Arguments.of(Named.of("pgpainless-wot-cli", WotCLIHarness().runner())))
// sq-wot, if environment variable "SQ_WOT" points to sq-wot executable
val sqWotExe = System.getenv("SQ_WOT")
if (sqWotExe != null && File(sqWotExe).let { it.exists() && it.isFile }) {
add(Arguments.of(Named.of("sq-wot", ExecutableHarness(sqWotExe, arrayOf()).runner())))
}
}
}
abstract fun execute(executable: String, envp: Array<String>)
}
}

View File

@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: BSD-3-Clause
package org.sequoia_pgp.wot.suite.harness
import org.bouncycastle.util.io.Streams
import org.sequoia_pgp.wot.suite.TestCase
import org.sequoia_pgp.wot.vectors.ArtifactVectors
import java.io.ByteArrayOutputStream
/**
* Harness for a WOT executable (e.g. sq-wot).
* @param executable full path to the executable file
* @param environment set of environment variables in the format 'key=value'
*/
class ExecutableHarness(val executable: String, val environment: Array<String>): Harness() {
override fun runner(): TestCase.ExecutionCallback {
return object: TestCase.ExecutionCallback {
override fun execute(vectors: ArtifactVectors, arguments: Array<String>): Pair<String, Int> {
val command = arrayOf(executable).plus(arguments)
val p = Runtime.getRuntime().exec(command, environment)
val output = p.inputStream.let {
val bOut = ByteArrayOutputStream()
Streams.pipeAll(it, bOut)
bOut.toString()
}
Streams.pipeAll(p.errorStream, System.err)
val exit = p.waitFor()
return output to exit
}
}
}
}

View File

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: BSD-3-Clause
package org.sequoia_pgp.wot.suite.harness
import org.sequoia_pgp.wot.suite.TestCase
/**
* Abstract class to produce [TestCase.ExecutionCallback] instances for WOT CLI implementations.
*/
abstract class Harness {
/**
* Return a [TestCase.ExecutionCallback] which executes a [TestCase] using a custom WOT implementation.
*/
abstract fun runner(): TestCase.ExecutionCallback
}

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: BSD-3-Clause
package org.sequoia_pgp.wot.suite.harness
import org.pgpainless.wot.cli.WotCLI
import org.sequoia_pgp.wot.suite.TestCase
import org.sequoia_pgp.wot.vectors.ArtifactVectors
import java.io.ByteArrayOutputStream
import java.io.PrintStream
/**
* Harness for the [WotCLI] class.
*/
class WotCLIHarness: Harness() {
override fun runner(): TestCase.ExecutionCallback {
return object: TestCase.ExecutionCallback {
override fun execute(vectors: ArtifactVectors, arguments: Array<String>): Pair<String, Int> {
val origStdout = System.out
val bOut = ByteArrayOutputStream()
System.setOut(PrintStream(bOut))
val exitCode = WotCLI.execute(arguments)
System.setOut(origStdout)
return bOut.toString() to exitCode
}
}
}
}

View File

@ -4,20 +4,39 @@
package org.sequoia_pgp.wot.vectors
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import org.pgpainless.policy.Policy
import org.pgpainless.wot.KeyRingCertificateStore
import org.pgpainless.wot.WebOfTrust
import org.pgpainless.wot.network.Network
import org.pgpainless.wot.network.ReferenceTime
import java.io.File
import java.io.InputStream
import java.lang.IllegalArgumentException
import java.nio.file.Files
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
import kotlin.io.path.outputStream
interface ArtifactVectors {
val tempFilePrefix: String
val tempKeyRingFile: File
get() {
val path = Files.createTempFile(tempFilePrefix, ".pgp")
val outputStream = path.outputStream()
Streams.pipeAll(keyRingInputStream(), outputStream)
outputStream.close()
val file = path.toFile()
file.deleteOnExit()
return file
}
private fun parseDate(string: String): Date {
return try {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss z")
@ -48,4 +67,8 @@ interface ArtifactVectors {
fun keyRingInputStream(): InputStream {
return ArtifactVectors::class.java.classLoader.getResourceAsStream(getResourceName())!!
}
}

View File

@ -59,6 +59,9 @@ class BestViaRootVectors: ArtifactVectors {
* Create certifications.
*/
val t1 = parseReferenceTime("2021-09-27 12:52:50 UTC")
override val tempFilePrefix: String
get() = "best-via-root"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/best-via-root.pgp"

View File

@ -62,6 +62,8 @@ class CertExpiredVectors: ArtifactVectors {
* Create certifications (amount = 120).
*/
val t3 = parseReferenceTime("2020-04-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = "cert-expired"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cert-expired.pgp"

View File

@ -52,6 +52,9 @@ class CertRevokedHardVectors: ArtifactVectors {
*/
val t3 = parseReferenceTime("2020-04-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = "cert-revoked-hard"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cert-revoked-hard.pgp"
}

View File

@ -147,6 +147,8 @@ class CertRevokedSoftVectors: ArtifactVectors {
*/
val t3 = parseReferenceTime("2020-04-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = "cert-revoked-soft"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cert-revoked-soft.pgp"

View File

@ -95,6 +95,9 @@ class CertificationLivenessVectors: ArtifactVectors {
*/
val t3 = parseReferenceTime("2020-04-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = ""
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/certification-liveness.pgp"
}

View File

@ -41,6 +41,9 @@ class CertificationNetworkVectors: ArtifactVectors {
*/
val t0 = parseReferenceTime("2023-01-19 12:00:00 UTC")
override val tempFilePrefix: String
get() = "certification-network"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/certification-network.pgp"
}

View File

@ -77,6 +77,9 @@ class CertificationRevokedVectors: ArtifactVectors {
*/
val t3 = parseReferenceTime("2020-04-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = "certification-revoked"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/certification-revoked.pgp"
}

View File

@ -6,6 +6,9 @@ package org.sequoia_pgp.wot.vectors
class CliquesLocalOptima2Vectors: CliquesVectors() {
override val tempFilePrefix: String
get() = "cliques-local-optima-2"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cliques-local-optima-2.pgp"
}

View File

@ -6,6 +6,9 @@ package org.sequoia_pgp.wot.vectors
class CliquesLocalOptimaVectors: CliquesVectors() {
override val tempFilePrefix: String
get() = "cliques-local-optima"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cliques-local-optima.pgp"
}

View File

@ -110,6 +110,9 @@ open class CliquesVectors: ArtifactVectors {
*/
val t0 = parseReferenceTime("2021-02-14 00:00:00 UTC")
override val tempFilePrefix: String
get() = "cliques"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cliques.pgp"
}

View File

@ -54,6 +54,9 @@ class CycleVectors: ArtifactVectors {
*/
val t0 = parseReferenceTime("2021-10-01 12:00:00 UTC")
override val tempFilePrefix: String
get() = "cycle"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/cycle.pgp"
}

View File

@ -58,6 +58,9 @@ class GpgTrustrootsVectors: ArtifactVectors {
*/
val t1 = parseReferenceTime("2020-02-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = "gpg-trustroots"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/gpg-trustroots.pgp"
}

View File

@ -285,6 +285,9 @@ class InfinityAndBeyondVectors: ArtifactVectors {
*/
val t0 = parseReferenceTime("2022-01-28 15:18:00 UTC")
override val tempFilePrefix: String
get() = "infinity-and-beyond"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/infinity-and-beyond.pgp"
}

View File

@ -28,6 +28,9 @@ class IsolatedRootVectors: ArtifactVectors {
*/
val t1 = parseReferenceTime("2020-02-01 00:00:00 UTC")
override val tempFilePrefix: String
get() = "isolated-root"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/isolated-root.pgp"
}

View File

@ -83,6 +83,9 @@ class LocalOptimaVectors: ArtifactVectors {
*/
val t0 = parseReferenceTime("2021-10-01 10:27:00 UTC")
override val tempFilePrefix: String
get() = "local-optima"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/local-optima.pgp"
}

View File

@ -48,6 +48,9 @@ class MultipleCertifications1Vectors: ArtifactVectors {
*/
val t0 = parseReferenceTime("2021-10-06 12:20:00 UTC")
override val tempFilePrefix: String
get() = "multiple-certifications-1"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/multiple-certifications-1.pgp"
}

View File

@ -55,6 +55,9 @@ class MultipleUserIds1Vectors: ArtifactVectors {
val daveUid = "<dave@other.org>"
// Certified by: 9CA36907B46FE7B6B9EE9601E78064C12B6D7902
override val tempFilePrefix: String
get() = "multiple-userids-1"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/multiple-userids-1.pgp"
}

View File

@ -54,6 +54,9 @@ class MultipleUserIds2Vectors: ArtifactVectors {
val frankUid = "<frank@other.org>"
// Certified by: 5528B9E5DAFC519ED2E37F0377B332E4111456CB
override val tempFilePrefix: String
get() = "multiple-userids-2"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/multiple-userids-2.pgp"
}

View File

@ -55,6 +55,9 @@ class MultipleUserIds3Vectors: ArtifactVectors {
// Certified by: 9FB1D2F41AB5C478378E728C8DD5A5A434EEAAB8
// Certified by: 296935FAE420CCCF3AEDCEC9232BFF0AE9A7E5DB
override val tempFilePrefix: String
get() = "multiple-userids-3"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/multiple-userids-3.pgp"
}

View File

@ -21,6 +21,9 @@ class OverrideVectors: ArtifactVectors {
// TODO: Extract fingerprints and UIDs
override val tempFilePrefix: String
get() = "override"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/override.pgp"
}

View File

@ -23,6 +23,9 @@ class PunyCodeVectors: ArtifactVectors {
// TODO: Extract fingerprints and UIDs
override val tempFilePrefix: String
get() = "puny-code"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/puny-code.pgp"
}

View File

@ -50,6 +50,9 @@ class Regex1Vectors: ArtifactVectors {
val frankUid = "<frank@other.org>"
// Certified by: 319810FAD46CBE96DAD7F1F5B014902592999B21
override val tempFilePrefix: String
get() = "regex-1"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/regex-1.pgp"
}

View File

@ -42,6 +42,9 @@ class Regex2Vectors: ArtifactVectors {
val edUid = "<ed@example.org>"
// Certified by: 58077E659732526C1B8BF9837EFC0EDE07B506A8
override val tempFilePrefix: String
get() = "regex-2"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/regex-2.pgp"
}

View File

@ -53,6 +53,9 @@ class Regex3Vectors: ArtifactVectors {
val henryUid = "<henry@their.org>"
// Certified by: A75DC1A1EDA5282F3A7381B51824E46BBCC801F0
override val tempFilePrefix: String
get() = "regex-3"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/regex-3.pgp"
}

View File

@ -79,6 +79,9 @@ class RoundaboutVectors: ArtifactVectors {
val jennyFpr = Fingerprint("AE40578962411356F9609CAA9C2447E61FFDBB15")
val jennyUid = "<jenny@example.org>"
override val tempFilePrefix: String
get() = "roundabout"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/roundabout.pgp"
}

View File

@ -40,6 +40,9 @@ class SelfSignedVectors: ArtifactVectors {
val daveUid = "<dave@example.org>"
// Certified by: 830230061426EE99A0455E6ADA869CF879A5630D
override val tempFilePrefix: String
get() = "self-signed"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/self-signed.pgp"
}

View File

@ -11,6 +11,9 @@ class Sha1Vectors: ArtifactVectors {
// TODO: Extract fingerprints and UIDs
override val tempFilePrefix: String
get() = "sha1"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/sha1.pgp"
}

View File

@ -50,6 +50,9 @@ class SimpleVectors: ArtifactVectors {
val frankFpr = Fingerprint("2693237D2CED0BB68F118D78DC86A97CD2C819D9")
val frankUid = "<frank@example.org>"
override val tempFilePrefix: String
get() = "simple"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/simple.pgp"
}

View File

@ -8,6 +8,9 @@ class TrivialVectors: ArtifactVectors {
// TODO: Extract fingerprints and UIDs
override val tempFilePrefix: String
get() = "trivial"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/trivial.pgp"
}

View File

@ -54,6 +54,9 @@ class UserIdRevokedVectors: ArtifactVectors {
// Certified by: EA479A77CD074458EAFE56B4861BF42FF490C581
// Certified by: EA479A77CD074458EAFE56B4861BF42FF490C581
override val tempFilePrefix: String
get() = "userid-revoked"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/userid-revoked.pgp"
}

View File

@ -39,6 +39,9 @@ class ZeroTrustVectors: ArtifactVectors {
val carolUid = "<carol@example.org>"
// Certified by: A1042B157AFA71F005208D645915549D8D21A97B
override val tempFilePrefix: String
get() = "zero-trust"
override fun getResourceName(): String {
return "org/sequoia_pgp/wot/vectors/zero-trust.pgp"
}