Skip to content

Commit

Permalink
Add integ test for http server
Browse files Browse the repository at this point in the history
This fixes #40

Signed-off-by: Bennet Huber <[email protected]>
  • Loading branch information
bhuber committed Feb 13, 2025
1 parent 49c1933 commit 1f93bdf
Show file tree
Hide file tree
Showing 9 changed files with 862 additions and 8 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,22 @@ First, enable the HTTP server from the command line,
GOFAIL_HTTP="127.0.0.1:1234" ./cmd
```


Activate a failpoint with curl,
Activate a single failpoint with curl,

```sh
$ curl http://127.0.0.1:1234/SomeFuncString -XPUT -d'return("hello")'
```

Activate multiple failpoints atomically with the special `/failpoints` endpoint. The payload is the same as for `GOFAIL_FAILPOINTS` above:

```sh
$ curl http://127.0.0.1:1234/failpoints -XPUT -d'failpoint1=return("hello");failpoint2=sleep(10)'
```

List the failpoints,

```sh
$ curl http://127.0.0.1:1234/SomeFuncString=return("hello")
$ curl http://127.0.0.1:1234/SomeFuncString
```

Retrieve the execution count of a failpoint,
Expand Down
6 changes: 4 additions & 2 deletions examples/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@ GOFAIL_HTTP=:22381 go run cmd.go
curl -L http://localhost:22381
curl \
-L http://localhost:22381/github.com/coreos/gofail/examples/ExampleLabels \
-L http://localhost:22381/ExampleLabels \
-X PUT -d'return'
curl \
-L http://localhost:22381/github.com/coreos/gofail/examples/ExampleLabels \
-L http://localhost:22381/ExampleLabels \
-X DELETE
*/

func main() {
for {
log.Println(examples.ExampleFunc())
log.Println(examples.ExampleOneLineFunc())
log.Println(examples.ExampleLabelsFunc())
time.Sleep(time.Second)
}
Expand Down
4 changes: 2 additions & 2 deletions integration/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Integration Tests

Each directory contains a scenario

- sleep: the enabling and disabling of a failpoint won't be delayed due to an ongoing sleep() action
* sleep: the enabling and disabling of a failpoint won't be delayed due to an ongoing sleep() action
* server: exercises the HTTP failpoint control API and checks basic functionality
10 changes: 9 additions & 1 deletion integration/makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ run-all-integration-tests:
# we compile and execute all integration tests
# add new integration test targets here
$(MAKE) run-integration-test-sleep
$(MAKE) run-integration-test-server

# we disable all failpoints
$(MAKE) gofail-disable
Expand All @@ -19,10 +20,17 @@ clean-all-integration-tests: clean-integration-test-sleep gofail-disable
.PHONY: gofail-enable
gofail-enable: build-gofail
$(GOFAIL_BINARY) enable ./integration/sleep/failpoints
$(GOFAIL_BINARY) enable ./integration/server/failpoints

.PHONY: gofail-disable
gofail-disable: build-gofail
${GOFAIL_BINARY} disable ./integration/sleep/failpoints
$(GOFAIL_BINARY) disable ./integration/sleep/failpoints
$(GOFAIL_BINARY) disable ./integration/server/failpoints

# run integration test - server
.PHONY: run-integration-test-server
run-integration-test-server:
cd ./integration/server && go test -v .

# run integration test - sleep
.PHONY: run-integration-test-sleep
Expand Down
28 changes: 28 additions & 0 deletions integration/server/failpoints/failpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package failpoints

func ExampleFunc() string {
// gofail: var ExampleString string
// return ExampleString
return "example"
}

func ExampleOneLineFunc() string {
// gofail: var ExampleOneLine struct{}
return "abc"
}

func ExampleLabelsFunc() string {
i := 0
s := ""
// gofail: myLabel:
for i < 5 {
s = s + "i"
i++
for j := 0; j < 5; j++ {
s = s + "j"
// gofail: var ExampleLabels struct{}
// continue myLabel
}
}
return s
}
16 changes: 16 additions & 0 deletions integration/server/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module go.etcd.io/gofail/integration/server

go 1.22

toolchain go1.22.10

require github.com/stretchr/testify v1.10.0

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.etcd.io/gofail v0.1.1-0.20240328162059-93c579a86c46 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace go.etcd.io/gofail => ./../../
11 changes: 11 additions & 0 deletions integration/server/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.etcd.io/gofail v0.1.1-0.20240328162059-93c579a86c46 h1:q2duvcm+tRj5lNb5RcDQ6QTs6n9Ou0L0p/74jEJwQaE=
go.etcd.io/gofail v0.1.1-0.20240328162059-93c579a86c46/go.mod h1:UD5kxjMWxJacjLWHSqGM3zn4a9ItpE06Eg7ttpm0Lhs=
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=
84 changes: 84 additions & 0 deletions integration/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package main

import (
"encoding/json"
"fmt"
"go.etcd.io/gofail/integration/server/failpoints"
"log"
"net/http"
"os"
"reflect"
"strings"
)

var funcMap = map[string]interface{}{
"ExampleFunc": failpoints.ExampleFunc,
"ExampleOneLineFunc": failpoints.ExampleOneLineFunc,
"ExampleLabelsFunc": failpoints.ExampleLabelsFunc,
}

func callFuncByName(name string, args []string) (interface{}, error) {
fn, exists := funcMap[name]
if !exists {
return nil, fmt.Errorf("function %s does not exist", name)
}

fnValue := reflect.ValueOf(fn)
expectedNArgs := fnValue.Type().NumIn()
gotNArgs := len(args)
if expectedNArgs != gotNArgs {
return nil, fmt.Errorf("wrong number of arguments for function %s. "+
"Expected %d, got %d", name, expectedNArgs, gotNArgs)
}

in := make([]reflect.Value, len(args))
for i, arg := range args {
in[i] = reflect.ValueOf(arg)
}

result := fnValue.Call(in)
if len(result) == 0 {
return nil, nil
}
return result[0].Interface(), nil
}

func handler(w http.ResponseWriter, r *http.Request) {
log.Printf("received request: %v", r)
pathParts := strings.Split(r.URL.Path, "/")
if len(pathParts) < 3 {
http.Error(w, "invalid URL path", http.StatusBadRequest)
return
}
funcName := pathParts[2]
args := r.URL.Query()["args"]

result, err := callFuncByName(funcName, args)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

response, err := json.Marshal(result)
if err != nil {
http.Error(w, "failed to marshal response", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
_, err = w.Write(response)
if err != nil {
http.Error(w, "failed to write response", http.StatusInternalServerError)
}
}

func main() {
if len(os.Args) < 2 {
log.Fatal("Port number is required as a command line argument")
}
port := os.Args[1]

http.HandleFunc("/call/", handler)
log.Printf("Starting server on :%s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
Loading

0 comments on commit 1f93bdf

Please sign in to comment.