metadata_test.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. // Copyright (c) 2015 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. "strconv"
  7. "testing"
  8. )
  9. // Tests V1 and V2 metadata "compilation" from example data which might be returned
  10. // from metadata schema queries (see getKeyspaceMetadata, getTableMetadata, and getColumnMetadata)
  11. func TestCompileMetadata(t *testing.T) {
  12. // V1 tests - these are all based on real examples from the integration test ccm cluster
  13. keyspace := &KeyspaceMetadata{
  14. Name: "V1Keyspace",
  15. }
  16. tables := []TableMetadata{
  17. {
  18. // This table, found in the system keyspace, has no key aliases or column aliases
  19. Keyspace: "V1Keyspace",
  20. Name: "Schema",
  21. KeyValidator: "org.apache.cassandra.db.marshal.BytesType",
  22. Comparator: "org.apache.cassandra.db.marshal.UTF8Type",
  23. DefaultValidator: "org.apache.cassandra.db.marshal.BytesType",
  24. KeyAliases: []string{},
  25. ColumnAliases: []string{},
  26. ValueAlias: "",
  27. },
  28. {
  29. // This table, found in the system keyspace, has key aliases, column aliases, and a value alias.
  30. Keyspace: "V1Keyspace",
  31. Name: "hints",
  32. KeyValidator: "org.apache.cassandra.db.marshal.UUIDType",
  33. Comparator: "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.TimeUUIDType,org.apache.cassandra.db.marshal.Int32Type)",
  34. DefaultValidator: "org.apache.cassandra.db.marshal.BytesType",
  35. KeyAliases: []string{"target_id"},
  36. ColumnAliases: []string{"hint_id", "message_version"},
  37. ValueAlias: "mutation",
  38. },
  39. {
  40. // This table, found in the system keyspace, has a comparator with collections, but no column aliases
  41. Keyspace: "V1Keyspace",
  42. Name: "peers",
  43. KeyValidator: "org.apache.cassandra.db.marshal.InetAddressType",
  44. Comparator: "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type,org.apache.cassandra.db.marshal.ColumnToCollectionType(746f6b656e73:org.apache.cassandra.db.marshal.SetType(org.apache.cassandra.db.marshal.UTF8Type)))",
  45. DefaultValidator: "org.apache.cassandra.db.marshal.BytesType",
  46. KeyAliases: []string{"peer"},
  47. ColumnAliases: []string{},
  48. ValueAlias: "",
  49. },
  50. {
  51. // This table, found in the system keyspace, has a column alias, but not a composite comparator
  52. Keyspace: "V1Keyspace",
  53. Name: "IndexInfo",
  54. KeyValidator: "org.apache.cassandra.db.marshal.UTF8Type",
  55. Comparator: "org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.UTF8Type)",
  56. DefaultValidator: "org.apache.cassandra.db.marshal.BytesType",
  57. KeyAliases: []string{"table_name"},
  58. ColumnAliases: []string{"index_name"},
  59. ValueAlias: "",
  60. },
  61. {
  62. // This table, found in the gocql_test keyspace following an integration test run, has a composite comparator with collections as well as a column alias
  63. Keyspace: "V1Keyspace",
  64. Name: "wiki_page",
  65. KeyValidator: "org.apache.cassandra.db.marshal.UTF8Type",
  66. Comparator: "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.TimeUUIDType,org.apache.cassandra.db.marshal.UTF8Type,org.apache.cassandra.db.marshal.ColumnToCollectionType(74616773:org.apache.cassandra.db.marshal.SetType(org.apache.cassandra.db.marshal.UTF8Type),6174746163686d656e7473:org.apache.cassandra.db.marshal.MapType(org.apache.cassandra.db.marshal.UTF8Type,org.apache.cassandra.db.marshal.BytesType)))",
  67. DefaultValidator: "org.apache.cassandra.db.marshal.BytesType",
  68. KeyAliases: []string{"title"},
  69. ColumnAliases: []string{"revid"},
  70. ValueAlias: "",
  71. },
  72. {
  73. // This is a made up example with multiple unnamed aliases
  74. Keyspace: "V1Keyspace",
  75. Name: "no_names",
  76. KeyValidator: "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UUIDType,org.apache.cassandra.db.marshal.UUIDType)",
  77. Comparator: "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.Int32Type,org.apache.cassandra.db.marshal.Int32Type,org.apache.cassandra.db.marshal.Int32Type)",
  78. DefaultValidator: "org.apache.cassandra.db.marshal.BytesType",
  79. KeyAliases: []string{},
  80. ColumnAliases: []string{},
  81. ValueAlias: "",
  82. },
  83. }
  84. columns := []ColumnMetadata{
  85. // Here are the regular columns from the peers table for testing regular columns
  86. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "data_center", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UTF8Type"},
  87. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "host_id", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UUIDType"},
  88. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "rack", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UTF8Type"},
  89. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "release_version", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UTF8Type"},
  90. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "rpc_address", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.InetAddressType"},
  91. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "schema_version", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UUIDType"},
  92. {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "tokens", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.SetType(org.apache.cassandra.db.marshal.UTF8Type)"},
  93. }
  94. compileMetadata(1, keyspace, tables, columns, nil, nil, nil)
  95. assertKeyspaceMetadata(
  96. t,
  97. keyspace,
  98. &KeyspaceMetadata{
  99. Name: "V1Keyspace",
  100. Tables: map[string]*TableMetadata{
  101. "Schema": {
  102. PartitionKey: []*ColumnMetadata{
  103. {
  104. Name: "key",
  105. Type: NativeType{typ: TypeBlob},
  106. },
  107. },
  108. ClusteringColumns: []*ColumnMetadata{},
  109. Columns: map[string]*ColumnMetadata{
  110. "key": {
  111. Name: "key",
  112. Type: NativeType{typ: TypeBlob},
  113. Kind: ColumnPartitionKey,
  114. },
  115. },
  116. },
  117. "hints": {
  118. PartitionKey: []*ColumnMetadata{
  119. {
  120. Name: "target_id",
  121. Type: NativeType{typ: TypeUUID},
  122. },
  123. },
  124. ClusteringColumns: []*ColumnMetadata{
  125. {
  126. Name: "hint_id",
  127. Type: NativeType{typ: TypeTimeUUID},
  128. Order: ASC,
  129. },
  130. {
  131. Name: "message_version",
  132. Type: NativeType{typ: TypeInt},
  133. Order: ASC,
  134. },
  135. },
  136. Columns: map[string]*ColumnMetadata{
  137. "target_id": {
  138. Name: "target_id",
  139. Type: NativeType{typ: TypeUUID},
  140. Kind: ColumnPartitionKey,
  141. },
  142. "hint_id": {
  143. Name: "hint_id",
  144. Type: NativeType{typ: TypeTimeUUID},
  145. Order: ASC,
  146. Kind: ColumnClusteringKey,
  147. },
  148. "message_version": {
  149. Name: "message_version",
  150. Type: NativeType{typ: TypeInt},
  151. Order: ASC,
  152. Kind: ColumnClusteringKey,
  153. },
  154. "mutation": {
  155. Name: "mutation",
  156. Type: NativeType{typ: TypeBlob},
  157. Kind: ColumnRegular,
  158. },
  159. },
  160. },
  161. "peers": {
  162. PartitionKey: []*ColumnMetadata{
  163. {
  164. Name: "peer",
  165. Type: NativeType{typ: TypeInet},
  166. },
  167. },
  168. ClusteringColumns: []*ColumnMetadata{},
  169. Columns: map[string]*ColumnMetadata{
  170. "peer": {
  171. Name: "peer",
  172. Type: NativeType{typ: TypeInet},
  173. Kind: ColumnPartitionKey,
  174. },
  175. "data_center": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "data_center", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UTF8Type", Type: NativeType{typ: TypeVarchar}},
  176. "host_id": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "host_id", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UUIDType", Type: NativeType{typ: TypeUUID}},
  177. "rack": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "rack", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UTF8Type", Type: NativeType{typ: TypeVarchar}},
  178. "release_version": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "release_version", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UTF8Type", Type: NativeType{typ: TypeVarchar}},
  179. "rpc_address": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "rpc_address", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.InetAddressType", Type: NativeType{typ: TypeInet}},
  180. "schema_version": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "schema_version", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.UUIDType", Type: NativeType{typ: TypeUUID}},
  181. "tokens": {Keyspace: "V1Keyspace", Table: "peers", Kind: ColumnRegular, Name: "tokens", ComponentIndex: 0, Validator: "org.apache.cassandra.db.marshal.SetType(org.apache.cassandra.db.marshal.UTF8Type)", Type: CollectionType{NativeType: NativeType{typ: TypeSet}}},
  182. },
  183. },
  184. "IndexInfo": {
  185. PartitionKey: []*ColumnMetadata{
  186. {
  187. Name: "table_name",
  188. Type: NativeType{typ: TypeVarchar},
  189. },
  190. },
  191. ClusteringColumns: []*ColumnMetadata{
  192. {
  193. Name: "index_name",
  194. Type: NativeType{typ: TypeVarchar},
  195. Order: DESC,
  196. },
  197. },
  198. Columns: map[string]*ColumnMetadata{
  199. "table_name": {
  200. Name: "table_name",
  201. Type: NativeType{typ: TypeVarchar},
  202. Kind: ColumnPartitionKey,
  203. },
  204. "index_name": {
  205. Name: "index_name",
  206. Type: NativeType{typ: TypeVarchar},
  207. Order: DESC,
  208. Kind: ColumnClusteringKey,
  209. },
  210. "value": {
  211. Name: "value",
  212. Type: NativeType{typ: TypeBlob},
  213. Kind: ColumnRegular,
  214. },
  215. },
  216. },
  217. "wiki_page": {
  218. PartitionKey: []*ColumnMetadata{
  219. {
  220. Name: "title",
  221. Type: NativeType{typ: TypeVarchar},
  222. },
  223. },
  224. ClusteringColumns: []*ColumnMetadata{
  225. {
  226. Name: "revid",
  227. Type: NativeType{typ: TypeTimeUUID},
  228. Order: ASC,
  229. },
  230. },
  231. Columns: map[string]*ColumnMetadata{
  232. "title": {
  233. Name: "title",
  234. Type: NativeType{typ: TypeVarchar},
  235. Kind: ColumnPartitionKey,
  236. },
  237. "revid": {
  238. Name: "revid",
  239. Type: NativeType{typ: TypeTimeUUID},
  240. Kind: ColumnClusteringKey,
  241. },
  242. },
  243. },
  244. "no_names": {
  245. PartitionKey: []*ColumnMetadata{
  246. {
  247. Name: "key",
  248. Type: NativeType{typ: TypeUUID},
  249. },
  250. {
  251. Name: "key2",
  252. Type: NativeType{typ: TypeUUID},
  253. },
  254. },
  255. ClusteringColumns: []*ColumnMetadata{
  256. {
  257. Name: "column",
  258. Type: NativeType{typ: TypeInt},
  259. Order: ASC,
  260. },
  261. {
  262. Name: "column2",
  263. Type: NativeType{typ: TypeInt},
  264. Order: ASC,
  265. },
  266. {
  267. Name: "column3",
  268. Type: NativeType{typ: TypeInt},
  269. Order: ASC,
  270. },
  271. },
  272. Columns: map[string]*ColumnMetadata{
  273. "key": {
  274. Name: "key",
  275. Type: NativeType{typ: TypeUUID},
  276. Kind: ColumnPartitionKey,
  277. },
  278. "key2": {
  279. Name: "key2",
  280. Type: NativeType{typ: TypeUUID},
  281. Kind: ColumnPartitionKey,
  282. },
  283. "column": {
  284. Name: "column",
  285. Type: NativeType{typ: TypeInt},
  286. Order: ASC,
  287. Kind: ColumnClusteringKey,
  288. },
  289. "column2": {
  290. Name: "column2",
  291. Type: NativeType{typ: TypeInt},
  292. Order: ASC,
  293. Kind: ColumnClusteringKey,
  294. },
  295. "column3": {
  296. Name: "column3",
  297. Type: NativeType{typ: TypeInt},
  298. Order: ASC,
  299. Kind: ColumnClusteringKey,
  300. },
  301. "value": {
  302. Name: "value",
  303. Type: NativeType{typ: TypeBlob},
  304. Kind: ColumnRegular,
  305. },
  306. },
  307. },
  308. },
  309. },
  310. )
  311. // V2 test - V2+ protocol is simpler so here are some toy examples to verify that the mapping works
  312. keyspace = &KeyspaceMetadata{
  313. Name: "V2Keyspace",
  314. }
  315. tables = []TableMetadata{
  316. {
  317. Keyspace: "V2Keyspace",
  318. Name: "Table1",
  319. },
  320. {
  321. Keyspace: "V2Keyspace",
  322. Name: "Table2",
  323. },
  324. }
  325. columns = []ColumnMetadata{
  326. {
  327. Keyspace: "V2Keyspace",
  328. Table: "Table1",
  329. Name: "KEY1",
  330. Kind: ColumnPartitionKey,
  331. ComponentIndex: 0,
  332. Validator: "org.apache.cassandra.db.marshal.UTF8Type",
  333. },
  334. {
  335. Keyspace: "V2Keyspace",
  336. Table: "Table1",
  337. Name: "Key1",
  338. Kind: ColumnPartitionKey,
  339. ComponentIndex: 0,
  340. Validator: "org.apache.cassandra.db.marshal.UTF8Type",
  341. },
  342. {
  343. Keyspace: "V2Keyspace",
  344. Table: "Table2",
  345. Name: "Column1",
  346. Kind: ColumnPartitionKey,
  347. ComponentIndex: 0,
  348. Validator: "org.apache.cassandra.db.marshal.UTF8Type",
  349. },
  350. {
  351. Keyspace: "V2Keyspace",
  352. Table: "Table2",
  353. Name: "Column2",
  354. Kind: ColumnClusteringKey,
  355. ComponentIndex: 0,
  356. Validator: "org.apache.cassandra.db.marshal.UTF8Type",
  357. },
  358. {
  359. Keyspace: "V2Keyspace",
  360. Table: "Table2",
  361. Name: "Column3",
  362. Kind: ColumnClusteringKey,
  363. ComponentIndex: 1,
  364. Validator: "org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.UTF8Type)",
  365. },
  366. {
  367. Keyspace: "V2Keyspace",
  368. Table: "Table2",
  369. Name: "Column4",
  370. Kind: ColumnRegular,
  371. Validator: "org.apache.cassandra.db.marshal.UTF8Type",
  372. },
  373. }
  374. compileMetadata(2, keyspace, tables, columns, nil, nil, nil)
  375. assertKeyspaceMetadata(
  376. t,
  377. keyspace,
  378. &KeyspaceMetadata{
  379. Name: "V2Keyspace",
  380. Tables: map[string]*TableMetadata{
  381. "Table1": {
  382. PartitionKey: []*ColumnMetadata{
  383. {
  384. Name: "Key1",
  385. Type: NativeType{typ: TypeVarchar},
  386. },
  387. },
  388. ClusteringColumns: []*ColumnMetadata{},
  389. Columns: map[string]*ColumnMetadata{
  390. "KEY1": {
  391. Name: "KEY1",
  392. Type: NativeType{typ: TypeVarchar},
  393. Kind: ColumnPartitionKey,
  394. },
  395. "Key1": {
  396. Name: "Key1",
  397. Type: NativeType{typ: TypeVarchar},
  398. Kind: ColumnPartitionKey,
  399. },
  400. },
  401. },
  402. "Table2": {
  403. PartitionKey: []*ColumnMetadata{
  404. {
  405. Name: "Column1",
  406. Type: NativeType{typ: TypeVarchar},
  407. },
  408. },
  409. ClusteringColumns: []*ColumnMetadata{
  410. {
  411. Name: "Column2",
  412. Type: NativeType{typ: TypeVarchar},
  413. Order: ASC,
  414. },
  415. {
  416. Name: "Column3",
  417. Type: NativeType{typ: TypeVarchar},
  418. Order: DESC,
  419. },
  420. },
  421. Columns: map[string]*ColumnMetadata{
  422. "Column1": {
  423. Name: "Column1",
  424. Type: NativeType{typ: TypeVarchar},
  425. Kind: ColumnPartitionKey,
  426. },
  427. "Column2": {
  428. Name: "Column2",
  429. Type: NativeType{typ: TypeVarchar},
  430. Order: ASC,
  431. Kind: ColumnClusteringKey,
  432. },
  433. "Column3": {
  434. Name: "Column3",
  435. Type: NativeType{typ: TypeVarchar},
  436. Order: DESC,
  437. Kind: ColumnClusteringKey,
  438. },
  439. "Column4": {
  440. Name: "Column4",
  441. Type: NativeType{typ: TypeVarchar},
  442. Kind: ColumnRegular,
  443. },
  444. },
  445. },
  446. },
  447. },
  448. )
  449. }
  450. // Helper function for asserting that actual metadata returned was as expected
  451. func assertKeyspaceMetadata(t *testing.T, actual, expected *KeyspaceMetadata) {
  452. if len(expected.Tables) != len(actual.Tables) {
  453. t.Errorf("Expected len(%s.Tables) to be %v but was %v", expected.Name, len(expected.Tables), len(actual.Tables))
  454. }
  455. for keyT := range expected.Tables {
  456. et := expected.Tables[keyT]
  457. at, found := actual.Tables[keyT]
  458. if !found {
  459. t.Errorf("Expected %s.Tables[%s] but was not found", expected.Name, keyT)
  460. } else {
  461. if keyT != at.Name {
  462. t.Errorf("Expected %s.Tables[%s].Name to be %v but was %v", expected.Name, keyT, keyT, at.Name)
  463. }
  464. if len(et.PartitionKey) != len(at.PartitionKey) {
  465. t.Errorf("Expected len(%s.Tables[%s].PartitionKey) to be %v but was %v", expected.Name, keyT, len(et.PartitionKey), len(at.PartitionKey))
  466. } else {
  467. for i := range et.PartitionKey {
  468. if et.PartitionKey[i].Name != at.PartitionKey[i].Name {
  469. t.Errorf("Expected %s.Tables[%s].PartitionKey[%d].Name to be '%v' but was '%v'", expected.Name, keyT, i, et.PartitionKey[i].Name, at.PartitionKey[i].Name)
  470. }
  471. if expected.Name != at.PartitionKey[i].Keyspace {
  472. t.Errorf("Expected %s.Tables[%s].PartitionKey[%d].Keyspace to be '%v' but was '%v'", expected.Name, keyT, i, expected.Name, at.PartitionKey[i].Keyspace)
  473. }
  474. if keyT != at.PartitionKey[i].Table {
  475. t.Errorf("Expected %s.Tables[%s].PartitionKey[%d].Table to be '%v' but was '%v'", expected.Name, keyT, i, keyT, at.PartitionKey[i].Table)
  476. }
  477. if et.PartitionKey[i].Type.Type() != at.PartitionKey[i].Type.Type() {
  478. t.Errorf("Expected %s.Tables[%s].PartitionKey[%d].Type.Type to be %v but was %v", expected.Name, keyT, i, et.PartitionKey[i].Type.Type(), at.PartitionKey[i].Type.Type())
  479. }
  480. if i != at.PartitionKey[i].ComponentIndex {
  481. t.Errorf("Expected %s.Tables[%s].PartitionKey[%d].ComponentIndex to be %v but was %v", expected.Name, keyT, i, i, at.PartitionKey[i].ComponentIndex)
  482. }
  483. if ColumnPartitionKey != at.PartitionKey[i].Kind {
  484. t.Errorf("Expected %s.Tables[%s].PartitionKey[%d].Kind to be '%v' but was '%v'", expected.Name, keyT, i, ColumnPartitionKey, at.PartitionKey[i].Kind)
  485. }
  486. }
  487. }
  488. if len(et.ClusteringColumns) != len(at.ClusteringColumns) {
  489. t.Errorf("Expected len(%s.Tables[%s].ClusteringColumns) to be %v but was %v", expected.Name, keyT, len(et.ClusteringColumns), len(at.ClusteringColumns))
  490. } else {
  491. for i := range et.ClusteringColumns {
  492. if at.ClusteringColumns[i] == nil {
  493. t.Fatalf("Unexpected nil value: %s.Tables[%s].ClusteringColumns[%d]", expected.Name, keyT, i)
  494. }
  495. if et.ClusteringColumns[i].Name != at.ClusteringColumns[i].Name {
  496. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].Name to be '%v' but was '%v'", expected.Name, keyT, i, et.ClusteringColumns[i].Name, at.ClusteringColumns[i].Name)
  497. }
  498. if expected.Name != at.ClusteringColumns[i].Keyspace {
  499. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].Keyspace to be '%v' but was '%v'", expected.Name, keyT, i, expected.Name, at.ClusteringColumns[i].Keyspace)
  500. }
  501. if keyT != at.ClusteringColumns[i].Table {
  502. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].Table to be '%v' but was '%v'", expected.Name, keyT, i, keyT, at.ClusteringColumns[i].Table)
  503. }
  504. if et.ClusteringColumns[i].Type.Type() != at.ClusteringColumns[i].Type.Type() {
  505. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].Type.Type to be %v but was %v", expected.Name, keyT, i, et.ClusteringColumns[i].Type.Type(), at.ClusteringColumns[i].Type.Type())
  506. }
  507. if i != at.ClusteringColumns[i].ComponentIndex {
  508. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].ComponentIndex to be %v but was %v", expected.Name, keyT, i, i, at.ClusteringColumns[i].ComponentIndex)
  509. }
  510. if et.ClusteringColumns[i].Order != at.ClusteringColumns[i].Order {
  511. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].Order to be %v but was %v", expected.Name, keyT, i, et.ClusteringColumns[i].Order, at.ClusteringColumns[i].Order)
  512. }
  513. if ColumnClusteringKey != at.ClusteringColumns[i].Kind {
  514. t.Errorf("Expected %s.Tables[%s].ClusteringColumns[%d].Kind to be '%v' but was '%v'", expected.Name, keyT, i, ColumnClusteringKey, at.ClusteringColumns[i].Kind)
  515. }
  516. }
  517. }
  518. if len(et.Columns) != len(at.Columns) {
  519. eKeys := make([]string, 0, len(et.Columns))
  520. for key := range et.Columns {
  521. eKeys = append(eKeys, key)
  522. }
  523. aKeys := make([]string, 0, len(at.Columns))
  524. for key := range at.Columns {
  525. aKeys = append(aKeys, key)
  526. }
  527. t.Errorf("Expected len(%s.Tables[%s].Columns) to be %v (keys:%v) but was %v (keys:%v)", expected.Name, keyT, len(et.Columns), eKeys, len(at.Columns), aKeys)
  528. } else {
  529. for keyC := range et.Columns {
  530. ec := et.Columns[keyC]
  531. ac, found := at.Columns[keyC]
  532. if !found {
  533. t.Errorf("Expected %s.Tables[%s].Columns[%s] but was not found", expected.Name, keyT, keyC)
  534. } else {
  535. if keyC != ac.Name {
  536. t.Errorf("Expected %s.Tables[%s].Columns[%s].Name to be '%v' but was '%v'", expected.Name, keyT, keyC, keyC, at.Name)
  537. }
  538. if expected.Name != ac.Keyspace {
  539. t.Errorf("Expected %s.Tables[%s].Columns[%s].Keyspace to be '%v' but was '%v'", expected.Name, keyT, keyC, expected.Name, ac.Keyspace)
  540. }
  541. if keyT != ac.Table {
  542. t.Errorf("Expected %s.Tables[%s].Columns[%s].Table to be '%v' but was '%v'", expected.Name, keyT, keyC, keyT, ac.Table)
  543. }
  544. if ec.Type.Type() != ac.Type.Type() {
  545. t.Errorf("Expected %s.Tables[%s].Columns[%s].Type.Type to be %v but was %v", expected.Name, keyT, keyC, ec.Type.Type(), ac.Type.Type())
  546. }
  547. if ec.Order != ac.Order {
  548. t.Errorf("Expected %s.Tables[%s].Columns[%s].Order to be %v but was %v", expected.Name, keyT, keyC, ec.Order, ac.Order)
  549. }
  550. if ec.Kind != ac.Kind {
  551. t.Errorf("Expected %s.Tables[%s].Columns[%s].Kind to be '%v' but was '%v'", expected.Name, keyT, keyC, ec.Kind, ac.Kind)
  552. }
  553. }
  554. }
  555. }
  556. }
  557. }
  558. }
  559. // Tests the cassandra type definition parser
  560. func TestTypeParser(t *testing.T) {
  561. // native type
  562. assertParseNonCompositeType(
  563. t,
  564. "org.apache.cassandra.db.marshal.UTF8Type",
  565. assertTypeInfo{Type: TypeVarchar},
  566. )
  567. // reversed
  568. assertParseNonCompositeType(
  569. t,
  570. "org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.UUIDType)",
  571. assertTypeInfo{Type: TypeUUID, Reversed: true},
  572. )
  573. // set
  574. assertParseNonCompositeType(
  575. t,
  576. "org.apache.cassandra.db.marshal.SetType(org.apache.cassandra.db.marshal.Int32Type)",
  577. assertTypeInfo{
  578. Type: TypeSet,
  579. Elem: &assertTypeInfo{Type: TypeInt},
  580. },
  581. )
  582. // list
  583. assertParseNonCompositeType(
  584. t,
  585. "org.apache.cassandra.db.marshal.ListType(org.apache.cassandra.db.marshal.TimeUUIDType)",
  586. assertTypeInfo{
  587. Type: TypeList,
  588. Elem: &assertTypeInfo{Type: TypeTimeUUID},
  589. },
  590. )
  591. // map
  592. assertParseNonCompositeType(
  593. t,
  594. " org.apache.cassandra.db.marshal.MapType( org.apache.cassandra.db.marshal.UUIDType , org.apache.cassandra.db.marshal.BytesType ) ",
  595. assertTypeInfo{
  596. Type: TypeMap,
  597. Key: &assertTypeInfo{Type: TypeUUID},
  598. Elem: &assertTypeInfo{Type: TypeBlob},
  599. },
  600. )
  601. // custom
  602. assertParseNonCompositeType(
  603. t,
  604. "org.apache.cassandra.db.marshal.UserType(sandbox,61646472657373,737472656574:org.apache.cassandra.db.marshal.UTF8Type,63697479:org.apache.cassandra.db.marshal.UTF8Type,7a6970:org.apache.cassandra.db.marshal.Int32Type)",
  605. assertTypeInfo{Type: TypeCustom, Custom: "org.apache.cassandra.db.marshal.UserType(sandbox,61646472657373,737472656574:org.apache.cassandra.db.marshal.UTF8Type,63697479:org.apache.cassandra.db.marshal.UTF8Type,7a6970:org.apache.cassandra.db.marshal.Int32Type)"},
  606. )
  607. assertParseNonCompositeType(
  608. t,
  609. "org.apache.cassandra.db.marshal.DynamicCompositeType(u=>org.apache.cassandra.db.marshal.UUIDType,d=>org.apache.cassandra.db.marshal.DateType,t=>org.apache.cassandra.db.marshal.TimeUUIDType,b=>org.apache.cassandra.db.marshal.BytesType,s=>org.apache.cassandra.db.marshal.UTF8Type,B=>org.apache.cassandra.db.marshal.BooleanType,a=>org.apache.cassandra.db.marshal.AsciiType,l=>org.apache.cassandra.db.marshal.LongType,i=>org.apache.cassandra.db.marshal.IntegerType,x=>org.apache.cassandra.db.marshal.LexicalUUIDType)",
  610. assertTypeInfo{Type: TypeCustom, Custom: "org.apache.cassandra.db.marshal.DynamicCompositeType(u=>org.apache.cassandra.db.marshal.UUIDType,d=>org.apache.cassandra.db.marshal.DateType,t=>org.apache.cassandra.db.marshal.TimeUUIDType,b=>org.apache.cassandra.db.marshal.BytesType,s=>org.apache.cassandra.db.marshal.UTF8Type,B=>org.apache.cassandra.db.marshal.BooleanType,a=>org.apache.cassandra.db.marshal.AsciiType,l=>org.apache.cassandra.db.marshal.LongType,i=>org.apache.cassandra.db.marshal.IntegerType,x=>org.apache.cassandra.db.marshal.LexicalUUIDType)"},
  611. )
  612. // composite defs
  613. assertParseCompositeType(
  614. t,
  615. "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type)",
  616. []assertTypeInfo{
  617. {Type: TypeVarchar},
  618. },
  619. nil,
  620. )
  621. assertParseCompositeType(
  622. t,
  623. "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.DateType),org.apache.cassandra.db.marshal.UTF8Type)",
  624. []assertTypeInfo{
  625. {Type: TypeTimestamp, Reversed: true},
  626. {Type: TypeVarchar},
  627. },
  628. nil,
  629. )
  630. assertParseCompositeType(
  631. t,
  632. "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type,org.apache.cassandra.db.marshal.ColumnToCollectionType(726f77735f6d6572676564:org.apache.cassandra.db.marshal.MapType(org.apache.cassandra.db.marshal.Int32Type,org.apache.cassandra.db.marshal.LongType)))",
  633. []assertTypeInfo{
  634. {Type: TypeVarchar},
  635. },
  636. map[string]assertTypeInfo{
  637. "rows_merged": {
  638. Type: TypeMap,
  639. Key: &assertTypeInfo{Type: TypeInt},
  640. Elem: &assertTypeInfo{Type: TypeBigInt},
  641. },
  642. },
  643. )
  644. }
  645. // expected data holder
  646. type assertTypeInfo struct {
  647. Type Type
  648. Reversed bool
  649. Elem *assertTypeInfo
  650. Key *assertTypeInfo
  651. Custom string
  652. }
  653. // Helper function for asserting that the type parser returns the expected
  654. // results for the given definition
  655. func assertParseNonCompositeType(
  656. t *testing.T,
  657. def string,
  658. typeExpected assertTypeInfo,
  659. ) {
  660. result := parseType(def)
  661. if len(result.reversed) != 1 {
  662. t.Errorf("%s expected %d reversed values but there were %d", def, 1, len(result.reversed))
  663. }
  664. assertParseNonCompositeTypes(
  665. t,
  666. def,
  667. []assertTypeInfo{typeExpected},
  668. result.types,
  669. )
  670. // expect no composite part of the result
  671. if result.isComposite {
  672. t.Errorf("%s: Expected not composite", def)
  673. }
  674. if result.collections != nil {
  675. t.Errorf("%s: Expected nil collections: %v", def, result.collections)
  676. }
  677. }
  678. // Helper function for asserting that the type parser returns the expected
  679. // results for the given definition
  680. func assertParseCompositeType(
  681. t *testing.T,
  682. def string,
  683. typesExpected []assertTypeInfo,
  684. collectionsExpected map[string]assertTypeInfo,
  685. ) {
  686. result := parseType(def)
  687. if len(result.reversed) != len(typesExpected) {
  688. t.Errorf("%s expected %d reversed values but there were %d", def, len(typesExpected), len(result.reversed))
  689. }
  690. assertParseNonCompositeTypes(
  691. t,
  692. def,
  693. typesExpected,
  694. result.types,
  695. )
  696. // expect composite part of the result
  697. if !result.isComposite {
  698. t.Errorf("%s: Expected composite", def)
  699. }
  700. if result.collections == nil {
  701. t.Errorf("%s: Expected non-nil collections: %v", def, result.collections)
  702. }
  703. for name, typeExpected := range collectionsExpected {
  704. // check for an actual type for this name
  705. typeActual, found := result.collections[name]
  706. if !found {
  707. t.Errorf("%s.tcollections: Expected param named %s but there wasn't", def, name)
  708. } else {
  709. // remove the actual from the collection so we can detect extras
  710. delete(result.collections, name)
  711. // check the type
  712. assertParseNonCompositeTypes(
  713. t,
  714. def+"collections["+name+"]",
  715. []assertTypeInfo{typeExpected},
  716. []TypeInfo{typeActual},
  717. )
  718. }
  719. }
  720. if len(result.collections) != 0 {
  721. t.Errorf("%s.collections: Expected no more types in collections, but there was %v", def, result.collections)
  722. }
  723. }
  724. // Helper function for asserting that the type parser returns the expected
  725. // results for the given definition
  726. func assertParseNonCompositeTypes(
  727. t *testing.T,
  728. context string,
  729. typesExpected []assertTypeInfo,
  730. typesActual []TypeInfo,
  731. ) {
  732. if len(typesActual) != len(typesExpected) {
  733. t.Errorf("%s: Expected %d types, but there were %d", context, len(typesExpected), len(typesActual))
  734. }
  735. for i := range typesExpected {
  736. typeExpected := typesExpected[i]
  737. typeActual := typesActual[i]
  738. // shadow copy the context for local modification
  739. context := context
  740. if len(typesExpected) > 1 {
  741. context = context + "[" + strconv.Itoa(i) + "]"
  742. }
  743. // check the type
  744. if typeActual.Type() != typeExpected.Type {
  745. t.Errorf("%s: Expected to parse Type to %s but was %s", context, typeExpected.Type, typeActual.Type())
  746. }
  747. // check the custom
  748. if typeActual.Custom() != typeExpected.Custom {
  749. t.Errorf("%s: Expected to parse Custom %s but was %s", context, typeExpected.Custom, typeActual.Custom())
  750. }
  751. collection, _ := typeActual.(CollectionType)
  752. // check the elem
  753. if typeExpected.Elem != nil {
  754. if collection.Elem == nil {
  755. t.Errorf("%s: Expected to parse Elem, but was nil ", context)
  756. } else {
  757. assertParseNonCompositeTypes(
  758. t,
  759. context+".Elem",
  760. []assertTypeInfo{*typeExpected.Elem},
  761. []TypeInfo{collection.Elem},
  762. )
  763. }
  764. } else if collection.Elem != nil {
  765. t.Errorf("%s: Expected to not parse Elem, but was %+v", context, collection.Elem)
  766. }
  767. // check the key
  768. if typeExpected.Key != nil {
  769. if collection.Key == nil {
  770. t.Errorf("%s: Expected to parse Key, but was nil ", context)
  771. } else {
  772. assertParseNonCompositeTypes(
  773. t,
  774. context+".Key",
  775. []assertTypeInfo{*typeExpected.Key},
  776. []TypeInfo{collection.Key},
  777. )
  778. }
  779. } else if collection.Key != nil {
  780. t.Errorf("%s: Expected to not parse Key, but was %+v", context, collection.Key)
  781. }
  782. }
  783. }