Skip to content

Commit

Permalink
Merge pull request #100 from suyuan32/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
suyuan32 authored May 23, 2023
2 parents f625be6 + fce29bd commit 76630aa
Show file tree
Hide file tree
Showing 24 changed files with 1,012 additions and 192 deletions.
7 changes: 2 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
**/.idea
**/.DS_Store
**/logs
**/adhoc
**/coverage.txt

# for test purpose
**/adhoc
go.work
go.work.sum

Expand All @@ -28,8 +29,4 @@ go.work.sum
*~
!OWNERS

.github

coverage.txt

*.log
8 changes: 7 additions & 1 deletion core/prof/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package prof

import (
"fmt"
"io"
"os"
"runtime"
"time"
)
Expand All @@ -13,6 +15,10 @@ const (

// DisplayStats prints the goroutine, memory, GC stats with given interval, default to 5 seconds.
func DisplayStats(interval ...time.Duration) {
displayStatsWithWriter(os.Stdout, interval...)
}

func displayStatsWithWriter(writer io.Writer, interval ...time.Duration) {
duration := defaultInterval
for _, val := range interval {
duration = val
Expand All @@ -24,7 +30,7 @@ func DisplayStats(interval ...time.Duration) {
for range ticker.C {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Goroutines: %d, Alloc: %vm, TotalAlloc: %vm, Sys: %vm, NumGC: %v\n",
fmt.Fprintf(writer, "Goroutines: %d, Alloc: %vm, TotalAlloc: %vm, Sys: %vm, NumGC: %v\n",
runtime.NumGoroutine(), m.Alloc/mega, m.TotalAlloc/mega, m.Sys/mega, m.NumGC)
}
}()
Expand Down
36 changes: 36 additions & 0 deletions core/prof/runtime_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package prof

import (
"strings"
"sync"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestDisplayStats(t *testing.T) {
writer := &threadSafeBuffer{
buf: strings.Builder{},
}
displayStatsWithWriter(writer, time.Millisecond*10)
time.Sleep(time.Millisecond * 50)
assert.Contains(t, writer.String(), "Goroutines: ")
}

type threadSafeBuffer struct {
buf strings.Builder
lock sync.Mutex
}

func (b *threadSafeBuffer) String() string {
b.lock.Lock()
defer b.lock.Unlock()
return b.buf.String()
}

func (b *threadSafeBuffer) Write(p []byte) (n int, err error) {
b.lock.Lock()
defer b.lock.Unlock()
return b.buf.Write(p)
}
4 changes: 3 additions & 1 deletion core/stat/internal/cgroup_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package internal
import (
"bufio"
"fmt"
"math"
"os"
"path"
"strconv"
Expand Down Expand Up @@ -280,9 +281,10 @@ func runningInUserNS() bool {

// We assume we are in the initial user namespace if we have a full
// range - 4294967295 uids starting at uid 0.
if a == 0 && b == 0 && c == 4294967295 {
if a == 0 && b == 0 && c == math.MaxUint32 {
return
}

inUserNS = true
})

Expand Down
27 changes: 27 additions & 0 deletions core/stat/internal/cgroup_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package internal

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestRunningInUserNS(t *testing.T) {
// should be false in docker
assert.False(t, runningInUserNS())
}

func TestCgroupV1(t *testing.T) {
if isCgroup2UnifiedMode() {
cg, err := currentCgroupV1()
assert.NoError(t, err)
_, err = cg.cpus()
assert.Error(t, err)
_, err = cg.cpuPeriodUs()
assert.Error(t, err)
_, err = cg.cpuQuotaUs()
assert.Error(t, err)
_, err = cg.usageAllCpus()
assert.Error(t, err)
}
}
59 changes: 59 additions & 0 deletions core/stores/builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,62 @@ func TestFieldNamesWithDashTagAndOptions(t *testing.T) {
assert.Equal(t, expected, out)
})
}

func TestPostgreSqlJoin(t *testing.T) {
// Test with empty input array
var input []string
var expectedOutput string
assert.Equal(t, expectedOutput, PostgreSqlJoin(input))

// Test with single element input array
input = []string{"foo"}
expectedOutput = "foo = $2"
assert.Equal(t, expectedOutput, PostgreSqlJoin(input))

// Test with multiple elements input array
input = []string{"foo", "bar", "baz"}
expectedOutput = "foo = $2, bar = $3, baz = $4"
assert.Equal(t, expectedOutput, PostgreSqlJoin(input))
}

type testStruct struct {
Foo string `db:"foo"`
Bar int `db:"bar"`
Baz bool `db:"-"`
}

func TestRawFieldNames(t *testing.T) {
// Test with a struct without tags
in := struct {
Foo string
Bar int
}{}
expectedOutput := []string{"`Foo`", "`Bar`"}
assert.ElementsMatch(t, expectedOutput, RawFieldNames(in))

// Test pg without db tag
expectedOutput = []string{"Foo", "Bar"}
assert.ElementsMatch(t, expectedOutput, RawFieldNames(in, true))

// Test with a struct with tags
input := testStruct{}
expectedOutput = []string{"`foo`", "`bar`"}
assert.ElementsMatch(t, expectedOutput, RawFieldNames(input))

// Test with nil input (pointer)
var nilInput *testStruct
assert.Panics(t, func() {
RawFieldNames(nilInput)
}, "RawFieldNames should panic with nil input")

// Test with non-struct input
inputInt := 42
assert.Panics(t, func() {
RawFieldNames(inputInt)
}, "RawFieldNames should panic with non-struct input")

// Test with PostgreSQL flag
input = testStruct{}
expectedOutput = []string{"foo", "bar"}
assert.ElementsMatch(t, expectedOutput, RawFieldNames(input, true))
}
132 changes: 95 additions & 37 deletions core/stores/cache/cachenode_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//go:build !race

// Disable data race detection is because of the timingWheel in cacheNode.
package cache

import (
Expand Down Expand Up @@ -34,8 +31,10 @@ func init() {

func TestCacheNode_DelCache(t *testing.T) {
t.Run("del cache", func(t *testing.T) {
store := redistest.CreateRedis(t)
store.Type = redis.ClusterType
r, err := miniredis.Run()
assert.NoError(t, err)
defer r.Close()
store := redis.New(r.Addr(), redis.Cluster())

cn := cacheNode{
rds: store,
Expand All @@ -56,16 +55,16 @@ func TestCacheNode_DelCache(t *testing.T) {
})

t.Run("del cache with errors", func(t *testing.T) {
old := timingWheel
old := timingWheel.Load()
ticker := timex.NewFakeTicker()
var err error
timingWheel, err = collection.NewTimingWheelWithTicker(
tw, err := collection.NewTimingWheelWithTicker(
time.Millisecond, timingWheelSlots, func(key, value any) {
clean(key, value)
}, ticker)
timingWheel.Store(tw)
assert.NoError(t, err)
t.Cleanup(func() {
timingWheel = old
timingWheel.Store(old)
})

r, err := miniredis.Run()
Expand Down Expand Up @@ -166,40 +165,99 @@ func TestCacheNode_TakeBadRedis(t *testing.T) {
}

func TestCacheNode_TakeNotFound(t *testing.T) {
store := redistest.CreateRedis(t)
t.Run("not found", func(t *testing.T) {
store := redistest.CreateRedis(t)

cn := cacheNode{
rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"),
errNotFound: errTestNotFound,
}
var str string
err := cn.Take(&str, "any", func(v any) error {
return errTestNotFound
cn := cacheNode{
rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"),
errNotFound: errTestNotFound,
}
var str string
err := cn.Take(&str, "any", func(v any) error {
return errTestNotFound
})
assert.True(t, cn.IsNotFound(err))
assert.True(t, cn.IsNotFound(cn.Get("any", &str)))
val, err := store.Get("any")
assert.Nil(t, err)
assert.Equal(t, `*`, val)

store.Set("any", "*")
err = cn.Take(&str, "any", func(v any) error {
return nil
})
assert.True(t, cn.IsNotFound(err))
assert.True(t, cn.IsNotFound(cn.Get("any", &str)))

store.Del("any")
errDummy := errors.New("dummy")
err = cn.Take(&str, "any", func(v any) error {
return errDummy
})
assert.Equal(t, errDummy, err)
})
assert.True(t, cn.IsNotFound(err))
assert.True(t, cn.IsNotFound(cn.Get("any", &str)))
val, err := store.Get("any")
assert.Nil(t, err)
assert.Equal(t, `*`, val)

store.Set("any", "*")
err = cn.Take(&str, "any", func(v any) error {
return nil
t.Run("not found with redis error", func(t *testing.T) {
r, err := miniredis.Run()
assert.NoError(t, err)
defer r.Close()
store, err := redis.NewRedis(redis.RedisConf{
Host: r.Addr(),
Type: redis.NodeType,
})
assert.NoError(t, err)

cn := cacheNode{
rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"),
errNotFound: errTestNotFound,
}
var str string
err = cn.Take(&str, "any", func(v any) error {
r.SetError("mock error")
return errTestNotFound
})
assert.True(t, cn.IsNotFound(err))
})
assert.True(t, cn.IsNotFound(err))
assert.True(t, cn.IsNotFound(cn.Get("any", &str)))
}

store.Del("any")
errDummy := errors.New("dummy")
err = cn.Take(&str, "any", func(v any) error {
return errDummy
func TestCacheNode_TakeCtxWithRedisError(t *testing.T) {
t.Run("not found with redis error", func(t *testing.T) {
r, err := miniredis.Run()
assert.NoError(t, err)
defer r.Close()
store, err := redis.NewRedis(redis.RedisConf{
Host: r.Addr(),
Type: redis.NodeType,
})
assert.NoError(t, err)

cn := cacheNode{
rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"),
errNotFound: errTestNotFound,
}
var str string
err = cn.Take(&str, "any", func(v any) error {
str = "foo"
r.SetError("mock error")
return nil
})
assert.NoError(t, err)
})
assert.Equal(t, errDummy, err)
}

func TestCacheNode_TakeNotFoundButChangedByOthers(t *testing.T) {
Expand Down
28 changes: 28 additions & 0 deletions core/stores/cache/cacheopt_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cache

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestCacheOptions(t *testing.T) {
t.Run("default options", func(t *testing.T) {
o := newOptions()
assert.Equal(t, defaultExpiry, o.Expiry)
assert.Equal(t, defaultNotFoundExpiry, o.NotFoundExpiry)
})

t.Run("with expiry", func(t *testing.T) {
o := newOptions(WithExpiry(time.Second))
assert.Equal(t, time.Second, o.Expiry)
assert.Equal(t, defaultNotFoundExpiry, o.NotFoundExpiry)
})

t.Run("with not found expiry", func(t *testing.T) {
o := newOptions(WithNotFoundExpiry(time.Second))
assert.Equal(t, defaultExpiry, o.Expiry)
assert.Equal(t, time.Second, o.NotFoundExpiry)
})
}
Loading

0 comments on commit 76630aa

Please sign in to comment.