internal/test: introduce integration tests using Playwright (#81)
This commit is contained in:
parent
1509b06cb9
commit
af6f05554f
4 changed files with 294 additions and 0 deletions
|
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
- Fixed and clarified installation instructions
|
- Fixed and clarified installation instructions
|
||||||
|
- Introduced integration tests using Playwright
|
||||||
|
|
||||||
## v1.14.2
|
## v1.14.2
|
||||||
|
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/a-h/templ v0.3.833
|
github.com/a-h/templ v0.3.833
|
||||||
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456
|
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||||
|
github.com/playwright-community/playwright-go v0.5001.0
|
||||||
github.com/prometheus/client_golang v1.21.1
|
github.com/prometheus/client_golang v1.21.1
|
||||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
|
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
|
||||||
github.com/yl2chen/cidranger v1.0.2
|
github.com/yl2chen/cidranger v1.0.2
|
||||||
|
@ -21,11 +22,14 @@ require (
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cli/browser v1.3.0 // indirect
|
github.com/cli/browser v1.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
|
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
||||||
github.com/fatih/color v1.16.0 // indirect
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||||
|
github.com/go-stack/stack v1.8.1 // indirect
|
||||||
github.com/klauspost/compress v1.17.11 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
|
13
go.sum
13
go.sum
|
@ -19,6 +19,8 @@ github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEf
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
|
||||||
|
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||||
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456 h1:CkmB2l68uhvRlwOTPrwnuitSxi/S3Cg4L5QYOcL9MBc=
|
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456 h1:CkmB2l68uhvRlwOTPrwnuitSxi/S3Cg4L5QYOcL9MBc=
|
||||||
|
@ -31,8 +33,13 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||||
|
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||||
|
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
|
@ -44,10 +51,14 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
|
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
|
||||||
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
|
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
|
||||||
|
github.com/playwright-community/playwright-go v0.5001.0 h1:EY3oB+rU9cUp6CLHguWE8VMZTwAg+83Yyb7dQqEmGLg=
|
||||||
|
github.com/playwright-community/playwright-go v0.5001.0/go.mod h1:kBNWs/w2aJ2ZUp1wEOOFLXgOqvppFngM5OS+qyhl+ZM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -63,6 +74,7 @@ github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+
|
||||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0=
|
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||||
|
@ -147,5 +159,6 @@ google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNI
|
||||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
276
internal/test/playwright_test.go
Normal file
276
internal/test/playwright_test.go
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
//go:build integration
|
||||||
|
|
||||||
|
// Integration tests for Anubis, using Playwright.
|
||||||
|
//
|
||||||
|
// These tests require an already running Anubis and Playwright server.
|
||||||
|
//
|
||||||
|
// Anubis must be configured to redirect to the server started by the test suite.
|
||||||
|
// The bind address and the Anubis server can be specified using the flags `-bind` and `-anubis` respectively.
|
||||||
|
//
|
||||||
|
// Playwright must be started in server mode using `npx playwright@1.50.1 run-server --port 3000`.
|
||||||
|
// The version must match the minor used by the playwright-go package.
|
||||||
|
//
|
||||||
|
// On unsupported systems you may be able to use a container instead: https://playwright.dev/docs/docker#remote-connection
|
||||||
|
//
|
||||||
|
// In that case you may need to set the `-playwright` flag to the container's URL, and specify the `--host` the run-server command listens on.
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/playwright-community/playwright-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
anubisServer = flag.String("anubis", "http://localhost:8923", "Anubis server URL")
|
||||||
|
serverBindAddr = flag.String("bind", "localhost:3923", "test server bind address")
|
||||||
|
playwrightServer = flag.String("playwright", "ws://localhost:3000", "Playwright server URL")
|
||||||
|
playwrightMaxTime = flag.Duration("playwright-max-time", 5*time.Second, "maximum time for Playwright requests")
|
||||||
|
playwrightMaxHardTime = flag.Duration("playwright-max-hard-time", 5*time.Minute, "maximum time for hard Playwright requests")
|
||||||
|
|
||||||
|
testCases = []testCase{
|
||||||
|
{name: "firefox", action: actionChallenge, realIP: placeholderIP, userAgent: "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0"},
|
||||||
|
{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"},
|
||||||
|
{name: "kagiBadIP", action: actionChallenge, isHard: true, realIP: placeholderIP, userAgent: "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)"},
|
||||||
|
{name: "kagiGoodIP", action: actionAllow, realIP: "216.18.205.234", userAgent: "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)"},
|
||||||
|
{name: "unknownAgent", action: actionAllow, realIP: placeholderIP, userAgent: "AnubisTest/0"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
actionAllow action = "ALLOW"
|
||||||
|
actionDeny action = "DENY"
|
||||||
|
actionChallenge action = "CHALLENGE"
|
||||||
|
|
||||||
|
placeholderIP = "fd11:5ee:bad:c0de::"
|
||||||
|
)
|
||||||
|
|
||||||
|
type action string
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
name string
|
||||||
|
action action
|
||||||
|
isHard bool
|
||||||
|
realIP, userAgent string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlaywrightBrowser(t *testing.T) {
|
||||||
|
pw := setupPlaywright(t)
|
||||||
|
spawnTestServer(t)
|
||||||
|
browsers := []playwright.BrowserType{pw.Chromium, pw.Firefox, pw.WebKit}
|
||||||
|
|
||||||
|
for _, typ := range browsers {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
name := fmt.Sprintf("%s@%s", tc.name, typ.Name())
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
_, hasDeadline := t.Deadline()
|
||||||
|
if tc.isHard && hasDeadline {
|
||||||
|
t.Skip("skipping hard challenge with deadline")
|
||||||
|
}
|
||||||
|
|
||||||
|
perfomedAction := executeTestCase(t, tc, typ)
|
||||||
|
|
||||||
|
if perfomedAction != tc.action {
|
||||||
|
t.Errorf("unexpected test result, expected %s, got %s", tc.action, perfomedAction)
|
||||||
|
} else {
|
||||||
|
t.Logf("test passed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildBrowserConnect(name string) string {
|
||||||
|
u, _ := url.Parse(*playwrightServer)
|
||||||
|
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("browser", name)
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeTestCase(t *testing.T, tc testCase, typ playwright.BrowserType) action {
|
||||||
|
deadline, _ := t.Deadline()
|
||||||
|
|
||||||
|
browser, err := typ.Connect(buildBrowserConnect(typ.Name()), playwright.BrowserTypeConnectOptions{
|
||||||
|
ExposeNetwork: playwright.String("<loopback>"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not connect to remote browser: %v", err)
|
||||||
|
}
|
||||||
|
defer browser.Close()
|
||||||
|
|
||||||
|
ctx, err := browser.NewContext(playwright.BrowserNewContextOptions{
|
||||||
|
AcceptDownloads: playwright.Bool(false),
|
||||||
|
ExtraHttpHeaders: map[string]string{
|
||||||
|
"X-Real-Ip": tc.realIP,
|
||||||
|
},
|
||||||
|
UserAgent: playwright.String(tc.userAgent),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create context: %v", err)
|
||||||
|
}
|
||||||
|
defer ctx.Close()
|
||||||
|
|
||||||
|
page, err := ctx.NewPage()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create page: %v", err)
|
||||||
|
}
|
||||||
|
defer page.Close()
|
||||||
|
|
||||||
|
// Attempt challenge.
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
_, err = page.Goto(*anubisServer, playwright.PageGotoOptions{
|
||||||
|
Timeout: pwTimeout(tc, deadline),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
pwFail(t, page, "could not navigate to test server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hadChallenge := false
|
||||||
|
switch tc.action {
|
||||||
|
case actionChallenge:
|
||||||
|
// FIXME: This could race if challenge is completed too quickly.
|
||||||
|
checkImage(t, tc, deadline, page, "#image[src*=pensive], #image[src*=happy]")
|
||||||
|
hadChallenge = true
|
||||||
|
case actionDeny:
|
||||||
|
checkImage(t, tc, deadline, page, "#image[src*=sad]")
|
||||||
|
return actionDeny
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure protected resource was provided.
|
||||||
|
|
||||||
|
res, err := page.Locator("#anubis-test").TextContent(playwright.LocatorTextContentOptions{
|
||||||
|
Timeout: pwTimeout(tc, deadline),
|
||||||
|
})
|
||||||
|
end := time.Now()
|
||||||
|
if err != nil {
|
||||||
|
pwFail(t, page, "could not get text content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tm int64
|
||||||
|
if _, err := fmt.Sscanf(res, "%d", &tm); err != nil {
|
||||||
|
pwFail(t, page, "unexpected output: %s", res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tm < start.Unix() || end.Unix() < tm {
|
||||||
|
pwFail(t, page, "unexpected timestamp in output: %d not in range %d..%d", tm, start.Unix(), end.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
if hadChallenge {
|
||||||
|
return actionChallenge
|
||||||
|
} else {
|
||||||
|
return actionAllow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkImage(t *testing.T, tc testCase, deadline time.Time, page playwright.Page, locator string) {
|
||||||
|
image := page.Locator(locator)
|
||||||
|
err := image.WaitFor(playwright.LocatorWaitForOptions{
|
||||||
|
Timeout: pwTimeout(tc, deadline),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
pwFail(t, page, "could not wait for result: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
failIsVisible, err := image.IsVisible()
|
||||||
|
if err != nil {
|
||||||
|
pwFail(t, page, "could not check result image: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !failIsVisible {
|
||||||
|
pwFail(t, page, "expected result image not visible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pwFail(t *testing.T, page playwright.Page, format string, args ...any) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
saveScreenshot(t, page)
|
||||||
|
t.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pwTimeout(tc testCase, deadline time.Time) *float64 {
|
||||||
|
max := *playwrightMaxTime
|
||||||
|
if tc.isHard {
|
||||||
|
max = *playwrightMaxHardTime
|
||||||
|
}
|
||||||
|
|
||||||
|
d := deadline.Sub(time.Now())
|
||||||
|
if d <= 0 || d > max {
|
||||||
|
return playwright.Float(float64(max.Milliseconds()))
|
||||||
|
}
|
||||||
|
return playwright.Float(float64(d.Milliseconds()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveScreenshot(t *testing.T, page playwright.Page) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data, err := page.Screenshot()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("could not take screenshot: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.CreateTemp("", "anubis-test-fail-*.png")
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("could not create temporary file: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("could not write screenshot: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("screenshot saved to %s", f.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupPlaywright(t *testing.T) *playwright.Playwright {
|
||||||
|
err := playwright.Install(&playwright.RunOptions{
|
||||||
|
SkipInstallBrowsers: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not install Playwright: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pw, err := playwright.Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not start Playwright: %v", err)
|
||||||
|
}
|
||||||
|
return pw
|
||||||
|
}
|
||||||
|
|
||||||
|
func spawnTestServer(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
s := new(http.Server)
|
||||||
|
s.Addr = *serverBindAddr
|
||||||
|
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("Content-Type", "text/html")
|
||||||
|
fmt.Fprintf(w, "<html><body><span id=anubis-test>%d</span></body></html>", time.Now().Unix())
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
t.Logf("test HTTP server terminated unexpectedly: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := s.Shutdown(context.Background()); err != nil {
|
||||||
|
t.Fatalf("could not shutdown test server: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue