Skip to content

Commit

Permalink
test: HTTPTransport
Browse files Browse the repository at this point in the history
The ConcurrentSendAndFlush test reveals a data race in the HTTPTransport
implementation.
  • Loading branch information
rhcarvalho committed Jan 22, 2020
1 parent 03949d5 commit 2bc3a3e
Showing 1 changed file with 112 additions and 0 deletions.
112 changes: 112 additions & 0 deletions transport_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package sentry

import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"sync"
"sync/atomic"
"testing"
"time"
)
Expand Down Expand Up @@ -152,3 +157,110 @@ func TestRetryAfterDateHeader(t *testing.T) {
}
assertEqual(t, retryAfter(now, &r), time.Second*13)
}

func TestHTTPTransport(t *testing.T) {
var (
counter uint64
event struct {
EventID string `json:"event_id"`
}
)

// ch is used to control the test HTTP server.
ch := make(chan bool)
unblockServer := func() {
ch <- true
}

ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
dec := json.NewDecoder(r.Body)
err := dec.Decode(&event)
if err != nil {
t.Fatal(err)
}
// Wait for signal to continue.
<-ch
t.Logf("[SERVER] {%.4s} event received (#%d)", event.EventID, atomic.AddUint64(&counter, 1))
}))
defer ts.Close()

tr := NewHTTPTransport()
tr.Configure(ClientOptions{
Dsn: fmt.Sprintf("https://test@%s/1", ts.Listener.Addr()),
HTTPClient: ts.Client(),
})

sendEvent := func() string {
e := NewEvent()
id := uuid()
e.EventID = EventID(id)

tr.SendEvent(e)
t.Logf("[CLIENT] {%.4s} event sent", e.EventID)
return id
}

counterValue := func() uint64 {
return atomic.LoadUint64(&counter)
}

counterMustBe := func(n uint64) {
counter := counterValue()
if counter != n {
t.Fatalf("[SERVER] counter = %d, want %d", counter, n)
}
}

mustFlush := func(id string) {
ok := tr.Flush(100 * time.Millisecond)
if !ok {
t.Fatalf("[CLIENT] {%.4s} Flush() timed out", id)
}
}

testSendSingleEvent := func(t *testing.T) {
// Sending a single event should increase the server event counter by
// exactly one.

initialCounter := counterValue()
id := sendEvent()

// Server is blocked waiting for us, right now counter must not have
// changed yet.
counterMustBe(initialCounter)

// After unblocking the server, Flush must guarantee that the counter
// increased by one.
unblockServer()
mustFlush(id)
counterMustBe(initialCounter + 1)
}

t.Run("SendSingleEvent", testSendSingleEvent)

t.Run("FlushMultipleTimes", func(t *testing.T) {
// Flushing multiple times should not increase the server counter.

initialCounter := counterValue()
for i := 0; i < 10; i++ {
mustFlush(fmt.Sprintf("loop%d", i))
}
counterMustBe(initialCounter)
})

t.Run("ConcurrentSendAndFlush", func(t *testing.T) {
// It should be safe to send events and flush concurrently.

var wg sync.WaitGroup
wg.Add(2)
go func() {
testSendSingleEvent(t)
wg.Done()
}()
go func() {
mustFlush("from goroutine")
wg.Done()
}()
wg.Wait()
})
}

0 comments on commit 2bc3a3e

Please sign in to comment.