Skip to content

Commit

Permalink
metadata: Added Scylla metadata describer and dumper
Browse files Browse the repository at this point in the history
  • Loading branch information
zimnx authored and mmatczuk committed May 8, 2020
1 parent 2b8a7d9 commit a9e843a
Show file tree
Hide file tree
Showing 24 changed files with 2,509 additions and 277 deletions.
278 changes: 278 additions & 0 deletions cassandra_only_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"net"
"reflect"
"strconv"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -366,3 +367,280 @@ func TestLexicalUUIDType(t *testing.T) {
t.Errorf("got %s, expected %s", gotUUID, column1)
}
}

// Integration test of just querying for data from the system.schema_keyspace table where the keyspace DOES exist.
func TestGetKeyspaceMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()

keyspaceMetadata, err := getKeyspaceMetadata(session, "gocql_test")
if err != nil {
t.Fatalf("failed to query the keyspace metadata with err: %v", err)
}
if keyspaceMetadata == nil {
t.Fatal("failed to query the keyspace metadata, nil returned")
}
if keyspaceMetadata.Name != "gocql_test" {
t.Errorf("Expected keyspace name to be 'gocql' but was '%s'", keyspaceMetadata.Name)
}
if keyspaceMetadata.StrategyClass != "org.apache.cassandra.locator.SimpleStrategy" {
t.Errorf("Expected replication strategy class to be 'org.apache.cassandra.locator.SimpleStrategy' but was '%s'", keyspaceMetadata.StrategyClass)
}
if keyspaceMetadata.StrategyOptions == nil {
t.Error("Expected replication strategy options map but was nil")
}
rfStr, ok := keyspaceMetadata.StrategyOptions["replication_factor"]
if !ok {
t.Fatalf("Expected strategy option 'replication_factor' but was not found in %v", keyspaceMetadata.StrategyOptions)
}
rfInt, err := strconv.Atoi(rfStr.(string))
if err != nil {
t.Fatalf("Error converting string to int with err: %v", err)
}
if rfInt != *flagRF {
t.Errorf("Expected replication factor to be %d but was %d", *flagRF, rfInt)
}
}

// Integration test of just querying for data from the system.schema_keyspace table where the keyspace DOES NOT exist.
func TestGetKeyspaceMetadataFails(t *testing.T) {
session := createSession(t)
defer session.Close()

_, err := getKeyspaceMetadata(session, "gocql_keyspace_does_not_exist")

if err != ErrKeyspaceDoesNotExist || err == nil {
t.Fatalf("Expected error of type ErrKeySpaceDoesNotExist. Instead, error was %v", err)
}
}

// Integration test of just querying for data from the system.schema_columnfamilies table
func TestGetTableMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()

if err := createTable(session, "CREATE TABLE gocql_test.test_table_metadata (first_id int, second_id int, third_id int, PRIMARY KEY (first_id, second_id))"); err != nil {
t.Fatalf("failed to create table with error '%v'", err)
}

tables, err := getTableMetadata(session, "gocql_test")
if err != nil {
t.Fatalf("failed to query the table metadata with err: %v", err)
}
if tables == nil {
t.Fatal("failed to query the table metadata, nil returned")
}

var testTable *TableMetadata

// verify all tables have minimum expected data
for i := range tables {
table := &tables[i]

if table.Name == "" {
t.Errorf("Expected table name to be set, but it was empty: index=%d metadata=%+v", i, table)
}
if table.Keyspace != "gocql_test" {
t.Errorf("Expected keyspace for '%s' table metadata to be 'gocql_test' but was '%s'", table.Name, table.Keyspace)
}
if session.cfg.ProtoVersion < 4 {
// TODO(zariel): there has to be a better way to detect what metadata version
// we are in, and a better way to structure the code so that it is abstracted away
// from us here
if table.KeyValidator == "" {
t.Errorf("Expected key validator to be set for table %s", table.Name)
}
if table.Comparator == "" {
t.Errorf("Expected comparator to be set for table %s", table.Name)
}
if table.DefaultValidator == "" {
t.Errorf("Expected default validator to be set for table %s", table.Name)
}
}

// these fields are not set until the metadata is compiled
if table.PartitionKey != nil {
t.Errorf("Did not expect partition key for table %s", table.Name)
}
if table.ClusteringColumns != nil {
t.Errorf("Did not expect clustering columns for table %s", table.Name)
}
if table.Columns != nil {
t.Errorf("Did not expect columns for table %s", table.Name)
}

// for the next part of the test after this loop, find the metadata for the test table
if table.Name == "test_table_metadata" {
testTable = table
}
}

// verify actual values on the test tables
if testTable == nil {
t.Fatal("Expected table metadata for name 'test_table_metadata'")
}
if session.cfg.ProtoVersion == protoVersion1 {
if testTable.KeyValidator != "org.apache.cassandra.db.marshal.Int32Type" {
t.Errorf("Expected test_table_metadata key validator to be 'org.apache.cassandra.db.marshal.Int32Type' but was '%s'", testTable.KeyValidator)
}
if testTable.Comparator != "org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.Int32Type,org.apache.cassandra.db.marshal.UTF8Type)" {
t.Errorf("Expected test_table_metadata key validator to be 'org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.Int32Type,org.apache.cassandra.db.marshal.UTF8Type)' but was '%s'", testTable.Comparator)
}
if testTable.DefaultValidator != "org.apache.cassandra.db.marshal.BytesType" {
t.Errorf("Expected test_table_metadata key validator to be 'org.apache.cassandra.db.marshal.BytesType' but was '%s'", testTable.DefaultValidator)
}
expectedKeyAliases := []string{"first_id"}
if !reflect.DeepEqual(testTable.KeyAliases, expectedKeyAliases) {
t.Errorf("Expected key aliases %v but was %v", expectedKeyAliases, testTable.KeyAliases)
}
expectedColumnAliases := []string{"second_id"}
if !reflect.DeepEqual(testTable.ColumnAliases, expectedColumnAliases) {
t.Errorf("Expected key aliases %v but was %v", expectedColumnAliases, testTable.ColumnAliases)
}
}
if testTable.ValueAlias != "" {
t.Errorf("Expected value alias '' but was '%s'", testTable.ValueAlias)
}
}

// Integration test of just querying for data from the system.schema_columns table
func TestGetColumnMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()

if err := createTable(session, "CREATE TABLE gocql_test.test_column_metadata (first_id int, second_id int, third_id int, PRIMARY KEY (first_id, second_id))"); err != nil {
t.Fatalf("failed to create table with error '%v'", err)
}

if err := session.Query("CREATE INDEX index_column_metadata ON test_column_metadata ( third_id )").Exec(); err != nil {
t.Fatalf("failed to create index with err: %v", err)
}

columns, err := getColumnMetadata(session, "gocql_test")
if err != nil {
t.Fatalf("failed to query column metadata with err: %v", err)
}
if columns == nil {
t.Fatal("failed to query column metadata, nil returned")
}

testColumns := map[string]*ColumnMetadata{}

// verify actual values on the test columns
for i := range columns {
column := &columns[i]

if column.Name == "" {
t.Errorf("Expected column name to be set, but it was empty: index=%d metadata=%+v", i, column)
}
if column.Table == "" {
t.Errorf("Expected column %s table name to be set, but it was empty", column.Name)
}
if column.Keyspace != "gocql_test" {
t.Errorf("Expected column %s keyspace name to be 'gocql_test', but it was '%s'", column.Name, column.Keyspace)
}
if column.Kind == ColumnUnkownKind {
t.Errorf("Expected column %s kind to be set, but it was empty", column.Name)
}
if session.cfg.ProtoVersion == 1 && column.Kind != ColumnRegular {
t.Errorf("Expected column %s kind to be set to 'regular' for proto V1 but it was '%s'", column.Name, column.Kind)
}
if column.Validator == "" {
t.Errorf("Expected column %s validator to be set, but it was empty", column.Name)
}

// find the test table columns for the next step after this loop
if column.Table == "test_column_metadata" {
testColumns[column.Name] = column
}
}

if session.cfg.ProtoVersion == 1 {
// V1 proto only returns "regular columns"
if len(testColumns) != 1 {
t.Errorf("Expected 1 test columns but there were %d", len(testColumns))
}
thirdID, found := testColumns["third_id"]
if !found {
t.Fatalf("Expected to find column 'third_id' metadata but there was only %v", testColumns)
}

if thirdID.Kind != ColumnRegular {
t.Errorf("Expected %s column kind to be '%s' but it was '%s'", thirdID.Name, ColumnRegular, thirdID.Kind)
}

if thirdID.Index.Name != "index_column_metadata" {
t.Errorf("Expected %s column index name to be 'index_column_metadata' but it was '%s'", thirdID.Name, thirdID.Index.Name)
}
} else {
if len(testColumns) != 3 {
t.Errorf("Expected 3 test columns but there were %d", len(testColumns))
}
firstID, found := testColumns["first_id"]
if !found {
t.Fatalf("Expected to find column 'first_id' metadata but there was only %v", testColumns)
}
secondID, found := testColumns["second_id"]
if !found {
t.Fatalf("Expected to find column 'second_id' metadata but there was only %v", testColumns)
}
thirdID, found := testColumns["third_id"]
if !found {
t.Fatalf("Expected to find column 'third_id' metadata but there was only %v", testColumns)
}

if firstID.Kind != ColumnPartitionKey {
t.Errorf("Expected %s column kind to be '%s' but it was '%s'", firstID.Name, ColumnPartitionKey, firstID.Kind)
}
if secondID.Kind != ColumnClusteringKey {
t.Errorf("Expected %s column kind to be '%s' but it was '%s'", secondID.Name, ColumnClusteringKey, secondID.Kind)
}
if thirdID.Kind != ColumnRegular {
t.Errorf("Expected %s column kind to be '%s' but it was '%s'", thirdID.Name, ColumnRegular, thirdID.Kind)
}

if !session.useSystemSchema && thirdID.Index.Name != "index_column_metadata" {
// TODO(zariel): update metadata to scan index from system_schema
t.Errorf("Expected %s column index name to be 'index_column_metadata' but it was '%s'", thirdID.Name, thirdID.Index.Name)
}
}
}

func TestViewMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()
createViews(t, session)

views, err := getViewsMetadata(session, "gocql_test")
if err != nil {
t.Fatalf("failed to query view metadata with err: %v", err)
}
if views == nil {
t.Fatal("failed to query view metadata, nil returned")
}

if len(views) != 1 {
t.Fatal("expected one view")
}

textType := TypeText
if flagCassVersion.Before(3, 0, 0) {
textType = TypeVarchar
}

expectedView := ViewMetadata{
Keyspace: "gocql_test",
Name: "basicview",
FieldNames: []string{"birthday", "nationality", "weight", "height"},
FieldTypes: []TypeInfo{
NativeType{typ: TypeTimestamp},
NativeType{typ: textType},
NativeType{typ: textType},
NativeType{typ: textType},
},
}

if !reflect.DeepEqual(views[0], expectedView) {
t.Fatalf("view is %+v, but expected %+v", views[0], expectedView)
}
}
Loading

0 comments on commit a9e843a

Please sign in to comment.