View a markdown version of this page

Leitfaden zum Testen von Plugins - Amazon Inspector

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Leitfaden zum Testen von Plugins

Plugin-Autoren schreiben und testen Lua-Plugins vollständig in Lua — es ist keine Go-Toolchain erforderlich. Die Tests befinden sich zusammen mit dem Plugin unter init_test.lua und werden über den Befehl ausgeführt. inspector-sbomgen plugin test

Allgemeine Informationen zur Plugin-Erstellung finden Sie im. Leitfaden für Plugin-Entwickler Den vollständigen Funktionskatalog (einschließlich der testing.* API) finden Sie unterPlugin-API-Referenz.

-- init_test.lua (next to init.lua) function test_discovers_curl_version() local result = testing.scan_directory("_testdata/include/curl") testing.assert_equals(1, #result.findings) testing.assert_equals("libcurl", result.findings[1].name) testing.assert_equals("8.14.1", result.findings[1].version) end
# Run every test under a plugin directory inspector-sbomgen plugin test --path ./my-plugins # Verbose output — show each test name and result inspector-sbomgen plugin test --path ./my-plugins -v

Schnellstart

1. Erstellen Sie eine Testdatei

Platziere es init_test.lua neben deinem Plugininit.lua:

my-plugin/ ├── discovery/cross-platform/extra-ecosystems/curl/ │ ├── init.lua │ ├── init_test.lua │ └── _testdata/ │ └── include/curl/curlver.h

2. Schreiben Sie Testfunktionen

Jede globale Funktion, die mit beginnt, test_ wird erkannt und ausgeführt:

function test_finds_libcurl() local result = testing.scan_directory("_testdata/include/curl") testing.assert_equals(1, #result.findings) testing.assert_equals("libcurl", result.findings[1].name) end function test_no_findings_for_empty_dir() local result = testing.scan_directory("_testdata/empty") testing.assert_equals(0, #result.findings) end

3. Tests ausführen

inspector-sbomgen plugin test --path ./my-plugin

Verzeichnis-Layout

Struktur des Plugins

Testdateien und Testdaten befinden sich zusammen mit dem Plugin:

my-plugins/ ├── discovery/ │ └── cross-platform/ │ └── extra-ecosystems/ │ └── curl/ │ ├── init.lua # plugin source │ ├── init_test.lua # test file │ └── _testdata/ # test fixtures │ ├── include/curl/curlver.h │ └── binaries/unix/curl ├── collection/ │ └── cross-platform/ │ └── extra-ecosystems/ │ └── curl-installation/ │ ├── init.lua │ └── init_test.lua

Benennung der Testdateien

  • Standard: init_test.lua neben den Plugins init.lua

  • Mehrere Testdateien pro Plugin: Jede passende Datei *_test.lua wird erkannt

  • Beispiele: init_test.lua, parsing_test.lua, discovery_test.lua.

Testdaten: _testdata/

Die Testdaten befinden sich _testdata/ neben dem Plugin. Der führende Unterstrich ist eine Konvention, die Fixtures visuell von der Plugin-Quelle trennt. Der plugin test Befehl wird _testdata/ bei der Suche nach *_test.lua Dateien nicht angezeigt, sodass Fixtures niemals mit Testdateien verwechselt werden.

Testdateien verweisen auf Fixtures mit relativen Pfaden:

local result = testing.scan_directory("_testdata/include/curl")

Pfade werden relativ zu dem Verzeichnis aufgelöst, das die Testdatei enthält.

Die testing.*-API

Funktionen scannen

Jede Scanfunktion erzeugt ein Artefakt, führt die Discovery → Collection-Pipeline des Plugins aus und gibt Ergebnisse zurück. Der Testautor erstellt Artefakte, Event-Busse oder Register niemals manuell.

-- Scan a directory of test fixtures (most common) local result = testing.scan_directory("_testdata/curl") -- Alias for scan_directory (archives use the same backend) local result = testing.scan_archive("_testdata/app.tar.gz") -- Scan as a localhost artifact local result = testing.scan_localhost("_testdata/curl") -- Scan a compiled binary local result = testing.scan_binary("_testdata/binaries/curl") -- Scan a mounted volume local result = testing.scan_volume("_testdata/volume-root") -- Scan a container image tarball local result = testing.scan_container("_testdata/images/alpine.tar")

Jede Scanfunktion:

  • Erzeugt für jeden Anruf ein neues Artefakt (keine Statuslecks zwischen Aufrufen)

  • Lädt nur das Discovery + Collection-Paar des aktuellen Plugins

  • Gibt eine Ergebnistabelle zurück

Ergebnistabelle

result.findings -- array of finding tables result.findings[1].name -- package name (string) result.findings[1].version -- package version (string) result.findings[1].purl -- package URL (string) result.findings[1].component_type -- component type (string) result.findings[1].properties -- table<string, string> result.findings[1].children -- array of nested finding tables (same shape)

Assertionen

-- Equality testing.assert_equals(expected, actual, message?) testing.assert_not_equals(expected, actual, message?) -- Truthiness testing.assert_true(value, message?) testing.assert_false(value, message?) -- Nil checks testing.assert_nil(value, message?) testing.assert_not_nil(value, message?) -- String testing.assert_contains(haystack, needle, message?) testing.assert_matches(string, pattern, message?) -- Tables testing.assert_length(table, expected_length, message?) -- Control flow testing.fail(message) -- immediately fail the current test testing.skip(message) -- skip the current test (not a failure)

sbomgen.*Standard-API

Die vollständige sbomgen.* API (Datei-I/O, Regex, Systeminformationen, Protokollierung usw.) ist in Testdateien verfügbar, genau wie in Produktions-Plugins. sbomgen.*Funktionen, die ein Artefakt benötigen (z. B.sbomgen.read_file()), funktionieren jedoch nur innerhalb eines testing.scan_* Callbacks — sie sind nicht auf der obersten Ebene einer Testfunktion verfügbar.

Ausführen von Tests

# Run all tests under a plugin directory inspector-sbomgen plugin test --path ./my-plugins # Filter by regex pattern inspector-sbomgen plugin test --path ./my-plugins --run curl # Verbose output (show each test name and result) inspector-sbomgen plugin test --path ./my-plugins -v # Stop on the first failing test inspector-sbomgen plugin test --path ./my-plugins --fail-fast

Das --path Flag akzeptiert ein Plugin-Stammverzeichnis (enthält discovery/ and/or collection/) oder ein einzelnes Ökosystemverzeichnis (automatisch erkannt). Der Befehl wird mit einem Wert ungleich Null beendet, wenn ein Test fehlschlägt.

Ausgabeformat

Mit -v druckt jeder Test eine === RUN Zeile und eine Ergebniszeile (--- PASS,--- FAIL, oder--- SKIP). Ohne werden -v nur fehlgeschlagene Tests gedruckt. Am Ende wird eine Übersichtszeile gedruckt:

=== RUN curl/discovery/init_test/test_discovers_libcurl_header --- PASS: curl/discovery/init_test/test_discovers_libcurl_header (0.04s) === RUN curl/discovery/init_test/test_discovers_curl_binary_unix --- PASS: curl/discovery/init_test/test_discovers_curl_binary_unix (0.04s) === RUN curl/discovery/init_test/test_no_findings_for_unrelated_files --- PASS: curl/discovery/init_test/test_no_findings_for_unrelated_files (0.04s) ok 3 tests passed

Plugin-Helfer testen

Die Testdatei wird in dieselbe Lua-VM geladen wie die des init.lua Plugins. Im Plugin definierte globale Funktionen können von Tests aus aufgerufen werden. Um Hilfsfunktionen zu testen, stellen Sie sie als globale Funktionen oder in einer Modultabelle zur Verfügung:

-- init.lua M = {} function M.parse_version(raw) return string.match(raw, "(%d+%.%d+%.%d+)") end function collect(file_path) local ver = M.parse_version(...) -- ... end
-- init_test.lua function test_parse_version_extracts_semver() testing.assert_equals("1.2.3", M.parse_version("curl/1.2.3")) end function test_parse_version_returns_nil_for_garbage() testing.assert_nil(M.parse_version("not-a-version")) end

localIn deklarierte Funktionen init.lua sind für die Testdatei nicht sichtbar. Das ist Standard-Lua-Scoping.

Verhalten und Invarianten

Gemeinsam genutzte VM, gemeinsam genutzter Status

Testfunktionen innerhalb einer einzigen Datei teilen sich eine Lua-VM. Eine in einer test_* Funktion festgelegte globale Variable ist für nachfolgende Funktionen sichtbar. Wenn zwei Funktionen dieselbe globale Definition definieren, überschreibt die zweite die erste. Jeder Test sollte eigenständig sein und nicht vom Status anderer Tests abhängen.

Nicht deterministische Ausführungsreihenfolge

Testfunktionen werden erkannt, indem die globale Tabelle von Lua iteriert wird, die eine Hash-basierte Reihenfolge verwendet. Es kann nicht garantiert werden, dass Tests in der Reihenfolge ausgeführt werden, in der sie definiert sind. Schreiben Sie keine Tests, die von der Ausführungsreihenfolge abhängen.

Neues Artefakt pro Scanaufruf

Jeder Aufruf testing.scan_directory() (oder jede Scanfunktion) erzeugt ein völlig neues Artefakt. Es gibt keinen Status zwischen Scanaufrufen innerhalb eines Tests oder zwischen Tests.

Das Plugin wird geladen

Plugins werden einmal pro Testlauf geladen, nicht einmal pro Testdatei. Der Test-Runner lädt alle Plugins aus dem bereitgestellten Dateisystem und ordnet dann jede Testdatei der entsprechenden Plugin-VM nach Phase, Plattform, Kategorie und Ökosystem zu.

Verhalten der Assertion

Wenn eine Assertion fehlschlägt, wird der Fehler aufgezeichnet, aber die Testfunktion wird weiterhin ausgeführt — nachfolgende Assertionen und Anweisungen werden weiterhin ausgeführt. Wenn mehr als eine Assertion im selben Test fehlschlägt, ist der jüngste Fehler die in der Zusammenfassung gemeldete Meldung. Frühere Fehler werden überschrieben. Um einen Test beim ersten Fehler zu beenden, kehren Sie nach der fehlgeschlagenen Assertion von der Funktion zurück (oder verwenden Sie die Funktion testing.fail() innerhalb einer Bedingung).

Einschränkungen

  • localFunktionen sind nicht testbar. Nur globale Funktionen von init.lua sind für die Testdatei sichtbar. Stellen Sie Helfer über eine Modultabelle zur Verfügung, wenn sie getestet werden müssen.

  • Es werden keine I/O externen Scan-Aufrufe für sbomgen.* Dateien angezeigt. Funktionen wie sbomgen.read_file() benötigen einen Artefaktkontext, der nur innerhalb von testing.scan_* Aufrufen existiert.

  • Keine Lifecycle-Hooks. Es gibt kein before_eachafter_each,setup, oderteardown. Jede Testfunktion verwaltet ihren eigenen Status.

  • Kein Test-Timeout. Eine Testfunktion, die für immer wiederholt wird, lässt den Runner hängen.

  • Keine Berichterstattung. Es gibt keine Möglichkeit zu messen, welche Linien trainiert init.lua wurden.

  • Es gibt keine Benchmarks. Das Testframework unterstützt keine Leistungsbenchmarks.

Verantwortlichkeiten des Entwicklers

Beim Schreiben eines neuen Lua-Plugins

  • Erstelle init_test.lua neben deinem init.lua

  • Erstellen Sie _testdata/ mit minimalen Vorrichtungen, die die Logik Ihres Plugins trainieren

  • Schreiben Sie test_* Funktionen, die Folgendes abdecken: erfolgreiche Erkennung, Versionsextraktion, Grenzfälle und Szenarien ohne Übereinstimmung

  • Führen Sie Tests vor dem Absenden lokal aus

Richtlinien für Testdaten

  • Halten Sie die Fixtures auf ein Minimum — verwenden Sie die kleinste Datei, die das Verhalten trainiert

  • Vermeiden Sie es, große Binärdateien zu speichern, _testdata/ wenn eine kleine Textfixierung ausreichen würde

  • Jedes Plugin _testdata/ sollte eigenständig sein — keine Verweise auf Dateien außerhalb des Plugin-Verzeichnisses