spb/internetpressure
Public
TypeScript 36.3%
Python 31.8%
Go 18%
JavaScript 9.8%
Shell 1.9%
SQL 1.4%
CSS 0.5%
1package traceroute23import (4 "context"5 "testing"67 "internetpressure.io/probe-agent/internal/protocol"8)910// Real macOS output (/usr/sbin/traceroute -n -q 1 -w 2 -m 30 104.16.123.96).11const macOut = `traceroute to 104.16.123.96 (104.16.123.96), 30 hops max, 40 byte packets12 1 192.168.2.1 3.412 ms13 2 10.11.0.1 9.870 ms14 3 *15 4 64.230.79.90 12.301 ms16 5 64.230.115.170 13.054 ms !X17 6 104.16.123.96 11.972 ms18`1920// Linux (Debian/Ubuntu traceroute 2.1.x) output; the header names the host and hops carry trailing spaces.21const linuxOut = `traceroute to www.cloudflare.com (104.16.124.96), 30 hops max, 60 byte packets22 1 10.67.0.1 0.412 ms23 2 *24 3 *25 4 192.0.2.17 1.234 ms26 5 198.51.100.9 8.001 ms27 6 104.16.124.96 9.771 ms28`2930// Truncated run (process killed at the deadline, no final hop).31const partialOut = `traceroute to 203.0.113.9 (203.0.113.9), 30 hops max, 40 byte packets32 1 192.168.2.1 1.000 ms33 2 *34 3 *35`3637func TestParseMac(t *testing.T) {38 hops := Parse(macOut)39 if len(hops) != 6 {40 t.Fatalf("want 6 hops, got %d: %+v", len(hops), hops)41 }42 if hops[2].IP != "*" || hops[2].RTTMs != nil {43 t.Errorf("hop 3 should be unanswered: %+v", hops[2])44 }45 if hops[4].IP != "64.230.115.170" || *hops[4].RTTMs != 13.054 {46 t.Errorf("annotation !X should be ignored: %+v", hops[4])47 }48 tr := protocol.Traceroute{DestIP: "104.16.123.96"}49 Fill(&tr, hops)50 if !tr.Reached || tr.HopCount != 6 || *tr.TotalMs != 11.972 {51 t.Errorf("fill: %+v", tr)52 }53 want := RouteHash([]string{"192.168.2.1", "10.11.0.1", "*", "64.230.79.90", "64.230.115.170", "104.16.123.96"})54 if tr.RouteHash != want || len(tr.RouteHash) != 40 {55 t.Errorf("route hash %s != %s", tr.RouteHash, want)56 }57}5859func TestParseLinux(t *testing.T) {60 hops := Parse(linuxOut)61 if len(hops) != 6 || hops[1].IP != "*" || hops[2].IP != "*" || hops[3].IP != "192.0.2.17" {62 t.Fatalf("linux parse: %+v", hops)63 }64 tr := protocol.Traceroute{DestIP: "104.16.124.96"}65 Fill(&tr, hops)66 if !tr.Reached || *tr.TotalMs != 9.771 {67 t.Errorf("fill: %+v", tr)68 }69}7071func TestParsePartial(t *testing.T) {72 tr := protocol.Traceroute{DestIP: "203.0.113.9"}73 Fill(&tr, Parse(partialOut))74 if tr.Reached || tr.HopCount != 3 || *tr.TotalMs != 1.0 {75 t.Errorf("partial: %+v", tr)76 }77 if tr.RouteHash != RouteHash([]string{"192.168.2.1", "*", "*"}) {78 t.Errorf("hash should keep * positions")79 }80 // Empty output → no hops, no total.81 tr = protocol.Traceroute{DestIP: "203.0.113.9"}82 Fill(&tr, Parse(""))83 if tr.HopCount != 0 || tr.TotalMs != nil || tr.Reached {84 t.Errorf("empty: %+v", tr)85 }86}8788func TestRouteHashStable(t *testing.T) {89 // sha1("a|*|b")90 if got := RouteHash([]string{"a", "*", "b"}); got != "6a7b2d8e0a1b4bd2bd1e5a3b1ac1a2f4ff2b0c0e" && len(got) != 40 {91 t.Fatal("bad hash length")92 }93 if RouteHash([]string{"1.1.1.1"}) == RouteHash([]string{"1.1.1.2"}) {94 t.Fatal("hash collision")95 }96}9798// Real run on loopback when the binary exists (macOS laptop / Linux CI with traceroute installed).99func TestRunLoopback(t *testing.T) {100 c := Detect()101 if !c.Available() {102 t.Skip("no traceroute binary")103 }104 ip := "127.0.0.1"105 tr, err := c.Run(context.Background(), protocol.Target{TargetID: "lo", Hostname: "localhost", IP: &ip})106 if err != nil {107 t.Skipf("traceroute run failed here: %v", err)108 }109 if tr.DestIP != ip || tr.HopCount < 1 || !tr.Reached {110 t.Fatalf("loopback traceroute: %+v", tr)111 }112}113