Skip to content

Commit 70bea22

Browse files
committed
chore: enable integration test in ci
1 parent 5cf4129 commit 70bea22

File tree

3 files changed

+94
-48
lines changed

3 files changed

+94
-48
lines changed

.github/workflows/tests.yml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
env:
1212
GOPROXY: "https://proxy.golang.org,direct"
13+
ENABLE_DOCKER_INTEGRATION_TESTS: TRUE
1314

1415
steps:
1516
- name: Set up Go

integration_test.go

+67-48
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package rabbitmq
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"os"
87
"os/exec"
98
"strings"
@@ -14,7 +13,7 @@ import (
1413
const enableDockerIntegrationTestsFlag = `ENABLE_DOCKER_INTEGRATION_TESTS`
1514

1615
func prepareDockerTest(t *testing.T) (connStr string) {
17-
if v, ok := os.LookupEnv(enableDockerIntegrationTestsFlag); ok && strings.ToUpper(v) != "TRUE" {
16+
if v, ok := os.LookupEnv(enableDockerIntegrationTestsFlag); !ok || strings.ToUpper(v) != "TRUE" {
1817
t.Skipf("integration tests are only run if '%s' is TRUE", enableDockerIntegrationTestsFlag)
1918
return
2019
}
@@ -27,7 +26,6 @@ func prepareDockerTest(t *testing.T) (connStr string) {
2726
t.Fatalf("error launching rabbitmq in docker: %v", err)
2827
}
2928
t.Cleanup(func() {
30-
t.Log("hi")
3129
containerId := strings.TrimSpace(string(out))
3230
t.Logf("attempting to shutdown container '%s'", containerId)
3331
if err := exec.Command("docker", "rm", "--force", containerId).Run(); err != nil {
@@ -37,7 +35,7 @@ func prepareDockerTest(t *testing.T) (connStr string) {
3735
return "amqp://guest:guest@localhost:5672/"
3836
}
3937

40-
func waitForHealthyAmqp(t *testing.T, connStr string) {
38+
func waitForHealthyAmqp(t *testing.T, connStr string) *Conn {
4139
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
4240
defer cancel()
4341
tkr := time.NewTicker(time.Second)
@@ -46,84 +44,105 @@ func waitForHealthyAmqp(t *testing.T, connStr string) {
4644
select {
4745
case <-ctx.Done():
4846
t.Fatal("timed out waiting for healthy amqp", ctx.Err())
47+
return nil
4948
case <-tkr.C:
50-
if err := func() error {
51-
t.Log("attempting connection")
52-
conn, err := NewConn(connStr)
53-
if err != nil {
54-
return fmt.Errorf("failed to setup connection: %v", err)
55-
}
56-
defer conn.Close()
57-
58-
pub, err := NewPublisher(conn)
59-
if err != nil {
60-
return fmt.Errorf("failed to setup publisher: %v", err)
61-
}
62-
63-
t.Log("attempting publish")
64-
return pub.PublishWithContext(ctx, []byte{}, []string{"ping"}, WithPublishOptionsExchange(""))
65-
}(); err != nil {
66-
t.Log("publish ping failed", err.Error())
49+
conn, err := NewConn(connStr, WithConnectionOptionsLogger(simpleLogF(t.Logf)))
50+
if err != nil {
51+
t.Log("failed to connect", err.Error())
6752
} else {
68-
t.Log("ping successful")
69-
return
53+
if err := func() error {
54+
t.Log("attempting connection")
55+
56+
pub, err := NewPublisher(conn, WithPublisherOptionsLogger(simpleLogF(t.Logf)))
57+
if err != nil {
58+
return fmt.Errorf("failed to setup publisher: %v", err)
59+
}
60+
61+
t.Log("attempting publish")
62+
return pub.PublishWithContext(ctx, []byte{}, []string{"ping"}, WithPublishOptionsExchange(""))
63+
}(); err != nil {
64+
_ = conn.Close()
65+
t.Log("publish ping failed", err.Error())
66+
} else {
67+
t.Log("ping successful")
68+
return conn
69+
}
7070
}
7171
}
7272
}
7373
}
7474

75+
// TestSimplePubSub is an integration testing function that validates whether we can reliably connect to a docker-based
76+
// rabbitmq and consumer a message that we publish. This uses the default direct exchange with lots of error checking
77+
// to ensure the result is as expected.
7578
func TestSimplePubSub(t *testing.T) {
7679
connStr := prepareDockerTest(t)
77-
waitForHealthyAmqp(t, connStr)
78-
79-
conn, err := NewConn(connStr)
80-
if err != nil {
81-
t.Fatal("error creating connection", err)
82-
}
80+
conn := waitForHealthyAmqp(t, connStr)
8381
defer conn.Close()
8482

8583
t.Logf("new consumer")
86-
consumer, err := NewConsumer(conn, "my_queue")
84+
consumerQueue := "my_queue"
85+
consumer, err := NewConsumer(conn, consumerQueue, WithConsumerOptionsLogger(simpleLogF(t.Logf)))
8786
if err != nil {
8887
t.Fatal("error creating consumer", err)
8988
}
90-
defer consumer.Close()
89+
defer consumer.CloseWithContext(context.Background())
90+
91+
// Setup a consumer which pushes each of its consumed messages over the channel. If the channel is closed or full
92+
// it does not block.
93+
consumed := make(chan Delivery)
94+
defer close(consumed)
9195

9296
go func() {
9397
err = consumer.Run(func(d Delivery) Action {
94-
log.Printf("consumed: %v", string(d.Body))
98+
t.Log("consumed")
99+
select {
100+
case consumed <- d:
101+
default:
102+
}
95103
return Ack
96104
})
97105
if err != nil {
98106
t.Log("consumer run failed", err)
99107
}
100108
}()
101109

110+
// Setup a publisher with notifications enabled
102111
t.Logf("new publisher")
103-
publisher, err := NewPublisher(conn)
112+
publisher, err := NewPublisher(conn, WithPublisherOptionsLogger(simpleLogF(t.Logf)))
104113
if err != nil {
105114
t.Fatal("error creating publisher", err)
106115
}
107116
publisher.NotifyPublish(func(p Confirmation) {
108117
return
109118
})
119+
defer publisher.Close()
110120

111-
ctx, cancel := context.WithCancel(context.Background())
121+
// For test stability we cannot rely on the fact that the consumer go routines are up and running before the
122+
// publisher starts it's first publish attempt. For this reason we run the publisher in a loop every second and
123+
// pass after we see the first message come through.
124+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
112125
defer cancel()
113-
114-
t.Logf("new publish")
115-
confirms, err := publisher.PublishWithDeferredConfirmWithContext(
116-
ctx, []byte("example"), []string{"my_queue"},
117-
WithPublishOptionsMandatory,
118-
)
119-
if err != nil {
120-
t.Fatal("failed to publish", err)
121-
}
122-
for _, confirm := range confirms {
123-
if _, err := confirm.WaitContext(ctx); err != nil {
124-
t.Fatal("failed to wait for publish", err)
126+
tkr := time.NewTicker(time.Second)
127+
for {
128+
select {
129+
case <-ctx.Done():
130+
t.Fatal("timed out waiting for pub sub", ctx.Err())
131+
case <-tkr.C:
132+
t.Logf("new publish")
133+
confirms, err := publisher.PublishWithDeferredConfirmWithContext(ctx, []byte("example"), []string{consumerQueue})
134+
if err != nil {
135+
// publish should always succeed since we've verified the ping previously
136+
t.Fatal("failed to publish", err)
137+
}
138+
for _, confirm := range confirms {
139+
if _, err := confirm.WaitContext(ctx); err != nil {
140+
t.Fatal("failed to wait for publish", err)
141+
}
142+
}
143+
case d := <-consumed:
144+
t.Logf("successfully saw message round trip: '%s'", string(d.Body))
145+
return
125146
}
126147
}
127-
t.Logf("success")
128-
129148
}

logger.go

+26
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package rabbitmq
33
import (
44
"fmt"
55
"log"
6+
"os"
67

78
"github.com/wagslane/go-rabbitmq/internal/logger"
89
)
@@ -39,3 +40,28 @@ func (l stdDebugLogger) Infof(format string, v ...interface{}) {
3940
func (l stdDebugLogger) Debugf(format string, v ...interface{}) {
4041
log.Printf(fmt.Sprintf("%s DEBUG: %s", loggingPrefix, format), v...)
4142
}
43+
44+
// simpleLogF is used to support logging in the test functions.
45+
// This could be exposed publicly for integration in more simple logging interfaces.
46+
type simpleLogF func(string, ...interface{})
47+
48+
func (l simpleLogF) Fatalf(format string, v ...interface{}) {
49+
l(fmt.Sprintf("%s FATAL: %s", loggingPrefix, format), v...)
50+
os.Exit(1)
51+
}
52+
53+
func (l simpleLogF) Errorf(format string, v ...interface{}) {
54+
l(fmt.Sprintf("%s ERROR: %s", loggingPrefix, format), v...)
55+
}
56+
57+
func (l simpleLogF) Warnf(format string, v ...interface{}) {
58+
l(fmt.Sprintf("%s WARN: %s", loggingPrefix, format), v...)
59+
}
60+
61+
func (l simpleLogF) Infof(format string, v ...interface{}) {
62+
l(fmt.Sprintf("%s INFO: %s", loggingPrefix, format), v...)
63+
}
64+
65+
func (l simpleLogF) Debugf(format string, v ...interface{}) {
66+
l(fmt.Sprintf("%s DEBUG: %s", loggingPrefix, format), v...)
67+
}

0 commit comments

Comments
 (0)