Skip to content

Commit

Permalink
added test and workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
Don Johnson committed Dec 27, 2024
1 parent 762224e commit b06b55e
Show file tree
Hide file tree
Showing 8 changed files with 395 additions and 4 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,5 @@ jobs:

- name: Build
run: go build ./...

# Uncomment for tests if desired:
# - name: Test
# run: go test ./... -v
- name: Test
run: go test ./... -v
62 changes: 62 additions & 0 deletions pkg/capture/capture_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package capture_test

import (
"os"
"testing"

"osi-replay/pkg/capture"
"osi-replay/pkg/common"
)

// Test invalid interface name
func TestCapturePackets_InvalidInterface(t *testing.T) {
logger := common.NewLogger("test-capture")
cfg := &common.CaptureConfig{
InterfaceName: "does-not-exist",
Promiscuous: true,
SnapLen: 65535,
PcapFile: "test_capture.pcap",
}

err := capture.CapturePackets(cfg, logger)
if err == nil {
t.Fatalf("Expected an error for a non-existent interface, got nil")
}
// Clean up if the file got created
_ = os.Remove("test_capture.pcap")
}

// Test file creation error by providing an invalid path
func TestCapturePackets_FileCreationError(t *testing.T) {
logger := common.NewLogger("test-capture")
cfg := &common.CaptureConfig{
InterfaceName: "lo", // or "eth0" depending on your system
Promiscuous: true,
SnapLen: 65535,
PcapFile: "/invalid-dir/test_capture.pcap",
}

err := capture.CapturePackets(cfg, logger)
if err == nil {
t.Fatal("Expected an error due to invalid file path, got nil")
}
}

// Optional real capture test (skipped by default)
func TestCapturePackets_Simple(t *testing.T) {
t.Skip("Skipping real capture test in CI or restricted environment")

logger := common.NewLogger("test-capture")
cfg := &common.CaptureConfig{
InterfaceName: "lo", // or another valid interface
Promiscuous: true,
SnapLen: 65535,
PcapFile: "test_capture.pcap",
}

err := capture.CapturePackets(cfg, logger)
if err != nil {
t.Errorf("Unexpected error capturing on interface 'lo': %v", err)
}
_ = os.Remove("test_capture.pcap")
}
35 changes: 35 additions & 0 deletions pkg/common/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package common_test

import (
"os"
"path/filepath"
"testing"

"osi-replay/pkg/common"
)

func TestEnsureFileWritable_NewFile(t *testing.T) {
testFile := filepath.Join(os.TempDir(), "ensure_writable_test.file")
os.Remove(testFile) // ensure a clean state

err := common.EnsureFileWritable(testFile)
if err != nil {
t.Fatalf("Expected no error creating test file, got: %v", err)
}
// Clean up
os.Remove(testFile)
}

func TestEnsureFileWritable_ExistingFile(t *testing.T) {
testFile := filepath.Join(os.TempDir(), "ensure_writable_test.file")
// Pre-create the file
f, _ := os.Create(testFile)
f.Close()

err := common.EnsureFileWritable(testFile)
if err != nil {
t.Errorf("Expected no error for existing file, got: %v", err)
}
// Clean up
os.Remove(testFile)
}
50 changes: 50 additions & 0 deletions pkg/replay/replay_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package replay_test

import (
"os"
"path/filepath"
"testing"

"osi-replay/pkg/common"
"osi-replay/pkg/replay"
)

// Test missing PCAP file
func TestReplayPackets_NoSuchFile(t *testing.T) {
logger := common.NewLogger("test-replay")
cfg := &common.CaptureConfig{
InterfaceName: "eth999", // likely non-existent
SnapLen: 65535,
Promiscuous: false,
PcapFile: "no_such_file.pcap",
}

err := replay.ReplayPackets(cfg, logger)
if err == nil {
t.Errorf("Expected error when PCAP file does not exist")
}
}

// Optional real replay test (skipped by default)
func TestReplayPackets_Basic(t *testing.T) {
t.Skip("Skipping real replay test in CI or restricted environment")

// Provide a small real PCAP in a testdata/ folder:
pcapFile := filepath.Join("testdata", "small_test.pcap")
if _, err := os.Stat(pcapFile); os.IsNotExist(err) {
t.Skipf("Skipping: testdata file %v not found", pcapFile)
}

logger := common.NewLogger("test-replay")
cfg := &common.CaptureConfig{
InterfaceName: "lo", // or eth0, if valid
SnapLen: 65535,
Promiscuous: false,
PcapFile: pcapFile,
}

err := replay.ReplayPackets(cfg, logger)
if err != nil {
t.Errorf("Unexpected error replaying pcap: %v", err)
}
}
81 changes: 81 additions & 0 deletions pkg/rewriter/rewriter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package rewriter_test

import (
"net"
"testing"

"github.com/google/gopacket"
"github.com/google/gopacket/layers"

"osi-replay/pkg/rewriter"
)

