/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/sqlmock.go

https://github.com/cloudinsight/cloudinsight-agent · Go · 457 lines · 340 code · 66 blank · 51 comment · 87 complexity · 035b3d39e15402989a4b62785252aefe MD5 · raw file

  1. /*
  2. Package sqlmock is a mock library implementing sql driver. Which has one and only
  3. purpose - to simulate any sql driver behavior in tests, without needing a real
  4. database connection. It helps to maintain correct **TDD** workflow.
  5. It does not require any modifications to your source code in order to test
  6. and mock database operations. Supports concurrency and multiple database mocking.
  7. The driver allows to mock any sql driver method behavior.
  8. */
  9. package sqlmock
  10. import (
  11. "database/sql"
  12. "database/sql/driver"
  13. "fmt"
  14. "regexp"
  15. )
  16. // Sqlmock interface serves to create expectations
  17. // for any kind of database action in order to mock
  18. // and test real database behavior.
  19. type Sqlmock interface {
  20. // ExpectClose queues an expectation for this database
  21. // action to be triggered. the *ExpectedClose allows
  22. // to mock database response
  23. ExpectClose() *ExpectedClose
  24. // ExpectationsWereMet checks whether all queued expectations
  25. // were met in order. If any of them was not met - an error is returned.
  26. ExpectationsWereMet() error
  27. // ExpectPrepare expects Prepare() to be called with sql query
  28. // which match sqlRegexStr given regexp.
  29. // the *ExpectedPrepare allows to mock database response.
  30. // Note that you may expect Query() or Exec() on the *ExpectedPrepare
  31. // statement to prevent repeating sqlRegexStr
  32. ExpectPrepare(sqlRegexStr string) *ExpectedPrepare
  33. // ExpectQuery expects Query() or QueryRow() to be called with sql query
  34. // which match sqlRegexStr given regexp.
  35. // the *ExpectedQuery allows to mock database response.
  36. ExpectQuery(sqlRegexStr string) *ExpectedQuery
  37. // ExpectExec expects Exec() to be called with sql query
  38. // which match sqlRegexStr given regexp.
  39. // the *ExpectedExec allows to mock database response
  40. ExpectExec(sqlRegexStr string) *ExpectedExec
  41. // ExpectBegin expects *sql.DB.Begin to be called.
  42. // the *ExpectedBegin allows to mock database response
  43. ExpectBegin() *ExpectedBegin
  44. // ExpectCommit expects *sql.Tx.Commit to be called.
  45. // the *ExpectedCommit allows to mock database response
  46. ExpectCommit() *ExpectedCommit
  47. // ExpectRollback expects *sql.Tx.Rollback to be called.
  48. // the *ExpectedRollback allows to mock database response
  49. ExpectRollback() *ExpectedRollback
  50. // MatchExpectationsInOrder gives an option whether to match all
  51. // expectations in the order they were set or not.
  52. //
  53. // By default it is set to - true. But if you use goroutines
  54. // to parallelize your query executation, that option may
  55. // be handy.
  56. MatchExpectationsInOrder(bool)
  57. }
  58. type sqlmock struct {
  59. ordered bool
  60. dsn string
  61. opened int
  62. drv *mockDriver
  63. expected []expectation
  64. }
  65. func (c *sqlmock) open() (*sql.DB, Sqlmock, error) {
  66. db, err := sql.Open("sqlmock", c.dsn)
  67. if err != nil {
  68. return db, c, err
  69. }
  70. return db, c, db.Ping()
  71. }
  72. func (c *sqlmock) ExpectClose() *ExpectedClose {
  73. e := &ExpectedClose{}
  74. c.expected = append(c.expected, e)
  75. return e
  76. }
  77. func (c *sqlmock) MatchExpectationsInOrder(b bool) {
  78. c.ordered = b
  79. }
  80. // Close a mock database driver connection. It may or may not
  81. // be called depending on the sircumstances, but if it is called
  82. // there must be an *ExpectedClose expectation satisfied.
  83. // meets http://golang.org/pkg/database/sql/driver/#Conn interface
  84. func (c *sqlmock) Close() error {
  85. c.drv.Lock()
  86. defer c.drv.Unlock()
  87. c.opened--
  88. if c.opened == 0 {
  89. delete(c.drv.conns, c.dsn)
  90. }
  91. var expected *ExpectedClose
  92. var fulfilled int
  93. var ok bool
  94. for _, next := range c.expected {
  95. next.Lock()
  96. if next.fulfilled() {
  97. next.Unlock()
  98. fulfilled++
  99. continue
  100. }
  101. if expected, ok = next.(*ExpectedClose); ok {
  102. break
  103. }
  104. next.Unlock()
  105. if c.ordered {
  106. return fmt.Errorf("call to database Close, was not expected, next expectation is: %s", next)
  107. }
  108. }
  109. if expected == nil {
  110. msg := "call to database Close was not expected"
  111. if fulfilled == len(c.expected) {
  112. msg = "all expectations were already fulfilled, " + msg
  113. }
  114. return fmt.Errorf(msg)
  115. }
  116. expected.triggered = true
  117. expected.Unlock()
  118. return expected.err
  119. }
  120. func (c *sqlmock) ExpectationsWereMet() error {
  121. for _, e := range c.expected {
  122. if !e.fulfilled() {
  123. return fmt.Errorf("there is a remaining expectation which was not matched: %s", e)
  124. }
  125. }
  126. return nil
  127. }
  128. // Begin meets http://golang.org/pkg/database/sql/driver/#Conn interface
  129. func (c *sqlmock) Begin() (driver.Tx, error) {
  130. var expected *ExpectedBegin
  131. var ok bool
  132. var fulfilled int
  133. for _, next := range c.expected {
  134. next.Lock()
  135. if next.fulfilled() {
  136. next.Unlock()
  137. fulfilled++
  138. continue
  139. }
  140. if expected, ok = next.(*ExpectedBegin); ok {
  141. break
  142. }
  143. next.Unlock()
  144. if c.ordered {
  145. return nil, fmt.Errorf("call to database transaction Begin, was not expected, next expectation is: %s", next)
  146. }
  147. }
  148. if expected == nil {
  149. msg := "call to database transaction Begin was not expected"
  150. if fulfilled == len(c.expected) {
  151. msg = "all expectations were already fulfilled, " + msg
  152. }
  153. return nil, fmt.Errorf(msg)
  154. }
  155. expected.triggered = true
  156. expected.Unlock()
  157. return c, expected.err
  158. }
  159. func (c *sqlmock) ExpectBegin() *ExpectedBegin {
  160. e := &ExpectedBegin{}
  161. c.expected = append(c.expected, e)
  162. return e
  163. }
  164. // Exec meets http://golang.org/pkg/database/sql/driver/#Execer
  165. func (c *sqlmock) Exec(query string, args []driver.Value) (res driver.Result, err error) {
  166. query = stripQuery(query)
  167. var expected *ExpectedExec
  168. var fulfilled int
  169. var ok bool
  170. for _, next := range c.expected {
  171. next.Lock()
  172. if next.fulfilled() {
  173. next.Unlock()
  174. fulfilled++
  175. continue
  176. }
  177. if c.ordered {
  178. if expected, ok = next.(*ExpectedExec); ok {
  179. break
  180. }
  181. next.Unlock()
  182. return nil, fmt.Errorf("call to exec query '%s' with args %+v, was not expected, next expectation is: %s", query, args, next)
  183. }
  184. if exec, ok := next.(*ExpectedExec); ok {
  185. if err := exec.attemptMatch(query, args); err == nil {
  186. expected = exec
  187. break
  188. }
  189. }
  190. next.Unlock()
  191. }
  192. if expected == nil {
  193. msg := "call to exec '%s' query with args %+v was not expected"
  194. if fulfilled == len(c.expected) {
  195. msg = "all expectations were already fulfilled, " + msg
  196. }
  197. return nil, fmt.Errorf(msg, query, args)
  198. }
  199. defer expected.Unlock()
  200. if !expected.queryMatches(query) {
  201. return nil, fmt.Errorf("exec query '%s', does not match regex '%s'", query, expected.sqlRegex.String())
  202. }
  203. if err := expected.argsMatches(args); err != nil {
  204. return nil, fmt.Errorf("exec query '%s', arguments do not match: %s", query, err)
  205. }
  206. expected.triggered = true
  207. if expected.err != nil {
  208. return nil, expected.err // mocked to return error
  209. }
  210. if expected.result == nil {
  211. return nil, fmt.Errorf("exec query '%s' with args %+v, must return a database/sql/driver.result, but it was not set for expectation %T as %+v", query, args, expected, expected)
  212. }
  213. return expected.result, err
  214. }
  215. func (c *sqlmock) ExpectExec(sqlRegexStr string) *ExpectedExec {
  216. e := &ExpectedExec{}
  217. e.sqlRegex = regexp.MustCompile(sqlRegexStr)
  218. c.expected = append(c.expected, e)
  219. return e
  220. }
  221. // Prepare meets http://golang.org/pkg/database/sql/driver/#Conn interface
  222. func (c *sqlmock) Prepare(query string) (driver.Stmt, error) {
  223. var expected *ExpectedPrepare
  224. var fulfilled int
  225. var ok bool
  226. for _, next := range c.expected {
  227. next.Lock()
  228. if next.fulfilled() {
  229. next.Unlock()
  230. fulfilled++
  231. continue
  232. }
  233. if expected, ok = next.(*ExpectedPrepare); ok {
  234. break
  235. }
  236. next.Unlock()
  237. if c.ordered {
  238. return nil, fmt.Errorf("call to Prepare statement with query '%s', was not expected, next expectation is: %s", query, next)
  239. }
  240. }
  241. query = stripQuery(query)
  242. if expected == nil {
  243. msg := "call to Prepare '%s' query was not expected"
  244. if fulfilled == len(c.expected) {
  245. msg = "all expectations were already fulfilled, " + msg
  246. }
  247. return nil, fmt.Errorf(msg, query)
  248. }
  249. defer expected.Unlock()
  250. if !expected.sqlRegex.MatchString(query) {
  251. return nil, fmt.Errorf("query '%s', does not match regex [%s]", query, expected.sqlRegex.String())
  252. }
  253. expected.triggered = true
  254. return &statement{c, query, expected.closeErr}, expected.err
  255. }
  256. func (c *sqlmock) ExpectPrepare(sqlRegexStr string) *ExpectedPrepare {
  257. e := &ExpectedPrepare{sqlRegex: regexp.MustCompile(sqlRegexStr), mock: c}
  258. c.expected = append(c.expected, e)
  259. return e
  260. }
  261. // Query meets http://golang.org/pkg/database/sql/driver/#Queryer
  262. func (c *sqlmock) Query(query string, args []driver.Value) (rw driver.Rows, err error) {
  263. query = stripQuery(query)
  264. var expected *ExpectedQuery
  265. var fulfilled int
  266. var ok bool
  267. for _, next := range c.expected {
  268. next.Lock()
  269. if next.fulfilled() {
  270. next.Unlock()
  271. fulfilled++
  272. continue
  273. }
  274. if c.ordered {
  275. if expected, ok = next.(*ExpectedQuery); ok {
  276. break
  277. }
  278. next.Unlock()
  279. return nil, fmt.Errorf("call to query '%s' with args %+v, was not expected, next expectation is: %s", query, args, next)
  280. }
  281. if qr, ok := next.(*ExpectedQuery); ok {
  282. if err := qr.attemptMatch(query, args); err == nil {
  283. expected = qr
  284. break
  285. }
  286. }
  287. next.Unlock()
  288. }
  289. if expected == nil {
  290. msg := "call to query '%s' with args %+v was not expected"
  291. if fulfilled == len(c.expected) {
  292. msg = "all expectations were already fulfilled, " + msg
  293. }
  294. return nil, fmt.Errorf(msg, query, args)
  295. }
  296. defer expected.Unlock()
  297. if !expected.queryMatches(query) {
  298. return nil, fmt.Errorf("query '%s', does not match regex [%s]", query, expected.sqlRegex.String())
  299. }
  300. if err := expected.argsMatches(args); err != nil {
  301. return nil, fmt.Errorf("exec query '%s', arguments do not match: %s", query, err)
  302. }
  303. expected.triggered = true
  304. if expected.err != nil {
  305. return nil, expected.err // mocked to return error
  306. }
  307. if expected.rows == nil {
  308. return nil, fmt.Errorf("query '%s' with args %+v, must return a database/sql/driver.rows, but it was not set for expectation %T as %+v", query, args, expected, expected)
  309. }
  310. return expected.rows, err
  311. }
  312. func (c *sqlmock) ExpectQuery(sqlRegexStr string) *ExpectedQuery {
  313. e := &ExpectedQuery{}
  314. e.sqlRegex = regexp.MustCompile(sqlRegexStr)
  315. c.expected = append(c.expected, e)
  316. return e
  317. }
  318. func (c *sqlmock) ExpectCommit() *ExpectedCommit {
  319. e := &ExpectedCommit{}
  320. c.expected = append(c.expected, e)
  321. return e
  322. }
  323. func (c *sqlmock) ExpectRollback() *ExpectedRollback {
  324. e := &ExpectedRollback{}
  325. c.expected = append(c.expected, e)
  326. return e
  327. }
  328. // Commit meets http://golang.org/pkg/database/sql/driver/#Tx
  329. func (c *sqlmock) Commit() error {
  330. var expected *ExpectedCommit
  331. var fulfilled int
  332. var ok bool
  333. for _, next := range c.expected {
  334. next.Lock()
  335. if next.fulfilled() {
  336. next.Unlock()
  337. fulfilled++
  338. continue
  339. }
  340. if expected, ok = next.(*ExpectedCommit); ok {
  341. break
  342. }
  343. next.Unlock()
  344. if c.ordered {
  345. return fmt.Errorf("call to commit transaction, was not expected, next expectation is: %s", next)
  346. }
  347. }
  348. if expected == nil {
  349. msg := "call to commit transaction was not expected"
  350. if fulfilled == len(c.expected) {
  351. msg = "all expectations were already fulfilled, " + msg
  352. }
  353. return fmt.Errorf(msg)
  354. }
  355. expected.triggered = true
  356. expected.Unlock()
  357. return expected.err
  358. }
  359. // Rollback meets http://golang.org/pkg/database/sql/driver/#Tx
  360. func (c *sqlmock) Rollback() error {
  361. var expected *ExpectedRollback
  362. var fulfilled int
  363. var ok bool
  364. for _, next := range c.expected {
  365. next.Lock()
  366. if next.fulfilled() {
  367. next.Unlock()
  368. fulfilled++
  369. continue
  370. }
  371. if expected, ok = next.(*ExpectedRollback); ok {
  372. break
  373. }
  374. next.Unlock()
  375. if c.ordered {
  376. return fmt.Errorf("call to rollback transaction, was not expected, next expectation is: %s", next)
  377. }
  378. }
  379. if expected == nil {
  380. msg := "call to rollback transaction was not expected"
  381. if fulfilled == len(c.expected) {
  382. msg = "all expectations were already fulfilled, " + msg
  383. }
  384. return fmt.Errorf(msg)
  385. }
  386. expected.triggered = true
  387. expected.Unlock()
  388. return expected.err
  389. }