-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* test: add unit test for slowloris * test: add test for SlowBodyReadRequest * doc: add example * chore: setup ci * test: tune test validation * test: remove racy validations
- Loading branch information
Showing
12 changed files
with
487 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# To get started with Dependabot version updates, you'll need to specify which | ||
# package ecosystems to update and where the package manifests are located. | ||
# Please see the documentation for all configuration options: | ||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates | ||
|
||
version: 2 | ||
updates: | ||
- package-ecosystem: "gomod" # See documentation for possible values | ||
directory: "/" # Location of package manifests | ||
schedule: | ||
interval: "weekly" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
name: "Unit Test" | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
branches: [main] | ||
|
||
jobs: | ||
test: | ||
strategy: | ||
matrix: | ||
go-version: [">=1.19.0", ">=1.20.0", ">=1.21.0"] | ||
os: [ubuntu-latest] | ||
runs-on: ${{ matrix.os }} | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v3 | ||
- name: Install Go | ||
uses: actions/setup-go@v3 | ||
with: | ||
go-version: ${{ matrix.go-version }} | ||
- name: Test | ||
run: | | ||
go test -v -race "./..." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package turtle | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"net/url" | ||
"time" | ||
) | ||
|
||
func ExampleSlowloris() { | ||
u, err := url.Parse("http://127.0.0.1:8080") | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
s := Slowloris{ | ||
Target: Target{ | ||
Url: *u, | ||
}, | ||
SendGibberish: true, | ||
GibberishInterval: 5 * time.Millisecond, | ||
UserAgents: []string{ | ||
"turtle/0.0.1", | ||
"turtle/0.0.1 - slowloris", | ||
}, | ||
} | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
_ = s.Run(ctx) | ||
} | ||
|
||
func ExampleSlowBodyReadRequest() { | ||
u, err := url.Parse("http://127.0.0.1:8080") | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
s := SlowBodyReadRequest{ | ||
Target: Target{ | ||
Url: *u, | ||
}, | ||
Method: http.MethodPost, | ||
BodyReadTimeout: 180 * time.Second, | ||
} | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
_ = s.Run(ctx) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package turtle | ||
|
||
import ( | ||
"context" | ||
"net/url" | ||
"os" | ||
"os/signal" | ||
"strconv" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func getTestDuration(t testing.TB) time.Duration { | ||
t.Helper() | ||
|
||
const envKey = "TURTLE_TEST_DURATION" | ||
|
||
if v := os.Getenv(envKey);v != "" { | ||
d, err := time.ParseDuration(v) | ||
require.NoError(t, err, "invalid value for %q", envKey) | ||
return d | ||
} | ||
|
||
return 3 * time.Second | ||
} | ||
|
||
func getTestConnections(t testing.TB) int { | ||
t.Helper() | ||
|
||
const envKey = "TURTLE_TEST_CONNECTIONS" | ||
|
||
if v := os.Getenv(envKey);v != "" { | ||
d, err := strconv.ParseInt(v, 10, 32) | ||
require.NoError(t, err, "invalid value for %q", envKey) | ||
return int(d) | ||
} | ||
|
||
return 10 | ||
} | ||
|
||
func getTestTarget(t testing.TB, u url.URL) Target { | ||
t.Helper() | ||
|
||
return Target{ | ||
Url: u, | ||
Duration: getTestDuration(t), | ||
Connections: getTestConnections(t), | ||
} | ||
} | ||
|
||
func getTestContext() (context.Context, context.CancelFunc) { | ||
return signal.NotifyContext(context.Background(), os.Interrupt) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,11 @@ | ||
module github.com/b4fun/turtle | ||
|
||
go 1.20 | ||
go 1.20 | ||
|
||
require github.com/stretchr/testify v1.8.4 | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package testhttp | ||
|
||
import ( | ||
"context" | ||
"net" | ||
"net/http" | ||
"net/url" | ||
"sync" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func newLocalListener() (net.Listener, error) { | ||
l, err := net.Listen("tcp", "127.0.0.1:0") | ||
if err != nil { | ||
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return l, nil | ||
} | ||
|
||
func CreateTestServer(ctx context.Context, t testing.TB, mu ...func(s *http.Server)) (*url.URL, <-chan struct{}) { | ||
t.Helper() | ||
|
||
ln, err := newLocalListener() | ||
require.NoError(t, err) | ||
t.Logf("listening at %q", ln.Addr()) | ||
|
||
t.Cleanup(func() { | ||
_ = ln.Close() | ||
}) | ||
|
||
server := &http.Server{ | ||
Addr: ln.Addr().String(), | ||
} | ||
for _, m := range mu { | ||
m(server) | ||
} | ||
|
||
serverStopped := make(chan struct{}) | ||
go func() { | ||
_ = server.Serve(ln) | ||
close(serverStopped) | ||
}() | ||
go func() { | ||
<-ctx.Done() | ||
server.Shutdown(context.Background()) | ||
}() | ||
|
||
u, err := url.Parse("http://" + ln.Addr().String()) | ||
require.NoError(t, err) | ||
|
||
return u, serverStopped | ||
} | ||
|
||
type ConnStateCounters struct { | ||
mu sync.Mutex // protects below | ||
connTimeline []string // value is connection's remote addr | ||
connStatesTimeline map[string][]http.ConnState // key is connection's remote addr | ||
} | ||
|
||
func NewConnStateCounters() *ConnStateCounters { | ||
return &ConnStateCounters{ | ||
connStatesTimeline: make(map[string][]http.ConnState), | ||
} | ||
} | ||
|
||
func (c *ConnStateCounters) ServerConnState(conn net.Conn, state http.ConnState) { | ||
remoteAddr := conn.RemoteAddr().String() | ||
|
||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
statesTimeline, exists := c.connStatesTimeline[remoteAddr] | ||
if !exists { | ||
c.connTimeline = append(c.connTimeline, remoteAddr) | ||
} | ||
c.connStatesTimeline[remoteAddr] = append(statesTimeline, state) | ||
} | ||
|
||
func (c *ConnStateCounters) String() string { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
var s string | ||
for _, addr := range c.connTimeline { | ||
s += addr + ":" | ||
timeline := c.connStatesTimeline[addr] | ||
if len(timeline) == 0 { | ||
s += " (no states)\n" | ||
continue | ||
} | ||
for idx, state := range timeline { | ||
s += state.String() | ||
if idx < len(timeline) - 1 { | ||
s += " -> " | ||
} | ||
} | ||
s += "\n" | ||
} | ||
return s | ||
} | ||
|
||
func (c *ConnStateCounters) GetConns() []string { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
return c.connTimeline[:] | ||
} | ||
|
||
func (c *ConnStateCounters) GetConnStateTimeline(addr string) []http.ConnState { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
v, exists := c.connStatesTimeline[addr] | ||
if !exists { | ||
return nil | ||
} | ||
|
||
return v[:] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package turtle | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_Target_defaults(t *testing.T) { | ||
v := &Target{} | ||
assert.NoError(t, v.defaults()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.