func TestRewritePacket_Basic(t *testing.T) {
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

eth := &layers.Ethernet{
SrcMAC: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
DstMAC: net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
EthernetType: layers.EthernetTypeIPv4,
}
ip4 := &layers.IPv4{
SrcIP: net.ParseIP("192.168.1.100"),
DstIP: net.ParseIP("192.168.1.200"),
Version: 4,
IHL: 5,
Protocol: layers.IPProtocolTCP,
}

if err := gopacket.SerializeLayers(buf, opts, eth, ip4); err != nil {
t.Fatalf("Error serializing layers: %v", err)
}

original := buf.Bytes()

cfg := &rewriter.RewriteConfig{
IPMapSrc: map[string]string{"192.168.1.100": "10.0.0.5"},
IPMapDst: map[string]string{"192.168.1.200": "10.0.0.10"},
MACMapSrc: map[string]string{
"00:11:22:33:44:55": "66:77:88:99:aa:bb",
},
MACMapDst: map[string]string{
"aa:bb:cc:dd:ee:ff": "11:22:33:44:55:66",
},
}

newData, err := rewriter.RewritePacket(original, cfg)
if err != nil {
t.Fatalf("RewritePacket returned error: %v", err)
}

newPacket := gopacket.NewPacket(newData, layers.LayerTypeEthernet, gopacket.Default)
ethLayer := newPacket.Layer(layers.LayerTypeEthernet)
ipLayer := newPacket.Layer(layers.LayerTypeIPv4)

if ethLayer == nil || ipLayer == nil {
t.Fatalf("Missing expected layers in rewritten packet")
}

ethOut, _ := ethLayer.(*layers.Ethernet)
ip4Out, _ := ipLayer.(*layers.IPv4)

// Verify MAC addresses
if ethOut.SrcMAC.String() != "66:77:88:99:aa:bb" {
t.Errorf("Expected MAC src 66:77:88:99:aa:bb, got %s", ethOut.SrcMAC)
}
if ethOut.DstMAC.String() != "11:22:33:44:55:66" {
t.Errorf("Expected MAC dst 11:22:33:44:55:66, got %s", ethOut.DstMAC)
}

// Verify IP addresses
if ip4Out.SrcIP.String() != "10.0.0.5" {
t.Errorf("Expected IP src 10.0.0.5, got %s", ip4Out.SrcIP)
}
if ip4Out.DstIP.String() != "10.0.0.10" {
t.Errorf("Expected IP dst 10.0.0.10, got %s", ip4Out.DstIP)
}
}
63 changes: 63 additions & 0 deletions pkg/sanitizer/sanitizer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package sanitizer_test

import (
"net"
"testing"

"github.com/google/gopacket"
"github.com/google/gopacket/layers"

"osi-replay/pkg/sanitizer"
)

func TestSanitizePacket_BlockedIP(t *testing.T) {
// Synthetic IPv4 packet with src=10.0.0.1
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ip := &layers.IPv4{
Version: 4,
IHL: 5,
SrcIP: net.ParseIP("10.0.0.1"),
DstIP: net.ParseIP("192.168.1.10"),
}

if err := gopacket.SerializeLayers(buf, opts, ip); err != nil {
t.Fatalf("Error serializing IP packet: %v", err)
}

packet := gopacket.NewPacket(buf.Bytes(), layers.LayerTypeIPv4, gopacket.Default)
newPacket, keep := sanitizer.SanitizePacket(packet)
if keep || newPacket != nil {
t.Errorf("Expected packet to be dropped for blocked IP 10.0.0.1")
}
}

func TestSanitizePacket_AllowedIP(t *testing.T) {
// Synthetic IPv4 packet with src=192.168.100.5, not in blockedIPs
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ip := &layers.IPv4{
Version: 4,
IHL: 5,
SrcIP: net.ParseIP("192.168.100.5"),
DstIP: net.ParseIP("192.168.100.10"),
}

if err := gopacket.SerializeLayers(buf, opts, ip); err != nil {
t.Fatalf("Error serializing IP packet: %v", err)
}

packet := gopacket.NewPacket(buf.Bytes(), layers.LayerTypeIPv4, gopacket.Default)
newPacket, keep := sanitizer.SanitizePacket(packet)
if !keep || newPacket == nil {
t.Errorf("Expected packet to pass sanitizer, but was dropped")
}
}
46 changes: 46 additions & 0 deletions pkg/transform/transform_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package transform_test

import (
"os"
"path/filepath"
"testing"

"osi-replay/pkg/common"
"osi-replay/pkg/transform"
)

// Test error on nonexistent input file
func TestRun_NoSuchFile(t *testing.T) {
logger := common.NewLogger("test-transform")
err := transform.Run("no_such_file.pcap", "out.pcap", logger)
if err == nil {
t.Errorf("Expected error with nonexistent input file, got nil")
}
_ = os.Remove("out.pcap")
}

// Optional real transform test
func TestRun_Basic(t *testing.T) {
t.Skip("Skipping real transform test if no testdata pcap available")

pcapIn := filepath.Join("testdata", "example_in.pcap")
pcapOut := filepath.Join("testdata", "example_out.pcap")

if _, err := os.Stat(pcapIn); os.IsNotExist(err) {
t.Skipf("Skipping test, no input pcap at %s", pcapIn)
}

logger := common.NewLogger("test-transform")
_ = os.Remove(pcapOut)

err := transform.Run(pcapIn, pcapOut, logger)
if err != nil {
t.Errorf("Unexpected error transforming pcap: %v", err)
}

// Check if output got created
if _, err := os.Stat(pcapOut); os.IsNotExist(err) {
t.Errorf("Output file %s not created", pcapOut)
}
_ = os.Remove(pcapOut)
}
Loading

0 comments on commit b06b55e

Please sign in to comment.