Skip to content

Commit

Permalink
Add an option to only produce dropped packets.
Browse files Browse the repository at this point in the history
  • Loading branch information
fruffy committed Feb 12, 2024
1 parent 6544bdb commit e8907a7
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 1 deletion.
8 changes: 8 additions & 0 deletions backends/p4tools/modules/testgen/lib/test_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ bool TestBackEnd::run(const FinalState &state) {
}
}

// Don't increase the test count if --dropped-packet-only is enabled and we produce a test
// with an output packet.
if (testgenOptions.droppedPacketOnly) {
if (!executionState->getProperty<bool>("drop")) {
return needsToTerminate(testCount);
}
}

// If assertion mode is active, ignore any test that does not trigger an assertion.
if (testgenOptions.assertionModeEnabled) {
if (!executionState->getProperty<bool>("assertionTriggered")) {
Expand Down
16 changes: 15 additions & 1 deletion backends/p4tools/modules/testgen/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,21 @@ TestgenOptions::TestgenOptions()
}
return true;
},
"Produced tests must have an output packet.");
"Produced tests must have an output packet as outcome.");

registerOption(
"--dropped-packet-only", nullptr,
[this](const char *) {
droppedPacketOnly = true;
if (!selectedBranches.empty()) {
::error(
"--input-branches cannot guarantee --dropped-packet-only."
" Aborting.");
return false;
}
return true;
},
"Produced tests must have a dropped packet as outcome.");

registerOption(
"--path-selection", "pathSelectionPolicy",
Expand Down
3 changes: 3 additions & 0 deletions backends/p4tools/modules/testgen/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class TestgenOptions : public AbstractP4cToolOptions {
/// Enforces the test generation of tests with mandatory output packet.
bool outputPacketOnly = false;

/// Enforces the test generation of tests with mandatory dropped packet.
bool droppedPacketOnly = false;

/// Add conditions defined in assert/assume to the path conditions.
/// Only tests which satisfy these conditions can be generated. This is active by default.
bool enforceAssumptions = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(TESTGEN_SOURCES

set(TESTGEN_GTEST_SOURCES
${TESTGEN_GTEST_SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/test/testgen_api/output_option_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/testgen_api/api_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/test_backend/ptf.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/test_backend/stf.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "test/gtest/helpers.h"

#include "backends/p4tools/modules/testgen/options.h"
#include "backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.h"
#include "backends/p4tools/modules/testgen/testgen.h"

namespace Test {

TEST(P4TestgenOutputOptionTest, GenerateOuputsCorrectly) {
std::stringstream streamTest;
streamTest << R"p4(
header ethernet_t {
bit<48> dst_addr;
bit<48> src_addr;
bit<16> ether_type;
}
struct Headers {
ethernet_t eth_hdr;
}
struct Metadata { }
parser parse(packet_in pkt, out Headers hdr, inout Metadata m, inout standard_metadata_t sm) {
state start {
pkt.extract(hdr.eth_hdr);
transition accept;
}
}
control ingress(inout Headers hdr, inout Metadata meta, inout standard_metadata_t sm) {
apply {
if (hdr.eth_hdr.dst_addr == 0xDEADDEADDEAD && hdr.eth_hdr.src_addr == 0xBEEFBEEFBEEF && hdr.eth_hdr.ether_type == 0xF00D) {
mark_to_drop(sm);
}
}
}
control egress(inout Headers hdr, inout Metadata meta, inout standard_metadata_t sm) {
apply {}
}
control deparse(packet_out pkt, in Headers hdr) {
apply {
pkt.emit(hdr.eth_hdr);
}
}
control verifyChecksum(inout Headers hdr, inout Metadata meta) {
apply {}
}
control computeChecksum(inout Headers hdr, inout Metadata meta) {
apply {}
}
V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), deparse()) main;
)p4";

auto source = P4_SOURCE(P4Headers::V1MODEL, streamTest.str().c_str());
auto compilerOptions = CompilerOptions();
compilerOptions.target = "bmv2";
compilerOptions.arch = "v1model";
auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get();
testgenOptions.testBackend = "PROTOBUF_IR";
testgenOptions.testBaseName = "dummy";
testgenOptions.seed = 1;
testgenOptions.maxTests = 0;
// Create a bespoke packet for the Ethernet extract call.
testgenOptions.minPktSize = 112;
testgenOptions.maxPktSize = 112;

// In this test we only generate tests with dropped packets.
{
testgenOptions.droppedPacketOnly = true;

auto testListOpt =
P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions);

ASSERT_TRUE(testListOpt.has_value());
auto testList = testListOpt.value();
ASSERT_EQ(testList.size(), 1);
const auto *test = testList[0];
const auto *protobufIrTest = test->to<P4Tools::P4Testgen::Bmv2::ProtobufIrTest>();
ASSERT_TRUE(protobufIrTest != nullptr);
EXPECT_THAT(protobufIrTest->getFormattedTest(),
testing::Not(testing::HasSubstr(R"(expected_output_packet)")));
}

// Here we flip the option and only generate tests with forwarded packets.
{
testgenOptions.droppedPacketOnly = false;
testgenOptions.outputPacketOnly = true;

auto testListOpt =
P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions);

ASSERT_TRUE(testListOpt.has_value());
auto testList = testListOpt.value();
ASSERT_EQ(testList.size(), 1);
const auto *test = testList[0];
const auto *protobufIrTest = test->to<P4Tools::P4Testgen::Bmv2::ProtobufIrTest>();
ASSERT_TRUE(protobufIrTest != nullptr);
EXPECT_THAT(protobufIrTest->getFormattedTest(),
testing::HasSubstr(R"(expected_output_packet)"));
}
}

} // namespace Test

0 comments on commit e8907a7

Please sign in to comment.