Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: PutBlockNumber unit tests #447

Merged
merged 17 commits into from
Dec 18, 2019
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