How to rerun only failed tests in go testing - go

I have a package with several files and tests. Currently to rerun failed tests I'm using:
func TestMain(m *testing.M) {
var r int = -1
maxRuns := 3
for i := 0; i < maxRuns && r != 0; i++ {
r = m.Run()
}
os.Exit(r)
}
Actually it works, however it reruns all package tests in a single test failure scenario. So sometimes it leads to the next sequence: PASSED,PASSED,FAILED. This way the test marked as FAILED.
My goal is to rerun only failed tests in a package, mark it as PASSED at the moment of a first success, mark test as FAILED only in case of a triple failure. Any suggestion?

This is probably long answered, but the way I've seen this for integration tests is wrapping the retry code in a function that takes a callback to your test implementation. This is particularly helpful if you're making API calls and have things where context.Done would be needed to check for hanging calls or timeouts. For example: https://pkg.go.dev/k8s.io/client-go/util/retry
Here's a simple example.
func MyPolicy(ctx context.Context, t *testing.T, retries int, testImpl func(context.Context, t *testing.T)) error {
for i := 0; i < retries; i++ {
err := testImpl(ctx, t)
if err != nil {
t.Logf("Test error: %v", err)
continue
}
return nil
}
return fmt.Errorf("Retry budget of %d attempts exhausted", retries)
}
func TestIntegration(t *testing.T) {
impl := func(ctx context.Context, t *testing.T) error {
// implement here calling t.Logf when needed not t.Fatal/Error
}
if err := MyPolicy(context.Background(), t, 3, impl); err != nil {
t.Fatalf("Test failed with: %v", err)
}
}

Related

how to check if two wrap error are equal in golang?

I have a simple error wrap type in errdefs.go:
package errdefs
type errInvalidAttribute struct{ error }
func (e errInvalidAttribute) Unwrap() error {
return e.error
}
func InvalidAttribute(err error) error {
if err == nil || IsInvalidAttribute(err) {
return err
}
return errInvalidAttribute{err}
}
func IsInvalidAttribute(err error) bool {
return errors.As(err, &errInvalidAttribute{})
}
The following is a unit test of this file:
package errdefs_test
func TestWrapErrorEqual(t *testing.T) {
err1 := errdefs.InvalidAttribute(fmt.Errorf("this is a wrap error"))
err2 := errdefs.InvalidAttribute(fmt.Errorf("this is a wrap error"))
if err1 != err2 {
t.Errorf(" != now work")
}
if !errors.Is(err1, err2) {
t.Errorf("errors.Is not work")
}
}
then I run unit-test:
$ go test .
--- FAIL: TestInvali (0.00s)
errdefs_test.go:62: != not work
errdefs_test.go:66: errors.Is not work
FAIL
FAIL errdefs 0.496s
FAIL
!= and errors.Is not work well,so how do I check if two wrap errors are equal in golang?
The equality operator as well as errors.Is check the equality of the references of the error objects. So, two instantiated error objects will never be equal.
Most libraries instantiate error variables on startup and use the references for equality checks.
var (
ErrInvalidArgument = errors.New("invalid argument")
)
func ErrInvalidArgument(err error) bool {
return err == ErrInvalidArgument
}
Of course, you can also check the equality of the string returned by error#Error, if it is not dynamically assembled.
So, you test function would look like following.
func TestWrapErrorEqual(t *testing.T) {
wrappedErr := fmt.Errorf("this is a wrap error")
err1 := errdefs.InvalidAttribute(wrappedErr )
err2 := errdefs.InvalidAttribute(wrappedErr )
if err1.Unwrap() != err2.Unwrap() {
t.Errorf(" != now work")
}
if !errors.Is(err1.Unwrap(), err2.Unwrap()) {
t.Errorf("errors.Is not work")
}
}
I hope I got your question right and this is somewhat helpful.

Automated integration testing in lambda support (golang, serverless)

So I have a web app running in serverless. It spins up a bunch of lambdas and then a 'test' lambda is invoked at a later stage of our pipeline to run some api tests against the other lambbas. It passes or fails code pipeline depending on the result of the tests.
My concern is the implementation of the tests portion itself.
We're using golang, and I wasn't able to successfully find a way to have a bunch of go test files and run them, record the results and determine pass/fail or not.. but I wanted to use the test suite and library in order to run my assertions. So I came up with this solution which was to break about the go test library and run it myself using MainStart(), ex:
// T is used to manage our test cases manually using MainStart
type T struct{}
func (*T) ImportPath() string { return "" }
func (*T) MatchString(pat, str string) (bool, error) { return true, nil }
func (*T) SetPanicOnExit0(bool) {}
func (*T) StartCPUProfile(io.Writer) error { return nil }
func (*T) StopCPUProfile() {}
func (*T) StartTestLog(io.Writer) {}
func (*T) StopTestLog() error { return nil }
func (*T) WriteHeapProfile(io.Writer) error { return nil }
func (*T) WriteProfileTo(string, io.Writer, int) error { return nil }
func (h *Handler) Handle(ctx context.Context, event events.CodePipelineEvent) (interface{}, error) {
job := event.CodePipelineJob
ok := runTest()
if ok {
logger.Info("Tests Passed!")
input := &codepipeline.PutJobSuccessResultInput{
JobId: &job.ID,
success, err := h.service.PutJobSuccessResult(input)
return success, err
} else {
logger.Info("Tests Failed :(")
input := &codepipeline.PutJobFailureResultInput{
JobId: &job.ID,
FailureDetails: &codepipeline.FailureDetails{
Message: aws.String("tests failed"),
Type: aws.String("JobFailed"),
},
failure, err := h.service.PutJobFailureResult(input)
return failure, err
}
}
}
// NewHandler returns a pointer to a Handler struct
func NewHandler(service *codepipeline.CodePipeline) *Handler {
return &Handler{
service,
}
}
// runTest returns the test results
func runTest() bool {
testSuite := []testing.InternalTest{
{Name: "Test Service", F: TestService},
}
logger.Info("Running Tests")
errors := testing.MainStart(&T{}, testSuite, nil, nil).Run()
if errors == 0 {
return true
} else {
return false
}
}
So the test looks like this:
func TestServices(t *testing.T) {
logger.Info("blah blah do tests")
}
And for reference, main.go contains:
// Initial code pipeline session
cpSession := session.Must(session.NewSession())
// Create the credentials from AssumeRoleProvider to assume the role
// referenced by the "putJobResultRoleArn" ARN.
creds := stscreds.NewCredentials(cpSession, "putJobResultRoleArn", func(p *stscreds.AssumeRoleProvider) {
p.RoleARN = roleArn
p.RoleSessionName = "put_job_result_session"
})
// Create a new instance of the CodePipeline client with a session
svc := codepipeline.New(cpSession, &aws.Config{Credentials: creds})
intTesthandler := inttest.NewHandler(
svc,
)
lambda.Start(func(ctx context.Context, event events.CodePipelineEvent) (interface{}, error) {
return intTesthandler.Handle(ctx, event)
})
This works quite well, but what I don't like is:
It's using an unsupported approach from golang that could break in the future
I have to handhold any failures, meaning if one fails, I need to write code to stop the rest of the suite (if there were more tests) from running.
Bit of a learning curve
To note the tests I have mainly do an http request to an api endpoint and validate the response + parse/store the data.
Anyone have any other creative solution? Is there a repo out there that makes it simple to run integration tests in golang?
Cheers

Mock/test basic http.get request

I am leaning to write unit tests and I was wondering the correct way to unit test a basic http.get request.
I found an API online that returns fake data and wrote a basic program that gets some user data and prints out an ID:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type UserData struct {
Meta interface{} `json:"meta"`
Data struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Gender string `json:"gender"`
Status string `json:"status"`
} `json:"data"`
}
func main() {
resp := sendRequest()
body := readBody(resp)
id := unmarshallData(body)
fmt.Println(id)
}
func sendRequest() *http.Response {
resp, err := http.Get("https://gorest.co.in/public/v1/users/1841")
if err != nil {
log.Fatalln(err)
}
return resp
}
func readBody(resp *http.Response) []byte {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
return body
}
func unmarshallData(body []byte) int {
var userData UserData
json.Unmarshal(body, &userData)
return userData.Data.ID
}
This works and prints out 1841. I then wanted to write some tests that validate that the code is behaving as expected, e.g. that it correctly fails if an error is returned, that the data returned can be unmarshalled. I have been reading online and looking at examples but they are all far more complex that what I feel I am trying to achieve.
I have started with the following test that ensures that the data passed to the unmarshallData function can be unmarshalled:
package main
import (
"testing"
)
func Test_unmarshallData(t *testing.T) {
type args struct {
body []byte
}
tests := []struct {
name string
args args
want int
}{
{name: "Unmarshall", args: struct{ body []byte }{body: []byte("{\"meta\":null,\"data\":{\"id\":1841,\"name\":\"Piya\",\"email\":\"priya#gmai.com\",\"gender\":\"female\",\"status\":\"active\"}}")}, want: 1841},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := unmarshallData(tt.args.body); got != tt.want {
t.Errorf("unmarshallData() = %v, want %v", got, tt.want)
}
})
}
}
Any advise on where to go from here would be appreciated.
before moving on to the testing, your code has a serious flow, which will become a problem if you don't take care about it in your future programming tasks.
https://pkg.go.dev/net/http See the second example
The client must close the response body when finished with it
Let's fix that now (we will have to come back on this subject later), two possibilities.
1/ within main, use defer to Close that resource after you have drained it;
func main() {
resp := sendRequest()
defer body.Close()
body := readBody(resp)
id := unmarshallData(body)
fmt.Println(id)
}
2/ Do that within readBody
func readBody(resp *http.Response) []byte {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
return body
}
Using a defer is the expected manner to close the resource. It helps the reader to identify the lifetime span of the resource and improve readability.
Notes : I will not be using much of the table test driven pattern, but you should, like you did in your OP.
Moving on to the testing part.
Tests can be written under the same package or its fellow version with a trailing _test, such as [package target]_test. This has implications in two ways.
Using a separate package, they will be ignored in the final build. Which will help to produce smaller binaries.
Using a separate package, you test the API in a black box manner, you can access only the identifiers it explicitly exposes.
Your current tests are white boxed, meaning you can access any declaration of main, public or not.
About sendRequest, writing a test around this is not very interesting because it does too little, and your tests should not be written to test the std library.
But for the sake of the demonstration, and for good reasons we might want to not rely on external resources to execute our tests.
In order to achieve that we must make the global dependencies consumed within it, an injected dependency. So that later on, it is possible to replace the one thing it depends on to react, the http.Get method.
func sendRequest(client interface{Get() (*http.Response, error)}) *http.Response {
resp, err := client.Get("https://gorest.co.in/public/v1/users/1841")
if err != nil {
log.Fatalln(err)
}
return resp
}
Here i use an inlined interface declaration interface{Get() (*http.Response, error)}.
Now we can add a new test which injects a piece of code that will return exactly the values that will trigger the behavior we want to test within our code.
type fakeGetter struct {
resp *http.Response
err error
}
func (f fakeGetter) Get(u string) (*http.Response, error) {
return f.resp, f.err
}
func TestSendRequestReturnsNilResponseOnError(t *testing.T) {
c := fakeGetter{
err: fmt.Errorf("whatever error will do"),
}
resp := sendRequest(c)
if resp != nil {
t.Fatal("it should return a nil response when an error arises")
}
}
Now run this test and see the result. It is not conclusive because your function contains a call to log.Fatal, which in turns executes an os.Exit; We cannot test that.
If we try to change that, we might think we might call for panic instead because we can recover.
I don't recommend doing that, in my opinion, this is smelly and bad, but it exists, so we might consider. This is also the least possible change to the function signature. Returning an error would break even more the current signatures. I want to minimize this for that demonstration. But, as a rule of thumb, return an error and always check them.
In the sendRequest function, replace this call log.Fatalln(err) with panic(err) and update the test to capture the panic.
func TestSendRequestReturnsNilResponseOnError(t *testing.T) {
var hasPanicked bool
defer func() {
_ = recover() // if you capture the output value or recover, you get the error gave to the panic call. We have no use of it.
hasPanicked = true
}()
c := fakeGetter{
err: fmt.Errorf("whatever error will do"),
}
resp := sendRequest(c)
if resp != nil {
t.Fatal("it should return a nil response when an error arises")
}
if !hasPanicked {
t.Fatal("it should have panicked")
}
}
We can now move on to the other execution path, the non error return.
For that we forge the desired *http.Response instance we want to pass into our function, we will then check its properties to figure out if what the function does is inline with what we expect.
We will consider we want to ensure it is returned unmodified : /
Below test only sets two properties, and I will do it to demonstrate how to set the Body with a NopCloser and strings.NewReader as it is often needed later on using the Go language;
I also use reflect.DeepEqual as brute force equality checker, usually you can be more fine grained and get better tests. DeepEqual does the job in this case but it introduces complexity that does not justify systematic use of it.
func TestSendRequestReturnsUnmodifiedResponse(t *testing.T) {
c := fakeGetter{
err: nil,
resp: &http.Response{
Status: http.StatusOK,
Body: ioutil.NopCloser(strings.NewReader("some text")),
},
}
resp := sendRequest(c)
if !reflect.DeepEqual(resp, c.resp) {
t.Fatal("the response should not have been modified")
}
}
At that point you may have figured that this small function sendRequest is not good, if you did not I ensure you it is not. It does too little, it merely wraps the http.Get method and its testing is of little interest for the survival of the business logic.
Moving on to readBody function.
All remarks that applied for sendRequest apply here too.
it does too little
it os.Exits
One thing does not apply. As the call to ioutil.ReadAll does not rely on external resources, there is no point in attempting to inject that dependency. We can test around.
Though, for the sake of the demonstration, it is the time to talk about the missing call to defer resp.Body.Close().
Let us assume we go for the second proposition made in introduction and test for that.
The http.Response struct adequately exposes its Body recipient as an interface.
To ensure the code calls for the `Close, we can write a stub for it.
That stub will record if that call was made, the test can then check for that and trigger an error if it was not.
type closeCallRecorder struct {
hasClosed bool
}
func (c *closeCallRecorder) Close() error {
c.hasClosed = true
return nil
}
func (c *closeCallRecorder) Read(p []byte) (int, error) {
return 0, nil
}
func TestReadBodyCallsClose(t *testing.T) {
body := &closeCallRecorder{}
res := &http.Response{
Body: body,
}
_ = readBody(res)
if !body.hasClosed {
t.Fatal("the response body was not closed")
}
}
Similarly, and for the sake of the demonstration, we might want to test if the function has called for Read.
type readCallRecorder struct {
hasRead bool
}
func (c *readCallRecorder) Read(p []byte) (int, error) {
c.hasRead = true
return 0, nil
}
func TestReadBodyHasReadAnything(t *testing.T) {
body := &readCallRecorder{}
res := &http.Response{
Body: ioutil.NopCloser(body),
}
_ = readBody(res)
if !body.hasRead {
t.Fatal("the response body was not read")
}
}
We an also verify the body was not modified in betwen,
func TestReadBodyDidNotModifyTheResponse(t *testing.T) {
want := "this"
res := &http.Response{
Body: ioutil.NopCloser(strings.NewReader(want)),
}
resp := readBody(res)
if got := string(resp); want != got {
t.Fatal("invalid response, wanted=%q got %q", want, got)
}
}
We have almost done, lets move one to the unmarshallData function.
You have already wrote a test about it. It is okish, though, i would write it this way to make it leaner:
type UserData struct {
Meta interface{} `json:"meta"`
Data Data `json:"data"`
}
type Data struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Gender string `json:"gender"`
Status string `json:"status"`
}
func Test_unmarshallData(t *testing.T) {
type args struct {
body []byte
}
tests := []UserData{
UserData{Data: Data{ID: 1841}},
}
for _, u := range tests {
want := u.ID
b, _ := json.Marshal(u)
t.Run("Unmarshal", func(t *testing.T) {
if got := unmarshallData(b); got != want {
t.Errorf("unmarshallData() = %v, want %v", got, want)
}
})
}
}
Then, the usual apply :
don't log.Fatal
what are you testing ? the marshaller ?
Finally, now that we have gathered all those pieces, we can refactor to write a more sensible function and re use all those pieces to help us testing such code.
I won't do it, but here is a starter, which still panics, and I still don't recommend, but the previous demonstration has shown everything needed to test a version of it that returns an error.
type userFetcher struct {
Requester interface {
Get(u string) (*http.Response, error)
}
}
func (u userFetcher) Fetch() int {
resp, err := u.Requester.Get("https://gorest.co.in/public/v1/users/1841") // it does not really matter that this string is static, using the requester we can mock the response, its body and the error.
if err != nil {
panic(err)
}
defer resp.Body.Close() //always.
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
var userData UserData
err = json.Unmarshal(body, &userData)
if err != nil {
panic(err)
}
return userData.Data.ID
}

Things to be taken care Before Running Stellar Horizon Test Cases

I have cloned the Stellar Horizon Repo from GitHub written in Go.
I thought to run the test cases first.where the test cases have been written by using GINKGO Testing Framework. I have been running the test cases using ginkgo command
eg : ginkgo (package path name will be given here).
This is how I run test cases. Test cases for particular package has been executing properly.
But I am getting a panic in the first test file only. Which I debugged and found that the panic is occurring while running a command. Please find the below details for reference .
File name : action_accounts_test.go
func name : TestAccountAction_Show() // Has been defined below
func TestAccountActions_Show(t *testing.T) {
ht := StartHTTPTest(t, "allow_trust") **// This function is not returning anything. Its //getting panic inside this //**
defer ht.Finish()
// existing account
w := ht.Get(
"/accounts/GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU",
)
if ht.Assert.Equal(200, w.Code) {
var result horizon.Account
err := json.Unmarshal(w.Body.Bytes(), &result)
ht.Require.NoError(err)
ht.Assert.Equal("8589934593", result.Sequence)
ht.Assert.NotEqual(0, result.LastModifiedLedger)
for _, balance := range result.Balances {
if balance.Type == "native" {
ht.Assert.Equal(uint32(0), balance.LastModifiedLedger)
} else {
ht.Assert.NotEqual(uint32(0), balance.LastModifiedLedger)
}
}
}
// missing account
w = ht.Get("/accounts/GDBAPLDCAEJV6LSEDFEAUDAVFYSNFRUYZ4X75YYJJMMX5KFVUOHX46SQ")
ht.Assert.Equal(404, w.Code)
}
I did a Debugging and found that its getting panic in the below func call which happens inside the above func StartHTTPTest()
scenarios.Load(StellarCoreDatabaseURL(), stellarCorePath)
scenarios.Load(DatabaseURL(), horizonPath)
Definition of the particular func
func Load(url string, path string) {
log.Println("database url", url, " Path : ", path)
sql, err := Asset(path)
log.Println("Print err:", err, " sql :", sql)
if err != nil {
log.Panic(err)
}
reader := bytes.NewReader(sql)
cmd := exec.Command("psql", url)
cmd.Stdin = reader
err = cmd.Run() **// Exactly here it return some error**
log.Println("Print err", err)
if err != nil { **// Since err is not nil .the statement will get executed .**
**log.Panic(err)**
}
}
The Error returned by cmd.Run() is exit status 2
I just printed the error and found this is the error exit status 2
What is the reason for the particular error?

Gikngo Tests hang during goapp tests

I'm trying to use Gikngo to write some tests for appengine.
My setup for the tests is as follows:
suite_test.go:
BeforeSuite() {
inst, err = aetest.NewInstance(options)
if err != nil {
Fail(fmt.Sprintf("%s", err))
}
}
var(
req *http.Request
ctx context.Context
)
BeforeEach() {
req = inst.NewRequest()
ctx = appengine.NewContext(req)
// Clean up local datastore using the context.
}
validation_test.go
Describe("Some Test", func() {
It("ValidateFoo", func() {
// Access ctx here
})
...
It("ValidateBar", func() {
// Access ctx here.
})
})
I see our tests consistently hanging with the error of the type:
Expected success, but got an error:
<*url.Error | 0xc8210570b0>: {
Op: "Post",
URL: "http://localhost:59072",
Err: {s: "EOF"},
}
Post http://localhost:59072: EOF
This seems to indicate that the API server has become inaccessible. However, the test output does not seem to indicate this.
What are the ways in which we can debug a goapp test?
It turns out that Ginkgo or Golang had nothing to do with this. There seems to be some limitation on the number of fields one can read per second from dev_appserver.py. (I suspect that it might be related to SQLite which is the DB that dev_appserver uses internally).
The following code points out the problem:
package preorder
import (
"fmt"
"testing"
"google.golang.org/appengine"
"google.golang.org/appengine/aetest"
"google.golang.org/appengine/datastore"
)
func TestLoad(t *testing.T) {
opts := aetest.Options{StronglyConsistentDatastore: true}
inst, _ := aetest.NewInstance(&opts)
defer inst.Close()
for i := 0; i < 10000; i++ {
req, _ := inst.NewRequest("GET", "/", nil)
ctx := appengine.NewContext(req)
k := datastore.NewKey(ctx, ENTITY_NAME, "", 12345, nil)
var entity Entity
datastore.Get(ctx, k, &entity)
fmt.Println("Iteration Count: ", i)
ctx.Done()
}
}
Any help on figuring out how to work around the limit of 240 operations would be appreciated. One technique I can think of is to artificially inject delays.

Resources