metadata_test.go 30 KB

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