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
|
|
|
|
|
}
|