Skip to content

Commit

Permalink
test: PutBlockNumber unit tests (#447)
Browse files Browse the repository at this point in the history
* put unit test
  • Loading branch information
robdefeo committed Dec 18, 2019
1 parent c3def15 commit aa49fe0
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 0 deletions.
32 changes: 32 additions & 0 deletions cmd/indexer/internal/datastore/pq/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package pq

import (
"fmt"

"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" // needed for postgres to work
"github.com/pkg/errors"
)

func NewConnection(user, password, databaseName, host, sslmode string, port int) (*sqlx.DB, error) {
// The first argument corresponds to the driver name that the driver
// (in this case, `lib/pq`) used to register itself in `database/sql`.
// The next argument specifies the parameters to be used in the connection.
// Details about this string can be seen at https://godoc.org/github.com/lib/pq
db, err := sqlx.Connect("postgres", fmt.Sprintf(
"user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
user, password, databaseName, host, port, sslmode))
if err != nil {
return nil, errors.Wrapf(err,
"Couldn't open connection to postgre database (%s)", databaseName)
}

// Ping verifies if the connection to the database is alive or if a
// new connection can be made.
if err = db.Ping(); err != nil {
return nil, errors.Wrapf(err,
"Couldn't ping postgre database (%s)", databaseName)
}

return db, nil
}
35 changes: 35 additions & 0 deletions cmd/indexer/internal/datastore/pq/mappings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package pq

import (
"github.com/mailchain/mailchain/internal/protocols"
"github.com/mailchain/mailchain/internal/protocols/ethereum"
"github.com/pkg/errors"
)

func getProtocolNetworkUint8(prot, net string) (protocol, network uint8, err error) {
uProtocol, ok := protocolUint8[prot]
if !ok {
return 0, 0, errors.Errorf("unknown protocol: %q", prot)
}

uNetwork, ok := protocolNetworkUint8[prot][net]
if !ok {
return 0, 0, errors.Errorf("unknown protocol.network: \"%s.%s\"", prot, net)
}

return uProtocol, uNetwork, nil
}

var protocolUint8 = map[string]uint8{ //nolint:gochecknoglobals
protocols.Ethereum: 1,
}

var protocolNetworkUint8 = map[string]map[string]uint8{ //nolint:gochecknoglobals
protocols.Ethereum: {
ethereum.Mainnet: 1,
ethereum.Goerli: 2,
ethereum.Kovan: 3,
ethereum.Rinkeby: 4,
ethereum.Ropsten: 5,
},
}
80 changes: 80 additions & 0 deletions cmd/indexer/internal/datastore/pq/sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package pq

import (
"context"
"time"

"github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
"github.com/mailchain/mailchain/cmd/indexer/internal/datastore"
"github.com/pkg/errors"
)

// SyncStore database connection object
type SyncStore struct {
db *sqlx.DB
}

// NewSyncStore create new postgres database
func NewSyncStore(db *sqlx.DB) (datastore.SyncStore, error) {
return &SyncStore{db: db}, nil
}

type sync struct {
Protocol uint8 `db:"protocol"`
Network uint8 `db:"network"`

BlockNo uint64 `db:"block_no"`

CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}

func (s SyncStore) GetBlockNumber(ctx context.Context, protocol, network string) (blockNo uint64, err error) {
p, n, err := getProtocolNetworkUint8(protocol, network)
if err != nil {
return 0, errors.WithStack((err))
}

sql, args, err := squirrel.Select("block_no").
From("sync").
PlaceholderFormat(squirrel.Dollar).
Where(squirrel.Eq{"protocol": p}).
Where(squirrel.Eq{"network": n}).
ToSql()
if err != nil {
return 0, errors.WithStack((err))
}

state := sync{}
if err := s.db.Get(&state, sql, args); err != nil {
return 0, errors.WithStack(err)
}

return state.BlockNo, nil
}

func (s SyncStore) PutBlockNumber(ctx context.Context, protocol, network string, blockNo uint64) error {
p, n, err := getProtocolNetworkUint8(protocol, network)
if err != nil {
return errors.WithStack((err))
}

sql, args, err := squirrel.Update("sync").
Set("block_no", blockNo).
Set("updated_at", time.Now()).
PlaceholderFormat(squirrel.Dollar).
Where(squirrel.Eq{"protocol": p}).
Where(squirrel.Eq{"network": n}).
ToSql()
if err != nil {
return errors.WithStack(err)
}

_, err = s.db.Exec(sql, args...)
if err != nil {
return errors.WithStack(err)
}

return nil
}
103 changes: 103 additions & 0 deletions cmd/indexer/internal/datastore/pq/sync_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package pq

import (
"context"
"database/sql"
"regexp"
"testing"

"github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
)

func TestSyncStore_PutBlockNumber(t *testing.T) {
type args struct {
ctx context.Context
protocol string
network string
blockNo uint64
}
type mock struct {
db *sql.DB
sqlmock sqlmock.Sqlmock
}
tests := []struct {
name string
args args
mock mock
wantErr bool
}{
{
"success",
args{
context.Background(),
"ethereum",
"mainnet",
144,
},
func() mock {
db, m, err := sqlmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
m.ExpectExec(regexp.QuoteMeta(`UPDATE sync SET block_no = $1, updated_at = $2 WHERE protocol = $3 AND network = $4`)).
WithArgs(uint64(144), anyTime{}, uint8(1), uint8(1)).
WillReturnResult(sqlmock.NewResult(1, 1))

return mock{db, m}
}(),
false,
},
{
"err-update-failed",
args{
context.Background(),
"ethereum",
"mainnet",
144,
},
func() mock {
db, m, err := sqlmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
m.ExpectExec(regexp.QuoteMeta(`UPDATE sync SET block_no = $1, updated_at = $2 WHERE protocol = $3 AND network = $4`)).
WithArgs(uint64(144), anyTime{}, uint8(1), uint8(1)).
WillReturnError(sql.ErrNoRows)

return mock{db, m}
}(),
true,
},

{
"err-protocol-network",
args{
context.Background(),
"ethereum",
"unknown",
144,
},
func() mock {
db, m, err := sqlmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}

return mock{db, m}
}(),
true,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := SyncStore{db: sqlx.NewDb(tt.mock.db, "postgres")}
if err := s.PutBlockNumber(tt.args.ctx, tt.args.protocol, tt.args.network, tt.args.blockNo); (err != nil) != tt.wantErr {
t.Errorf("SyncStore.PutBlockNumber() error = %v, wantErr %v", err, tt.wantErr)
}

if err := tt.mock.sqlmock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled expectations: %s", err)
}
})
}
}
14 changes: 14 additions & 0 deletions cmd/indexer/internal/datastore/pq/time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package pq

import (
"database/sql/driver"
"time"
)

type anyTime struct{}

// Match satisfies sqlmock.Argument interface
func (a anyTime) Match(v driver.Value) bool {
_, ok := v.(time.Time)
return ok
}
1 change: 1 addition & 0 deletions cmd/indexer/internal/processor/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "context"

//go:generate mockgen -source=block.go -package=processortest -destination=./processortest/block_mock.go

// Block processes an individual block
type Block interface {
Run(ctx context.Context, protocol, network string, blk interface{}) error
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/mailchain/mailchain

require (
github.com/DATA-DOG/go-sqlmock v1.3.3
github.com/Masterminds/squirrel v1.1.0
github.com/andreburgaud/crypt2go v0.0.0-20170529041511-18fdff33d8fa
github.com/apilayer/freegeoip v3.5.0+incompatible // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Masterminds/squirrel v1.1.0 h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs=
github.com/Masterminds/squirrel v1.1.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
Expand Down

0 comments on commit aa49fe0

Please sign in to comment.