go-transaction-manager
232 строки · 5.0 Кб
1//go:build go1.14
2// +build go1.14
3
4package mongo5
6import (7"context"8"errors"9"sync"10"testing"11"time"12
13"github.com/stretchr/testify/assert"14"github.com/stretchr/testify/require"15"go.mongodb.org/mongo-driver/bson/primitive"16"go.mongodb.org/mongo-driver/mongo"17"go.mongodb.org/mongo-driver/mongo/integration/mtest"18"go.mongodb.org/mongo-driver/mongo/options"19"go.mongodb.org/mongo-driver/mongo/writeconcern"20
21trmcontext "github.com/avito-tech/go-transaction-manager/trm/v2/context"22"github.com/avito-tech/go-transaction-manager/trm/v2/drivers/mock"23
24"github.com/avito-tech/go-transaction-manager/trm/v2"25"github.com/avito-tech/go-transaction-manager/trm/v2/manager"26"github.com/avito-tech/go-transaction-manager/trm/v2/settings"27)
28
29type user struct {30ID primitive.ObjectID `bson:"_id,omitempty"`31}
32
33func TestTransaction(t *testing.T) {34t.Parallel()35
36type args struct {37ctx context.Context38}39
40type fields struct {41settings trm.Settings42}43
44testErr := errors.New("error test")45doNil := func(_ *mtest.T, _ context.Context) error {46return nil47}48defaultFields := func(_ *mtest.T) fields {49return fields{50settings: MustSettings(settings.Must(51settings.WithPropagation(trm.PropagationRequiresNew),52), WithSessionOpts(&options.SessionOptions{})),53}54}55
56mt := mtest.New(57t,58mtest.NewOptions().ClientType(mtest.Mock),59)60
61tests := map[string]struct {62fields func(mt *mtest.T) fields63args args
64do func(mt *mtest.T, ctx context.Context) error65wantErr assert.ErrorAssertionFunc66}{67"success": {68fields: defaultFields,69args: args{70ctx: context.Background(),71},72do: doNil,73wantErr: assert.NoError,74},75"begin_session_error": {76fields: func(_ *mtest.T) fields {77return fields{78settings: MustSettings(settings.Must(79settings.WithPropagation(trm.PropagationNested),80), WithSessionOpts((&options.SessionOptions{}).81SetSnapshot(true).82SetCausalConsistency(true))),83}84},85args: args{86ctx: context.Background(),87},88do: func(mt *mtest.T, _ context.Context) error {89require.NotNil(mt, 1, "should not be here")90
91return nil92},93wantErr: func(t assert.TestingT, err error, _ ...interface{}) bool {94return assert.ErrorIs(t, err, trm.ErrBegin)95},96},97"begin_transaction_error": {98fields: func(_ *mtest.T) fields {99return fields{100settings: MustSettings(settings.Must(101settings.WithPropagation(trm.PropagationNested),102), WithTransactionOpts((&options.TransactionOptions{}).103SetWriteConcern(&writeconcern.WriteConcern{W: 0}))),104}105},106args: args{107ctx: context.Background(),108},109do: func(mt *mtest.T, _ context.Context) error {110require.NotNil(mt, 1, "should not be here")111
112return nil113},114wantErr: func(t assert.TestingT, err error, _ ...interface{}) bool {115return assert.ErrorIs(t, err, trm.ErrBegin)116},117},118"commit_error": {119fields: defaultFields,120args: args{121ctx: context.Background(),122},123do: func(mt *mtest.T, ctx context.Context) error {124_, _ = mt.Coll.InsertOne(ctx, user{125ID: primitive.NewObjectID(),126})127
128return nil129},130wantErr: func(t assert.TestingT, err error, _ ...interface{}) bool {131var divErr mongo.CommandError132
133return assert.ErrorAs(t, err, &divErr) &&134assert.ErrorIs(t, err, trm.ErrCommit)135},136},137"rollback_after_error": {138fields: defaultFields,139args: args{140ctx: context.Background(),141},142do: func(mt *mtest.T, ctx context.Context) error {143s := mongo.SessionFromContext(ctx)144
145require.NoError(mt, s.AbortTransaction(ctx))146
147return testErr148},149wantErr: func(t assert.TestingT, err error, _ ...interface{}) bool {150return assert.ErrorIs(t, err, testErr) &&151assert.ErrorIs(t, err, trm.ErrRollback)152},153},154}155for name, tt := range tests {156tt := tt157mt.Run(name, func(mt *mtest.T) {158mt.Parallel()159
160log := mock.NewLog()161
162f := tt.fields(mt)163
164m := manager.Must(165NewDefaultFactory(mt.Client),166manager.WithLog(log),167manager.WithSettings(f.settings),168)169
170var tr trm.Transaction171err := m.Do(tt.args.ctx, func(ctx context.Context) error {172tr = trmcontext.DefaultManager.Default(ctx)173
174var trNested trm.Transaction175err := m.Do(ctx, func(ctx context.Context) error {176trNested = trmcontext.DefaultManager.Default(ctx)177
178require.NotNil(t, trNested)179
180return tt.do(mt, ctx)181})182
183if trNested != nil {184require.False(t, trNested.IsActive())185}186
187return err188})189
190if tr != nil {191require.False(t, tr.IsActive())192}193
194if !tt.wantErr(t, err) {195return196}197})198}199}
200
201func TestTransaction_awaitDone_byContext(t *testing.T) {202t.Parallel()203
204mt := mtest.New(205t,206mtest.NewOptions().207ClientType(mtest.Mock).208ShareClient(true),209)210
211wg := sync.WaitGroup{}212wg.Add(1)213
214f := NewDefaultFactory(mt.Client)215ctx, cancel := context.WithCancel(context.Background())216
217go func() {218defer wg.Done()219
220_, tr, err := f(ctx, settings.Must())221
222cancel()223<-time.After(time.Second)224
225<-ctx.Done()226
227require.NoError(mt, err)228require.False(mt, tr.IsActive())229}()230
231wg.Wait()232}
233