blockchain/internal/lib/cassandra/ez_transaction_test.go

248 lines
5.6 KiB
Go
Raw Normal View History

2025-08-05 23:41:29 +00:00
package cassandra
import (
2025-08-06 07:08:32 +00:00
"fmt"
"testing"
2025-08-05 23:41:29 +00:00
"github.com/gocql/gocql"
"github.com/stretchr/testify/assert"
)
type TE struct {
2025-08-06 07:08:32 +00:00
ID gocql.UUID `db:"id" partition_key:"true"`
Name string `db:"name"`
2025-08-05 23:41:29 +00:00
}
func (m *TE) TableName() string {
return "test_entity"
}
func TestNewEZTransactionInsert(t *testing.T) {
2025-08-06 07:08:32 +00:00
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
2025-08-05 23:41:29 +00:00
2025-08-06 07:08:32 +00:00
err := db.EnsureTable(`
2025-08-05 23:41:29 +00:00
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
2025-08-06 07:08:32 +00:00
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
2025-08-05 23:41:29 +00:00
// 1. 呼叫 Insert
2025-08-06 07:08:32 +00:00
err := tx.Insert(container.Ctx, &tt.doc)
2025-08-05 23:41:29 +00:00
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
2025-08-06 07:08:32 +00:00
err = db.Get(container.Ctx, &got, "my_keyspace")
2025-08-05 23:41:29 +00:00
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) {
2025-08-06 07:08:32 +00:00
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
2025-08-05 23:41:29 +00:00
2025-08-06 07:08:32 +00:00
err := db.EnsureTable(`
2025-08-05 23:41:29 +00:00
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
2025-08-06 07:08:32 +00:00
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
2025-08-05 23:41:29 +00:00
// 1. 呼叫 Delete
2025-08-06 07:08:32 +00:00
err := tx.Insert(container.Ctx, &tt.doc)
2025-08-05 23:41:29 +00:00
assert.NoError(t, err, "Insert() 應該不會錯誤")
// 2. 呼叫 Delete
2025-08-06 07:08:32 +00:00
err = tx.Delete(container.Ctx, &tt.doc)
2025-08-05 23:41:29 +00:00
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
2025-08-06 07:08:32 +00:00
err = db.Get(container.Ctx, &got, "my_keyspace")
2025-08-05 23:41:29 +00:00
assert.Equal(t, err, gocql.ErrNotFound)
})
}
}
func TestNewEZTransactionUpdate(t *testing.T) {
2025-08-06 07:08:32 +00:00
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
2025-08-05 23:41:29 +00:00
assert.NoError(t, db.EnsureTable(`
CREATE TABLE IF NOT EXISTS my_keyspace.test_entity (
2025-08-06 07:08:32 +00:00
id UUID PRIMARY KEY,
name TEXT
2025-08-05 23:41:29 +00:00
);
`))
// 2. 插入初始資料
id := gocql.TimeUUID()
before := TE{ID: id, Name: "Before"}
2025-08-06 07:08:32 +00:00
assert.NoError(t, db.Insert(container.Ctx, &before, "my_keyspace"))
2025-08-05 23:41:29 +00:00
// 定義多組更新案例
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 一次(覆蓋舊值)
2025-08-06 07:08:32 +00:00
assert.NoError(t, db.Insert(container.Ctx, &before, "my_keyspace"))
2025-08-05 23:41:29 +00:00
// 3. 建立 transaction 並呼叫 Update
2025-08-06 07:08:32 +00:00
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
2025-08-05 23:41:29 +00:00
updateDoc := TE{ID: id, Name: tt.newName}
2025-08-06 07:08:32 +00:00
err := tx.Update(container.Ctx, &updateDoc)
2025-08-05 23:41:29 +00:00
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
2025-08-06 07:08:32 +00:00
err = db.Get(container.Ctx, &got, "my_keyspace")
2025-08-05 23:41:29 +00:00
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) {
2025-08-06 07:08:32 +00:00
container, db := setupForTest(t)
defer func() {
_ = container.Container.Terminate(container.Ctx)
fmt.Println("[TEST] Container terminated")
}()
2025-08-05 23:41:29 +00:00
assert.NoError(t, db.EnsureTable(`
CREATE TABLE IF NOT EXISTS my_keyspace.test_entity (
2025-08-06 07:08:32 +00:00
id UUID PRIMARY KEY,
name TEXT
2025-08-05 23:41:29 +00:00
);
`))
// 3. 用 Transaction 插入一筆資料,並 Commit
id := gocql.TimeUUID()
doc := TE{ID: id, Name: "Alice"}
2025-08-06 07:08:32 +00:00
tx := NewEZTransaction(container.Ctx, "my_keyspace", db)
err := tx.Insert(container.Ctx, &doc)
2025-08-05 23:41:29 +00:00
assert.NoError(t, err)
err = tx.Commit()
assert.NoError(t, err)
// 4. Query 確認資料已存在
var got TE
got.ID = id
2025-08-06 07:08:32 +00:00
err = db.Get(container.Ctx, &got, "my_keyspace")
2025-08-05 23:41:29 +00:00
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
2025-08-06 07:08:32 +00:00
err = db.Get(container.Ctx, &afterGot, "my_keyspace")
2025-08-05 23:41:29 +00:00
assert.Error(t, err)
// Output:
// after commit: Alice
// after rollback: not found
}