cassandra_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. // Copyright (c) 2012 The gocql Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gocql
  5. import (
  6. "bytes"
  7. "flag"
  8. "reflect"
  9. "sort"
  10. "speter.net/go/exp/math/dec/inf"
  11. "strconv"
  12. "strings"
  13. "sync"
  14. "testing"
  15. "time"
  16. )
  17. var (
  18. flagCluster = flag.String("cluster", "127.0.0.1", "a comma-separated list of host:port tuples")
  19. flagProto = flag.Int("proto", 2, "protcol version")
  20. flagCQL = flag.String("cql", "3.0.0", "CQL version")
  21. )
  22. var initOnce sync.Once
  23. func createSession(t *testing.T) *Session {
  24. cluster := NewCluster(strings.Split(*flagCluster, ",")...)
  25. cluster.ProtoVersion = *flagProto
  26. cluster.CQLVersion = *flagCQL
  27. cluster.Authenticator = PasswordAuthenticator{
  28. Username: "cassandra",
  29. Password: "cassandra",
  30. }
  31. initOnce.Do(func() {
  32. session, err := cluster.CreateSession()
  33. if err != nil {
  34. t.Fatal("createSession:", err)
  35. }
  36. // Drop and re-create the keyspace once. Different tests should use their own
  37. // individual tables, but can assume that the table does not exist before.
  38. if err := session.Query(`DROP KEYSPACE gocql_test`).Exec(); err != nil {
  39. t.Log("drop keyspace:", err)
  40. }
  41. if err := session.Query(`CREATE KEYSPACE gocql_test
  42. WITH replication = {
  43. 'class' : 'SimpleStrategy',
  44. 'replication_factor' : 1
  45. }`).Exec(); err != nil {
  46. t.Fatal("create keyspace:", err)
  47. }
  48. session.Close()
  49. })
  50. cluster.Keyspace = "gocql_test"
  51. session, err := cluster.CreateSession()
  52. if err != nil {
  53. t.Fatal("createSession:", err)
  54. }
  55. return session
  56. }
  57. func TestEmptyHosts(t *testing.T) {
  58. cluster := NewCluster()
  59. if session, err := cluster.CreateSession(); err == nil {
  60. session.Close()
  61. t.Error("expected err, got nil")
  62. }
  63. }
  64. //TestUseStatementError checks to make sure the correct error is returned when the user tries to execute a use statement.
  65. func TestUseStatementError(t *testing.T) {
  66. session := createSession(t)
  67. defer session.Close()
  68. if err := session.Query("USE gocql_test").Exec(); err != nil {
  69. if err != ErrUseStmt {
  70. t.Error("expected ErrUseStmt, got " + err.Error())
  71. }
  72. } else {
  73. t.Error("expected err, got nil.")
  74. }
  75. }
  76. //TestInvalidKeyspace checks that an invalid keyspace will return promptly and without a flood of connections
  77. func TestInvalidKeyspace(t *testing.T) {
  78. cluster := NewCluster(strings.Split(*flagCluster, ",")...)
  79. cluster.ProtoVersion = *flagProto
  80. cluster.CQLVersion = *flagCQL
  81. cluster.Keyspace = "invalidKeyspace"
  82. session, err := cluster.CreateSession()
  83. if err != nil {
  84. if err != ErrNoConnectionsStarted {
  85. t.Errorf("Expected ErrNoConnections but got %v", err)
  86. }
  87. } else {
  88. session.Close() //Clean up the session
  89. t.Error("expected err, got nil.")
  90. }
  91. }
  92. func TestCRUD(t *testing.T) {
  93. session := createSession(t)
  94. defer session.Close()
  95. if err := session.Query(`CREATE TABLE page (
  96. title varchar,
  97. revid timeuuid,
  98. body varchar,
  99. views bigint,
  100. protected boolean,
  101. modified timestamp,
  102. rating decimal,
  103. tags set<varchar>,
  104. attachments map<varchar, text>,
  105. PRIMARY KEY (title, revid)
  106. )`).Exec(); err != nil {
  107. t.Fatal("create table:", err)
  108. }
  109. for _, page := range pageTestData {
  110. if err := session.Query(`INSERT INTO page
  111. (title, revid, body, views, protected, modified, rating, tags, attachments)
  112. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
  113. page.Title, page.RevId, page.Body, page.Views, page.Protected,
  114. page.Modified, page.Rating, page.Tags, page.Attachments).Exec(); err != nil {
  115. t.Fatal("insert:", err)
  116. }
  117. }
  118. var count int
  119. if err := session.Query("SELECT COUNT(*) FROM page").Scan(&count); err != nil {
  120. t.Error("select count:", err)
  121. }
  122. if count != len(pageTestData) {
  123. t.Errorf("count: expected %d, got %d\n", len(pageTestData), count)
  124. }
  125. for _, original := range pageTestData {
  126. page := new(Page)
  127. err := session.Query(`SELECT title, revid, body, views, protected, modified,
  128. tags, attachments, rating
  129. FROM page WHERE title = ? AND revid = ? LIMIT 1`,
  130. original.Title, original.RevId).Scan(&page.Title, &page.RevId,
  131. &page.Body, &page.Views, &page.Protected, &page.Modified, &page.Tags,
  132. &page.Attachments, &page.Rating)
  133. if err != nil {
  134. t.Error("select page:", err)
  135. continue
  136. }
  137. sort.Sort(sort.StringSlice(page.Tags))
  138. sort.Sort(sort.StringSlice(original.Tags))
  139. if !reflect.DeepEqual(page, original) {
  140. t.Errorf("page: expected %#v, got %#v\n", original, page)
  141. }
  142. }
  143. }
  144. func TestTracing(t *testing.T) {
  145. session := createSession(t)
  146. defer session.Close()
  147. if err := session.Query(`CREATE TABLE trace (id int primary key)`).Exec(); err != nil {
  148. t.Fatal("create:", err)
  149. }
  150. buf := &bytes.Buffer{}
  151. trace := NewTraceWriter(session, buf)
  152. if err := session.Query(`INSERT INTO trace (id) VALUES (?)`, 42).Trace(trace).Exec(); err != nil {
  153. t.Error("insert:", err)
  154. } else if buf.Len() == 0 {
  155. t.Error("insert: failed to obtain any tracing")
  156. }
  157. buf.Reset()
  158. var value int
  159. if err := session.Query(`SELECT id FROM trace WHERE id = ?`, 42).Trace(trace).Scan(&value); err != nil {
  160. t.Error("select:", err)
  161. } else if value != 42 {
  162. t.Errorf("value: expected %d, got %d", 42, value)
  163. } else if buf.Len() == 0 {
  164. t.Error("select: failed to obtain any tracing")
  165. }
  166. }
  167. func TestPaging(t *testing.T) {
  168. if *flagProto == 1 {
  169. t.Skip("Paging not supported. Please use Cassandra >= 2.0")
  170. }
  171. session := createSession(t)
  172. defer session.Close()
  173. if err := session.Query("CREATE TABLE paging (id int primary key)").Exec(); err != nil {
  174. t.Fatal("create table:", err)
  175. }
  176. for i := 0; i < 100; i++ {
  177. if err := session.Query("INSERT INTO paging (id) VALUES (?)", i).Exec(); err != nil {
  178. t.Fatal("insert:", err)
  179. }
  180. }
  181. iter := session.Query("SELECT id FROM paging").PageSize(10).Iter()
  182. var id int
  183. count := 0
  184. for iter.Scan(&id) {
  185. count++
  186. }
  187. if err := iter.Close(); err != nil {
  188. t.Fatal("close:", err)
  189. }
  190. if count != 100 {
  191. t.Fatalf("expected %d, got %d", 100, count)
  192. }
  193. }
  194. func TestCAS(t *testing.T) {
  195. if *flagProto == 1 {
  196. t.Skip("lightweight transactions not supported. Please use Cassandra >= 2.0")
  197. }
  198. session := createSession(t)
  199. defer session.Close()
  200. if err := session.Query(`CREATE TABLE cas_table (
  201. title varchar,
  202. revid timeuuid,
  203. PRIMARY KEY (title, revid)
  204. )`).Exec(); err != nil {
  205. t.Fatal("create:", err)
  206. }
  207. title, revid := "baz", TimeUUID()
  208. var titleCAS string
  209. var revidCAS UUID
  210. if applied, err := session.Query(`INSERT INTO cas_table (title, revid)
  211. VALUES (?, ?) IF NOT EXISTS`,
  212. title, revid).ScanCAS(&titleCAS, &revidCAS); err != nil {
  213. t.Fatal("insert:", err)
  214. } else if !applied {
  215. t.Fatal("insert should have been applied")
  216. }
  217. if applied, err := session.Query(`INSERT INTO cas_table (title, revid)
  218. VALUES (?, ?) IF NOT EXISTS`,
  219. title, revid).ScanCAS(&titleCAS, &revidCAS); err != nil {
  220. t.Fatal("insert:", err)
  221. } else if applied {
  222. t.Fatal("insert should not have been applied")
  223. } else if title != titleCAS || revid != revidCAS {
  224. t.Fatalf("expected %s/%v but got %s/%v", title, revid, titleCAS, revidCAS)
  225. }
  226. }
  227. func TestBatch(t *testing.T) {
  228. if *flagProto == 1 {
  229. t.Skip("atomic batches not supported. Please use Cassandra >= 2.0")
  230. }
  231. session := createSession(t)
  232. defer session.Close()
  233. if err := session.Query(`CREATE TABLE batch_table (id int primary key)`).Exec(); err != nil {
  234. t.Fatal("create table:", err)
  235. }
  236. batch := NewBatch(LoggedBatch)
  237. for i := 0; i < 100; i++ {
  238. batch.Query(`INSERT INTO batch_table (id) VALUES (?)`, i)
  239. }
  240. if err := session.ExecuteBatch(batch); err != nil {
  241. t.Fatal("execute batch:", err)
  242. }
  243. count := 0
  244. if err := session.Query(`SELECT COUNT(*) FROM batch_table`).Scan(&count); err != nil {
  245. t.Fatal("select count:", err)
  246. } else if count != 100 {
  247. t.Fatalf("count: expected %d, got %d\n", 100, count)
  248. }
  249. }
  250. // TestBatchLimit tests gocql to make sure batch operations larger than the maximum
  251. // statement limit are not submitted to a cassandra node.
  252. func TestBatchLimit(t *testing.T) {
  253. if *flagProto == 1 {
  254. t.Skip("atomic batches not supported. Please use Cassandra >= 2.0")
  255. }
  256. session := createSession(t)
  257. defer session.Close()
  258. if err := session.Query(`CREATE TABLE batch_table2 (id int primary key)`).Exec(); err != nil {
  259. t.Fatal("create table:", err)
  260. }
  261. batch := NewBatch(LoggedBatch)
  262. for i := 0; i < 65537; i++ {
  263. batch.Query(`INSERT INTO batch_table2 (id) VALUES (?)`, i)
  264. }
  265. if err := session.ExecuteBatch(batch); err != ErrTooManyStmts {
  266. t.Fatal("gocql attempted to execute a batch larger than the support limit of statements.")
  267. }
  268. }
  269. // TestTooManyQueryArgs tests to make sure the library correctly handles the application level bug
  270. // whereby too many query arguments are passed to a query
  271. func TestTooManyQueryArgs(t *testing.T) {
  272. if *flagProto == 1 {
  273. t.Skip("atomic batches not supported. Please use Cassandra >= 2.0")
  274. }
  275. session := createSession(t)
  276. defer session.Close()
  277. if err := session.Query(`CREATE TABLE too_many_query_args (id int primary key, value int)`).Exec(); err != nil {
  278. t.Fatal("create table:", err)
  279. }
  280. _, err := session.Query(`SELECT * FROM too_many_query_args WHERE id = ?`, 1, 2).Iter().SliceMap()
  281. if err == nil {
  282. t.Fatal("'`SELECT * FROM too_many_query_args WHERE id = ?`, 1, 2' should return an ErrQueryArgLength")
  283. }
  284. if err != ErrQueryArgLength {
  285. t.Fatalf("'`SELECT * FROM too_many_query_args WHERE id = ?`, 1, 2' should return an ErrQueryArgLength, but returned: %s", err)
  286. }
  287. batch := session.NewBatch(UnloggedBatch)
  288. batch.Query("INSERT INTO too_many_query_args (id, value) VALUES (?, ?)", 1, 2, 3)
  289. err = session.ExecuteBatch(batch)
  290. if err == nil {
  291. t.Fatal("'`INSERT INTO too_many_query_args (id, value) VALUES (?, ?)`, 1, 2, 3' should return an ErrQueryArgLength")
  292. }
  293. if err != ErrQueryArgLength {
  294. t.Fatalf("'INSERT INTO too_many_query_args (id, value) VALUES (?, ?)`, 1, 2, 3' should return an ErrQueryArgLength, but returned: %s", err)
  295. }
  296. }
  297. // TestNotEnoughQueryArgs tests to make sure the library correctly handles the application level bug
  298. // whereby not enough query arguments are passed to a query
  299. func TestNotEnoughQueryArgs(t *testing.T) {
  300. if *flagProto == 1 {
  301. t.Skip("atomic batches not supported. Please use Cassandra >= 2.0")
  302. }
  303. session := createSession(t)
  304. defer session.Close()
  305. if err := session.Query(`CREATE TABLE not_enough_query_args (id int, cluster int, value int, primary key (id, cluster))`).Exec(); err != nil {
  306. t.Fatal("create table:", err)
  307. }
  308. _, err := session.Query(`SELECT * FROM not_enough_query_args WHERE id = ? and cluster = ?`, 1).Iter().SliceMap()
  309. if err == nil {
  310. t.Fatal("'`SELECT * FROM not_enough_query_args WHERE id = ? and cluster = ?`, 1' should return an ErrQueryArgLength")
  311. }
  312. if err != ErrQueryArgLength {
  313. t.Fatalf("'`SELECT * FROM too_few_query_args WHERE id = ? and cluster = ?`, 1' should return an ErrQueryArgLength, but returned: %s", err)
  314. }
  315. batch := session.NewBatch(UnloggedBatch)
  316. batch.Query("INSERT INTO not_enough_query_args (id, cluster, value) VALUES (?, ?, ?)", 1, 2)
  317. err = session.ExecuteBatch(batch)
  318. if err == nil {
  319. t.Fatal("'`INSERT INTO not_enough_query_args (id, cluster, value) VALUES (?, ?, ?)`, 1, 2' should return an ErrQueryArgLength")
  320. }
  321. if err != ErrQueryArgLength {
  322. t.Fatalf("'INSERT INTO not_enough_query_args (id, cluster, value) VALUES (?, ?, ?)`, 1, 2' should return an ErrQueryArgLength, but returned: %s", err)
  323. }
  324. }
  325. // TestCreateSessionTimeout tests to make sure the CreateSession function timeouts out correctly
  326. // and prevents an infinite loop of connection retries.
  327. func TestCreateSessionTimeout(t *testing.T) {
  328. go func() {
  329. <-time.After(2 * time.Second)
  330. t.Fatal("no startup timeout")
  331. }()
  332. c := NewCluster("127.0.0.1:1")
  333. _, err := c.CreateSession()
  334. if err == nil {
  335. t.Fatal("expected ErrNoConnectionsStarted, but no error was returned.")
  336. }
  337. if err != ErrNoConnectionsStarted {
  338. t.Fatalf("expected ErrNoConnectionsStarted, but received %v", err)
  339. }
  340. }
  341. type Page struct {
  342. Title string
  343. RevId UUID
  344. Body string
  345. Views int64
  346. Protected bool
  347. Modified time.Time
  348. Rating *inf.Dec
  349. Tags []string
  350. Attachments map[string]Attachment
  351. }
  352. type Attachment []byte
  353. var rating, _ = inf.NewDec(0, 0).SetString("0.131")
  354. var pageTestData = []*Page{
  355. &Page{
  356. Title: "Frontpage",
  357. RevId: TimeUUID(),
  358. Body: "Welcome to this wiki page!",
  359. Rating: rating,
  360. Modified: time.Date(2013, time.August, 13, 9, 52, 3, 0, time.UTC),
  361. Tags: []string{"start", "important", "test"},
  362. Attachments: map[string]Attachment{
  363. "logo": Attachment("\x00company logo\x00"),
  364. "favicon": Attachment("favicon.ico"),
  365. },
  366. },
  367. &Page{
  368. Title: "Foobar",
  369. RevId: TimeUUID(),
  370. Body: "foo::Foo f = new foo::Foo(foo::Foo::INIT);",
  371. Modified: time.Date(2013, time.August, 13, 9, 52, 3, 0, time.UTC),
  372. },
  373. }
  374. func TestSliceMap(t *testing.T) {
  375. session := createSession(t)
  376. defer session.Close()
  377. if err := session.Query(`CREATE TABLE slice_map_table (
  378. testuuid timeuuid PRIMARY KEY,
  379. testtimestamp timestamp,
  380. testvarchar varchar,
  381. testbigint bigint,
  382. testblob blob,
  383. testbool boolean,
  384. testfloat float,
  385. testdouble double,
  386. testint int,
  387. testdecimal decimal,
  388. testset set<int>,
  389. testmap map<varchar, varchar>
  390. )`).Exec(); err != nil {
  391. t.Fatal("create table:", err)
  392. }
  393. m := make(map[string]interface{})
  394. m["testuuid"] = TimeUUID()
  395. m["testvarchar"] = "Test VarChar"
  396. m["testbigint"] = time.Now().Unix()
  397. m["testtimestamp"] = time.Now().Truncate(time.Millisecond).UTC()
  398. m["testblob"] = []byte("test blob")
  399. m["testbool"] = true
  400. m["testfloat"] = float32(4.564)
  401. m["testdouble"] = float64(4.815162342)
  402. m["testint"] = 2343
  403. m["testdecimal"] = inf.NewDec(100, 0)
  404. m["testset"] = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
  405. m["testmap"] = map[string]string{"field1": "val1", "field2": "val2", "field3": "val3"}
  406. sliceMap := []map[string]interface{}{m}
  407. if err := session.Query(`INSERT INTO slice_map_table (testuuid, testtimestamp, testvarchar, testbigint, testblob, testbool, testfloat, testdouble, testint, testdecimal, testset, testmap) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
  408. m["testuuid"], m["testtimestamp"], m["testvarchar"], m["testbigint"], m["testblob"], m["testbool"], m["testfloat"], m["testdouble"], m["testint"], m["testdecimal"], m["testset"], m["testmap"]).Exec(); err != nil {
  409. t.Fatal("insert:", err)
  410. }
  411. if returned, retErr := session.Query(`SELECT * FROM slice_map_table`).Iter().SliceMap(); retErr != nil {
  412. t.Fatal("select:", retErr)
  413. } else {
  414. if sliceMap[0]["testuuid"] != returned[0]["testuuid"] {
  415. t.Fatal("returned testuuid did not match")
  416. }
  417. if sliceMap[0]["testtimestamp"] != returned[0]["testtimestamp"] {
  418. t.Fatalf("returned testtimestamp did not match: %v %v", sliceMap[0]["testtimestamp"], returned[0]["testtimestamp"])
  419. }
  420. if sliceMap[0]["testvarchar"] != returned[0]["testvarchar"] {
  421. t.Fatal("returned testvarchar did not match")
  422. }
  423. if sliceMap[0]["testbigint"] != returned[0]["testbigint"] {
  424. t.Fatal("returned testbigint did not match")
  425. }
  426. if !reflect.DeepEqual(sliceMap[0]["testblob"], returned[0]["testblob"]) {
  427. t.Fatal("returned testblob did not match")
  428. }
  429. if sliceMap[0]["testbool"] != returned[0]["testbool"] {
  430. t.Fatal("returned testbool did not match")
  431. }
  432. if sliceMap[0]["testfloat"] != returned[0]["testfloat"] {
  433. t.Fatal("returned testfloat did not match")
  434. }
  435. if sliceMap[0]["testdouble"] != returned[0]["testdouble"] {
  436. t.Fatal("returned testdouble did not match")
  437. }
  438. if sliceMap[0]["testint"] != returned[0]["testint"] {
  439. t.Fatal("returned testint did not match")
  440. }
  441. expectedDecimal := sliceMap[0]["testdecimal"].(*inf.Dec)
  442. returnedDecimal := returned[0]["testdecimal"].(*inf.Dec)
  443. if expectedDecimal.Cmp(returnedDecimal) != 0 {
  444. t.Fatal("returned testdecimal did not match")
  445. }
  446. if !reflect.DeepEqual(sliceMap[0]["testset"], returned[0]["testset"]) {
  447. t.Fatal("returned testset did not match")
  448. }
  449. if !reflect.DeepEqual(sliceMap[0]["testmap"], returned[0]["testmap"]) {
  450. t.Fatal("returned testmap did not match")
  451. }
  452. }
  453. // Test for MapScan()
  454. testMap := make(map[string]interface{})
  455. if !session.Query(`SELECT * FROM slice_map_table`).Iter().MapScan(testMap) {
  456. t.Fatal("MapScan failed to work with one row")
  457. }
  458. if sliceMap[0]["testuuid"] != testMap["testuuid"] {
  459. t.Fatal("returned testuuid did not match")
  460. }
  461. if sliceMap[0]["testtimestamp"] != testMap["testtimestamp"] {
  462. t.Fatal("returned testtimestamp did not match")
  463. }
  464. if sliceMap[0]["testvarchar"] != testMap["testvarchar"] {
  465. t.Fatal("returned testvarchar did not match")
  466. }
  467. if sliceMap[0]["testbigint"] != testMap["testbigint"] {
  468. t.Fatal("returned testbigint did not match")
  469. }
  470. if !reflect.DeepEqual(sliceMap[0]["testblob"], testMap["testblob"]) {
  471. t.Fatal("returned testblob did not match")
  472. }
  473. if sliceMap[0]["testbool"] != testMap["testbool"] {
  474. t.Fatal("returned testbool did not match")
  475. }
  476. if sliceMap[0]["testfloat"] != testMap["testfloat"] {
  477. t.Fatal("returned testfloat did not match")
  478. }
  479. if sliceMap[0]["testdouble"] != testMap["testdouble"] {
  480. t.Fatal("returned testdouble did not match")
  481. }
  482. if sliceMap[0]["testint"] != testMap["testint"] {
  483. t.Fatal("returned testint did not match")
  484. }
  485. expectedDecimal := sliceMap[0]["testdecimal"].(*inf.Dec)
  486. returnedDecimal := testMap["testdecimal"].(*inf.Dec)
  487. if expectedDecimal.Cmp(returnedDecimal) != 0 {
  488. t.Fatal("returned testdecimal did not match")
  489. }
  490. if !reflect.DeepEqual(sliceMap[0]["testset"], testMap["testset"]) {
  491. t.Fatal("returned testset did not match")
  492. }
  493. if !reflect.DeepEqual(sliceMap[0]["testmap"], testMap["testmap"]) {
  494. t.Fatal("returned testmap did not match")
  495. }
  496. }
  497. func TestScanWithNilArguments(t *testing.T) {
  498. session := createSession(t)
  499. defer session.Close()
  500. if err := session.Query(`CREATE TABLE scan_with_nil_arguments (
  501. foo varchar,
  502. bar int,
  503. PRIMARY KEY (foo, bar)
  504. )`).Exec(); err != nil {
  505. t.Fatal("create:", err)
  506. }
  507. for i := 1; i <= 20; i++ {
  508. if err := session.Query("INSERT INTO scan_with_nil_arguments (foo, bar) VALUES (?, ?)",
  509. "squares", i*i).Exec(); err != nil {
  510. t.Fatal("insert:", err)
  511. }
  512. }
  513. iter := session.Query("SELECT * FROM scan_with_nil_arguments WHERE foo = ?", "squares").Iter()
  514. var n int
  515. count := 0
  516. for iter.Scan(nil, &n) {
  517. count += n
  518. }
  519. if err := iter.Close(); err != nil {
  520. t.Fatal("close:", err)
  521. }
  522. if count != 2870 {
  523. t.Fatalf("expected %d, got %d", 2870, count)
  524. }
  525. }
  526. func TestScanCASWithNilArguments(t *testing.T) {
  527. if *flagProto == 1 {
  528. t.Skip("lightweight transactions not supported. Please use Cassandra >= 2.0")
  529. }
  530. session := createSession(t)
  531. defer session.Close()
  532. if err := session.Query(`CREATE TABLE scan_cas_with_nil_arguments (
  533. foo varchar,
  534. bar varchar,
  535. PRIMARY KEY (foo, bar)
  536. )`).Exec(); err != nil {
  537. t.Fatal("create:", err)
  538. }
  539. foo := "baz"
  540. var cas string
  541. if applied, err := session.Query(`INSERT INTO scan_cas_with_nil_arguments (foo, bar)
  542. VALUES (?, ?) IF NOT EXISTS`,
  543. foo, foo).ScanCAS(nil, nil); err != nil {
  544. t.Fatal("insert:", err)
  545. } else if !applied {
  546. t.Fatal("insert should have been applied")
  547. }
  548. if applied, err := session.Query(`INSERT INTO scan_cas_with_nil_arguments (foo, bar)
  549. VALUES (?, ?) IF NOT EXISTS`,
  550. foo, foo).ScanCAS(&cas, nil); err != nil {
  551. t.Fatal("insert:", err)
  552. } else if applied {
  553. t.Fatal("insert should not have been applied")
  554. } else if foo != cas {
  555. t.Fatalf("expected %v but got %v", foo, cas)
  556. }
  557. if applied, err := session.Query(`INSERT INTO scan_cas_with_nil_arguments (foo, bar)
  558. VALUES (?, ?) IF NOT EXISTS`,
  559. foo, foo).ScanCAS(nil, &cas); err != nil {
  560. t.Fatal("insert:", err)
  561. } else if applied {
  562. t.Fatal("insert should not have been applied")
  563. } else if foo != cas {
  564. t.Fatalf("expected %v but got %v", foo, cas)
  565. }
  566. }
  567. func injectInvalidPreparedStatement(t *testing.T, session *Session, table string) (string, *Conn) {
  568. if err := session.Query(`CREATE TABLE ` + table + ` (
  569. foo varchar,
  570. bar int,
  571. PRIMARY KEY (foo, bar)
  572. )`).Exec(); err != nil {
  573. t.Fatal("create:", err)
  574. }
  575. stmt := "INSERT INTO " + table + " (foo, bar) VALUES (?, 7)"
  576. conn := session.Pool.Pick(nil)
  577. flight := new(inflightPrepare)
  578. stmtsLRU.mu.Lock()
  579. stmtsLRU.lru.Add(conn.addr+stmt, flight)
  580. stmtsLRU.mu.Unlock()
  581. flight.info = &queryInfo{
  582. id: []byte{'f', 'o', 'o', 'b', 'a', 'r'},
  583. args: []ColumnInfo{ColumnInfo{
  584. Keyspace: "gocql_test",
  585. Table: table,
  586. Name: "foo",
  587. TypeInfo: &TypeInfo{
  588. Type: TypeVarchar,
  589. },
  590. }},
  591. }
  592. return stmt, conn
  593. }
  594. func TestReprepareStatement(t *testing.T) {
  595. session := createSession(t)
  596. defer session.Close()
  597. stmt, conn := injectInvalidPreparedStatement(t, session, "test_reprepare_statement")
  598. query := session.Query(stmt, "bar")
  599. if err := conn.executeQuery(query).Close(); err != nil {
  600. t.Fatalf("Failed to execute query for reprepare statement: %v", err)
  601. }
  602. }
  603. func TestReprepareBatch(t *testing.T) {
  604. if *flagProto == 1 {
  605. t.Skip("atomic batches not supported. Please use Cassandra >= 2.0")
  606. }
  607. session := createSession(t)
  608. defer session.Close()
  609. stmt, conn := injectInvalidPreparedStatement(t, session, "test_reprepare_statement_batch")
  610. batch := session.NewBatch(UnloggedBatch)
  611. batch.Query(stmt, "bar")
  612. if err := conn.executeBatch(batch); err != nil {
  613. t.Fatalf("Failed to execute query for reprepare statement: %v", err)
  614. }
  615. }
  616. //TestPreparedCacheEviction will make sure that the cache size is maintained
  617. func TestPreparedCacheEviction(t *testing.T) {
  618. session := createSession(t)
  619. defer session.Close()
  620. stmtsLRU.mu.Lock()
  621. stmtsLRU.Max(4)
  622. stmtsLRU.mu.Unlock()
  623. if err := session.Query("CREATE TABLE prepcachetest (id int,mod int,PRIMARY KEY (id))").Exec(); err != nil {
  624. t.Fatalf("failed to create table with error '%v'", err)
  625. }
  626. //Fill the table
  627. for i := 0; i < 2; i++ {
  628. if err := session.Query("INSERT INTO prepcachetest (id,mod) VALUES (?, ?)", i, 10000%(i+1)).Exec(); err != nil {
  629. t.Fatalf("insert into prepcachetest failed, err '%v'", err)
  630. }
  631. }
  632. //Populate the prepared statement cache with select statements
  633. var id, mod int
  634. for i := 0; i < 2; i++ {
  635. err := session.Query("SELECT id,mod FROM prepcachetest WHERE id = "+strconv.FormatInt(int64(i), 10)).Scan(&id, &mod)
  636. if err != nil {
  637. t.Fatalf("select from prepcachetest failed, error '%v'", err)
  638. }
  639. }
  640. //generate an update statement to test they are prepared
  641. err := session.Query("UPDATE prepcachetest SET mod = ? WHERE id = ?", 1, 11).Exec()
  642. if err != nil {
  643. t.Fatalf("update prepcachetest failed, error '%v'", err)
  644. }
  645. //generate a delete statement to test they are prepared
  646. err = session.Query("DELETE FROM prepcachetest WHERE id = ?", 1).Exec()
  647. if err != nil {
  648. t.Fatalf("delete from prepcachetest failed, error '%v'", err)
  649. }
  650. //generate an insert statement to test they are prepared
  651. err = session.Query("INSERT INTO prepcachetest (id,mod) VALUES (?, ?)", 3, 11).Exec()
  652. if err != nil {
  653. t.Fatalf("insert into prepcachetest failed, error '%v'", err)
  654. }
  655. //Make sure the cache size is maintained
  656. if stmtsLRU.lru.Len() != stmtsLRU.lru.MaxEntries {
  657. t.Fatalf("expected cache size of %v, got %v", stmtsLRU.lru.MaxEntries, stmtsLRU.lru.Len())
  658. }
  659. //Walk through all the configured hosts and test cache retention and eviction
  660. var selFound, insFound, updFound, delFound, selEvict bool
  661. for i := range session.cfg.Hosts {
  662. _, ok := stmtsLRU.lru.Get(session.cfg.Hosts[i] + ":9042SELECT id,mod FROM prepcachetest WHERE id = 1")
  663. selFound = selFound || ok
  664. _, ok = stmtsLRU.lru.Get(session.cfg.Hosts[i] + ":9042INSERT INTO prepcachetest (id,mod) VALUES (?, ?)")
  665. insFound = insFound || ok
  666. _, ok = stmtsLRU.lru.Get(session.cfg.Hosts[i] + ":9042UPDATE prepcachetest SET mod = ? WHERE id = ?")
  667. updFound = updFound || ok
  668. _, ok = stmtsLRU.lru.Get(session.cfg.Hosts[i] + ":9042DELETE FROM prepcachetest WHERE id = ?")
  669. delFound = delFound || ok
  670. _, ok = stmtsLRU.lru.Get(session.cfg.Hosts[i] + ":9042SELECT id,mod FROM prepcachetest WHERE id = 0")
  671. selEvict = selEvict || !ok
  672. }
  673. if !selEvict {
  674. t.Fatalf("expected first select statement to be purged, but statement was found in the cache.")
  675. }
  676. if !selFound {
  677. t.Fatalf("expected second select statement to be cached, but statement was purged or not prepared.")
  678. }
  679. if !insFound {
  680. t.Fatalf("expected insert statement to be cached, but statement was purged or not prepared.")
  681. }
  682. if !updFound {
  683. t.Fatalf("expected update statement to be cached, but statement was purged or not prepared.")
  684. }
  685. if !delFound {
  686. t.Error("expected delete statement to be cached, but statement was purged or not prepared.")
  687. }
  688. }