1- //go:build integration
2-
31// Integration tests for Anubis, using Playwright.
42//
53// These tests require an already running Anubis and Playwright server.
1614package test
1715
1816import (
19- "context"
2017 "flag"
2118 "fmt"
2219 "net/http"
20+ "net/http/httptest"
2321 "net/url"
2422 "os"
23+ "os/exec"
2524 "testing"
2625 "time"
2726
27+ "github.com/TecharoHQ/anubis"
28+ libanubis "github.com/TecharoHQ/anubis/lib"
2829 "github.com/playwright-community/playwright-go"
2930)
3031
3132var (
32- anubisServer = flag .String ("anubis" , "http://localhost:8923" , "Anubis server URL" )
3333 serverBindAddr = flag .String ("bind" , "localhost:3923" , "test server bind address" )
34+ playwrightPort = flag .Int ("playwright-port" , 3000 , "Playwright port" )
3435 playwrightServer = flag .String ("playwright" , "ws://localhost:3000" , "Playwright server URL" )
3536 playwrightMaxTime = flag .Duration ("playwright-max-time" , 5 * time .Second , "maximum time for Playwright requests" )
3637 playwrightMaxHardTime = flag .Duration ("playwright-max-hard-time" , 5 * time .Minute , "maximum time for hard Playwright requests" )
3738
3839 testCases = []testCase {
39- {name : "firefox" , action : actionChallenge , realIP : placeholderIP , userAgent : "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0" },
40- {name : "headlessChrome" , action : actionDeny , realIP : placeholderIP , userAgent : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/120.0.6099.28 Safari/537.36" },
41- {name : "kagiBadIP" , action : actionChallenge , isHard : true , realIP : placeholderIP , userAgent : "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)" },
42- {name : "kagiGoodIP" , action : actionAllow , realIP : "216.18.205.234" , userAgent : "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)" },
43- {name : "unknownAgent" , action : actionAllow , realIP : placeholderIP , userAgent : "AnubisTest/0" },
40+ {
41+ name : "firefox" ,
42+ action : actionChallenge ,
43+ realIP : placeholderIP ,
44+ userAgent : "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0" ,
45+ },
46+ {
47+ name : "headlessChrome" ,
48+ action : actionDeny ,
49+ realIP : placeholderIP ,
50+ userAgent : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/120.0.6099.28 Safari/537.36" ,
51+ },
52+ {
53+ name : "kagiBadIP" ,
54+ action : actionChallenge ,
55+ isHard : true ,
56+ realIP : placeholderIP ,
57+ userAgent : "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)" ,
58+ },
59+ {
60+ name : "kagiGoodIP" ,
61+ action : actionAllow ,
62+ realIP : "216.18.205.234" ,
63+ userAgent : "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)" ,
64+ },
65+ {
66+ name : "unknownAgent" ,
67+ action : actionAllow ,
68+ realIP : placeholderIP ,
69+ userAgent : "AnubisTest/0" ,
70+ },
4471 }
4572)
4673
@@ -49,7 +76,8 @@ const (
4976 actionDeny action = "DENY"
5077 actionChallenge action = "CHALLENGE"
5178
52- placeholderIP = "fd11:5ee:bad:c0de::"
79+ placeholderIP = "fd11:5ee:bad:c0de::"
80+ playwrightVersion = "1.50.1"
5381)
5482
5583type action string
@@ -61,9 +89,86 @@ type testCase struct {
6189 realIP , userAgent string
6290}
6391
92+ func doesNPXExist (t * testing.T ) {
93+ t .Helper ()
94+
95+ if _ , err := exec .LookPath ("npx" ); err != nil {
96+ t .Skipf ("npx not found in PATH, skipping integration smoke testing: %v" , err )
97+ }
98+ }
99+
100+ func run (t * testing.T , command string ) string {
101+ t .Helper ()
102+
103+ shPath , err := exec .LookPath ("sh" )
104+ if err != nil {
105+ t .Fatalf ("[unexpected] %v" , err )
106+ }
107+
108+ t .Logf ("running command: %s" , command )
109+
110+ cmd := exec .Command (shPath , "-c" , command )
111+ cmd .Stdin = nil
112+ cmd .Stderr = os .Stderr
113+ output , err := cmd .Output ()
114+ if err != nil {
115+ t .Fatalf ("can't run command: %v" , err )
116+ }
117+
118+ return string (output )
119+ }
120+
121+ func daemonize (t * testing.T , command string ) {
122+ t .Helper ()
123+
124+ shPath , err := exec .LookPath ("sh" )
125+ if err != nil {
126+ t .Fatalf ("[unexpected] %v" , err )
127+ }
128+
129+ t .Logf ("daemonizing command: %s" , command )
130+
131+ cmd := exec .Command (shPath , "-c" , command )
132+ cmd .Stdin = nil
133+ cmd .Stderr = os .Stderr
134+ cmd .Stdout = os .Stdout
135+
136+ if err := cmd .Start (); err != nil {
137+ t .Fatalf ("can't daemonize command: %v" , err )
138+ }
139+
140+ t .Cleanup (func () {
141+ cmd .Process .Kill ()
142+ })
143+ }
144+
145+ func startPlaywright (t * testing.T ) {
146+ t .Helper ()
147+
148+ run (t , fmt .Sprintf ("npx --yes playwright@%s install" , playwrightVersion ))
149+ daemonize (t , fmt .Sprintf ("npx --yes playwright@%s run-server --port %d" , playwrightVersion , * playwrightPort ))
150+
151+ for true {
152+ if _ , err := http .Get (fmt .Sprintf ("http://localhost:%d" , * playwrightPort )); err != nil {
153+ time .Sleep (250 * time .Millisecond )
154+ continue
155+ }
156+ break
157+ }
158+ }
159+
64160func TestPlaywrightBrowser (t * testing.T ) {
161+ if os .Getenv ("DONT_USE_NETWORK" ) != "" {
162+ t .Skip ("test requires network egress" )
163+ return
164+ }
165+
166+ doesNPXExist (t )
167+ startPlaywright (t )
168+
65169 pw := setupPlaywright (t )
66- spawnTestServer (t )
170+ anubisURL := spawnAnubis (t )
171+
67172 browsers := []playwright.BrowserType {pw .Chromium , pw .Firefox , pw .WebKit }
68173
69174 for _ , typ := range browsers {
@@ -75,7 +180,7 @@ func TestPlaywrightBrowser(t *testing.T) {
75180 t .Skip ("skipping hard challenge with deadline" )
76181 }
77182
78- perfomedAction := executeTestCase (t , tc , typ )
183+ perfomedAction := executeTestCase (t , tc , typ , anubisURL )
79184
80185 if perfomedAction != tc .action {
81186 t .Errorf ("unexpected test result, expected %s, got %s" , tc .action , perfomedAction )
@@ -97,7 +202,7 @@ func buildBrowserConnect(name string) string {
97202 return u .String ()
98203}
99204
100- func executeTestCase (t * testing.T , tc testCase , typ playwright.BrowserType ) action {
205+ func executeTestCase (t * testing.T , tc testCase , typ playwright.BrowserType , anubisURL string ) action {
101206 deadline , _ := t .Deadline ()
102207
103208 browser , err := typ .Connect (buildBrowserConnect (typ .Name ()), playwright.BrowserTypeConnectOptions {
@@ -129,7 +234,7 @@ func executeTestCase(t *testing.T, tc testCase, typ playwright.BrowserType) acti
129234 // Attempt challenge.
130235
131236 start := time .Now ()
132- _ , err = page .Goto (* anubisServer , playwright.PageGotoOptions {
237+ _ , err = page .Goto (anubisURL , playwright.PageGotoOptions {
133238 Timeout : pwTimeout (tc , deadline ),
134239 })
135240 if err != nil {
@@ -252,25 +357,34 @@ func setupPlaywright(t *testing.T) *playwright.Playwright {
252357 return pw
253358}
254359
255- func spawnTestServer (t * testing.T ) {
360+ func spawnAnubis (t * testing.T ) string {
256361 t .Helper ()
257362
258- s := new (http.Server )
259- s .Addr = * serverBindAddr
260- s .Handler = http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
363+ h := http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
261364 w .Header ().Add ("Content-Type" , "text/html" )
262365 fmt .Fprintf (w , "<html><body><span id=anubis-test>%d</span></body></html>" , time .Now ().Unix ())
263366 })
264367
265- go func () {
266- if err := s .ListenAndServe (); err != nil && err != http .ErrServerClosed {
267- t .Logf ("test HTTP server terminated unexpectedly: %v" , err )
268- }
269- }()
368+ policy , err := libanubis .LoadPoliciesOrDefault ("" , anubis .DefaultDifficulty )
369+ if err != nil {
370+ t .Fatal (err )
371+ }
372+
373+ s , err := libanubis .New (libanubis.Options {
374+ Next : h ,
375+ Policy : policy ,
376+ ServeRobotsTXT : true ,
377+ })
378+ if err != nil {
379+ t .Fatalf ("can't construct libanubis.Server: %v" , err )
380+ }
381+
382+ ts := httptest .NewServer (s )
383+ t .Log (ts .URL )
270384
271385 t .Cleanup (func () {
272- if err := s .Shutdown (context .Background ()); err != nil {
273- t .Fatalf ("could not shutdown test server: %v" , err )
274- }
386+ ts .Close ()
275387 })
388+
389+ return ts .URL
276390}
0 commit comments