notary/server/storage/rethink_realdb_test.go

180 lines
5.7 KiB
Go

// +build rethinkdb
// Uses a real RethinkDB connection testing purposes
package storage
import (
"os"
"testing"
"github.com/docker/go-connections/tlsconfig"
"github.com/stretchr/testify/require"
"github.com/theupdateframework/notary/storage/rethinkdb"
"github.com/theupdateframework/notary/tuf/data"
"gopkg.in/dancannon/gorethink.v3"
)
var tlsOpts = tlsconfig.Options{InsecureSkipVerify: true, ExclusiveRootPools: true}
func rethinkSessionSetup(t *testing.T) (*gorethink.Session, string) {
// Get the Rethink connection string from an environment variable
rethinkSource := os.Getenv("DBURL")
require.NotEqual(t, "", rethinkSource)
sess, err := rethinkdb.AdminConnection(tlsOpts, rethinkSource)
require.NoError(t, err)
return sess, rethinkSource
}
func rethinkDBSetup(t *testing.T) (RethinkDB, func()) {
session, _ := rethinkSessionSetup(t)
dbName := "servertestdb"
var cleanup = func() { gorethink.DBDrop(dbName).Exec(session) }
cleanup()
require.NoError(t, rethinkdb.SetupDB(session, dbName, []rethinkdb.Table{
TUFFilesRethinkTable,
ChangeRethinkTable,
}))
return NewRethinkDBStorage(dbName, "", "", session), cleanup
}
func TestRethinkBootstrapSetsUsernamePassword(t *testing.T) {
adminSession, source := rethinkSessionSetup(t)
dbname, username, password := "servertestdb", "testuser", "testpassword"
otherDB, otherUser, otherPass := "otherservertestdb", "otheruser", "otherpassword"
// create a separate user with access to a different DB
require.NoError(t, rethinkdb.SetupDB(adminSession, otherDB, nil))
defer gorethink.DBDrop(otherDB).Exec(adminSession)
require.NoError(t, rethinkdb.CreateAndGrantDBUser(adminSession, otherDB, otherUser, otherPass))
// Bootstrap
s := NewRethinkDBStorage(dbname, username, password, adminSession)
require.NoError(t, s.Bootstrap())
defer gorethink.DBDrop(dbname).Exec(adminSession)
// A user with an invalid password cannot connect to rethink DB at all
_, err := rethinkdb.UserConnection(tlsOpts, source, username, "wrongpass")
require.Error(t, err)
// 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)
require.NoError(t, err)
s = NewRethinkDBStorage(dbname, username, password, userSession)
_, _, 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 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.
func TestRethinkUpdateCurrentEmpty(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testUpdateCurrentEmptyStore(t, dbStore)
}
// UpdateCurrent will add a new TUF file if the version is higher than previous, but fail
// 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, false)
}
func TestRethinkGetVersion(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testGetVersion(t, dbStore)
}
// UpdateMany succeeds if the updates do not conflict with each other or with what's
// already in the DB
func TestRethinkUpdateManyNoConflicts(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testUpdateManyNoConflicts(t, dbStore)
}
// UpdateMany does not insert any rows (or at least rolls them back) if there
// are any conflicts.
func TestRethinkUpdateManyConflictRollback(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testUpdateManyConflictRollback(t, dbStore)
}
// Delete will remove all TUF metadata, all versions, associated with a gun
func TestRethinkDeleteSuccess(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testDeleteSuccess(t, dbStore)
}
func TestRethinkTUFMetaStoreGetCurrent(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testTUFMetaStoreGetCurrent(t, dbStore)
}
func TestRethinkDBGetChanges(t *testing.T) {
dbStore, cleanup := rethinkDBSetup(t)
defer cleanup()
testGetChanges(t, dbStore)
}