chore: add more tests (#3338)
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package proc
|
|
||||||
|
|
||||||
func dumpGoroutines() {
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,11 @@ const (
|
|||||||
debugLevel = 2
|
debugLevel = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
func dumpGoroutines() {
|
type creator interface {
|
||||||
|
Create(name string) (file *os.File, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpGoroutines(ctor creator) {
|
||||||
command := path.Base(os.Args[0])
|
command := path.Base(os.Args[0])
|
||||||
pid := syscall.Getpid()
|
pid := syscall.Getpid()
|
||||||
dumpFile := path.Join(os.TempDir(), fmt.Sprintf("%s-%d-goroutines-%s.dump",
|
dumpFile := path.Join(os.TempDir(), fmt.Sprintf("%s-%d-goroutines-%s.dump",
|
||||||
@@ -26,10 +30,16 @@ func dumpGoroutines() {
|
|||||||
|
|
||||||
logx.Infof("Got dump goroutine signal, printing goroutine profile to %s", dumpFile)
|
logx.Infof("Got dump goroutine signal, printing goroutine profile to %s", dumpFile)
|
||||||
|
|
||||||
if f, err := os.Create(dumpFile); err != nil {
|
if f, err := ctor.Create(dumpFile); err != nil {
|
||||||
logx.Errorf("Failed to dump goroutine profile, error: %v", err)
|
logx.Errorf("Failed to dump goroutine profile, error: %v", err)
|
||||||
} else {
|
} else {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
pprof.Lookup(goroutineProfile).WriteTo(f, debugLevel)
|
pprof.Lookup(goroutineProfile).WriteTo(f, debugLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fileCreator struct{}
|
||||||
|
|
||||||
|
func (fc fileCreator) Create(name string) (file *os.File, err error) {
|
||||||
|
return os.Create(name)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
|
||||||
package proc
|
package proc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -9,7 +13,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDumpGoroutines(t *testing.T) {
|
func TestDumpGoroutines(t *testing.T) {
|
||||||
buf := logtest.NewCollector(t)
|
t.Run("real file", func(t *testing.T) {
|
||||||
dumpGoroutines()
|
buf := logtest.NewCollector(t)
|
||||||
assert.True(t, strings.Contains(buf.String(), ".dump"))
|
dumpGoroutines(fileCreator{})
|
||||||
|
assert.True(t, strings.Contains(buf.String(), ".dump"))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("fake file", func(t *testing.T) {
|
||||||
|
const msg = "any message"
|
||||||
|
buf := logtest.NewCollector(t)
|
||||||
|
err := errors.New(msg)
|
||||||
|
dumpGoroutines(fakeCreator{
|
||||||
|
file: &os.File{},
|
||||||
|
err: err,
|
||||||
|
})
|
||||||
|
assert.True(t, strings.Contains(buf.String(), msg))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeCreator struct {
|
||||||
|
file *os.File
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc fakeCreator) Create(name string) (file *os.File, err error) {
|
||||||
|
return fc.file, fc.err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func init() {
|
|||||||
v := <-signals
|
v := <-signals
|
||||||
switch v {
|
switch v {
|
||||||
case syscall.SIGUSR1:
|
case syscall.SIGUSR1:
|
||||||
dumpGoroutines()
|
dumpGoroutines(fileCreator{})
|
||||||
case syscall.SIGUSR2:
|
case syscall.SIGUSR2:
|
||||||
if profiler == nil {
|
if profiler == nil {
|
||||||
profiler = StartProfile()
|
profiler = StartProfile()
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
|
||||||
package proc
|
package proc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -171,11 +171,11 @@ func add(nd *node, route string, item any) error {
|
|||||||
token := route[:i]
|
token := route[:i]
|
||||||
children := nd.getChildren(token)
|
children := nd.getChildren(token)
|
||||||
if child, ok := children[token]; ok {
|
if child, ok := children[token]; ok {
|
||||||
if child != nil {
|
if child == nil {
|
||||||
return add(child, route[i+1:], item)
|
return errInvalidState
|
||||||
}
|
}
|
||||||
|
|
||||||
return errInvalidState
|
return add(child, route[i+1:], item)
|
||||||
}
|
}
|
||||||
|
|
||||||
child := newNode(nil)
|
child := newNode(nil)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
type mockedRoute struct {
|
type mockedRoute struct {
|
||||||
route string
|
route string
|
||||||
value int
|
value any
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSearch(t *testing.T) {
|
func TestSearch(t *testing.T) {
|
||||||
@@ -187,6 +187,12 @@ func TestSearchInvalidItem(t *testing.T) {
|
|||||||
assert.Equal(t, errEmptyItem, err)
|
assert.Equal(t, errEmptyItem, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSearchInvalidState(t *testing.T) {
|
||||||
|
nd := newNode("0")
|
||||||
|
nd.children[0]["1"] = nil
|
||||||
|
assert.Error(t, add(nd, "1/2", "2"))
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkSearchTree(b *testing.B) {
|
func BenchmarkSearchTree(b *testing.B) {
|
||||||
const (
|
const (
|
||||||
avgLen = 1000
|
avgLen = 1000
|
||||||
|
|||||||
@@ -97,6 +97,9 @@ func (cc CachedConn) Exec(exec ExecFn, keys ...string) (sql.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExecCtx runs given exec on given keys, and returns execution result.
|
// ExecCtx runs given exec on given keys, and returns execution result.
|
||||||
|
// If DB operation succeeds, it will delete cache with given keys,
|
||||||
|
// if DB operation fails, it will return nil result and non-nil error,
|
||||||
|
// if DB operation succeeds but cache deletion fails, it will return result and non-nil error.
|
||||||
func (cc CachedConn) ExecCtx(ctx context.Context, exec ExecCtxFn, keys ...string) (
|
func (cc CachedConn) ExecCtx(ctx context.Context, exec ExecCtxFn, keys ...string) (
|
||||||
sql.Result, error) {
|
sql.Result, error) {
|
||||||
res, err := exec(ctx, cc.db)
|
res, err := exec(ctx, cc.db)
|
||||||
@@ -104,11 +107,7 @@ func (cc CachedConn) ExecCtx(ctx context.Context, exec ExecCtxFn, keys ...string
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cc.DelCacheCtx(ctx, keys...); err != nil {
|
return res, cc.DelCacheCtx(ctx, keys...)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecNoCache runs exec with given sql statement, without affecting cache.
|
// ExecNoCache runs exec with given sql statement, without affecting cache.
|
||||||
|
|||||||
@@ -471,31 +471,33 @@ func TestCachedConnExec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCachedConnExecDropCache(t *testing.T) {
|
func TestCachedConnExecDropCache(t *testing.T) {
|
||||||
r, err := miniredis.Run()
|
t.Run("drop cache", func(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
r, err := miniredis.Run()
|
||||||
defer fx.DoWithTimeout(func() error {
|
assert.Nil(t, err)
|
||||||
r.Close()
|
defer fx.DoWithTimeout(func() error {
|
||||||
return nil
|
r.Close()
|
||||||
}, time.Second)
|
return nil
|
||||||
|
}, time.Second)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
key = "user"
|
key = "user"
|
||||||
value = "any"
|
value = "any"
|
||||||
)
|
)
|
||||||
var conn trackedConn
|
var conn trackedConn
|
||||||
c := NewNodeConn(&conn, redis.New(r.Addr()), cache.WithExpiry(time.Second*30))
|
c := NewNodeConn(&conn, redis.New(r.Addr()), cache.WithExpiry(time.Second*30))
|
||||||
assert.Nil(t, c.SetCache(key, value))
|
assert.Nil(t, c.SetCache(key, value))
|
||||||
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
||||||
return conn.Exec("delete from user_table where id='kevin'")
|
return conn.Exec("delete from user_table where id='kevin'")
|
||||||
}, key)
|
}, key)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.True(t, conn.execValue)
|
assert.True(t, conn.execValue)
|
||||||
_, err = r.Get(key)
|
_, err = r.Get(key)
|
||||||
assert.Exactly(t, miniredis.ErrKeyNotFound, err)
|
assert.Exactly(t, miniredis.ErrKeyNotFound, err)
|
||||||
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
||||||
return nil, errors.New("foo")
|
return nil, errors.New("foo")
|
||||||
}, key)
|
}, key)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCachedConn_SetCacheWithExpire(t *testing.T) {
|
func TestCachedConn_SetCacheWithExpire(t *testing.T) {
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ func (manager *ResourceManager) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetResource returns the resource associated with given key.
|
// GetResource returns the resource associated with given key.
|
||||||
func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (io.Closer, error) {
|
func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (
|
||||||
|
io.Closer, error) {
|
||||||
val, err := manager.singleFlight.Do(key, func() (any, error) {
|
val, err := manager.singleFlight.Do(key, func() (any, error) {
|
||||||
manager.lock.RLock()
|
manager.lock.RLock()
|
||||||
resource, ok := manager.resources[key]
|
resource, ok := manager.resources[key]
|
||||||
|
|||||||
@@ -53,6 +53,19 @@ func TestComboHealthManager(t *testing.T) {
|
|||||||
assert.True(t, chm.IsReady())
|
assert.True(t, chm.IsReady())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("is ready verbose", func(t *testing.T) {
|
||||||
|
chm := newComboHealthManager()
|
||||||
|
hm := NewHealthManager(probeName)
|
||||||
|
|
||||||
|
assert.True(t, chm.IsReady())
|
||||||
|
chm.addProbe(hm)
|
||||||
|
assert.False(t, chm.IsReady())
|
||||||
|
hm.MarkReady()
|
||||||
|
assert.True(t, chm.IsReady())
|
||||||
|
assert.Contains(t, chm.verboseInfo(), probeName)
|
||||||
|
assert.Contains(t, chm.verboseInfo(), "is ready")
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("concurrent add probes", func(t *testing.T) {
|
t.Run("concurrent add probes", func(t *testing.T) {
|
||||||
chm := newComboHealthManager()
|
chm := newComboHealthManager()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user