driver_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. package mysql
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "net"
  6. "os"
  7. "sync"
  8. "testing"
  9. )
  10. var (
  11. dsn string
  12. netAddr string
  13. run bool
  14. once sync.Once
  15. )
  16. // See https://github.com/Go-SQL-Driver/MySQL/wiki/Testing
  17. func getEnv() bool {
  18. once.Do(func() {
  19. user := os.Getenv("MYSQL_TEST_USER")
  20. if user == "" {
  21. user = "root"
  22. }
  23. pass := os.Getenv("MYSQL_TEST_PASS")
  24. prot := os.Getenv("MYSQL_TEST_PROT")
  25. if prot == "" {
  26. prot = "tcp"
  27. }
  28. addr := os.Getenv("MYSQL_TEST_ADDR")
  29. if addr == "" {
  30. addr = "localhost:3306"
  31. }
  32. dbname := os.Getenv("MYSQL_TEST_DBNAME")
  33. if dbname == "" {
  34. dbname = "gotest"
  35. }
  36. netAddr = fmt.Sprintf("%s(%s)", prot, addr)
  37. dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&charset=utf8", user, pass, netAddr, dbname)
  38. c, err := net.Dial(prot, addr)
  39. if err == nil {
  40. run = true
  41. c.Close()
  42. }
  43. })
  44. return run
  45. }
  46. func mustExec(t *testing.T, db *sql.DB, query string, args ...interface{}) (res sql.Result) {
  47. res, err := db.Exec(query, args...)
  48. if err != nil {
  49. t.Fatalf("Error on Exec %q: %v", query, err)
  50. }
  51. return
  52. }
  53. func mustQuery(t *testing.T, db *sql.DB, query string, args ...interface{}) (rows *sql.Rows) {
  54. rows, err := db.Query(query, args...)
  55. if err != nil {
  56. t.Fatalf("Error on Query %q: %v", query, err)
  57. }
  58. return
  59. }
  60. func TestCRUD(t *testing.T) {
  61. if !getEnv() {
  62. t.Logf("MySQL-Server not running on %s. Skipping TestCRUD", netAddr)
  63. return
  64. }
  65. db, err := sql.Open("mysql", dsn)
  66. if err != nil {
  67. t.Fatalf("Error connecting: %v", err)
  68. }
  69. defer db.Close()
  70. mustExec(t, db, "DROP TABLE IF EXISTS test")
  71. // Create Table
  72. mustExec(t, db, "CREATE TABLE test (value BOOL)")
  73. // Test for unexpected data
  74. var out bool
  75. rows := mustQuery(t, db, ("SELECT * FROM test"))
  76. if rows.Next() {
  77. t.Error("unexpected data in empty table")
  78. }
  79. // Create Data
  80. res := mustExec(t, db, ("INSERT INTO test VALUES (1)"))
  81. count, err := res.RowsAffected()
  82. if err != nil {
  83. t.Fatalf("res.RowsAffected() returned error: %v", err)
  84. }
  85. if count != 1 {
  86. t.Fatalf("Expected 1 affected row, got %d", count)
  87. }
  88. id, err := res.LastInsertId()
  89. if err != nil {
  90. t.Fatalf("res.LastInsertId() returned error: %v", err)
  91. }
  92. if id != 0 {
  93. t.Fatalf("Expected InsertID 0, got %d", id)
  94. }
  95. // Read
  96. rows = mustQuery(t, db, ("SELECT value FROM test"))
  97. if rows.Next() {
  98. rows.Scan(&out)
  99. if true != out {
  100. t.Errorf("true != %t", out)
  101. }
  102. if rows.Next() {
  103. t.Error("unexpected data")
  104. }
  105. } else {
  106. t.Error("no data")
  107. }
  108. // Update
  109. res = mustExec(t, db, "UPDATE test SET value = ? WHERE value = ?", false, true)
  110. count, err = res.RowsAffected()
  111. if err != nil {
  112. t.Fatalf("res.RowsAffected() returned error: %v", err)
  113. }
  114. if count != 1 {
  115. t.Fatalf("Expected 1 affected row, got %d", count)
  116. }
  117. // Check Update
  118. rows = mustQuery(t, db, ("SELECT value FROM test"))
  119. if rows.Next() {
  120. rows.Scan(&out)
  121. if false != out {
  122. t.Errorf("false != %t", out)
  123. }
  124. if rows.Next() {
  125. t.Error("unexpected data")
  126. }
  127. } else {
  128. t.Error("no data")
  129. }
  130. // Delete
  131. res = mustExec(t, db, "DELETE FROM test WHERE value = ?", false)
  132. count, err = res.RowsAffected()
  133. if err != nil {
  134. t.Fatalf("res.RowsAffected() returned error: %v", err)
  135. }
  136. if count != 1 {
  137. t.Fatalf("Expected 1 affected row, got %d", count)
  138. }
  139. // Check for unexpected rows
  140. res = mustExec(t, db, "DELETE FROM test")
  141. count, err = res.RowsAffected()
  142. if err != nil {
  143. t.Fatalf("res.RowsAffected() returned error: %v", err)
  144. }
  145. if count != 0 {
  146. t.Fatalf("Expected 0 affected row, got %d", count)
  147. }
  148. }
  149. func TestInt(t *testing.T) {
  150. if !getEnv() {
  151. t.Logf("MySQL-Server not running on %s. Skipping TestInt", netAddr)
  152. return
  153. }
  154. db, err := sql.Open("mysql", dsn)
  155. if err != nil {
  156. t.Fatalf("Error connecting: %v", err)
  157. }
  158. defer db.Close()
  159. mustExec(t, db, "DROP TABLE IF EXISTS test")
  160. types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"}
  161. in := int64(42)
  162. var out int64
  163. var rows *sql.Rows
  164. // SIGNED
  165. for _, v := range types {
  166. mustExec(t, db, "CREATE TABLE test (value "+v+")")
  167. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  168. rows = mustQuery(t, db, ("SELECT value FROM test"))
  169. if rows.Next() {
  170. rows.Scan(&out)
  171. if in != out {
  172. t.Errorf("%s: %d != %d", v, in, out)
  173. }
  174. } else {
  175. t.Errorf("%s: no data", v)
  176. }
  177. mustExec(t, db, "DROP TABLE IF EXISTS test")
  178. }
  179. // UNSIGNED ZEROFILL
  180. for _, v := range types {
  181. mustExec(t, db, "CREATE TABLE test (value "+v+" ZEROFILL)")
  182. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  183. rows = mustQuery(t, db, ("SELECT value FROM test"))
  184. if rows.Next() {
  185. rows.Scan(&out)
  186. if in != out {
  187. t.Errorf("%s ZEROFILL: %d != %d", v, in, out)
  188. }
  189. } else {
  190. t.Errorf("%s ZEROFILL: no data", v)
  191. }
  192. mustExec(t, db, "DROP TABLE IF EXISTS test")
  193. }
  194. }
  195. func TestFloat(t *testing.T) {
  196. if !getEnv() {
  197. t.Logf("MySQL-Server not running on %s. Skipping TestFloat", netAddr)
  198. return
  199. }
  200. db, err := sql.Open("mysql", dsn)
  201. if err != nil {
  202. t.Fatalf("Error connecting: %v", err)
  203. }
  204. defer db.Close()
  205. mustExec(t, db, "DROP TABLE IF EXISTS test")
  206. types := [2]string{"FLOAT", "DOUBLE"}
  207. in := float32(42.23)
  208. var out float32
  209. var rows *sql.Rows
  210. for _, v := range types {
  211. mustExec(t, db, "CREATE TABLE test (value "+v+")")
  212. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  213. rows = mustQuery(t, db, ("SELECT value FROM test"))
  214. if rows.Next() {
  215. rows.Scan(&out)
  216. if in != out {
  217. t.Errorf("%s: %g != %g", v, in, out)
  218. }
  219. } else {
  220. t.Errorf("%s: no data", v)
  221. }
  222. mustExec(t, db, "DROP TABLE IF EXISTS test")
  223. }
  224. }
  225. func TestString(t *testing.T) {
  226. if !getEnv() {
  227. t.Logf("MySQL-Server not running on %s. Skipping TestString", netAddr)
  228. return
  229. }
  230. db, err := sql.Open("mysql", dsn)
  231. if err != nil {
  232. t.Fatalf("Error connecting: %v", err)
  233. }
  234. defer db.Close()
  235. mustExec(t, db, "DROP TABLE IF EXISTS test")
  236. types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"}
  237. in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย"
  238. var out string
  239. var rows *sql.Rows
  240. for _, v := range types {
  241. mustExec(t, db, "CREATE TABLE test (value "+v+") CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  242. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
  243. rows = mustQuery(t, db, ("SELECT value FROM test"))
  244. if rows.Next() {
  245. rows.Scan(&out)
  246. if in != out {
  247. t.Errorf("%s: %s != %s", v, in, out)
  248. }
  249. } else {
  250. t.Errorf("%s: no data", v)
  251. }
  252. mustExec(t, db, "DROP TABLE IF EXISTS test")
  253. }
  254. // BLOB
  255. mustExec(t, db, "CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  256. id := 2
  257. in = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
  258. "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
  259. "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " +
  260. "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. " +
  261. "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
  262. "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
  263. "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " +
  264. "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
  265. mustExec(t, db, ("INSERT INTO test VALUES (?, ?)"), id, in)
  266. err = db.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&out)
  267. if err != nil {
  268. t.Fatalf("Error on BLOB-Query: %v", err)
  269. } else if out != in {
  270. t.Errorf("BLOB: %s != %s", in, out)
  271. }
  272. return
  273. }
  274. func TestDateTime(t *testing.T) {
  275. if !getEnv() {
  276. t.Logf("MySQL-Server not running on %s. Skipping TestString", netAddr)
  277. return
  278. }
  279. db, err := sql.Open("mysql", dsn)
  280. if err != nil {
  281. t.Fatalf("Error connecting: %v", err)
  282. }
  283. defer db.Close()
  284. mustExec(t, db, "DROP TABLE IF EXISTS test")
  285. types := [...]string{"DATE", "DATETIME"}
  286. in := [...]string{"2012-06-14", "2011-11-20 21:27:37"}
  287. var out string
  288. var rows *sql.Rows
  289. for i, v := range types {
  290. mustExec(t, db, "CREATE TABLE test (value "+v+") CHARACTER SET utf8 COLLATE utf8_unicode_ci")
  291. mustExec(t, db, ("INSERT INTO test VALUES (?)"), in[i])
  292. rows = mustQuery(t, db, ("SELECT value FROM test"))
  293. if rows.Next() {
  294. rows.Scan(&out)
  295. if in[i] != out {
  296. t.Errorf("%s: %s != %s", v, in[i], out)
  297. }
  298. } else {
  299. t.Errorf("%s: no data", v)
  300. }
  301. mustExec(t, db, "DROP TABLE IF EXISTS test")
  302. }
  303. }
  304. func TestNULL(t *testing.T) {
  305. if !getEnv() {
  306. t.Logf("MySQL-Server not running on %s. Skipping TestNULL", netAddr)
  307. return
  308. }
  309. db, err := sql.Open("mysql", dsn)
  310. if err != nil {
  311. t.Fatalf("Error connecting: %v", err)
  312. }
  313. defer db.Close()
  314. nullStmt, err := db.Prepare("SELECT NULL")
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. defer nullStmt.Close()
  319. nonNullStmt, err := db.Prepare("SELECT 1")
  320. if err != nil {
  321. t.Fatal(err)
  322. }
  323. defer nonNullStmt.Close()
  324. // NullBool
  325. var nb sql.NullBool
  326. // Invalid
  327. err = nullStmt.QueryRow().Scan(&nb)
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. if nb.Valid {
  332. t.Error("Valid NullBool which should be invalid")
  333. }
  334. // Valid
  335. err = nonNullStmt.QueryRow().Scan(&nb)
  336. if err != nil {
  337. t.Fatal(err)
  338. }
  339. if !nb.Valid {
  340. t.Error("Invalid NullBool which should be valid")
  341. } else if nb.Bool != true {
  342. t.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool)
  343. }
  344. // NullFloat64
  345. var nf sql.NullFloat64
  346. // Invalid
  347. err = nullStmt.QueryRow().Scan(&nf)
  348. if err != nil {
  349. t.Fatal(err)
  350. }
  351. if nf.Valid {
  352. t.Error("Valid NullFloat64 which should be invalid")
  353. }
  354. // Valid
  355. err = nonNullStmt.QueryRow().Scan(&nf)
  356. if err != nil {
  357. t.Fatal(err)
  358. }
  359. if !nf.Valid {
  360. t.Error("Invalid NullFloat64 which should be valid")
  361. } else if nf.Float64 != float64(1) {
  362. t.Errorf("Unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64)
  363. }
  364. // NullInt64
  365. var ni sql.NullInt64
  366. // Invalid
  367. err = nullStmt.QueryRow().Scan(&ni)
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. if ni.Valid {
  372. t.Error("Valid NullInt64 which should be invalid")
  373. }
  374. // Valid
  375. err = nonNullStmt.QueryRow().Scan(&ni)
  376. if err != nil {
  377. t.Fatal(err)
  378. }
  379. if !ni.Valid {
  380. t.Error("Invalid NullInt64 which should be valid")
  381. } else if ni.Int64 != int64(1) {
  382. t.Errorf("Unexpected NullInt64 value: %d (should be 1)", ni.Int64)
  383. }
  384. // NullString
  385. var ns sql.NullString
  386. // Invalid
  387. err = nullStmt.QueryRow().Scan(&ns)
  388. if err != nil {
  389. t.Fatal(err)
  390. }
  391. if ns.Valid {
  392. t.Error("Valid NullString which should be invalid")
  393. }
  394. // Valid
  395. err = nonNullStmt.QueryRow().Scan(&ns)
  396. if err != nil {
  397. t.Fatal(err)
  398. }
  399. if !ns.Valid {
  400. t.Error("Invalid NullString which should be valid")
  401. } else if ns.String != `1` {
  402. t.Error("Unexpected NullString value:" + ns.String + " (should be `1`)")
  403. }
  404. // Insert NULL
  405. mustExec(t, db, "CREATE TABLE test (dummmy1 int, value int, dummy2 int)")
  406. mustExec(t, db, ("INSERT INTO test VALUES (?, ?, ?)"), 1, nil, 2)
  407. var out interface{}
  408. rows := mustQuery(t, db, ("SELECT * FROM test"))
  409. if rows.Next() {
  410. rows.Scan(&out)
  411. if out != nil {
  412. t.Errorf("%v != nil", out)
  413. }
  414. } else {
  415. t.Error("no data")
  416. }
  417. mustExec(t, db, "DROP TABLE IF EXISTS test")
  418. }
  419. // Special cases
  420. func TestRowsClose(t *testing.T) {
  421. if !getEnv() {
  422. t.Logf("MySQL-Server not running on %s. Skipping TestRowsClose", netAddr)
  423. return
  424. }
  425. db, err := sql.Open("mysql", dsn)
  426. if err != nil {
  427. t.Fatalf("Error connecting: %v", err)
  428. }
  429. defer db.Close()
  430. rows, err := db.Query("SELECT 1")
  431. if err != nil {
  432. t.Fatal(err)
  433. }
  434. err = rows.Close()
  435. if err != nil {
  436. t.Fatal(err)
  437. }
  438. if rows.Next() {
  439. t.Fatal("Unexpected row after rows.Close()")
  440. }
  441. err = rows.Err()
  442. if err != nil {
  443. t.Fatal(err)
  444. }
  445. }
  446. // dangling statements
  447. // http://code.google.com/p/go/issues/detail?id=3865
  448. func TestCloseStmtBeforeRows(t *testing.T) {
  449. if !getEnv() {
  450. t.Logf("MySQL-Server not running on %s. Skipping TestCloseStmtBeforeRows", netAddr)
  451. return
  452. }
  453. db, err := sql.Open("mysql", dsn)
  454. if err != nil {
  455. t.Fatalf("Error connecting: %v", err)
  456. }
  457. defer db.Close()
  458. stmt, err := db.Prepare("SELECT 1")
  459. if err != nil {
  460. t.Fatal(err)
  461. }
  462. rows, err := stmt.Query()
  463. if err != nil {
  464. stmt.Close()
  465. t.Fatal(err)
  466. }
  467. defer rows.Close()
  468. err = stmt.Close()
  469. if err != nil {
  470. t.Fatal(err)
  471. }
  472. if !rows.Next() {
  473. t.Fatal("Getting row failed")
  474. } else {
  475. err = rows.Err()
  476. if err != nil {
  477. t.Fatal(err)
  478. }
  479. var out bool
  480. err = rows.Scan(&out)
  481. if err != nil {
  482. t.Fatalf("Error on rows.Scan(): %v", err)
  483. }
  484. if out != true {
  485. t.Errorf("true != %t", out)
  486. }
  487. }
  488. }
  489. // It is valid to have multiple Rows for the same Stmt
  490. // http://code.google.com/p/go/issues/detail?id=3734
  491. func TestStmtMultiRows(t *testing.T) {
  492. if !getEnv() {
  493. t.Logf("MySQL-Server not running on %s. Skipping TestStmtMultiRows", netAddr)
  494. return
  495. }
  496. db, err := sql.Open("mysql", dsn)
  497. if err != nil {
  498. t.Fatalf("Error connecting: %v", err)
  499. }
  500. defer db.Close()
  501. stmt, err := db.Prepare("SELECT 1 UNION SELECT 0")
  502. if err != nil {
  503. t.Fatal(err)
  504. }
  505. rows1, err := stmt.Query()
  506. if err != nil {
  507. stmt.Close()
  508. t.Fatal(err)
  509. }
  510. defer rows1.Close()
  511. rows2, err := stmt.Query()
  512. if err != nil {
  513. stmt.Close()
  514. t.Fatal(err)
  515. }
  516. defer rows2.Close()
  517. var out bool
  518. // 1
  519. if !rows1.Next() {
  520. t.Fatal("1st rows1.Next failed")
  521. } else {
  522. err = rows1.Err()
  523. if err != nil {
  524. t.Fatal(err)
  525. }
  526. err = rows1.Scan(&out)
  527. if err != nil {
  528. t.Fatalf("Error on rows.Scan(): %v", err)
  529. }
  530. if out != true {
  531. t.Errorf("true != %t", out)
  532. }
  533. }
  534. if !rows2.Next() {
  535. t.Fatal("1st rows2.Next failed")
  536. } else {
  537. err = rows2.Err()
  538. if err != nil {
  539. t.Fatal(err)
  540. }
  541. err = rows2.Scan(&out)
  542. if err != nil {
  543. t.Fatalf("Error on rows.Scan(): %v", err)
  544. }
  545. if out != true {
  546. t.Errorf("true != %t", out)
  547. }
  548. }
  549. // 2
  550. if !rows1.Next() {
  551. t.Fatal("2nd rows1.Next failed")
  552. } else {
  553. err = rows1.Err()
  554. if err != nil {
  555. t.Fatal(err)
  556. }
  557. err = rows1.Scan(&out)
  558. if err != nil {
  559. t.Fatalf("Error on rows.Scan(): %v", err)
  560. }
  561. if out != false {
  562. t.Errorf("false != %t", out)
  563. }
  564. if rows1.Next() {
  565. t.Fatal("Unexpected row on rows1")
  566. }
  567. err = rows1.Close()
  568. if err != nil {
  569. t.Fatal(err)
  570. }
  571. }
  572. if !rows2.Next() {
  573. t.Fatal("2nd rows2.Next failed")
  574. } else {
  575. err = rows2.Err()
  576. if err != nil {
  577. t.Fatal(err)
  578. }
  579. err = rows2.Scan(&out)
  580. if err != nil {
  581. t.Fatalf("Error on rows.Scan(): %v", err)
  582. }
  583. if out != false {
  584. t.Errorf("false != %t", out)
  585. }
  586. if rows2.Next() {
  587. t.Fatal("Unexpected row on rows2")
  588. }
  589. err = rows2.Close()
  590. if err != nil {
  591. t.Fatal(err)
  592. }
  593. }
  594. }
  595. func TestConcurrent(t *testing.T) {
  596. if os.Getenv("MYSQL_TEST_CONCURRENT") != "1" {
  597. t.Log("CONCURRENT env var not set. Skipping TestConcurrent")
  598. return
  599. }
  600. if !getEnv() {
  601. t.Logf("MySQL-Server not running on %s. Skipping TestConcurrent", netAddr)
  602. return
  603. }
  604. db, err := sql.Open("mysql", dsn)
  605. if err != nil {
  606. t.Fatalf("Error connecting: %v", err)
  607. }
  608. defer db.Close()
  609. var max int
  610. err = db.QueryRow("SELECT @@max_connections").Scan(&max)
  611. if err != nil {
  612. t.Fatalf("%v", err)
  613. }
  614. t.Logf("Testing %d concurrent connections \r\n", max)
  615. canStop := false
  616. c := make(chan struct{}, max)
  617. for i := 0; i < max; i++ {
  618. go func() {
  619. tx, err := db.Begin()
  620. if err != nil {
  621. canStop = true
  622. t.Fatalf("Error on Con %d: %s", i, err.Error())
  623. }
  624. c <- struct{}{}
  625. for !canStop {
  626. _, err := tx.Exec("SELECT 1")
  627. if err != nil {
  628. canStop = true
  629. t.Fatalf("Error on Con %d: %s", i, err.Error())
  630. }
  631. }
  632. err = tx.Commit()
  633. if err != nil {
  634. canStop = true
  635. t.Fatalf("Error on Con %d: %s", i, err.Error())
  636. }
  637. }()
  638. }
  639. for i := 0; i < max; i++ {
  640. <-c
  641. }
  642. canStop = true
  643. }