Skip to content

Commit

Permalink
Improved unit test coverage and function documentation.
Browse files Browse the repository at this point in the history
- Added document lines for test functions
- Improved unit test coverage for token.go, metadata.go
- Added unit tests for policyConnPool in connectionpool.go, more work is needed here in the future
- Fixed a typo in connectionpool.go
  • Loading branch information
justinretailnext committed Apr 16, 2015
1 parent b6bbb37 commit ef8e794
Show file tree
Hide file tree
Showing 9 changed files with 691 additions and 97 deletions.
8 changes: 8 additions & 0 deletions cassandra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,7 @@ func TestEmptyTimestamp(t *testing.T) {
}
}

// Integration test of just querying for data from the system.schema_keyspace table
func TestGetKeyspaceMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()
Expand Down Expand Up @@ -1541,6 +1542,7 @@ func TestGetKeyspaceMetadata(t *testing.T) {
}
}

// Integration test of just querying for data from the system.schema_columnfamilies table
func TestGetTableMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()
Expand Down Expand Up @@ -1622,6 +1624,7 @@ func TestGetTableMetadata(t *testing.T) {
}
}

// Integration test of just querying for data from the system.schema_columns table
func TestGetColumnMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()
Expand Down Expand Up @@ -1723,6 +1726,7 @@ func TestGetColumnMetadata(t *testing.T) {
}
}

// Integration test of querying and composition the keyspace metadata
func TestKeyspaceMetadata(t *testing.T) {
session := createSession(t)
defer session.Close()
Expand Down Expand Up @@ -1785,6 +1789,7 @@ func TestKeyspaceMetadata(t *testing.T) {
}
}

// Integration test of the routing key calculation
func TestRoutingKey(t *testing.T) {
session := createSession(t)
defer session.Close()
Expand Down Expand Up @@ -1903,6 +1908,7 @@ func TestRoutingKey(t *testing.T) {
}
}

// Integration test of the token-aware policy-based connection pool
func TestTokenAwareConnPool(t *testing.T) {
cluster := createCluster()
cluster.ConnPoolType = NewTokenAwareConnPool
Expand Down Expand Up @@ -1946,4 +1952,6 @@ func TestTokenAwareConnPool(t *testing.T) {
if err := iter.Close(); err != nil {
t.Errorf("iter failed with err: %v", err)
}

// TODO add verification that the query went to the correct host
}
102 changes: 99 additions & 3 deletions conn_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build all unit

package gocql
Expand Down Expand Up @@ -177,7 +180,7 @@ func TestSlowQuery(t *testing.T) {
}
}

func TestRoundRobin(t *testing.T) {
func TestSimplePoolRoundRobin(t *testing.T) {
servers := make([]*TestServer, 5)
addrs := make([]string, len(servers))
for n := 0; n < len(servers); n++ {
Expand Down Expand Up @@ -223,7 +226,7 @@ func TestRoundRobin(t *testing.T) {
}

if diff > 0 {
t.Fatal("diff:", diff)
t.Errorf("Expected 0 difference in usage but was %d", diff)
}
}

Expand Down Expand Up @@ -258,7 +261,7 @@ func TestConnClosing(t *testing.T) {
conns := pool.Size()

if conns != numConns {
t.Fatalf("Expected to have %d connections but have %d", numConns, conns)
t.Errorf("Expected to have %d connections but have %d", numConns, conns)
}
}

Expand Down Expand Up @@ -373,6 +376,99 @@ func BenchmarkProtocolV3(b *testing.B) {
}
}

func TestRoundRobinConnPoolRoundRobin(t *testing.T) {
// create 5 test servers
servers := make([]*TestServer, 5)
addrs := make([]string, len(servers))
for n := 0; n < len(servers); n++ {
servers[n] = NewTestServer(t, defaultProto)
addrs[n] = servers[n].Address
defer servers[n].Stop()
}

// create a new cluster using the policy-based round robin conn pool
cluster := NewCluster(addrs...)
cluster.ConnPoolType = NewRoundRobinConnPool

db, err := cluster.CreateSession()
if err != nil {
t.Fatalf("failed to create a new session: %v", err)
}

// Sleep to allow the pool to fill
time.Sleep(100 * time.Millisecond)

// run concurrent queries against the pool, server usage should
// be even
var wg sync.WaitGroup
wg.Add(5)
for n := 0; n < 5; n++ {
go func() {
for j := 0; j < 5; j++ {
if err := db.Query("void").Exec(); err != nil {
t.Errorf("Query failed with error: %v", err)
}
}
wg.Done()
}()
}
wg.Wait()

db.Close()

// wait for the pool to drain
time.Sleep(100 * time.Millisecond)
size := db.Pool.Size()
if size != 0 {
t.Errorf("connection pool did not drain, still contains %d connections", size)
}

// verify that server usage is even
diff := 0
for n := 1; n < len(servers); n++ {
d := 0
if servers[n].nreq > servers[n-1].nreq {
d = int(servers[n].nreq - servers[n-1].nreq)
} else {
d = int(servers[n-1].nreq - servers[n].nreq)
}
if d > diff {
diff = d
}
}

if diff > 0 {
t.Errorf("expected 0 difference in usage but was %d", diff)
}
}

// This tests that the policy connection pool handles SSL correctly
func TestPolicyConnPoolSSL(t *testing.T) {
srv := NewSSLTestServer(t, defaultProto)
defer srv.Stop()

cluster := createTestSslCluster(srv.Address, defaultProto)
cluster.ConnPoolType = NewRoundRobinConnPool

db, err := cluster.CreateSession()
if err != nil {
t.Fatalf("failed to create new session: %v", err)
}

if err := db.Query("void").Exec(); err != nil {
t.Errorf("query failed due to error: %v", err)
}

db.Close()

// wait for the pool to drain
time.Sleep(100 * time.Millisecond)
size := db.Pool.Size()
if size != 0 {
t.Errorf("connection pool did not drain, still contains %d connections", size)
}
}

func NewTestServer(t testing.TB, protocol uint8) *TestServer {
laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
if err != nil {
Expand Down
11 changes: 10 additions & 1 deletion connectionpool.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gocql

import (
Expand Down Expand Up @@ -776,7 +780,7 @@ func (pool *hostConnPool) fill() {
}

func (pool *hostConnPool) logConnectErr(err error) {
if opErr, ok := err.(*net.OpError); ok && (opErr.Op == "dial" || opErr.Op == "red") {
if opErr, ok := err.(*net.OpError); ok && (opErr.Op == "dial" || opErr.Op == "read") {
// connection refused
// these are typical during a node outage so avoid log spam.
} else if err != nil {
Expand Down Expand Up @@ -837,6 +841,11 @@ func (pool *hostConnPool) HandleError(conn *Conn, err error, closed bool) {
pool.mu.Lock()
defer pool.mu.Unlock()

if pool.closed {
// pool closed
return
}

// find the connection index
for i, candidate := range pool.conns {
if candidate == conn {
Expand Down
28 changes: 20 additions & 8 deletions metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,17 @@ type schemaDescriber struct {
cache map[string]*KeyspaceMetadata
}

// creates a session bound schema describer which will query and cache
// keyspace metadata
func newSchemaDescriber(session *Session) *schemaDescriber {
return &schemaDescriber{
session: session,
cache: map[string]*KeyspaceMetadata{},
}
}

// returns the cached KeyspaceMetadata held by the describer for the named
// keyspace.
func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, error) {
s.mu.Lock()
defer s.mu.Unlock()
Expand All @@ -114,6 +118,8 @@ func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, err
return metadata, nil
}

// forcibly updates the current KeyspaceMetadata held by the schema describer
// for a given named keyspace.
func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
var err error

Expand Down Expand Up @@ -141,9 +147,11 @@ func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
return nil
}

// "compiles" keyspace, table, and column metadata for a keyspace together
// linking the metadata objects together and calculating the partition key
// and clustering key.
// "compiles" derived information about keyspace, table, and column metadata
// for a keyspace from the basic queried metadata objects returned by
// getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
// Links the metadata objects together and derives the column composition of
// the partition key and clustering key for a table.
func compileMetadata(
protoVersion int,
keyspace *KeyspaceMetadata,
Expand Down Expand Up @@ -178,8 +186,11 @@ func compileMetadata(
}
}

// V1 protocol does not return as much column metadata as V2+ so determining
// PartitionKey and ClusterColumns is more complex
// Compiles derived information from TableMetadata which have had
// ColumnMetadata added already. V1 protocol does not return as much
// column metadata as V2+ (because V1 doesn't support the "type" column in the
// system.schema_columns table) so determining PartitionKey and ClusterColumns
// is more complex.
func compileV1Metadata(tables []TableMetadata) {
for i := range tables {
table := &tables[i]
Expand Down Expand Up @@ -308,6 +319,7 @@ func compileV2Metadata(tables []TableMetadata) {
}
}

// returns the count of coluns with the given "kind" value.
func countColumnsOfKind(columns map[string]*ColumnMetadata, kind string) int {
count := 0
for _, column := range columns {
Expand All @@ -318,7 +330,7 @@ func countColumnsOfKind(columns map[string]*ColumnMetadata, kind string) int {
return count
}

// query only for the keyspace metadata for the specified keyspace
// query only for the keyspace metadata for the specified keyspace from system.schema_keyspace
func getKeyspaceMetadata(
session *Session,
keyspaceName string,
Expand Down Expand Up @@ -358,7 +370,7 @@ func getKeyspaceMetadata(
return keyspace, nil
}

// query for only the table metadata in the specified keyspace
// query for only the table metadata in the specified keyspace from system.schema_columnfamilies
func getTableMetadata(
session *Session,
keyspaceName string,
Expand Down Expand Up @@ -437,7 +449,7 @@ func getTableMetadata(
return tables, nil
}

// query for only the table metadata in the specified keyspace
// query for only the column metadata in the specified keyspace from system.schema_columns
func getColumnMetadata(
session *Session,
keyspaceName string,
Expand Down
Loading

0 comments on commit ef8e794

Please sign in to comment.