@ -14,6 +14,7 @@ limitations under the License.
package driver
package driver
import (
import (
"database/sql"
"database/sql/driver"
"database/sql/driver"
"errors"
"errors"
"fmt"
"fmt"
@ -103,6 +104,97 @@ func TestSQLGet(t *testing.T) {
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
}
}
// A real database failure must not be reported as "release not found": callers
// branch on ErrReleaseNotFound and would treat an outage as an absent release.
func TestSQLGetDatabaseError ( t * testing . T ) {
vers := int ( 1 )
name := "smug-pigeon"
namespace := "default"
key := testKey ( name , vers )
sqlDriver , mock := newTestFixtureSQL ( t )
query := fmt . Sprintf (
regexp . QuoteMeta ( "SELECT %s FROM %s WHERE %s = $1 AND %s = $2" ) ,
sqlReleaseTableBodyColumn ,
sqlReleaseTableName ,
sqlReleaseTableKeyColumn ,
sqlReleaseTableNamespaceColumn ,
)
dbErr := errors . New ( "connection refused" )
mock .
ExpectQuery ( query ) .
WithArgs ( key , namespace ) .
WillReturnError ( dbErr )
_ , err := sqlDriver . Get ( key )
require . Error ( t , err , "expected an error when the database query fails" )
require . NotErrorIs ( t , err , ErrReleaseNotFound , "database failure must not be reported as ErrReleaseNotFound" )
require . ErrorIs ( t , err , dbErr , "expected the underlying database error to be wrapped" )
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
}
// An empty result set is the only case that means "release not found".
func TestSQLGetNotFound ( t * testing . T ) {
vers := int ( 1 )
name := "smug-pigeon"
namespace := "default"
key := testKey ( name , vers )
sqlDriver , mock := newTestFixtureSQL ( t )
query := fmt . Sprintf (
regexp . QuoteMeta ( "SELECT %s FROM %s WHERE %s = $1 AND %s = $2" ) ,
sqlReleaseTableBodyColumn ,
sqlReleaseTableName ,
sqlReleaseTableKeyColumn ,
sqlReleaseTableNamespaceColumn ,
)
mock .
ExpectQuery ( query ) .
WithArgs ( key , namespace ) .
WillReturnError ( sql . ErrNoRows )
_ , err := sqlDriver . Get ( key )
require . ErrorIs ( t , err , ErrReleaseNotFound )
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
}
// Same contract for Delete's existence check, which must also not leave the
// transaction open when the lookup fails.
func TestSQLDeleteDatabaseError ( t * testing . T ) {
vers := int ( 1 )
name := "smug-pigeon"
namespace := "default"
key := testKey ( name , vers )
sqlDriver , mock := newTestFixtureSQL ( t )
selectQuery := fmt . Sprintf (
"SELECT %s FROM %s WHERE %s = $1 AND %s = $2" ,
sqlReleaseTableBodyColumn ,
sqlReleaseTableName ,
sqlReleaseTableKeyColumn ,
sqlReleaseTableNamespaceColumn ,
)
dbErr := errors . New ( "connection refused" )
mock . ExpectBegin ( )
mock .
ExpectQuery ( regexp . QuoteMeta ( selectQuery ) ) .
WithArgs ( key , namespace ) .
WillReturnError ( dbErr )
mock . ExpectRollback ( )
_ , err := sqlDriver . Delete ( key )
require . Error ( t , err , "expected an error when the database query fails" )
require . NotErrorIs ( t , err , ErrReleaseNotFound , "database failure must not be reported as ErrReleaseNotFound" )
require . ErrorIs ( t , err , dbErr , "expected the underlying database error to be wrapped" )
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
}
func TestSQLList ( t * testing . T ) {
func TestSQLList ( t * testing . T ) {
releases := [ ] * rspb . Release { }
releases := [ ] * rspb . Release { }
releases = append ( releases ,
releases = append ( releases ,
@ -269,6 +361,11 @@ func TestSqlCreateAlreadyExists(t *testing.T) {
sqlReleaseTableNamespaceColumn ,
sqlReleaseTableNamespaceColumn ,
)
)
// The failed insert aborts the transaction, so it is rolled back before the
// existence check runs - the check has to happen outside the transaction or
// PostgreSQL rejects it and ErrReleaseExists can never be returned.
mock . ExpectRollback ( )
// Let's check that we do make sure the error is due to a release already existing
// Let's check that we do make sure the error is due to a release already existing
mock .
mock .
ExpectQuery ( selectQuery ) .
ExpectQuery ( selectQuery ) .
@ -280,9 +377,10 @@ func TestSqlCreateAlreadyExists(t *testing.T) {
key ,
key ,
) ,
) ,
) . RowsWillBeClosed ( )
) . RowsWillBeClosed ( )
mock . ExpectRollback ( )
require . Errorf ( t , sqlDriver . Create ( key , rel ) , "failed to create release with key %s" , key )
err := sqlDriver . Create ( key , rel )
require . Errorf ( t , err , "expected Create to fail for an existing release with key %s" , key )
require . ErrorIs ( t , err , ErrReleaseExists )
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
assert . NoErrorf ( t , mock . ExpectationsWereMet ( ) , "sql expectations weren't met" )
}
}