github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/tests/integration/topic_transactions_test.go (about) 1 //go:build integration 2 // +build integration 3 4 package integration 5 6 import ( 7 "context" 8 "errors" 9 "io" 10 "os" 11 "strconv" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/stretchr/testify/require" 17 18 "github.com/ydb-platform/ydb-go-sdk/v3/internal/version" 19 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" 20 "github.com/ydb-platform/ydb-go-sdk/v3/query" 21 "github.com/ydb-platform/ydb-go-sdk/v3/topic/topicwriter" 22 ) 23 24 func TestTopicReadInTransaction(t *testing.T) { 25 if os.Getenv("YDB_VERSION") != "nightly" && version.Lt(os.Getenv("YDB_VERSION"), "25.0") { 26 t.Skip("require enables transactions for topics") 27 } 28 scope := newScope(t) 29 ctx := scope.Ctx 30 require.NoError(t, scope.TopicWriter().Write(ctx, topicwriter.Message{Data: strings.NewReader("asd")})) 31 scope.Logf("topic message written") 32 33 require.NoError(t, scope.Driver().Query().DoTx(ctx, func(ctx context.Context, tx query.TxActor) error { 34 reader := scope.TopicReaderNamed("first") 35 scope.Logf("trying to pop a batch") 36 batch, err := reader.PopMessagesBatchTx(ctx, tx) 37 scope.Logf("pop a batch result: %v", err) 38 if err != nil { 39 return err 40 } 41 content := string(xtest.Must(io.ReadAll(batch.Messages[0]))) 42 require.Equal(t, "asd", content) 43 _ = reader.Close(ctx) 44 return nil 45 })) 46 47 scope.Logf("first pop messages done") 48 49 scope.Logf("writting second message") 50 require.NoError(t, scope.TopicWriter().Write(ctx, topicwriter.Message{Data: strings.NewReader("bbb")})) 51 52 require.NoError(t, scope.Driver().Query().DoTx(ctx, func(ctx context.Context, tx query.TxActor) error { 53 reader := scope.TopicReaderNamed("second") 54 // err := tx.Exec(ctx, "SELECT 1", query.WithCommit()) 55 err := tx.Exec(ctx, "SELECT 1") 56 if err != nil { 57 return err 58 } 59 60 scope.Logf("trying second pop batch") 61 batch, err := reader.PopMessagesBatchTx(ctx, tx) 62 scope.Logf("second pop batch result: %v", err) 63 if err != nil { 64 return err 65 } 66 content := string(xtest.Must(io.ReadAll(batch.Messages[0]))) 67 require.Equal(t, "bbb", content) 68 return nil 69 })) 70 } 71 72 func TestWriteInTransaction(t *testing.T) { 73 if os.Getenv("YDB_VERSION") != "nightly" && version.Lt(os.Getenv("YDB_VERSION"), "25.0") { 74 t.Skip("require enables transactions for topics") 75 } 76 77 t.Run("OK", func(t *testing.T) { 78 scope := newScope(t) 79 reader := scope.TopicReader() 80 81 driver := scope.DriverWithGRPCLogging() 82 83 const writeTime = time.Second 84 protectCtx, cancel := context.WithTimeout(scope.Ctx, writeTime*10) 85 defer cancel() 86 87 deadline := time.Now().Add(writeTime) 88 transactionsCount := 0 89 for { 90 err := driver.Query().DoTx(scope.Ctx, func(ctx context.Context, tx query.TxActor) error { 91 writer, err := driver.Topic().StartTransactionalWriter(tx, scope.TopicPath()) 92 if err != nil { 93 return err 94 } 95 96 return writer.Write(ctx, topicwriter.Message{Data: strings.NewReader(strconv.Itoa(transactionsCount))}) 97 }) 98 require.NoError(t, err) 99 transactionsCount++ 100 if time.Now().After(deadline) { 101 break 102 } 103 } 104 105 for i := 0; i < transactionsCount; i++ { 106 mess, err := reader.ReadMessage(protectCtx) 107 require.NoError(t, err) 108 109 contentBytes, _ := io.ReadAll(mess) 110 content := string(contentBytes) 111 require.Equal(t, strconv.Itoa(i), content) 112 } 113 t.Logf("transactions count: %v", transactionsCount) 114 }) 115 116 t.Run("Rollback", func(t *testing.T) { 117 scope := newScope(t) 118 reader := scope.TopicReader() 119 120 driver := scope.Driver() 121 122 const writeTime = time.Second 123 protectCtx, cancel := context.WithTimeout(scope.Ctx, writeTime*10) 124 defer cancel() 125 126 deadline := time.Now().Add(writeTime) 127 transactionsCount := 0 128 testErr := errors.New("test") 129 for { 130 err := driver.Query().DoTx(scope.Ctx, func(ctx context.Context, tx query.TxActor) error { 131 writer, err := driver.Topic().StartTransactionalWriter(tx, scope.TopicPath()) 132 if err != nil { 133 return err 134 } 135 136 require.NoError(t, writer.Write(ctx, topicwriter.Message{Data: strings.NewReader(strconv.Itoa(transactionsCount))})) 137 return testErr 138 }) 139 require.ErrorIs(t, err, testErr) 140 transactionsCount++ 141 if time.Now().After(deadline) { 142 break 143 } 144 } 145 146 protectCtx, cancel = context.WithTimeout(scope.Ctx, time.Millisecond*10) 147 defer cancel() 148 149 mess, err := reader.ReadMessage(protectCtx) 150 require.ErrorIs(t, err, context.DeadlineExceeded) 151 _ = mess 152 t.Logf("transactions count: %v", transactionsCount) 153 }) 154 }