248 lines
5.6 KiB
Go
248 lines
5.6 KiB
Go
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
|
||
}
|