Skip to content

Commit 7b2ebee

Browse files
committed
contrib/drivers/mariadb: add transaction, where, hook, and ctx tests
Align MariaDB test coverage with MySQL baseline (PR 2/6). - Add transaction_test.go (58 transaction and savepoint tests) - Add model_where_test.go (52 where condition tests) - Add feature_hook_test.go (7 hook mechanism tests) - Add feature_ctx_test.go (8 context propagation tests) ref gogf#4689
1 parent 6204c13 commit 7b2ebee

5 files changed

Lines changed: 4751 additions & 2 deletions
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package mariadb_test
8+
9+
import (
10+
"context"
11+
"testing"
12+
"time"
13+
14+
"github.com/gogf/gf/v2/database/gdb"
15+
"github.com/gogf/gf/v2/os/glog"
16+
"github.com/gogf/gf/v2/test/gtest"
17+
)
18+
19+
func Test_Ctx(t *testing.T) {
20+
gtest.C(t, func(t *gtest.T) {
21+
db, err := gdb.Instance()
22+
t.AssertNil(err)
23+
24+
err1 := db.PingMaster()
25+
err2 := db.PingSlave()
26+
t.Assert(err1, nil)
27+
t.Assert(err2, nil)
28+
29+
newDb := db.Ctx(context.Background())
30+
t.AssertNE(newDb, nil)
31+
})
32+
}
33+
34+
func Test_Ctx_Query(t *testing.T) {
35+
db.GetLogger().(*glog.Logger).SetCtxKeys("SpanId", "TraceId")
36+
gtest.C(t, func(t *gtest.T) {
37+
db.SetDebug(true)
38+
defer db.SetDebug(false)
39+
ctx := context.WithValue(context.Background(), "TraceId", "12345678")
40+
ctx = context.WithValue(ctx, "SpanId", "0.1")
41+
db.Query(ctx, "select 1")
42+
})
43+
gtest.C(t, func(t *gtest.T) {
44+
db.SetDebug(true)
45+
defer db.SetDebug(false)
46+
db.Query(ctx, "select 2")
47+
})
48+
}
49+
50+
func Test_Ctx_Model(t *testing.T) {
51+
table := createInitTable()
52+
defer dropTable(table)
53+
db.GetLogger().(*glog.Logger).SetCtxKeys("SpanId", "TraceId")
54+
gtest.C(t, func(t *gtest.T) {
55+
db.SetDebug(true)
56+
defer db.SetDebug(false)
57+
ctx := context.WithValue(context.Background(), "TraceId", "12345678")
58+
ctx = context.WithValue(ctx, "SpanId", "0.1")
59+
db.Model(table).Ctx(ctx).All()
60+
})
61+
gtest.C(t, func(t *gtest.T) {
62+
db.SetDebug(true)
63+
defer db.SetDebug(false)
64+
db.Model(table).All()
65+
})
66+
}
67+
68+
// Test_Ctx_Timeout tests context timeout behavior
69+
func Test_Ctx_Timeout(t *testing.T) {
70+
table := createInitTable()
71+
defer dropTable(table)
72+
73+
gtest.C(t, func(t *gtest.T) {
74+
// Create a context with very short timeout
75+
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
76+
defer cancel()
77+
78+
// Wait for timeout
79+
time.Sleep(1 * time.Millisecond)
80+
81+
// Query should fail due to context timeout
82+
_, err := db.Model(table).Ctx(ctx).All()
83+
t.AssertNE(err, nil)
84+
})
85+
}
86+
87+
// Test_Ctx_Cancel tests context cancellation
88+
func Test_Ctx_Cancel(t *testing.T) {
89+
table := createInitTable()
90+
defer dropTable(table)
91+
92+
gtest.C(t, func(t *gtest.T) {
93+
ctx, cancel := context.WithCancel(context.Background())
94+
// Cancel immediately
95+
cancel()
96+
97+
// Query should fail due to cancelled context
98+
_, err := db.Model(table).Ctx(ctx).All()
99+
t.AssertNE(err, nil)
100+
})
101+
}
102+
103+
// Test_Ctx_Propagation_Transaction tests context propagation in transaction
104+
func Test_Ctx_Propagation_Transaction(t *testing.T) {
105+
table := createInitTable()
106+
defer dropTable(table)
107+
db.GetLogger().(*glog.Logger).SetCtxKeys("TraceId")
108+
109+
gtest.C(t, func(t *gtest.T) {
110+
db.SetDebug(true)
111+
defer db.SetDebug(false)
112+
113+
ctx := context.WithValue(context.Background(), "TraceId", "tx_trace_123")
114+
err := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
115+
// Context should propagate to transaction operations
116+
_, err := tx.Model(table).Ctx(ctx).Where("id", 1).One()
117+
return err
118+
})
119+
t.AssertNil(err)
120+
})
121+
}
122+
123+
// Test_Ctx_Multiple_Values tests context with multiple values
124+
func Test_Ctx_Multiple_Values(t *testing.T) {
125+
table := createInitTable()
126+
defer dropTable(table)
127+
db.GetLogger().(*glog.Logger).SetCtxKeys("TraceId", "RequestId", "UserId")
128+
129+
gtest.C(t, func(t *gtest.T) {
130+
db.SetDebug(true)
131+
defer db.SetDebug(false)
132+
133+
ctx := context.WithValue(context.Background(), "TraceId", "trace_001")
134+
ctx = context.WithValue(ctx, "RequestId", "req_002")
135+
ctx = context.WithValue(ctx, "UserId", "user_003")
136+
137+
db.Model(table).Ctx(ctx).Where("id", 1).One()
138+
})
139+
}
140+
141+
// Test_Ctx_Nested_Operations tests context in nested operations
142+
func Test_Ctx_Nested_Operations(t *testing.T) {
143+
table := createInitTable()
144+
defer dropTable(table)
145+
db.GetLogger().(*glog.Logger).SetCtxKeys("TraceId")
146+
147+
gtest.C(t, func(t *gtest.T) {
148+
db.SetDebug(true)
149+
defer db.SetDebug(false)
150+
151+
ctx := context.WithValue(context.Background(), "TraceId", "nested_trace")
152+
153+
// Nested query operations should all have context
154+
result, err := db.Model(table).Ctx(ctx).Where("id>", 0).All()
155+
t.AssertNil(err)
156+
157+
if len(result) > 0 {
158+
// Another query using same context
159+
_, err = db.Model(table).Ctx(ctx).Where("id", result[0]["id"]).One()
160+
t.AssertNil(err)
161+
}
162+
})
163+
}
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package mariadb_test
8+
9+
import (
10+
"context"
11+
"database/sql"
12+
"fmt"
13+
"testing"
14+
15+
"github.com/gogf/gf/v2/container/gvar"
16+
"github.com/gogf/gf/v2/database/gdb"
17+
"github.com/gogf/gf/v2/frame/g"
18+
"github.com/gogf/gf/v2/test/gtest"
19+
)
20+
21+
func Test_Model_Hook_Select(t *testing.T) {
22+
table := createInitTable()
23+
defer dropTable(table)
24+
25+
gtest.C(t, func(t *gtest.T) {
26+
m := db.Model(table).Hook(gdb.HookHandler{
27+
Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {
28+
result, err = in.Next(ctx)
29+
if err != nil {
30+
return
31+
}
32+
for i, record := range result {
33+
record["test"] = gvar.New(100 + record["id"].Int())
34+
result[i] = record
35+
}
36+
return
37+
},
38+
})
39+
all, err := m.Where(`id > 6`).OrderAsc(`id`).All()
40+
t.AssertNil(err)
41+
t.Assert(len(all), 4)
42+
t.Assert(all[0]["id"].Int(), 7)
43+
t.Assert(all[0]["test"].Int(), 107)
44+
t.Assert(all[1]["test"].Int(), 108)
45+
t.Assert(all[2]["test"].Int(), 109)
46+
t.Assert(all[3]["test"].Int(), 110)
47+
})
48+
}
49+
50+
func Test_Model_Hook_Insert(t *testing.T) {
51+
table := createTable()
52+
defer dropTable(table)
53+
54+
gtest.C(t, func(t *gtest.T) {
55+
m := db.Model(table).Hook(gdb.HookHandler{
56+
Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {
57+
for i, item := range in.Data {
58+
item["passport"] = fmt.Sprintf(`test_port_%d`, item["id"])
59+
item["nickname"] = fmt.Sprintf(`test_name_%d`, item["id"])
60+
in.Data[i] = item
61+
}
62+
return in.Next(ctx)
63+
},
64+
})
65+
_, err := m.Insert(g.Map{
66+
"id": 1,
67+
"nickname": "name_1",
68+
})
69+
t.AssertNil(err)
70+
one, err := m.One()
71+
t.AssertNil(err)
72+
t.Assert(one["id"].Int(), 1)
73+
t.Assert(one["passport"], `test_port_1`)
74+
t.Assert(one["nickname"], `test_name_1`)
75+
})
76+
}
77+
78+
func Test_Model_Hook_Update(t *testing.T) {
79+
table := createInitTable()
80+
defer dropTable(table)
81+
82+
gtest.C(t, func(t *gtest.T) {
83+
m := db.Model(table).Hook(gdb.HookHandler{
84+
Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {
85+
switch value := in.Data.(type) {
86+
case gdb.List:
87+
for i, data := range value {
88+
data["passport"] = `port`
89+
data["nickname"] = `name`
90+
value[i] = data
91+
}
92+
in.Data = value
93+
94+
case gdb.Map:
95+
value["passport"] = `port`
96+
value["nickname"] = `name`
97+
in.Data = value
98+
}
99+
return in.Next(ctx)
100+
},
101+
})
102+
_, err := m.Data(g.Map{
103+
"nickname": "name_1",
104+
}).WherePri(1).Update()
105+
t.AssertNil(err)
106+
107+
one, err := m.One()
108+
t.AssertNil(err)
109+
t.Assert(one["id"].Int(), 1)
110+
t.Assert(one["passport"], `port`)
111+
t.Assert(one["nickname"], `name`)
112+
})
113+
}
114+
115+
func Test_Model_Hook_Delete(t *testing.T) {
116+
table := createInitTable()
117+
defer dropTable(table)
118+
119+
gtest.C(t, func(t *gtest.T) {
120+
m := db.Model(table).Hook(gdb.HookHandler{
121+
Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {
122+
return db.Model(table).Data(g.Map{
123+
"nickname": `deleted`,
124+
}).Where(in.Condition).Update()
125+
},
126+
})
127+
_, err := m.Where(1).Delete()
128+
t.AssertNil(err)
129+
130+
all, err := m.All()
131+
t.AssertNil(err)
132+
for _, item := range all {
133+
t.Assert(item["nickname"].String(), `deleted`)
134+
}
135+
})
136+
}
137+
138+
// Test_Model_Hook_Multiple tests multiple hooks execution order
139+
func Test_Model_Hook_Multiple(t *testing.T) {
140+
table := createInitTable()
141+
defer dropTable(table)
142+
143+
gtest.C(t, func(t *gtest.T) {
144+
var execOrder []string
145+
146+
m := db.Model(table).Hook(gdb.HookHandler{
147+
Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {
148+
execOrder = append(execOrder, "hook1_before")
149+
result, err = in.Next(ctx)
150+
execOrder = append(execOrder, "hook1_after")
151+
return
152+
},
153+
}).Hook(gdb.HookHandler{
154+
Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {
155+
execOrder = append(execOrder, "hook2_before")
156+
result, err = in.Next(ctx)
157+
execOrder = append(execOrder, "hook2_after")
158+
return
159+
},
160+
})
161+
162+
_, err := m.Where("id", 1).One()
163+
t.AssertNil(err)
164+
165+
// Verify only the last registered hook executes (Hook is override, not chain)
166+
t.Assert(len(execOrder), 2)
167+
t.Assert(execOrder, g.Slice{"hook2_before", "hook2_after"})
168+
})
169+
}
170+
171+
// Test_Model_Hook_Error_Abort tests hook returning error aborts operation
172+
func Test_Model_Hook_Error_Abort(t *testing.T) {
173+
table := createInitTable()
174+
defer dropTable(table)
175+
176+
gtest.C(t, func(t *gtest.T) {
177+
m := db.Model(table).Hook(gdb.HookHandler{
178+
Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {
179+
// Return error to abort insert
180+
return nil, fmt.Errorf("hook aborted insert")
181+
},
182+
})
183+
184+
_, err := m.Insert(g.Map{
185+
"passport": "test_abort",
186+
"password": "pass",
187+
"nickname": "name",
188+
})
189+
t.AssertNE(err, nil)
190+
t.Assert(err.Error(), "hook aborted insert")
191+
192+
// Verify record was not inserted
193+
count, err := db.Model(table).Where("passport", "test_abort").Count()
194+
t.AssertNil(err)
195+
t.Assert(count, 0)
196+
})
197+
}
198+
199+
// Test_Model_Hook_Modify_Data tests hook modifying data before insert
200+
func Test_Model_Hook_Modify_Data(t *testing.T) {
201+
table := createTable()
202+
defer dropTable(table)
203+
204+
gtest.C(t, func(t *gtest.T) {
205+
m := db.Model(table).Hook(gdb.HookHandler{
206+
Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {
207+
// Modify all data items
208+
for i := range in.Data {
209+
in.Data[i]["password"] = "encrypted_" + fmt.Sprint(in.Data[i]["password"])
210+
in.Data[i]["nickname"] = "verified_" + fmt.Sprint(in.Data[i]["nickname"])
211+
}
212+
return in.Next(ctx)
213+
},
214+
})
215+
216+
_, err := m.Insert(g.Map{
217+
"passport": "test_user",
218+
"password": "plain123",
219+
"nickname": "john",
220+
})
221+
t.AssertNil(err)
222+
223+
// Verify data was modified by hook
224+
one, err := db.Model(table).Where("passport", "test_user").One()
225+
t.AssertNil(err)
226+
t.Assert(one["password"].String(), "encrypted_plain123")
227+
t.Assert(one["nickname"].String(), "verified_john")
228+
})
229+
}

0 commit comments

Comments
 (0)