Skip to content

Commit

Permalink
Merge pull request #854 from cyli/more-server-db-test-refactor
Browse files Browse the repository at this point in the history
More server DB tests
  • Loading branch information
cyli authored Jul 27, 2016
2 parents 04d102a + 3dbfaa9 commit fe3a8fa
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 187 deletions.
2 changes: 1 addition & 1 deletion buildscripts/dbtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function cleanup {
fi
}

clientCmd="make test"
clientCmd="make TESTOPTS='-p 1' test"
if [[ -z "${CIRCLECI}" ]]; then
BUILDOPTS="--force-rm"
else
Expand Down
15 changes: 12 additions & 3 deletions server/storage/memory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,19 @@ func TestMemoryUpdateCurrentEmpty(t *testing.T) {
}

// UpdateCurrent will successfully add a new (higher) version of an existing TUF file,
// but will return an error if there is an older version of a TUF file.
func TestMemoryUpdateCurrentVersionCheck(t *testing.T) {
// but will return an error if the to-be-added version already exists in the DB.
func TestMemoryUpdateCurrentVersionCheckOldVersionExists(t *testing.T) {
s := NewMemStorage()
expected := testUpdateCurrentVersionCheck(t, s)
expected := testUpdateCurrentVersionCheck(t, s, true)
assertExpectedMemoryTUFMeta(t, expected, s)
}

// UpdateCurrent will successfully add a new (higher) version of an existing TUF file,
// but will return an error if the to-be-added version does not exist in the DB, but
// is older than an existing version in the DB.
func TestMemoryUpdateCurrentVersionCheckOldVersionNotExist(t *testing.T) {
s := NewMemStorage()
expected := testUpdateCurrentVersionCheck(t, s, false)
assertExpectedMemoryTUFMeta(t, expected, s)
}

Expand Down
2 changes: 1 addition & 1 deletion server/storage/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func init() {
if i == 29 {
logrus.Fatalf("Unable to connect to %s after 60 seconds", dburl)
}
time.Sleep(2)
time.Sleep(2 * time.Second)
}

sqldbSetup = func(t *testing.T) (*SQLStorage, func()) {
Expand Down
56 changes: 51 additions & 5 deletions server/storage/rethink_realdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ func TestRethinkBootstrapSetsUsernamePassword(t *testing.T) {
_, err := rethinkdb.UserConnection(tlsOpts, source, username, "wrongpass")
require.Error(t, err)

// the other user cannot access rethink
// the other user cannot access rethink, causing health checks to fail
userSession, err := rethinkdb.UserConnection(tlsOpts, source, otherUser, otherPass)
require.NoError(t, err)
s = NewRethinkDBStorage(dbname, otherUser, otherPass, userSession)
_, _, err = s.GetCurrent("gun", data.CanonicalRootRole)
require.Error(t, err)
require.IsType(t, gorethink.RQLRuntimeError{}, err)
require.Error(t, s.CheckHealth())

// our user can access the DB though
userSession, err = rethinkdb.UserConnection(tlsOpts, source, username, password)
Expand All @@ -75,6 +76,35 @@ func TestRethinkBootstrapSetsUsernamePassword(t *testing.T) {
_, _, err = s.GetCurrent("gun", data.CanonicalRootRole)
require.Error(t, err)
require.IsType(t, ErrNotFound{}, err)
require.NoError(t, s.CheckHealth())
}

func TestRethinkCheckHealth(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()

// sanity check - all tables present - health check passes
require.NoError(t, dbStore.CheckHealth())

// if the DB is unreachable, health check fails
require.NoError(t, dbStore.sess.Close())
require.Error(t, dbStore.CheckHealth())

// if the connection is reopened, health check succeeds
require.NoError(t, dbStore.sess.Reconnect())
require.NoError(t, dbStore.CheckHealth())

// only one table existing causes health check to fail
require.NoError(t, gorethink.DB(dbStore.dbName).TableDrop(TUFFilesRethinkTable.Name).Exec(dbStore.sess))
require.Error(t, dbStore.CheckHealth())

// No tables, health check fails
require.NoError(t, gorethink.DB(dbStore.dbName).TableDrop(PubKeysRethinkTable.Name).Exec(dbStore.sess))
require.Error(t, dbStore.CheckHealth())

// No DB, health check fails
cleanup()
require.Error(t, dbStore.CheckHealth())
}

// UpdateCurrent will add a new TUF file if no previous version of that gun and role existed.
Expand All @@ -86,14 +116,23 @@ func TestRethinkUpdateCurrentEmpty(t *testing.T) {
}

// UpdateCurrent will add a new TUF file if the version is higher than previous, but fail
// if the version is equal to or less than the current, whether or not that previous
// version exists
func TestRethinkUpdateCurrentVersionCheck(t *testing.T) {
// if the version already exists in the DB
func TestRethinkUpdateCurrentVersionCheckOldVersionExists(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()

testUpdateCurrentVersionCheck(t, dbStore, true)
}

// UpdateCurrent will successfully add a new (higher) version of an existing TUF file,
// but will return an error if the to-be-added version does not exist in the DB, but
// is older than an existing version in the DB.
func TestRethinkUpdateCurrentVersionCheckOldVersionNotExist(t *testing.T) {
t.Skip("Currently rethink only errors if the previous version exists - it doesn't check for strictly increasing")
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()

testUpdateCurrentVersionCheck(t, dbStore)
testUpdateCurrentVersionCheck(t, dbStore, false)
}

// UpdateMany succeeds if the updates do not conflict with each other or with what's
Expand Down Expand Up @@ -121,3 +160,10 @@ func TestRethinkDeleteSuccess(t *testing.T) {

testDeleteSuccess(t, dbStore)
}

func TestRethinkTUFMetaStoreGetCurrent(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()

testTUFMetaStoreGetCurrent(t, dbStore)
}
16 changes: 6 additions & 10 deletions server/storage/rethinkdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/notary/storage/rethinkdb"
"github.com/docker/notary/tuf/data"
"github.com/docker/notary/tuf/utils"
"gopkg.in/dancannon/gorethink.v2"
)

Expand Down Expand Up @@ -327,15 +326,12 @@ func (rdb RethinkDB) Bootstrap() error {

// CheckHealth checks that all tables and databases exist and are query-able
func (rdb RethinkDB) CheckHealth() error {
var tables []string
res, err := gorethink.DB(rdb.dbName).TableList().Run(rdb.sess)
if err != nil {
return err
}
defer res.Close()
err = res.All(&tables)
if err != nil || !utils.StrSliceContains(tables, RDBTUFFile{}.TableName()) || !utils.StrSliceContains(tables, RDBKey{}.TableName()) {
return fmt.Errorf("%s is unavailable and missing one or more tables", rdb.dbName)
for _, table := range []string{TUFFilesRethinkTable.Name, PubKeysRethinkTable.Name} {
res, err := gorethink.DB(rdb.dbName).Table(table).Info().Run(rdb.sess)
if err != nil {
return fmt.Errorf("%s is unavailable, or missing one or more tables, or permissions are incorrectly set", rdb.dbName)
}
defer res.Close()
}
return nil
}
5 changes: 3 additions & 2 deletions server/storage/sqldb.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,10 @@ func isReadErr(q *gorm.DB, row TUFFile) error {
return nil
}

// Delete deletes all the records for a specific GUN
// Delete deletes all the records for a specific GUN - we have to do a hard delete using Unscoped
// otherwise we can't insert for that GUN again
func (db *SQLStorage) Delete(gun string) error {
return db.Where(&TUFFile{Gun: gun}).Delete(TUFFile{}).Error
return db.Unscoped().Where(&TUFFile{Gun: gun}).Delete(TUFFile{}).Error
}

// GetKey returns the Public Key data for a gun+role
Expand Down
97 changes: 34 additions & 63 deletions server/storage/sqldb_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// +build !rethinkdb

package storage

import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"testing"
"time"

Expand Down Expand Up @@ -38,32 +39,6 @@ type sqldbSetupFunc func(*testing.T) (*SQLStorage, func())

var sqldbSetup sqldbSetupFunc

// SampleTUF returns a sample TUFFile with the given Version (ID will have
// to be set independently)
func SampleTUF(version int) TUFFile {
return SampleCustomTUF(data.CanonicalRootRole, "testGUN", []byte("1"), version)
}

func SampleCustomTUF(role, gun string, data []byte, version int) TUFFile {
checksum := sha256.Sum256(data)
hexChecksum := hex.EncodeToString(checksum[:])
return TUFFile{
Gun: gun,
Role: role,
Version: version,
Sha256: hexChecksum,
Data: data,
}
}

func SampleUpdate(version int) MetaUpdate {
return MetaUpdate{
Role: "root",
Version: version,
Data: []byte("1"),
}
}

func assertExpectedGormTUFMeta(t *testing.T, expected []StoredTUFMeta, gormDB gorm.DB) {
expectedGorm := make([]TUFFile, len(expected))
for i, tufObj := range expected {
Expand Down Expand Up @@ -101,14 +76,27 @@ func TestSQLUpdateCurrentEmpty(t *testing.T) {
dbStore.DB.Close()
}

// TestSQLUpdateCurrentNewVersion asserts that UpdateCurrent will add a
// TestSQLUpdateCurrentVersionCheckOldVersionExists asserts that UpdateCurrent will add a
// new (higher) version of an existing TUF file, and that an error is raised if
// trying to update to an older version of a TUF file that already exists.
func TestSQLUpdateCurrentVersionCheckOldVersionExists(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

expected := testUpdateCurrentVersionCheck(t, dbStore, true)
assertExpectedGormTUFMeta(t, expected, dbStore.DB)

dbStore.DB.Close()
}

// TestSQLUpdateCurrentVersionCheckOldVersionNotExist asserts that UpdateCurrent will add a
// new (higher) version of an existing TUF file, and that an error is raised if
// trying to update to an older version of a TUF file.
func TestSQLUpdateCurrentNewVersion(t *testing.T) {
// trying to update to an older version of a TUF file that doesn't exist in the DB.
func TestSQLUpdateCurrentVersionCheckOldVersionNotExist(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

expected := testUpdateCurrentVersionCheck(t, dbStore)
expected := testUpdateCurrentVersionCheck(t, dbStore, false)
assertExpectedGormTUFMeta(t, expected, dbStore.DB)

dbStore.DB.Close()
Expand Down Expand Up @@ -151,30 +139,6 @@ func TestSQLDelete(t *testing.T) {
dbStore.DB.Close()
}

func TestSQLGetCurrent(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

_, byt, err := dbStore.GetCurrent("testGUN", "root")
require.Nil(t, byt)
require.Error(t, err, "There should be an error Getting an empty table")
require.IsType(t, ErrNotFound{}, err, "Should get a not found error")

tuf := SampleTUF(0)
query := dbStore.DB.Create(&tuf)
require.NoError(t, query.Error, "Creating a row in an empty DB failed.")

cDate, byt, err := dbStore.GetCurrent("testGUN", "root")
require.NoError(t, err, "There should not be any errors getting.")
require.Equal(t, []byte("1"), byt, "Returned data was incorrect")
// the update date was sometime wthin the last minute
fmt.Println(cDate)
require.True(t, cDate.After(time.Now().Add(-1*time.Minute)))
require.True(t, cDate.Before(time.Now().Add(5*time.Second)))

dbStore.DB.Close()
}

func TestSQLGetKeyNoKey(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()
Expand Down Expand Up @@ -295,9 +259,9 @@ func TestSQLSetKeySameRoleGun(t *testing.T) {
dbStore.DB.Close()
}

// TestDBCheckHealthTableMissing asserts that the health check fails if one or
// TestSQLDBCheckHealthTableMissing asserts that the health check fails if one or
// both the tables are missing.
func TestDBCheckHealthTableMissing(t *testing.T) {
func TestSQLDBCheckHealthTableMissing(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

Expand All @@ -319,9 +283,9 @@ func TestDBCheckHealthTableMissing(t *testing.T) {
require.Error(t, err, "Cannot access table:")
}

// TestDBCheckHealthDBCOnnection asserts that if the DB is not connectable, the
// TestSQLDBCheckHealthDBConnection asserts that if the DB is not connectable, the
// health check fails.
func TestDBCheckHealthDBConnectionFail(t *testing.T) {
func TestSQLDBCheckHealthDBConnectionFail(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

Expand All @@ -332,17 +296,17 @@ func TestDBCheckHealthDBConnectionFail(t *testing.T) {
require.Error(t, err, "Cannot access table:")
}

// TestDBCheckHealthSuceeds asserts that if the DB is connectable and both
// TestSQLDBCheckHealthSuceeds asserts that if the DB is connectable and both
// tables exist, the health check succeeds.
func TestDBCheckHealthSucceeds(t *testing.T) {
func TestSQLDBCheckHealthSucceeds(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

err := dbStore.CheckHealth()
require.NoError(t, err)
}

func TestDBGetChecksum(t *testing.T) {
func TestSQLDBGetChecksum(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

Expand Down Expand Up @@ -398,11 +362,18 @@ func TestDBGetChecksum(t *testing.T) {
require.True(t, cDate.Before(time.Now().Add(5*time.Second)))
}

func TestDBGetChecksumNotFound(t *testing.T) {
func TestSQLDBGetChecksumNotFound(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

_, _, err := dbStore.GetChecksum("gun", data.CanonicalTimestampRole, "12345")
require.Error(t, err)
require.IsType(t, ErrNotFound{}, err)
}

func TestSQLTUFMetaStoreGetCurrent(t *testing.T) {
dbStore, cleanup := sqldbSetup(t)
defer cleanup()

testTUFMetaStoreGetCurrent(t, dbStore)
}
2 changes: 1 addition & 1 deletion server/storage/sqlite_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build !mysqldb
// +build !mysqldb,!rethinkdb

// Initializes an SQLlite DBs for testing purposes

Expand Down
Loading

0 comments on commit fe3a8fa

Please sign in to comment.