stmt_test.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. package sqlx
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "testing"
  7. "time"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. var errMockedPlaceholder = errors.New("placeholder")
  11. func TestStmt_exec(t *testing.T) {
  12. tests := []struct {
  13. name string
  14. query string
  15. args []any
  16. delay bool
  17. hasError bool
  18. err error
  19. lastInsertId int64
  20. rowsAffected int64
  21. }{
  22. {
  23. name: "normal",
  24. query: "select user from users where id=?",
  25. args: []any{1},
  26. lastInsertId: 1,
  27. rowsAffected: 2,
  28. },
  29. {
  30. name: "exec error",
  31. query: "select user from users where id=?",
  32. args: []any{1},
  33. hasError: true,
  34. err: errors.New("exec"),
  35. },
  36. {
  37. name: "exec more args error",
  38. query: "select user from users where id=? and name=?",
  39. args: []any{1},
  40. hasError: true,
  41. err: errors.New("exec"),
  42. },
  43. {
  44. name: "slowcall",
  45. query: "select user from users where id=?",
  46. args: []any{1},
  47. delay: true,
  48. lastInsertId: 1,
  49. rowsAffected: 2,
  50. },
  51. }
  52. for _, test := range tests {
  53. test := test
  54. fns := []func(args ...any) (sql.Result, error){
  55. func(args ...any) (sql.Result, error) {
  56. return exec(context.Background(), &mockedSessionConn{
  57. lastInsertId: test.lastInsertId,
  58. rowsAffected: test.rowsAffected,
  59. err: test.err,
  60. delay: test.delay,
  61. }, test.query, args...)
  62. },
  63. func(args ...any) (sql.Result, error) {
  64. return execStmt(context.Background(), &mockedStmtConn{
  65. lastInsertId: test.lastInsertId,
  66. rowsAffected: test.rowsAffected,
  67. err: test.err,
  68. delay: test.delay,
  69. }, test.query, args...)
  70. },
  71. }
  72. for _, fn := range fns {
  73. fn := fn
  74. t.Run(test.name, func(t *testing.T) {
  75. t.Parallel()
  76. res, err := fn(test.args...)
  77. if test.hasError {
  78. assert.NotNil(t, err)
  79. return
  80. }
  81. assert.Nil(t, err)
  82. lastInsertId, err := res.LastInsertId()
  83. assert.Nil(t, err)
  84. assert.Equal(t, test.lastInsertId, lastInsertId)
  85. rowsAffected, err := res.RowsAffected()
  86. assert.Nil(t, err)
  87. assert.Equal(t, test.rowsAffected, rowsAffected)
  88. })
  89. }
  90. }
  91. }
  92. func TestStmt_query(t *testing.T) {
  93. tests := []struct {
  94. name string
  95. query string
  96. args []any
  97. delay bool
  98. hasError bool
  99. err error
  100. }{
  101. {
  102. name: "normal",
  103. query: "select user from users where id=?",
  104. args: []any{1},
  105. },
  106. {
  107. name: "query error",
  108. query: "select user from users where id=?",
  109. args: []any{1},
  110. hasError: true,
  111. err: errors.New("exec"),
  112. },
  113. {
  114. name: "query more args error",
  115. query: "select user from users where id=? and name=?",
  116. args: []any{1},
  117. hasError: true,
  118. err: errors.New("exec"),
  119. },
  120. {
  121. name: "slowcall",
  122. query: "select user from users where id=?",
  123. args: []any{1},
  124. delay: true,
  125. },
  126. }
  127. for _, test := range tests {
  128. test := test
  129. fns := []func(args ...any) error{
  130. func(args ...any) error {
  131. return query(context.Background(), &mockedSessionConn{
  132. err: test.err,
  133. delay: test.delay,
  134. }, func(rows *sql.Rows) error {
  135. return nil
  136. }, test.query, args...)
  137. },
  138. func(args ...any) error {
  139. return queryStmt(context.Background(), &mockedStmtConn{
  140. err: test.err,
  141. delay: test.delay,
  142. }, func(rows *sql.Rows) error {
  143. return nil
  144. }, test.query, args...)
  145. },
  146. }
  147. for _, fn := range fns {
  148. fn := fn
  149. t.Run(test.name, func(t *testing.T) {
  150. t.Parallel()
  151. err := fn(test.args...)
  152. if test.hasError {
  153. assert.NotNil(t, err)
  154. return
  155. }
  156. assert.NotNil(t, err)
  157. })
  158. }
  159. }
  160. }
  161. func TestSetSlowThreshold(t *testing.T) {
  162. assert.Equal(t, defaultSlowThreshold, slowThreshold.Load())
  163. SetSlowThreshold(time.Second)
  164. assert.Equal(t, time.Second, slowThreshold.Load())
  165. }
  166. func TestDisableLog(t *testing.T) {
  167. assert.True(t, logSql.True())
  168. assert.True(t, logSlowSql.True())
  169. defer func() {
  170. logSql.Set(true)
  171. logSlowSql.Set(true)
  172. }()
  173. DisableLog()
  174. assert.False(t, logSql.True())
  175. assert.False(t, logSlowSql.True())
  176. }
  177. func TestDisableStmtLog(t *testing.T) {
  178. assert.True(t, logSql.True())
  179. assert.True(t, logSlowSql.True())
  180. defer func() {
  181. logSql.Set(true)
  182. logSlowSql.Set(true)
  183. }()
  184. DisableStmtLog()
  185. assert.False(t, logSql.True())
  186. assert.True(t, logSlowSql.True())
  187. }
  188. func TestNilGuard(t *testing.T) {
  189. assert.True(t, logSql.True())
  190. assert.True(t, logSlowSql.True())
  191. defer func() {
  192. logSql.Set(true)
  193. logSlowSql.Set(true)
  194. }()
  195. DisableLog()
  196. guard := newGuard("any")
  197. assert.Nil(t, guard.start("foo", "bar"))
  198. guard.finish(context.Background(), nil)
  199. assert.Equal(t, nilGuard{}, guard)
  200. }
  201. type mockedSessionConn struct {
  202. lastInsertId int64
  203. rowsAffected int64
  204. err error
  205. delay bool
  206. }
  207. func (m *mockedSessionConn) Exec(query string, args ...any) (sql.Result, error) {
  208. return m.ExecContext(context.Background(), query, args...)
  209. }
  210. func (m *mockedSessionConn) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) {
  211. if m.delay {
  212. time.Sleep(defaultSlowThreshold + time.Millisecond)
  213. }
  214. return mockedResult{
  215. lastInsertId: m.lastInsertId,
  216. rowsAffected: m.rowsAffected,
  217. }, m.err
  218. }
  219. func (m *mockedSessionConn) Query(query string, args ...any) (*sql.Rows, error) {
  220. return m.QueryContext(context.Background(), query, args...)
  221. }
  222. func (m *mockedSessionConn) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
  223. if m.delay {
  224. time.Sleep(defaultSlowThreshold + time.Millisecond)
  225. }
  226. err := errMockedPlaceholder
  227. if m.err != nil {
  228. err = m.err
  229. }
  230. return new(sql.Rows), err
  231. }
  232. type mockedStmtConn struct {
  233. lastInsertId int64
  234. rowsAffected int64
  235. err error
  236. delay bool
  237. }
  238. func (m *mockedStmtConn) Exec(args ...any) (sql.Result, error) {
  239. return m.ExecContext(context.Background(), args...)
  240. }
  241. func (m *mockedStmtConn) ExecContext(_ context.Context, _ ...any) (sql.Result, error) {
  242. if m.delay {
  243. time.Sleep(defaultSlowThreshold + time.Millisecond)
  244. }
  245. return mockedResult{
  246. lastInsertId: m.lastInsertId,
  247. rowsAffected: m.rowsAffected,
  248. }, m.err
  249. }
  250. func (m *mockedStmtConn) Query(args ...any) (*sql.Rows, error) {
  251. return m.QueryContext(context.Background(), args...)
  252. }
  253. func (m *mockedStmtConn) QueryContext(_ context.Context, _ ...any) (*sql.Rows, error) {
  254. if m.delay {
  255. time.Sleep(defaultSlowThreshold + time.Millisecond)
  256. }
  257. err := errMockedPlaceholder
  258. if m.err != nil {
  259. err = m.err
  260. }
  261. return new(sql.Rows), err
  262. }
  263. type mockedResult struct {
  264. lastInsertId int64
  265. rowsAffected int64
  266. }
  267. func (m mockedResult) LastInsertId() (int64, error) {
  268. return m.lastInsertId, nil
  269. }
  270. func (m mockedResult) RowsAffected() (int64, error) {
  271. return m.rowsAffected, nil
  272. }