fix_: enable tests to run with `-count` more than 1 (#5757)
* fix(TestProfilingCPU)_: enable run with -count=2 * fix(TestProfilingMem)_: enable run with -count=2 * fix(zaputil)_: register encoder only once * fix(timesource)_: global variables override in tests * fix(TestClosingsqlDB)_: delete database from cache * fix(postgres/helpers)_: drop connections before dropping database * fix_: linter * chore_: remove redundant condition
This commit is contained in:
parent
edead41fa6
commit
e0eb737c51
|
@ -3,7 +3,6 @@ package logutils
|
|||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
@ -123,15 +122,11 @@ func NewZapAdapter(logger log.Logger, enab zapcore.LevelEnabler) zapcore.Core {
|
|||
}
|
||||
}
|
||||
|
||||
var registerOnce sync.Once
|
||||
|
||||
// NewZapLoggerWithAdapter returns a logger forwarding all logs with level info and above.
|
||||
func NewZapLoggerWithAdapter(logger log.Logger) (*zap.Logger, error) {
|
||||
registerOnce.Do(func() {
|
||||
if err := zaputil.RegisterJSONHexEncoder(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
if err := zaputil.RegisterJSONHexEncoder(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cfg := zap.Config{
|
||||
Level: zap.NewAtomicLevelAt(zapcore.DebugLevel),
|
||||
|
|
|
@ -89,6 +89,11 @@ func TestClosingsqlDB(t *testing.T) {
|
|||
d, err := MakeNewDB(db)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup dbInstances to enable running test with -count more than 1.
|
||||
dbFileName, err := dbsetup.GetDBFilename(db)
|
||||
require.NoError(t, err)
|
||||
defer delete(dbInstances, dbFileName)
|
||||
|
||||
// Add settings data to the db
|
||||
err = d.CreateSettings(settings, config)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -29,6 +29,21 @@ func ResetDefaultTestPostgresDB() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = db.Close()
|
||||
}()
|
||||
|
||||
// Drop current and prevent any future connections. Used in tests. Details here:
|
||||
// https://stackoverflow.com/questions/17449420/postgresql-unable-to-drop-database-because-of-some-auto-connections-to-db
|
||||
_, err = db.Exec("REVOKE CONNECT ON DATABASE postgres FROM public;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("SELECT pid, pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'postgres' AND pid <> pg_backend_pid();")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("DROP DATABASE IF EXISTS postgres;")
|
||||
if err != nil {
|
||||
|
@ -36,5 +51,14 @@ func ResetDefaultTestPostgresDB() error {
|
|||
}
|
||||
|
||||
_, err = db.Exec("CREATE DATABASE postgres;")
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("GRANT CONNECT ON DATABASE postgres TO public;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package profiling
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime/pprof"
|
||||
|
@ -14,12 +15,14 @@ var cpuFile *os.File
|
|||
// StartCPUProfile enables CPU profiling for the current process. While profiling,
|
||||
// the profile will be buffered and written to the file in folder dataDir.
|
||||
func StartCPUProfile(dataDir string) error {
|
||||
if cpuFile == nil {
|
||||
var err error
|
||||
cpuFile, err = os.Create(filepath.Join(dataDir, CPUFilename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cpuFile != nil {
|
||||
return errors.New("cpu profiling is already started")
|
||||
}
|
||||
|
||||
var err error
|
||||
cpuFile, err = os.Create(filepath.Join(dataDir, CPUFilename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pprof.StartCPUProfile(cpuFile)
|
||||
|
@ -31,5 +34,7 @@ func StopCPUProfile() error {
|
|||
return nil
|
||||
}
|
||||
pprof.StopCPUProfile()
|
||||
return cpuFile.Close()
|
||||
err := cpuFile.Close()
|
||||
cpuFile = nil
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,8 +21,12 @@ func WriteHeapFile(dataDir string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer memFile.Close() //nolint: errcheck
|
||||
defer func() {
|
||||
memFile.Close() //nolint: errcheck
|
||||
memFile = nil
|
||||
}()
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
err = pprof.WriteHeapProfile(memFile)
|
||||
|
||||
|
|
|
@ -1,26 +1,20 @@
|
|||
package tt
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/status-im/status-go/protocol/zaputil"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var registerOnce sync.Once
|
||||
|
||||
// MustCreateTestLogger returns a logger based on the passed flags.
|
||||
func MustCreateTestLogger() *zap.Logger {
|
||||
return MustCreateTestLoggerWithConfig(loggerConfig())
|
||||
}
|
||||
|
||||
func MustCreateTestLoggerWithConfig(cfg zap.Config) *zap.Logger {
|
||||
registerOnce.Do(func() {
|
||||
if err := zaputil.RegisterConsoleHexEncoder(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
if err := zaputil.RegisterConsoleHexEncoder(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cfg.Encoding = "console-hex"
|
||||
l, err := cfg.Build()
|
||||
if err != nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package zaputil
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
@ -31,13 +32,22 @@ func (enc *jsonHexEncoder) Clone() zapcore.Encoder {
|
|||
return &jsonHexEncoder{Encoder: encoderClone}
|
||||
}
|
||||
|
||||
var (
|
||||
registerJSONHexEncoderOnce sync.Once
|
||||
registerConsoleHexEncodeOnce sync.Once
|
||||
)
|
||||
|
||||
// RegisterJSONHexEncoder registers a jsonHexEncoder under "json-hex" name.
|
||||
// Later, this name can be used as a value for zap.Config.Encoding to enable
|
||||
// jsonHexEncoder.
|
||||
func RegisterJSONHexEncoder() error {
|
||||
return zap.RegisterEncoder("json-hex", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
return NewJSONHexEncoder(cfg), nil
|
||||
var err error
|
||||
registerJSONHexEncoderOnce.Do(func() {
|
||||
err = zap.RegisterEncoder("json-hex", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
return NewJSONHexEncoder(cfg), nil
|
||||
})
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
type consoleHexEncoder struct {
|
||||
|
@ -61,7 +71,11 @@ func (enc *consoleHexEncoder) Clone() zapcore.Encoder {
|
|||
}
|
||||
|
||||
func RegisterConsoleHexEncoder() error {
|
||||
return zap.RegisterEncoder("console-hex", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
return NewConsoleHexEncoder(cfg), nil
|
||||
var err error
|
||||
registerConsoleHexEncodeOnce.Do(func() {
|
||||
err = zap.RegisterEncoder("console-hex", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||||
return NewConsoleHexEncoder(cfg), nil
|
||||
})
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -42,10 +42,6 @@ var defaultServers = []string{
|
|||
}
|
||||
var errUpdateOffset = errors.New("failed to compute offset")
|
||||
|
||||
var ntpTimeSource *NTPTimeSource
|
||||
var ntpTimeSourceCreator func() *NTPTimeSource
|
||||
var now func() time.Time
|
||||
|
||||
type ntpQuery func(string, ntp.QueryOptions) (*ntp.Response, error)
|
||||
|
||||
type queryResponse struct {
|
||||
|
@ -70,23 +66,6 @@ func (e multiRPCError) Error() string {
|
|||
return b.String()
|
||||
}
|
||||
|
||||
func init() {
|
||||
ntpTimeSourceCreator = func() *NTPTimeSource {
|
||||
if ntpTimeSource != nil {
|
||||
return ntpTimeSource
|
||||
}
|
||||
ntpTimeSource = &NTPTimeSource{
|
||||
servers: defaultServers,
|
||||
allowedFailures: DefaultMaxAllowedFailures,
|
||||
fastNTPSyncPeriod: FastNTPSyncPeriod,
|
||||
slowNTPSyncPeriod: SlowNTPSyncPeriod,
|
||||
timeQuery: ntp.QueryWithOptions,
|
||||
}
|
||||
return ntpTimeSource
|
||||
}
|
||||
now = time.Now
|
||||
}
|
||||
|
||||
func computeOffset(timeQuery ntpQuery, servers []string, allowedFailures int) (time.Duration, error) {
|
||||
if len(servers) == 0 {
|
||||
return 0, nil
|
||||
|
@ -138,9 +117,18 @@ func computeOffset(timeQuery ntpQuery, servers []string, allowedFailures int) (t
|
|||
return offsets[mid], nil
|
||||
}
|
||||
|
||||
var defaultTimeSource = &NTPTimeSource{
|
||||
servers: defaultServers,
|
||||
allowedFailures: DefaultMaxAllowedFailures,
|
||||
fastNTPSyncPeriod: FastNTPSyncPeriod,
|
||||
slowNTPSyncPeriod: SlowNTPSyncPeriod,
|
||||
timeQuery: ntp.QueryWithOptions,
|
||||
now: time.Now,
|
||||
}
|
||||
|
||||
// Default initializes time source with default config values.
|
||||
func Default() *NTPTimeSource {
|
||||
return ntpTimeSourceCreator()
|
||||
return defaultTimeSource
|
||||
}
|
||||
|
||||
// NTPTimeSource provides source of time that tries to be resistant to time skews.
|
||||
|
@ -151,6 +139,7 @@ type NTPTimeSource struct {
|
|||
fastNTPSyncPeriod time.Duration
|
||||
slowNTPSyncPeriod time.Duration
|
||||
timeQuery ntpQuery // for ease of testing
|
||||
now func() time.Time
|
||||
|
||||
quit chan struct{}
|
||||
started bool
|
||||
|
@ -163,7 +152,8 @@ type NTPTimeSource struct {
|
|||
func (s *NTPTimeSource) Now() time.Time {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return now().Add(s.latestOffset)
|
||||
n := s.now()
|
||||
return n.Add(s.latestOffset)
|
||||
}
|
||||
|
||||
func (s *NTPTimeSource) updateOffset() error {
|
||||
|
@ -238,13 +228,25 @@ func (s *NTPTimeSource) Stop() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *NTPTimeSource) GetCurrentTime() time.Time {
|
||||
s.Start()
|
||||
return s.Now()
|
||||
}
|
||||
|
||||
func (s *NTPTimeSource) GetCurrentTimeInMillis() uint64 {
|
||||
return convertToMillis(s.GetCurrentTime())
|
||||
}
|
||||
|
||||
func GetCurrentTime() time.Time {
|
||||
ts := Default()
|
||||
ts.Start()
|
||||
|
||||
return ts.Now()
|
||||
}
|
||||
|
||||
func GetCurrentTimeInMillis() uint64 {
|
||||
return uint64(GetCurrentTime().UnixNano() / int64(time.Millisecond))
|
||||
return convertToMillis(GetCurrentTime())
|
||||
}
|
||||
|
||||
func convertToMillis(t time.Time) uint64 {
|
||||
return uint64(t.UnixNano() / int64(time.Millisecond))
|
||||
}
|
||||
|
|
|
@ -177,6 +177,7 @@ func TestNTPTimeSource(t *testing.T) {
|
|||
servers: tc.servers,
|
||||
allowedFailures: tc.allowedFailures,
|
||||
timeQuery: tc.query,
|
||||
now: time.Now,
|
||||
}
|
||||
assert.WithinDuration(t, time.Now(), source.Now(), clockCompareDelta)
|
||||
err := source.updateOffset()
|
||||
|
@ -206,6 +207,7 @@ func TestRunningPeriodically(t *testing.T) {
|
|||
timeQuery: tc.query,
|
||||
fastNTPSyncPeriod: time.Duration(fastHits*10) * time.Millisecond,
|
||||
slowNTPSyncPeriod: time.Duration(slowHits*10) * time.Millisecond,
|
||||
now: time.Now,
|
||||
}
|
||||
lastCall := time.Now()
|
||||
// we're simulating a calls to updateOffset, testing ntp calls happens
|
||||
|
@ -259,54 +261,47 @@ func TestGetCurrentTimeInMillis(t *testing.T) {
|
|||
tc.responses[i] = queryResponse{Offset: responseOffset}
|
||||
}
|
||||
|
||||
ntpTimeSourceCreator = func() *NTPTimeSource {
|
||||
return &NTPTimeSource{
|
||||
servers: tc.servers,
|
||||
allowedFailures: tc.allowedFailures,
|
||||
timeQuery: tc.query,
|
||||
slowNTPSyncPeriod: SlowNTPSyncPeriod,
|
||||
}
|
||||
}
|
||||
now = func() time.Time {
|
||||
return time.Unix(1, 0)
|
||||
ts := NTPTimeSource{
|
||||
servers: tc.servers,
|
||||
allowedFailures: tc.allowedFailures,
|
||||
timeQuery: tc.query,
|
||||
slowNTPSyncPeriod: SlowNTPSyncPeriod,
|
||||
now: func() time.Time {
|
||||
return time.Unix(1, 0)
|
||||
},
|
||||
}
|
||||
|
||||
expectedTime := uint64(11000)
|
||||
n := GetCurrentTimeInMillis()
|
||||
n := ts.GetCurrentTimeInMillis()
|
||||
require.Equal(t, expectedTime, n)
|
||||
// test repeat invoke GetCurrentTimeInMillis
|
||||
n = GetCurrentTimeInMillis()
|
||||
n = ts.GetCurrentTimeInMillis()
|
||||
require.Equal(t, expectedTime, n)
|
||||
e := Default().Stop()
|
||||
e := ts.Stop()
|
||||
require.NoError(t, e)
|
||||
|
||||
// test invoke after stop
|
||||
n = GetCurrentTimeInMillis()
|
||||
n = ts.GetCurrentTimeInMillis()
|
||||
require.Equal(t, expectedTime, n)
|
||||
e = Default().Stop()
|
||||
e = ts.Stop()
|
||||
require.NoError(t, e)
|
||||
}
|
||||
|
||||
func TestGetCurrentTimeOffline(t *testing.T) {
|
||||
// covers https://github.com/status-im/status-desktop/issues/12691
|
||||
ntpTimeSourceCreator = func() *NTPTimeSource {
|
||||
if ntpTimeSource != nil {
|
||||
return ntpTimeSource
|
||||
}
|
||||
ntpTimeSource = &NTPTimeSource{
|
||||
servers: defaultServers,
|
||||
allowedFailures: DefaultMaxAllowedFailures,
|
||||
fastNTPSyncPeriod: 1 * time.Millisecond,
|
||||
slowNTPSyncPeriod: 1 * time.Second,
|
||||
timeQuery: func(string, ntp.QueryOptions) (*ntp.Response, error) {
|
||||
return nil, errors.New("offline")
|
||||
},
|
||||
}
|
||||
return ntpTimeSource
|
||||
ts := &NTPTimeSource{
|
||||
servers: defaultServers,
|
||||
allowedFailures: DefaultMaxAllowedFailures,
|
||||
fastNTPSyncPeriod: 1 * time.Millisecond,
|
||||
slowNTPSyncPeriod: 1 * time.Second,
|
||||
timeQuery: func(string, ntp.QueryOptions) (*ntp.Response, error) {
|
||||
return nil, errors.New("offline")
|
||||
},
|
||||
now: time.Now,
|
||||
}
|
||||
|
||||
// ensure there is no "panic: sync: negative WaitGroup counter"
|
||||
// when GetCurrentTime() is invoked more than once when offline
|
||||
_ = GetCurrentTime()
|
||||
_ = GetCurrentTime()
|
||||
_ = ts.GetCurrentTime()
|
||||
_ = ts.GetCurrentTime()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue