blockchain/internal/lib/cassandra/ez_transaction_test.go

248 lines
5.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cassandra
import (
"fmt"
"testing"
"github.com/gocql/gocql"
"github.com/stretchr/testify/assert"
)
type TE struct {
ID gocql.UUID `db:"id" partition_key:"true"`
Name string `db:"name"`
}
func (m *TE) TableName() string {
return "test_entity"
}
func TestNewEZTransactionInsert(t *testing.T) {
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
err := db.EnsureTable(`
CREATE TABLE IF NOT EXISTS my_keyspace.test_entity (
id UUID PRIMARY KEY,
name TEXT
);`)
assert.NoError(t, err)
// 定義 table-driven 測試案例
tests := []struct {
name string
doc TE
}{
{
name: "insert_record_alice",
doc: TE{
ID: gocql.TimeUUID(),
Name: "Alice",
},
},
{
name: "insert_record_bob",
doc: TE{
ID: gocql.TimeUUID(),
Name: "Bob",
},
},
{
name: "insert_record_empty_name",
doc: TE{
ID: gocql.TimeUUID(),
Name: "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 每個子案例都使用新的 transaction
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
// 1. 呼叫 Insert
err := tx.Insert(container.Ctx, &tt.doc)
assert.NoError(t, err, "Insert() 應該不會錯誤")
// 2. 呼叫 Commit真正寫入 Cassandra
err = tx.Commit()
assert.NoError(t, err, "Commit() 應該不會錯誤")
// 3. 從 Cassandra 查回資料,驗證
var got TE
got.ID = tt.doc.ID
err = db.Get(container.Ctx, &got, "my_keyspace")
assert.NoError(t, err)
// 驗證欄位值符合
assert.Equal(t, tt.doc.ID, got.ID, "ID 應一致")
assert.Equal(t, tt.doc.Name, got.Name, "Name 應一致")
})
}
}
func TestNewEZTransactionDelete(t *testing.T) {
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
err := db.EnsureTable(`
CREATE TABLE IF NOT EXISTS my_keyspace.test_entity (
id UUID PRIMARY KEY,
name TEXT
);`)
assert.NoError(t, err)
// 定義 table-driven 測試案例
tests := []struct {
name string
doc TE
}{
{
name: "ok",
doc: TE{
ID: gocql.TimeUUID(),
Name: "Alice",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 每個子案例都使用新的 transaction
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
// 1. 呼叫 Delete
err := tx.Insert(container.Ctx, &tt.doc)
assert.NoError(t, err, "Insert() 應該不會錯誤")
// 2. 呼叫 Delete
err = tx.Delete(container.Ctx, &tt.doc)
assert.NoError(t, err, "Delete() 應該不會錯誤")
// 3. 呼叫 Commit真正寫入 Cassandra
err = tx.Commit()
assert.NoError(t, err, "Commit() 應該不會錯誤")
//
// 4. 從 Cassandra 查回資料,驗證
var got TE
got.ID = tt.doc.ID
err = db.Get(container.Ctx, &got, "my_keyspace")
assert.Equal(t, err, gocql.ErrNotFound)
})
}
}
func TestNewEZTransactionUpdate(t *testing.T) {
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
assert.NoError(t, db.EnsureTable(`
CREATE TABLE IF NOT EXISTS my_keyspace.test_entity (
id UUID PRIMARY KEY,
name TEXT
);
`))
// 2. 插入初始資料
id := gocql.TimeUUID()
before := TE{ID: id, Name: "Before"}
assert.NoError(t, db.Insert(container.Ctx, &before, "my_keyspace"))
// 定義多組更新案例
tests := []struct {
name string
newName string
wantErr bool
}{
{name: "update_to_Alice", newName: "Alice"},
{name: "update_to_empty", newName: "", wantErr: true},
{name: "update_to_Bob", newName: "Bob"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 為每個案例都重置為 Before
// 重新 insert 一次(覆蓋舊值)
assert.NoError(t, db.Insert(container.Ctx, &before, "my_keyspace"))
// 3. 建立 transaction 並呼叫 Update
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
updateDoc := TE{ID: id, Name: tt.newName}
err := tx.Update(container.Ctx, &updateDoc)
if tt.wantErr {
assert.Error(t, err, "Update() 應該會出錯")
return
}
assert.NoError(t, err, "Update() 不應出錯")
// 4. Commit 實際寫入
err = tx.Commit()
assert.NoError(t, err, "Commit() 不應出錯")
// 5. 查詢並驗證
var got TE
got.ID = id
err = db.Get(container.Ctx, &got, "my_keyspace")
assert.NoError(t, err, "db.Get() 應成功")
assert.Equal(t, id, got.ID, "ID 應一致")
assert.Equal(t, tt.newName, got.Name, "Name 應被更新為最新值")
})
}
}
func Test_Rollback(t *testing.T) {
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
assert.NoError(t, db.EnsureTable(`
CREATE TABLE IF NOT EXISTS my_keyspace.test_entity (
id UUID PRIMARY KEY,
name TEXT
);
`))
// 3. 用 Transaction 插入一筆資料,並 Commit
id := gocql.TimeUUID()
doc := TE{ID: id, Name: "Alice"}
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
err := tx.Insert(container.Ctx, &doc)
assert.NoError(t, err)
err = tx.Commit()
assert.NoError(t, err)
// 4. Query 確認資料已存在
var got TE
got.ID = id
err = db.Get(container.Ctx, &got, "my_keyspace")
assert.NoError(t, err)
assert.Equal(t, got.Name, doc.Name)
// 5. 呼叫 Rollback應自動刪除剛剛那筆
err = tx.Rollback()
assert.NoError(t, err)
var afterGot TE
afterGot.ID = id
err = db.Get(container.Ctx, &afterGot, "my_keyspace")
assert.Error(t, err)
// Output:
// after commit: Alice
// after rollback: not found
}