Skip to content

Commit

Permalink
fix: add some unittest (#11)
Browse files Browse the repository at this point in the history
* add some unittest
* .

---------

Signed-off-by: Cattī Crūdēlēs <[email protected]>
  • Loading branch information
wzy9607 authored Feb 13, 2024
1 parent 2d0251a commit 38dc0d8
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 9 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ issues:
- funlen
- gomnd
- nakedret
- spancheck
- varnamelen
max-issues-per-linter: 0
max-same-issues: 0
7 changes: 7 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
with-expecter: true
dir: "mocks/{{.PackageName}}"
outpkg: "mock{{.PackageName}}"
packages:
github.com/rabbitmq/amqp091-go:
interfaces:
Acknowledger:
15 changes: 9 additions & 6 deletions acknowledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import (

"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"

"github.com/rabbitmq/amqp091-go"
)

type acknowledger struct {
ch *Channel
ctx context.Context //nolint:containedctx // consumer needs to retrieve the context via ContextFromDelivery.
span trace.Span
ch *Channel
acker amqp091.Acknowledger // The real acknowledger is amqp091.Channel
ctx context.Context //nolint:containedctx // consumer needs to retrieve the context via ContextFromDelivery.
span trace.Span
}

func (a *acknowledger) Ack(tag uint64, multiple bool) error {
err := a.ch.Channel.Ack(tag, multiple)
err := a.acker.Ack(tag, multiple)
if multiple {
a.endMultiple(tag, codes.Ok, "", err)
} else {
Expand All @@ -24,7 +27,7 @@ func (a *acknowledger) Ack(tag uint64, multiple bool) error {
}

func (a *acknowledger) Nack(tag uint64, multiple, requeue bool) error {
err := a.ch.Channel.Nack(tag, multiple, requeue)
err := a.acker.Nack(tag, multiple, requeue)
if multiple {
a.endMultiple(tag, codes.Error, "nack", err)
} else {
Expand All @@ -34,7 +37,7 @@ func (a *acknowledger) Nack(tag uint64, multiple, requeue bool) error {
}

func (a *acknowledger) Reject(tag uint64, requeue bool) error {
err := a.ch.Channel.Reject(tag, requeue)
err := a.acker.Reject(tag, requeue)
a.endOne(tag, codes.Error, "reject", err)
return err
}
Expand Down
200 changes: 200 additions & 0 deletions acknowledger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package amqp091otel

import (
"context"
"errors"
"slices"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/codes"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
"go.opentelemetry.io/otel/trace"

mockamqp091 "github.com/wzy9607/amqp091otel/mocks/amqp091"
)

func initMockTracerProvider() (*tracesdk.TracerProvider, *tracetest.InMemoryExporter) {
exp := tracetest.NewInMemoryExporter()
tp := tracesdk.NewTracerProvider(tracesdk.WithSyncer(exp))
return tp, exp
}

func Test_acknowledger(t *testing.T) {
t.Parallel()
type fields struct {
ch *Channel
acker *mockamqp091.MockAcknowledger
ctx context.Context
span trace.Span
}
type args struct {
tag uint64
multiple bool
requeue bool
}
tests := []struct {
name string
setup func(t *testing.T, fields *fields, args args) (exp *tracetest.InMemoryExporter)
fields fields
args args
wantErr bool
wantNonEndedSpansLen int
wantEndedSpansLen int
wantSpanStatus tracesdk.Status
}{
{
name: "ack one",
setup: func(t *testing.T, fields *fields, args args) (exp *tracetest.InMemoryExporter) {
t.Helper()
tp, exp := initMockTracerProvider()
_, fields.ch.spanMap[args.tag] = tp.Tracer("test").Start(fields.ctx, "should end 1")
_, fields.ch.spanMap[args.tag+1] = tp.Tracer("test").Start(fields.ctx, "should not end")
fields.span = fields.ch.spanMap[args.tag]

fields.acker.EXPECT().Ack(args.tag, args.multiple).Return(nil)
return exp
},
args: args{
tag: 2,
},
wantNonEndedSpansLen: 1,
wantEndedSpansLen: 1,
wantSpanStatus: tracesdk.Status{Code: codes.Ok, Description: ""},
}, {
name: "ack multiple",
setup: func(t *testing.T, fields *fields, args args) (exp *tracetest.InMemoryExporter) {
t.Helper()
tp, exp := initMockTracerProvider()
_, fields.ch.spanMap[args.tag] = tp.Tracer("test").Start(fields.ctx, "should end 1")
_, fields.ch.spanMap[args.tag-1] = tp.Tracer("test").Start(fields.ctx, "should end 2")
_, fields.ch.spanMap[args.tag+1] = tp.Tracer("test").Start(fields.ctx, "should not end")
fields.span = fields.ch.spanMap[args.tag]

fields.acker.EXPECT().Ack(args.tag, args.multiple).Return(nil)
return exp
},
args: args{
tag: 2,
multiple: true,
},
wantNonEndedSpansLen: 1,
wantEndedSpansLen: 2,
wantSpanStatus: tracesdk.Status{Code: codes.Ok, Description: ""},
}, {
name: "nack one",
setup: func(t *testing.T, fields *fields, args args) (exp *tracetest.InMemoryExporter) {
t.Helper()
tp, exp := initMockTracerProvider()
_, fields.ch.spanMap[args.tag] = tp.Tracer("test").Start(fields.ctx, "should end 1")
_, fields.ch.spanMap[args.tag+1] = tp.Tracer("test").Start(fields.ctx, "should not end")
fields.span = fields.ch.spanMap[args.tag]

fields.acker.EXPECT().Nack(args.tag, args.multiple, args.requeue).Return(nil)
return exp
},
args: args{
tag: 2,
},
wantNonEndedSpansLen: 1,
wantEndedSpansLen: 1,
wantSpanStatus: tracesdk.Status{Code: codes.Error, Description: "nack"},
}, {
name: "nack multiple, got error",
setup: func(t *testing.T, fields *fields, args args) (exp *tracetest.InMemoryExporter) {
t.Helper()
tp, exp := initMockTracerProvider()
_, fields.ch.spanMap[args.tag] = tp.Tracer("test").Start(fields.ctx, "should end 1")
_, fields.ch.spanMap[args.tag-1] = tp.Tracer("test").Start(fields.ctx, "should end 2")
_, fields.ch.spanMap[args.tag+1] = tp.Tracer("test").Start(fields.ctx, "should not end")
fields.span = fields.ch.spanMap[args.tag]

fields.acker.EXPECT().Nack(args.tag, args.multiple, args.requeue).Return(errors.New("some error"))
return exp
},
args: args{
tag: 2,
multiple: true,
},
wantErr: true,
wantNonEndedSpansLen: 1,
wantEndedSpansLen: 2,
wantSpanStatus: tracesdk.Status{Code: codes.Error, Description: "nack"},
}, {
name: "reject, got error",
setup: func(t *testing.T, fields *fields, args args) (exp *tracetest.InMemoryExporter) {
t.Helper()
tp, exp := initMockTracerProvider()
_, fields.ch.spanMap[args.tag] = tp.Tracer("test").Start(fields.ctx, "should end 1")
_, fields.ch.spanMap[args.tag+1] = tp.Tracer("test").Start(fields.ctx, "should not end")
fields.span = fields.ch.spanMap[args.tag]

fields.acker.EXPECT().Reject(args.tag, args.requeue).Return(errors.New("some error"))
return exp
},
args: args{
tag: 2,
},
wantErr: true,
wantNonEndedSpansLen: 1,
wantEndedSpansLen: 1,
wantSpanStatus: tracesdk.Status{Code: codes.Error, Description: "reject"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
tt.fields = fields{
ch: &Channel{spanMap: make(map[uint64]trace.Span)},
acker: mockamqp091.NewMockAcknowledger(t),
ctx: context.Background(),
}
exp := tt.setup(t, &tt.fields, tt.args)
a := &acknowledger{
ch: tt.fields.ch,
acker: tt.fields.acker,
ctx: tt.fields.ctx,
span: tt.fields.span,
}
var err error
switch {
case strings.HasPrefix(tt.name, "ack"):
err = a.Ack(tt.args.tag, tt.args.multiple)
case strings.HasPrefix(tt.name, "nack"):
err = a.Nack(tt.args.tag, tt.args.multiple, tt.args.requeue)
case strings.HasPrefix(tt.name, "reject"):
err = a.Reject(tt.args.tag, tt.args.requeue)
default:
t.Fatalf("unknown test case: %s", tt.name)
}
if !tt.wantErr {
require.NoError(t, err)
} else {
require.Error(t, err)
}

spans := exp.GetSpans()
// only check ended spans
spans = slices.DeleteFunc(spans, func(s tracetest.SpanStub) bool { return s.EndTime.IsZero() })
assert.Len(t, spans, tt.wantEndedSpansLen)
for _, span := range spans {
assert.Truef(t, strings.HasPrefix(span.Name, "should end"), "span %s is not expected to be ended", span.Name)
assert.Equal(t, tt.wantSpanStatus, span.Status)
if tt.wantErr {
assert.Len(t, span.Events, 1)
} else {
assert.Empty(t, span.Events)
}
}

assert.Lenf(t, tt.fields.ch.spanMap, tt.wantNonEndedSpansLen, "spanMap should only have non-ended spans")
for tag := range tt.fields.ch.spanMap {
assert.Greater(t, tag, tt.args.tag)
}
})
}
}
7 changes: 4 additions & 3 deletions channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ func (ch *Channel) startConsumerSpan(msg *amqp091.Delivery, queue string, operat
ctx, span := ch.cfg.Tracer.Start(parentCtx, //nolint:spancheck // span ends when msg is ack/nack/rejected
ch.nameWhenConsume(queue), opts...)
msg.Acknowledger = &acknowledger{
ch: ch,
ctx: ctx,
span: span,
ch: ch,
acker: ch.Channel,
ctx: ctx,
span: span,
}

ch.m.Lock()
Expand Down
2 changes: 2 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ coverage:
target: 80%
threshold: 2%
informational: true
ignore:
- "mocks/**"
47 changes: 47 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package amqp091otel

import (
"context"
"testing"

"github.com/stretchr/testify/assert"

"github.com/rabbitmq/amqp091-go"
)

func TestContextFromDelivery(t *testing.T) {
t.Parallel()
type key struct{}
ctxInst := context.WithValue(context.Background(), key{}, "value")
type args struct {
msg amqp091.Delivery
}
tests := []struct {
name string
args args
want context.Context
}{
{
name: "instrumented context",
args: args{
msg: amqp091.Delivery{
Acknowledger: &acknowledger{ctx: ctxInst},
},
},
want: ctxInst,
}, {
name: "background context",
args: args{
msg: amqp091.Delivery{},
},
want: context.Background(),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
assert.Equalf(t, tt.want, ContextFromDelivery(tt.args.msg), "ContextFromDelivery(%v)", tt.args.msg)
})
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/rabbitmq/amqp091-go v1.9.0
github.com/stretchr/testify v1.8.4
go.opentelemetry.io/otel v1.23.1
go.opentelemetry.io/otel/sdk v1.23.1
go.opentelemetry.io/otel/trace v1.23.1
)

Expand All @@ -14,6 +15,8 @@ require (
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.1 // indirect
go.opentelemetry.io/otel/metric v1.23.1 // indirect
golang.org/x/sys v0.17.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,26 @@ github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY=
go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA=
go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo=
go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI=
go.opentelemetry.io/otel/sdk v1.23.1 h1:O7JmZw0h76if63LQdsBMKQDWNb5oEcOThG9IrxscV+E=
go.opentelemetry.io/otel/sdk v1.23.1/go.mod h1:LzdEVR5am1uKOOwfBWFef2DCi1nu3SA8XQxx2IerWFk=
go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8=
go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
Loading

0 comments on commit 38dc0d8

Please sign in to comment.