mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-06-10 16:10:18 +08:00
Compare commits
62 Commits
v1.3.0-bet
...
v1.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e31128650e | ||
|
|
168740b64d | ||
|
|
cc4c4928e0 | ||
|
|
fba6543b23 | ||
|
|
877eb6ac56 | ||
|
|
259a5a13e7 | ||
|
|
cf7c7cb392 | ||
|
|
86d01e2e99 | ||
|
|
7a28e19a27 | ||
|
|
900ea63d68 | ||
|
|
87ab86cdd0 | ||
|
|
0697494ffd | ||
|
|
ffd69a2f5e | ||
|
|
66f10bb5e6 | ||
|
|
8131a0e777 | ||
|
|
32a557dff6 | ||
|
|
db949e40f1 | ||
|
|
e0454138e0 | ||
|
|
3b07ed1b97 | ||
|
|
daa98f5a27 | ||
|
|
842656aa90 | ||
|
|
aa29036cb3 | ||
|
|
607bae27fa | ||
|
|
7c63676be4 | ||
|
|
9e113909b3 | ||
|
|
bd105474ca | ||
|
|
a078f5d764 | ||
|
|
b215fa3ee6 | ||
|
|
50b1928502 | ||
|
|
493e3bcf4b | ||
|
|
6deb80625d | ||
|
|
6ab051568c | ||
|
|
2732d3cdae | ||
|
|
e8c307e4dc | ||
|
|
84ddc660c4 | ||
|
|
e60e707955 | ||
|
|
cf4321b2d0 | ||
|
|
1993faf2f8 | ||
|
|
0ce85376bf | ||
|
|
a40254156f | ||
|
|
05cc62f5ff | ||
|
|
9c2c90e533 | ||
|
|
822ee2e1c5 | ||
|
|
77482c8946 | ||
|
|
7ef0ab3119 | ||
|
|
8bd89a297a | ||
|
|
bb75cc796e | ||
|
|
0fdd8f54eb | ||
|
|
b1ffc464cd | ||
|
|
50174960e4 | ||
|
|
8f46eab977 | ||
|
|
ec299085f5 | ||
|
|
7727d70634 | ||
|
|
5f9d101bc6 | ||
|
|
6c2abe7474 | ||
|
|
14a902c1a7 | ||
|
|
5ad6a6d229 | ||
|
|
6f4b97864a | ||
|
|
0e0abc3a95 | ||
|
|
696fda1db4 | ||
|
|
c1d2634427 | ||
|
|
4b7a680ac5 |
24
.github/workflows/go.yml
vendored
24
.github/workflows/go.yml
vendored
@@ -7,11 +7,10 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
test-linux:
|
||||||
name: Build
|
name: Linux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Set up Go 1.x
|
- name: Set up Go 1.x
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
@@ -36,3 +35,22 @@ jobs:
|
|||||||
|
|
||||||
- name: Codecov
|
- name: Codecov
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v2
|
||||||
|
|
||||||
|
test-win:
|
||||||
|
name: Windows
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ^1.15
|
||||||
|
|
||||||
|
- name: Checkout codebase
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
go mod verify
|
||||||
|
go mod download
|
||||||
|
go test -v -race ./...
|
||||||
|
cd tools/goctl && go build -v goctl.go
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,7 +16,8 @@
|
|||||||
**/logs
|
**/logs
|
||||||
|
|
||||||
# for test purpose
|
# for test purpose
|
||||||
adhoc
|
**/adhoc
|
||||||
|
**/testdata
|
||||||
|
|
||||||
# gitlab ci
|
# gitlab ci
|
||||||
.cache
|
.cache
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ We hope that the items listed below will inspire further engagement from the com
|
|||||||
- [x] Support `goctl bug` to report bugs conveniently
|
- [x] Support `goctl bug` to report bugs conveniently
|
||||||
|
|
||||||
## 2022
|
## 2022
|
||||||
- [ ] Support `goctl mock` command to start a mocking server with given `.api` file
|
- [x] Support `context` in redis related methods for timeout and tracing
|
||||||
|
- [x] Support `context` in sql related methods for timeout and tracing
|
||||||
|
- [ ] Support `context` in mongodb related methods for timeout and tracing
|
||||||
- [ ] Add `httpx.Client` with governance, like circuit breaker etc.
|
- [ ] Add `httpx.Client` with governance, like circuit breaker etc.
|
||||||
- [ ] Support `goctl doctor` command to report potential issues for given service
|
- [ ] Support `goctl doctor` command to report potential issues for given service
|
||||||
- [ ] Support `context` in redis related methods for timeout and tracing
|
- [ ] Support `goctl mock` command to start a mocking server with given `.api` file
|
||||||
- [ ] Support `context` in sql related methods for timeout and tracing
|
|
||||||
- [ ] Support `context` in mongodb related methods for timeout and tracing
|
|
||||||
|
|||||||
@@ -61,3 +61,41 @@ func TestPutMore(t *testing.T) {
|
|||||||
assert.Equal(t, string(element), string(body.([]byte)))
|
assert.Equal(t, string(element), string(body.([]byte)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPutMoreWithHeaderNotZero(t *testing.T) {
|
||||||
|
elements := [][]byte{
|
||||||
|
[]byte("hello"),
|
||||||
|
[]byte("world"),
|
||||||
|
[]byte("again"),
|
||||||
|
}
|
||||||
|
queue := NewQueue(4)
|
||||||
|
for i := range elements {
|
||||||
|
queue.Put(elements[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// take 1
|
||||||
|
body, ok := queue.Take()
|
||||||
|
assert.True(t, ok)
|
||||||
|
element, ok := body.([]byte)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, element, []byte("hello"))
|
||||||
|
|
||||||
|
// put more
|
||||||
|
queue.Put([]byte("b4"))
|
||||||
|
queue.Put([]byte("b5")) // will store in elements[0]
|
||||||
|
queue.Put([]byte("b6")) // cause expansion
|
||||||
|
|
||||||
|
results := [][]byte{
|
||||||
|
[]byte("world"),
|
||||||
|
[]byte("again"),
|
||||||
|
[]byte("b4"),
|
||||||
|
[]byte("b5"),
|
||||||
|
[]byte("b6"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, element := range results {
|
||||||
|
body, ok := queue.Take()
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, string(element), string(body.([]byte)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ package discov
|
|||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// errEmptyEtcdHosts indicates that etcd hosts are empty.
|
||||||
|
errEmptyEtcdHosts = errors.New("empty etcd hosts")
|
||||||
|
// errEmptyEtcdKey indicates that etcd key is empty.
|
||||||
|
errEmptyEtcdKey = errors.New("empty etcd key")
|
||||||
|
)
|
||||||
|
|
||||||
// EtcdConf is the config item with the given key on etcd.
|
// EtcdConf is the config item with the given key on etcd.
|
||||||
type EtcdConf struct {
|
type EtcdConf struct {
|
||||||
Hosts []string
|
Hosts []string
|
||||||
@@ -27,9 +34,9 @@ func (c EtcdConf) HasTLS() bool {
|
|||||||
// Validate validates c.
|
// Validate validates c.
|
||||||
func (c EtcdConf) Validate() error {
|
func (c EtcdConf) Validate() error {
|
||||||
if len(c.Hosts) == 0 {
|
if len(c.Hosts) == 0 {
|
||||||
return errors.New("empty etcd hosts")
|
return errEmptyEtcdHosts
|
||||||
} else if len(c.Key) == 0 {
|
} else if len(c.Key) == 0 {
|
||||||
return errors.New("empty etcd key")
|
return errEmptyEtcdKey
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ type (
|
|||||||
errorArray []error
|
errorArray []error
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add adds err to be.
|
// Add adds errs to be, nil errors are ignored.
|
||||||
func (be *BatchError) Add(err error) {
|
func (be *BatchError) Add(errs ...error) {
|
||||||
|
for _, err := range errs {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
be.errs = append(be.errs, err)
|
be.errs = append(be.errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Err returns an error that represents all errors.
|
// Err returns an error that represents all errors.
|
||||||
func (be *BatchError) Err() error {
|
func (be *BatchError) Err() error {
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// errExceedFileSize indicates that the file size is exceeded.
|
||||||
|
var errExceedFileSize = errors.New("exceed file size")
|
||||||
|
|
||||||
// A RangeReader is used to read a range of content from a file.
|
// A RangeReader is used to read a range of content from a file.
|
||||||
type RangeReader struct {
|
type RangeReader struct {
|
||||||
file *os.File
|
file *os.File
|
||||||
@@ -29,7 +32,7 @@ func (rr *RangeReader) Read(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if rr.stop < rr.start || rr.start >= stat.Size() {
|
if rr.stop < rr.start || rr.start >= stat.Size() {
|
||||||
return 0, errors.New("exceed file size")
|
return 0, errExceedFileSize
|
||||||
}
|
}
|
||||||
|
|
||||||
if rr.stop-rr.start < int64(len(p)) {
|
if rr.stop-rr.start < int64(len(p)) {
|
||||||
|
|||||||
@@ -51,5 +51,5 @@ func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func formatError(v string, err error) error {
|
func formatError(v string, err error) error {
|
||||||
return fmt.Errorf("string: `%s`, error: `%s`", v, err.Error())
|
return fmt.Errorf("string: `%s`, error: `%w`", v, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,9 @@ func TestPeriodLimit_RedisUnavailable(t *testing.T) {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
seconds = 1
|
seconds = 1
|
||||||
total = 100
|
|
||||||
quota = 5
|
quota = 5
|
||||||
)
|
)
|
||||||
l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit")
|
l := NewPeriodLimit(seconds, quota, redis.New(s.Addr()), "periodlimit")
|
||||||
s.Close()
|
s.Close()
|
||||||
val, err := l.Take("first")
|
val, err := l.Take("first")
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package logx
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/timex"
|
"github.com/zeromicro/go-zero/core/timex"
|
||||||
@@ -79,7 +80,7 @@ func (l *durationLogger) WithDuration(duration time.Duration) Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *durationLogger) write(writer io.Writer, level string, val interface{}) {
|
func (l *durationLogger) write(writer io.Writer, level string, val interface{}) {
|
||||||
switch encoding {
|
switch atomic.LoadUint32(&encoding) {
|
||||||
case plainEncodingType:
|
case plainEncodingType:
|
||||||
writePlainAny(writer, level, val, l.Duration)
|
writePlainAny(writer, level, val, l.Duration)
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package logx
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -38,10 +39,10 @@ func TestWithDurationInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWithDurationInfoConsole(t *testing.T) {
|
func TestWithDurationInfoConsole(t *testing.T) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ var (
|
|||||||
// ErrLogServiceNameNotSet is an error that indicates that the service name is not set.
|
// ErrLogServiceNameNotSet is an error that indicates that the service name is not set.
|
||||||
ErrLogServiceNameNotSet = errors.New("log service name must be set")
|
ErrLogServiceNameNotSet = errors.New("log service name must be set")
|
||||||
|
|
||||||
timeFormat = "2006-01-02T15:04:05.000Z07"
|
timeFormat = "2006-01-02T15:04:05.000Z07:00"
|
||||||
writeConsole bool
|
writeConsole bool
|
||||||
logLevel uint32
|
logLevel uint32
|
||||||
encoding = jsonEncodingType
|
encoding uint32 = jsonEncodingType
|
||||||
// use uint32 for atomic operations
|
// use uint32 for atomic operations
|
||||||
disableStat uint32
|
disableStat uint32
|
||||||
infoLog io.WriteCloser
|
infoLog io.WriteCloser
|
||||||
@@ -137,9 +137,9 @@ func SetUp(c LogConf) error {
|
|||||||
}
|
}
|
||||||
switch c.Encoding {
|
switch c.Encoding {
|
||||||
case plainEncoding:
|
case plainEncoding:
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
default:
|
default:
|
||||||
encoding = jsonEncodingType
|
atomic.StoreUint32(&encoding, jsonEncodingType)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch c.Mode {
|
switch c.Mode {
|
||||||
@@ -424,7 +424,7 @@ func infoTextSync(msg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func outputAny(writer io.Writer, level string, val interface{}) {
|
func outputAny(writer io.Writer, level string, val interface{}) {
|
||||||
switch encoding {
|
switch atomic.LoadUint32(&encoding) {
|
||||||
case plainEncodingType:
|
case plainEncodingType:
|
||||||
writePlainAny(writer, level, val)
|
writePlainAny(writer, level, val)
|
||||||
default:
|
default:
|
||||||
@@ -438,7 +438,7 @@ func outputAny(writer io.Writer, level string, val interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func outputText(writer io.Writer, level, msg string) {
|
func outputText(writer io.Writer, level, msg string) {
|
||||||
switch encoding {
|
switch atomic.LoadUint32(&encoding) {
|
||||||
case plainEncodingType:
|
case plainEncodingType:
|
||||||
writePlainText(writer, level, msg)
|
writePlainText(writer, level, msg)
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -145,10 +145,10 @@ func TestStructedLogInfoConsoleAny(t *testing.T) {
|
|||||||
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
||||||
infoLog = writer
|
infoLog = writer
|
||||||
}, func(v ...interface{}) {
|
}, func(v ...interface{}) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
Infov(v)
|
Infov(v)
|
||||||
@@ -159,10 +159,10 @@ func TestStructedLogInfoConsoleAnyString(t *testing.T) {
|
|||||||
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
||||||
infoLog = writer
|
infoLog = writer
|
||||||
}, func(v ...interface{}) {
|
}, func(v ...interface{}) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
Infov(fmt.Sprint(v...))
|
Infov(fmt.Sprint(v...))
|
||||||
@@ -173,10 +173,10 @@ func TestStructedLogInfoConsoleAnyError(t *testing.T) {
|
|||||||
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
||||||
infoLog = writer
|
infoLog = writer
|
||||||
}, func(v ...interface{}) {
|
}, func(v ...interface{}) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
Infov(errors.New(fmt.Sprint(v...)))
|
Infov(errors.New(fmt.Sprint(v...)))
|
||||||
@@ -187,10 +187,10 @@ func TestStructedLogInfoConsoleAnyStringer(t *testing.T) {
|
|||||||
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
||||||
infoLog = writer
|
infoLog = writer
|
||||||
}, func(v ...interface{}) {
|
}, func(v ...interface{}) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
Infov(ValStringer{
|
Infov(ValStringer{
|
||||||
@@ -203,10 +203,10 @@ func TestStructedLogInfoConsoleText(t *testing.T) {
|
|||||||
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
doTestStructedLogConsole(t, func(writer io.WriteCloser) {
|
||||||
infoLog = writer
|
infoLog = writer
|
||||||
}, func(v ...interface{}) {
|
}, func(v ...interface{}) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, plainEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
Info(fmt.Sprint(v...))
|
Info(fmt.Sprint(v...))
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ func TestRedirector(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func captureOutput(f func()) string {
|
func captureOutput(f func()) string {
|
||||||
atomic.StoreUint32(&initialized, 1)
|
|
||||||
writer := new(mockWriter)
|
writer := new(mockWriter)
|
||||||
infoLog = writer
|
infoLog = writer
|
||||||
|
atomic.StoreUint32(&initialized, 1)
|
||||||
|
|
||||||
prevLevel := atomic.LoadUint32(&logLevel)
|
prevLevel := atomic.LoadUint32(&logLevel)
|
||||||
SetLevel(InfoLevel)
|
SetLevel(InfoLevel)
|
||||||
@@ -44,5 +44,9 @@ func captureOutput(f func()) string {
|
|||||||
func getContent(jsonStr string) string {
|
func getContent(jsonStr string) string {
|
||||||
var entry logEntry
|
var entry logEntry
|
||||||
json.Unmarshal([]byte(jsonStr), &entry)
|
json.Unmarshal([]byte(jsonStr), &entry)
|
||||||
return entry.Content.(string)
|
val, ok := entry.Content.(string)
|
||||||
|
if ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/timex"
|
"github.com/zeromicro/go-zero/core/timex"
|
||||||
@@ -80,7 +81,7 @@ func (l *traceLogger) write(writer io.Writer, level string, val interface{}) {
|
|||||||
traceID := traceIdFromContext(l.ctx)
|
traceID := traceIdFromContext(l.ctx)
|
||||||
spanID := spanIdFromContext(l.ctx)
|
spanID := spanIdFromContext(l.ctx)
|
||||||
|
|
||||||
switch encoding {
|
switch atomic.LoadUint32(&encoding) {
|
||||||
case plainEncodingType:
|
case plainEncodingType:
|
||||||
writePlainAny(writer, level, val, l.Duration, traceID, spanID)
|
writePlainAny(writer, level, val, l.Duration, traceID, spanID)
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ func TestTraceInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTraceInfoConsole(t *testing.T) {
|
func TestTraceInfoConsole(t *testing.T) {
|
||||||
old := encoding
|
old := atomic.LoadUint32(&encoding)
|
||||||
encoding = plainEncodingType
|
atomic.StoreUint32(&encoding, jsonEncodingType)
|
||||||
defer func() {
|
defer func() {
|
||||||
encoding = old
|
atomic.StoreUint32(&encoding, old)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var buf mockWriter
|
var buf mockWriter
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
@@ -14,7 +13,7 @@ const yamlTagKey = "json"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrUnsupportedType is an error that indicates the config format is not supported.
|
// ErrUnsupportedType is an error that indicates the config format is not supported.
|
||||||
ErrUnsupportedType = errors.New("only map-like configs are suported")
|
ErrUnsupportedType = errors.New("only map-like configs are supported")
|
||||||
|
|
||||||
yamlUnmarshaler = NewUnmarshaler(yamlTagKey)
|
yamlUnmarshaler = NewUnmarshaler(yamlTagKey)
|
||||||
)
|
)
|
||||||
@@ -29,39 +28,6 @@ func UnmarshalYamlReader(reader io.Reader, v interface{}) error {
|
|||||||
return unmarshalYamlReader(reader, v, yamlUnmarshaler)
|
return unmarshalYamlReader(reader, v, yamlUnmarshaler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
|
|
||||||
var o interface{}
|
|
||||||
if err := yamlUnmarshal(content, &o); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if m, ok := o.(map[string]interface{}); ok {
|
|
||||||
return unmarshaler.Unmarshal(m, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ErrUnsupportedType
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
|
|
||||||
content, err := ioutil.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return unmarshalYamlBytes(content, v, unmarshaler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
|
|
||||||
func yamlUnmarshal(in []byte, out interface{}) error {
|
|
||||||
var res interface{}
|
|
||||||
if err := yaml.Unmarshal(in, &res); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*out.(*interface{}) = cleanupMapValue(res)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
|
func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
|
||||||
res := make(map[string]interface{})
|
res := make(map[string]interface{})
|
||||||
for k, v := range in {
|
for k, v := range in {
|
||||||
@@ -96,3 +62,40 @@ func cleanupMapValue(v interface{}) interface{} {
|
|||||||
return Repr(v)
|
return Repr(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unmarshal(unmarshaler *Unmarshaler, o interface{}, v interface{}) error {
|
||||||
|
if m, ok := o.(map[string]interface{}); ok {
|
||||||
|
return unmarshaler.Unmarshal(m, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrUnsupportedType
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
|
||||||
|
var o interface{}
|
||||||
|
if err := yamlUnmarshal(content, &o); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmarshal(unmarshaler, o, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
|
||||||
|
var res interface{}
|
||||||
|
if err := yaml.NewDecoder(reader).Decode(&res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmarshal(unmarshaler, cleanupMapValue(res), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
|
||||||
|
func yamlUnmarshal(in []byte, out interface{}) error {
|
||||||
|
var res interface{}
|
||||||
|
if err := yaml.Unmarshal(in, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*out.(*interface{}) = cleanupMapValue(res)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -926,14 +926,17 @@ func TestUnmarshalYamlBytesError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalYamlReaderError(t *testing.T) {
|
func TestUnmarshalYamlReaderError(t *testing.T) {
|
||||||
payload := `abcd: cdef`
|
|
||||||
reader := strings.NewReader(payload)
|
|
||||||
var v struct {
|
var v struct {
|
||||||
Any string
|
Any string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader := strings.NewReader(`abcd: cdef`)
|
||||||
err := UnmarshalYamlReader(reader, &v)
|
err := UnmarshalYamlReader(reader, &v)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
reader = strings.NewReader("chenquan")
|
||||||
|
err = UnmarshalYamlReader(reader, &v)
|
||||||
|
assert.ErrorIs(t, err, ErrUnsupportedType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalYamlBadReader(t *testing.T) {
|
func TestUnmarshalYamlBadReader(t *testing.T) {
|
||||||
@@ -1011,6 +1014,6 @@ func TestUnmarshalYamlMapRune(t *testing.T) {
|
|||||||
|
|
||||||
type badReader struct{}
|
type badReader struct{}
|
||||||
|
|
||||||
func (b *badReader) Read(p []byte) (n int, err error) {
|
func (b *badReader) Read(_ []byte) (n int, err error) {
|
||||||
return 0, io.ErrLimitReached
|
return 0, io.ErrLimitReached
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ package mr
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/errorx"
|
"github.com/zeromicro/go-zero/core/errorx"
|
||||||
"github.com/zeromicro/go-zero/core/lang"
|
"github.com/zeromicro/go-zero/core/lang"
|
||||||
"github.com/zeromicro/go-zero/core/threading"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -42,6 +41,16 @@ type (
|
|||||||
// Option defines the method to customize the mapreduce.
|
// Option defines the method to customize the mapreduce.
|
||||||
Option func(opts *mapReduceOptions)
|
Option func(opts *mapReduceOptions)
|
||||||
|
|
||||||
|
mapperContext struct {
|
||||||
|
ctx context.Context
|
||||||
|
mapper MapFunc
|
||||||
|
source <-chan interface{}
|
||||||
|
panicChan *onceChan
|
||||||
|
collector chan<- interface{}
|
||||||
|
doneChan <-chan lang.PlaceholderType
|
||||||
|
workers int
|
||||||
|
}
|
||||||
|
|
||||||
mapReduceOptions struct {
|
mapReduceOptions struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
workers int
|
workers int
|
||||||
@@ -90,46 +99,72 @@ func FinishVoid(fns ...func()) {
|
|||||||
|
|
||||||
// ForEach maps all elements from given generate but no output.
|
// ForEach maps all elements from given generate but no output.
|
||||||
func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) {
|
func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) {
|
||||||
drain(Map(generate, func(item interface{}, writer Writer) {
|
|
||||||
mapper(item)
|
|
||||||
}, opts...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map maps all elements generated from given generate func, and returns an output channel.
|
|
||||||
func Map(generate GenerateFunc, mapper MapFunc, opts ...Option) chan interface{} {
|
|
||||||
options := buildOptions(opts...)
|
options := buildOptions(opts...)
|
||||||
source := buildSource(generate)
|
panicChan := &onceChan{channel: make(chan interface{})}
|
||||||
|
source := buildSource(generate, panicChan)
|
||||||
collector := make(chan interface{}, options.workers)
|
collector := make(chan interface{}, options.workers)
|
||||||
done := make(chan lang.PlaceholderType)
|
done := make(chan lang.PlaceholderType)
|
||||||
|
|
||||||
go executeMappers(options.ctx, mapper, source, collector, done, options.workers)
|
go executeMappers(mapperContext{
|
||||||
|
ctx: options.ctx,
|
||||||
|
mapper: func(item interface{}, writer Writer) {
|
||||||
|
mapper(item)
|
||||||
|
},
|
||||||
|
source: source,
|
||||||
|
panicChan: panicChan,
|
||||||
|
collector: collector,
|
||||||
|
doneChan: done,
|
||||||
|
workers: options.workers,
|
||||||
|
})
|
||||||
|
|
||||||
return collector
|
for {
|
||||||
|
select {
|
||||||
|
case v := <-panicChan.channel:
|
||||||
|
panic(v)
|
||||||
|
case _, ok := <-collector:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapReduce maps all elements generated from given generate func,
|
// MapReduce maps all elements generated from given generate func,
|
||||||
// and reduces the output elements with given reducer.
|
// and reduces the output elements with given reducer.
|
||||||
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc,
|
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc,
|
||||||
opts ...Option) (interface{}, error) {
|
opts ...Option) (interface{}, error) {
|
||||||
source := buildSource(generate)
|
panicChan := &onceChan{channel: make(chan interface{})}
|
||||||
return MapReduceChan(source, mapper, reducer, opts...)
|
source := buildSource(generate, panicChan)
|
||||||
|
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
|
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
|
||||||
func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer ReducerFunc,
|
func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer ReducerFunc,
|
||||||
opts ...Option) (interface{}, error) {
|
opts ...Option) (interface{}, error) {
|
||||||
|
panicChan := &onceChan{channel: make(chan interface{})}
|
||||||
|
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
|
||||||
|
func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapper MapperFunc,
|
||||||
|
reducer ReducerFunc, opts ...Option) (interface{}, error) {
|
||||||
options := buildOptions(opts...)
|
options := buildOptions(opts...)
|
||||||
|
// output is used to write the final result
|
||||||
output := make(chan interface{})
|
output := make(chan interface{})
|
||||||
defer func() {
|
defer func() {
|
||||||
|
// reducer can only write once, if more, panic
|
||||||
for range output {
|
for range output {
|
||||||
panic("more than one element written in reducer")
|
panic("more than one element written in reducer")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// collector is used to collect data from mapper, and consume in reducer
|
||||||
collector := make(chan interface{}, options.workers)
|
collector := make(chan interface{}, options.workers)
|
||||||
|
// if done is closed, all mappers and reducer should stop processing
|
||||||
done := make(chan lang.PlaceholderType)
|
done := make(chan lang.PlaceholderType)
|
||||||
writer := newGuardedWriter(options.ctx, output, done)
|
writer := newGuardedWriter(options.ctx, output, done)
|
||||||
var closeOnce sync.Once
|
var closeOnce sync.Once
|
||||||
|
// use atomic.Value to avoid data race
|
||||||
var retErr errorx.AtomicError
|
var retErr errorx.AtomicError
|
||||||
finish := func() {
|
finish := func() {
|
||||||
closeOnce.Do(func() {
|
closeOnce.Do(func() {
|
||||||
@@ -151,30 +186,38 @@ func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer Reducer
|
|||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
drain(collector)
|
drain(collector)
|
||||||
|
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
cancel(fmt.Errorf("%v", r))
|
panicChan.write(r)
|
||||||
} else {
|
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
|
finish()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
reducer(collector, writer, cancel)
|
reducer(collector, writer, cancel)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go executeMappers(options.ctx, func(item interface{}, w Writer) {
|
go executeMappers(mapperContext{
|
||||||
|
ctx: options.ctx,
|
||||||
|
mapper: func(item interface{}, w Writer) {
|
||||||
mapper(item, w, cancel)
|
mapper(item, w, cancel)
|
||||||
}, source, collector, done, options.workers)
|
},
|
||||||
|
source: source,
|
||||||
|
panicChan: panicChan,
|
||||||
|
collector: collector,
|
||||||
|
doneChan: done,
|
||||||
|
workers: options.workers,
|
||||||
|
})
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-options.ctx.Done():
|
case <-options.ctx.Done():
|
||||||
cancel(context.DeadlineExceeded)
|
cancel(context.DeadlineExceeded)
|
||||||
return nil, context.DeadlineExceeded
|
return nil, context.DeadlineExceeded
|
||||||
case value, ok := <-output:
|
case v := <-panicChan.channel:
|
||||||
|
panic(v)
|
||||||
|
case v, ok := <-output:
|
||||||
if err := retErr.Load(); err != nil {
|
if err := retErr.Load(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if ok {
|
} else if ok {
|
||||||
return value, nil
|
return v, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, ErrReduceNoOutput
|
return nil, ErrReduceNoOutput
|
||||||
}
|
}
|
||||||
@@ -221,12 +264,18 @@ func buildOptions(opts ...Option) *mapReduceOptions {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSource(generate GenerateFunc) chan interface{} {
|
func buildSource(generate GenerateFunc, panicChan *onceChan) chan interface{} {
|
||||||
source := make(chan interface{})
|
source := make(chan interface{})
|
||||||
threading.GoSafe(func() {
|
go func() {
|
||||||
defer close(source)
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
panicChan.write(r)
|
||||||
|
}
|
||||||
|
close(source)
|
||||||
|
}()
|
||||||
|
|
||||||
generate(source)
|
generate(source)
|
||||||
})
|
}()
|
||||||
|
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
@@ -238,39 +287,43 @@ func drain(channel <-chan interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeMappers(ctx context.Context, mapper MapFunc, input <-chan interface{},
|
func executeMappers(mCtx mapperContext) {
|
||||||
collector chan<- interface{}, done <-chan lang.PlaceholderType, workers int) {
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
defer func() {
|
defer func() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(collector)
|
close(mCtx.collector)
|
||||||
|
drain(mCtx.source)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
pool := make(chan lang.PlaceholderType, workers)
|
var failed int32
|
||||||
writer := newGuardedWriter(ctx, collector, done)
|
pool := make(chan lang.PlaceholderType, mCtx.workers)
|
||||||
for {
|
writer := newGuardedWriter(mCtx.ctx, mCtx.collector, mCtx.doneChan)
|
||||||
|
for atomic.LoadInt32(&failed) == 0 {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-mCtx.ctx.Done():
|
||||||
return
|
return
|
||||||
case <-done:
|
case <-mCtx.doneChan:
|
||||||
return
|
return
|
||||||
case pool <- lang.Placeholder:
|
case pool <- lang.Placeholder:
|
||||||
item, ok := <-input
|
item, ok := <-mCtx.source
|
||||||
if !ok {
|
if !ok {
|
||||||
<-pool
|
<-pool
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
// better to safely run caller defined method
|
go func() {
|
||||||
threading.GoSafe(func() {
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
atomic.AddInt32(&failed, 1)
|
||||||
|
mCtx.panicChan.write(r)
|
||||||
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
<-pool
|
<-pool
|
||||||
}()
|
}()
|
||||||
|
|
||||||
mapper(item, writer)
|
mCtx.mapper(item, writer)
|
||||||
})
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,3 +369,16 @@ func (gw guardedWriter) Write(v interface{}) {
|
|||||||
gw.channel <- v
|
gw.channel <- v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type onceChan struct {
|
||||||
|
channel chan interface{}
|
||||||
|
wrote int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oc *onceChan) write(val interface{}) {
|
||||||
|
if atomic.AddInt32(&oc.wrote, 1) > 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oc.channel <- val
|
||||||
|
}
|
||||||
|
|||||||
78
core/mr/mapreduce_fuzz_test.go
Normal file
78
core/mr/mapreduce_fuzz_test.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package mr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.uber.org/goleak"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FuzzMapReduce(f *testing.F) {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
f.Add(uint(10), uint(runtime.NumCPU()))
|
||||||
|
f.Fuzz(func(t *testing.T, num uint, workers uint) {
|
||||||
|
n := int64(num)%5000 + 5000
|
||||||
|
genPanic := rand.Intn(100) == 0
|
||||||
|
mapperPanic := rand.Intn(100) == 0
|
||||||
|
reducerPanic := rand.Intn(100) == 0
|
||||||
|
genIdx := rand.Int63n(n)
|
||||||
|
mapperIdx := rand.Int63n(n)
|
||||||
|
reducerIdx := rand.Int63n(n)
|
||||||
|
squareSum := (n - 1) * n * (2*n - 1) / 6
|
||||||
|
|
||||||
|
fn := func() (interface{}, error) {
|
||||||
|
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
|
||||||
|
|
||||||
|
return MapReduce(func(source chan<- interface{}) {
|
||||||
|
for i := int64(0); i < n; i++ {
|
||||||
|
source <- i
|
||||||
|
if genPanic && i == genIdx {
|
||||||
|
panic("foo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
|
v := item.(int64)
|
||||||
|
if mapperPanic && v == mapperIdx {
|
||||||
|
panic("bar")
|
||||||
|
}
|
||||||
|
writer.Write(v * v)
|
||||||
|
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
|
var idx int64
|
||||||
|
var total int64
|
||||||
|
for v := range pipe {
|
||||||
|
if reducerPanic && idx == reducerIdx {
|
||||||
|
panic("baz")
|
||||||
|
}
|
||||||
|
total += v.(int64)
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
writer.Write(total)
|
||||||
|
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
|
||||||
|
}
|
||||||
|
|
||||||
|
if genPanic || mapperPanic || reducerPanic {
|
||||||
|
var buf strings.Builder
|
||||||
|
buf.WriteString(fmt.Sprintf("n: %d", n))
|
||||||
|
buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
|
||||||
|
buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
|
||||||
|
buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
|
||||||
|
buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
|
||||||
|
buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
|
||||||
|
buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
|
||||||
|
assert.Panicsf(t, func() { fn() }, buf.String())
|
||||||
|
} else {
|
||||||
|
val, err := fn()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, squareSum, val.(int64))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
107
core/mr/mapreduce_fuzzcase_test.go
Normal file
107
core/mr/mapreduce_fuzzcase_test.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
//go:build fuzz
|
||||||
|
// +build fuzz
|
||||||
|
|
||||||
|
package mr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/zeromicro/go-zero/core/threading"
|
||||||
|
"gopkg.in/cheggaaa/pb.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// If Fuzz stuck, we don't know why, because it only returns hung or unexpected,
|
||||||
|
// so we need to simulate the fuzz test in test mode.
|
||||||
|
func TestMapReduceRandom(t *testing.T) {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
const (
|
||||||
|
times = 10000
|
||||||
|
nRange = 500
|
||||||
|
mega = 1024 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
bar := pb.New(times).Start()
|
||||||
|
runner := threading.NewTaskRunner(runtime.NumCPU())
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(times)
|
||||||
|
for i := 0; i < times; i++ {
|
||||||
|
runner.Schedule(func() {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() {
|
||||||
|
if time.Since(start) > time.Minute {
|
||||||
|
t.Fatal("timeout")
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
n := rand.Int63n(nRange)%nRange + nRange
|
||||||
|
workers := rand.Int()%50 + runtime.NumCPU()/2
|
||||||
|
genPanic := rand.Intn(100) == 0
|
||||||
|
mapperPanic := rand.Intn(100) == 0
|
||||||
|
reducerPanic := rand.Intn(100) == 0
|
||||||
|
genIdx := rand.Int63n(n)
|
||||||
|
mapperIdx := rand.Int63n(n)
|
||||||
|
reducerIdx := rand.Int63n(n)
|
||||||
|
squareSum := (n - 1) * n * (2*n - 1) / 6
|
||||||
|
|
||||||
|
fn := func() (interface{}, error) {
|
||||||
|
return MapReduce(func(source chan<- interface{}) {
|
||||||
|
for i := int64(0); i < n; i++ {
|
||||||
|
source <- i
|
||||||
|
if genPanic && i == genIdx {
|
||||||
|
panic("foo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
|
v := item.(int64)
|
||||||
|
if mapperPanic && v == mapperIdx {
|
||||||
|
panic("bar")
|
||||||
|
}
|
||||||
|
writer.Write(v * v)
|
||||||
|
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
|
var idx int64
|
||||||
|
var total int64
|
||||||
|
for v := range pipe {
|
||||||
|
if reducerPanic && idx == reducerIdx {
|
||||||
|
panic("baz")
|
||||||
|
}
|
||||||
|
total += v.(int64)
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
writer.Write(total)
|
||||||
|
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
|
||||||
|
}
|
||||||
|
|
||||||
|
if genPanic || mapperPanic || reducerPanic {
|
||||||
|
var buf strings.Builder
|
||||||
|
buf.WriteString(fmt.Sprintf("n: %d", n))
|
||||||
|
buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
|
||||||
|
buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
|
||||||
|
buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
|
||||||
|
buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
|
||||||
|
buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
|
||||||
|
buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
|
||||||
|
assert.Panicsf(t, func() { fn() }, buf.String())
|
||||||
|
} else {
|
||||||
|
val, err := fn()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, squareSum, val.(int64))
|
||||||
|
}
|
||||||
|
bar.Increment()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
bar.Finish()
|
||||||
|
}
|
||||||
@@ -11,8 +11,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/zeromicro/go-zero/core/stringx"
|
|
||||||
"github.com/zeromicro/go-zero/core/syncx"
|
|
||||||
"go.uber.org/goleak"
|
"go.uber.org/goleak"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -124,6 +122,7 @@ func TestForEach(t *testing.T) {
|
|||||||
t.Run("all", func(t *testing.T) {
|
t.Run("all", func(t *testing.T) {
|
||||||
defer goleak.VerifyNone(t)
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
|
assert.PanicsWithValue(t, "foo", func() {
|
||||||
ForEach(func(source chan<- interface{}) {
|
ForEach(func(source chan<- interface{}) {
|
||||||
for i := 0; i < tasks; i++ {
|
for i := 0; i < tasks; i++ {
|
||||||
source <- i
|
source <- i
|
||||||
@@ -132,76 +131,60 @@ func TestForEach(t *testing.T) {
|
|||||||
panic("foo")
|
panic("foo")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
func TestMap(t *testing.T) {
|
|
||||||
defer goleak.VerifyNone(t)
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
mapper MapFunc
|
|
||||||
expect int
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
mapper: func(item interface{}, writer Writer) {
|
|
||||||
v := item.(int)
|
|
||||||
writer.Write(v * v)
|
|
||||||
},
|
|
||||||
expect: 30,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mapper: func(item interface{}, writer Writer) {
|
|
||||||
v := item.(int)
|
|
||||||
if v%2 == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writer.Write(v * v)
|
|
||||||
},
|
|
||||||
expect: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mapper: func(item interface{}, writer Writer) {
|
|
||||||
v := item.(int)
|
|
||||||
if v%2 == 0 {
|
|
||||||
panic(v)
|
|
||||||
}
|
|
||||||
writer.Write(v * v)
|
|
||||||
},
|
|
||||||
expect: 10,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(stringx.Rand(), func(t *testing.T) {
|
|
||||||
channel := Map(func(source chan<- interface{}) {
|
|
||||||
for i := 1; i < 5; i++ {
|
|
||||||
source <- i
|
|
||||||
}
|
|
||||||
}, test.mapper, WithWorkers(-1))
|
|
||||||
|
|
||||||
var result int
|
|
||||||
for v := range channel {
|
|
||||||
result += v.(int)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, test.expect, result)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGeneratePanic(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
|
t.Run("all", func(t *testing.T) {
|
||||||
|
assert.PanicsWithValue(t, "foo", func() {
|
||||||
|
ForEach(func(source chan<- interface{}) {
|
||||||
|
panic("foo")
|
||||||
|
}, func(item interface{}) {
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapperPanic(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
|
const tasks = 1000
|
||||||
|
var run int32
|
||||||
|
t.Run("all", func(t *testing.T) {
|
||||||
|
assert.PanicsWithValue(t, "foo", func() {
|
||||||
|
_, _ = MapReduce(func(source chan<- interface{}) {
|
||||||
|
for i := 0; i < tasks; i++ {
|
||||||
|
source <- i
|
||||||
|
}
|
||||||
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
|
atomic.AddInt32(&run, 1)
|
||||||
|
panic("foo")
|
||||||
|
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
|
})
|
||||||
|
})
|
||||||
|
assert.True(t, atomic.LoadInt32(&run) < tasks/2)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapReduce(t *testing.T) {
|
func TestMapReduce(t *testing.T) {
|
||||||
defer goleak.VerifyNone(t)
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
name string
|
||||||
mapper MapperFunc
|
mapper MapperFunc
|
||||||
reducer ReducerFunc
|
reducer ReducerFunc
|
||||||
expectErr error
|
expectErr error
|
||||||
expectValue interface{}
|
expectValue interface{}
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
name: "simple",
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
expectValue: 30,
|
expectValue: 30,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "cancel with error",
|
||||||
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
v := item.(int)
|
v := item.(int)
|
||||||
if v%3 == 0 {
|
if v%3 == 0 {
|
||||||
@@ -212,6 +195,7 @@ func TestMapReduce(t *testing.T) {
|
|||||||
expectErr: errDummy,
|
expectErr: errDummy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "cancel with nil",
|
||||||
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
v := item.(int)
|
v := item.(int)
|
||||||
if v%3 == 0 {
|
if v%3 == 0 {
|
||||||
@@ -223,6 +207,7 @@ func TestMapReduce(t *testing.T) {
|
|||||||
expectValue: nil,
|
expectValue: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "cancel with more",
|
||||||
reducer: func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
reducer: func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
var result int
|
var result int
|
||||||
for item := range pipe {
|
for item := range pipe {
|
||||||
@@ -237,8 +222,9 @@ func TestMapReduce(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Run("MapReduce", func(t *testing.T) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(stringx.Rand(), func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
if test.mapper == nil {
|
if test.mapper == nil {
|
||||||
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
|
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
v := item.(int)
|
v := item.(int)
|
||||||
@@ -264,18 +250,40 @@ func TestMapReduce(t *testing.T) {
|
|||||||
assert.Equal(t, test.expectValue, value)
|
assert.Equal(t, test.expectValue, value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("MapReduce", func(t *testing.T) {
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
if test.mapper == nil {
|
||||||
|
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
|
v := item.(int)
|
||||||
|
writer.Write(v * v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if test.reducer == nil {
|
||||||
|
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
|
var result int
|
||||||
|
for item := range pipe {
|
||||||
|
result += item.(int)
|
||||||
|
}
|
||||||
|
writer.Write(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapReducePanicBothMapperAndReducer(t *testing.T) {
|
source := make(chan interface{})
|
||||||
defer goleak.VerifyNone(t)
|
go func() {
|
||||||
|
for i := 1; i < 5; i++ {
|
||||||
|
source <- i
|
||||||
|
}
|
||||||
|
close(source)
|
||||||
|
}()
|
||||||
|
|
||||||
_, _ = MapReduce(func(source chan<- interface{}) {
|
value, err := MapReduceChan(source, test.mapper, test.reducer, WithWorkers(-1))
|
||||||
source <- 0
|
assert.Equal(t, test.expectErr, err)
|
||||||
source <- 1
|
assert.Equal(t, test.expectValue, value)
|
||||||
}, func(item interface{}, writer Writer, cancel func(error)) {
|
})
|
||||||
panic("foo")
|
}
|
||||||
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
|
||||||
panic("bar")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,16 +310,19 @@ func TestMapReduceVoid(t *testing.T) {
|
|||||||
|
|
||||||
var value uint32
|
var value uint32
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
name string
|
||||||
mapper MapperFunc
|
mapper MapperFunc
|
||||||
reducer VoidReducerFunc
|
reducer VoidReducerFunc
|
||||||
expectValue uint32
|
expectValue uint32
|
||||||
expectErr error
|
expectErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
name: "simple",
|
||||||
expectValue: 30,
|
expectValue: 30,
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "cancel with error",
|
||||||
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
v := item.(int)
|
v := item.(int)
|
||||||
if v%3 == 0 {
|
if v%3 == 0 {
|
||||||
@@ -322,6 +333,7 @@ func TestMapReduceVoid(t *testing.T) {
|
|||||||
expectErr: errDummy,
|
expectErr: errDummy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "cancel with nil",
|
||||||
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
mapper: func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
v := item.(int)
|
v := item.(int)
|
||||||
if v%3 == 0 {
|
if v%3 == 0 {
|
||||||
@@ -332,6 +344,7 @@ func TestMapReduceVoid(t *testing.T) {
|
|||||||
expectErr: ErrCancelWithNil,
|
expectErr: ErrCancelWithNil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: "cancel with more",
|
||||||
reducer: func(pipe <-chan interface{}, cancel func(error)) {
|
reducer: func(pipe <-chan interface{}, cancel func(error)) {
|
||||||
for item := range pipe {
|
for item := range pipe {
|
||||||
result := atomic.AddUint32(&value, uint32(item.(int)))
|
result := atomic.AddUint32(&value, uint32(item.(int)))
|
||||||
@@ -345,7 +358,7 @@ func TestMapReduceVoid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(stringx.Rand(), func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
atomic.StoreUint32(&value, 0)
|
atomic.StoreUint32(&value, 0)
|
||||||
|
|
||||||
if test.mapper == nil {
|
if test.mapper == nil {
|
||||||
@@ -400,26 +413,11 @@ func TestMapReduceVoidWithDelay(t *testing.T) {
|
|||||||
assert.Equal(t, 0, result[1])
|
assert.Equal(t, 0, result[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapVoid(t *testing.T) {
|
|
||||||
defer goleak.VerifyNone(t)
|
|
||||||
|
|
||||||
const tasks = 1000
|
|
||||||
var count uint32
|
|
||||||
ForEach(func(source chan<- interface{}) {
|
|
||||||
for i := 0; i < tasks; i++ {
|
|
||||||
source <- i
|
|
||||||
}
|
|
||||||
}, func(item interface{}) {
|
|
||||||
atomic.AddUint32(&count, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Equal(t, tasks, int(count))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMapReducePanic(t *testing.T) {
|
func TestMapReducePanic(t *testing.T) {
|
||||||
defer goleak.VerifyNone(t)
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
v, err := MapReduce(func(source chan<- interface{}) {
|
assert.Panics(t, func() {
|
||||||
|
_, _ = MapReduce(func(source chan<- interface{}) {
|
||||||
source <- 0
|
source <- 0
|
||||||
source <- 1
|
source <- 1
|
||||||
}, func(item interface{}, writer Writer, cancel func(error)) {
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
@@ -430,9 +428,44 @@ func TestMapReducePanic(t *testing.T) {
|
|||||||
panic("panic")
|
panic("panic")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
assert.Nil(t, v)
|
})
|
||||||
assert.NotNil(t, err)
|
}
|
||||||
assert.Equal(t, "panic", err.Error())
|
|
||||||
|
func TestMapReducePanicOnce(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
|
assert.Panics(t, func() {
|
||||||
|
_, _ = MapReduce(func(source chan<- interface{}) {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
source <- i
|
||||||
|
}
|
||||||
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
|
i := item.(int)
|
||||||
|
if i == 0 {
|
||||||
|
panic("foo")
|
||||||
|
}
|
||||||
|
writer.Write(i)
|
||||||
|
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
|
for range pipe {
|
||||||
|
panic("bar")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapReducePanicBothMapperAndReducer(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
|
assert.Panics(t, func() {
|
||||||
|
_, _ = MapReduce(func(source chan<- interface{}) {
|
||||||
|
source <- 0
|
||||||
|
source <- 1
|
||||||
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
|
panic("foo")
|
||||||
|
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
|
||||||
|
panic("bar")
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapReduceVoidCancel(t *testing.T) {
|
func TestMapReduceVoidCancel(t *testing.T) {
|
||||||
@@ -461,13 +494,13 @@ func TestMapReduceVoidCancel(t *testing.T) {
|
|||||||
func TestMapReduceVoidCancelWithRemains(t *testing.T) {
|
func TestMapReduceVoidCancelWithRemains(t *testing.T) {
|
||||||
defer goleak.VerifyNone(t)
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
var done syncx.AtomicBool
|
var done int32
|
||||||
var result []int
|
var result []int
|
||||||
err := MapReduceVoid(func(source chan<- interface{}) {
|
err := MapReduceVoid(func(source chan<- interface{}) {
|
||||||
for i := 0; i < defaultWorkers*2; i++ {
|
for i := 0; i < defaultWorkers*2; i++ {
|
||||||
source <- i
|
source <- i
|
||||||
}
|
}
|
||||||
done.Set(true)
|
atomic.AddInt32(&done, 1)
|
||||||
}, func(item interface{}, writer Writer, cancel func(error)) {
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
i := item.(int)
|
i := item.(int)
|
||||||
if i == defaultWorkers/2 {
|
if i == defaultWorkers/2 {
|
||||||
@@ -482,7 +515,7 @@ func TestMapReduceVoidCancelWithRemains(t *testing.T) {
|
|||||||
})
|
})
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
assert.Equal(t, "anything", err.Error())
|
assert.Equal(t, "anything", err.Error())
|
||||||
assert.True(t, done.True())
|
assert.Equal(t, int32(1), done)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapReduceWithoutReducerWrite(t *testing.T) {
|
func TestMapReduceWithoutReducerWrite(t *testing.T) {
|
||||||
@@ -507,34 +540,51 @@ func TestMapReduceVoidPanicInReducer(t *testing.T) {
|
|||||||
defer goleak.VerifyNone(t)
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
const message = "foo"
|
const message = "foo"
|
||||||
var done syncx.AtomicBool
|
assert.Panics(t, func() {
|
||||||
err := MapReduceVoid(func(source chan<- interface{}) {
|
var done int32
|
||||||
|
_ = MapReduceVoid(func(source chan<- interface{}) {
|
||||||
for i := 0; i < defaultWorkers*2; i++ {
|
for i := 0; i < defaultWorkers*2; i++ {
|
||||||
source <- i
|
source <- i
|
||||||
}
|
}
|
||||||
done.Set(true)
|
atomic.AddInt32(&done, 1)
|
||||||
}, func(item interface{}, writer Writer, cancel func(error)) {
|
}, func(item interface{}, writer Writer, cancel func(error)) {
|
||||||
i := item.(int)
|
i := item.(int)
|
||||||
writer.Write(i)
|
writer.Write(i)
|
||||||
}, func(pipe <-chan interface{}, cancel func(error)) {
|
}, func(pipe <-chan interface{}, cancel func(error)) {
|
||||||
panic(message)
|
panic(message)
|
||||||
}, WithWorkers(1))
|
}, WithWorkers(1))
|
||||||
assert.NotNil(t, err)
|
})
|
||||||
assert.Equal(t, message, err.Error())
|
}
|
||||||
assert.True(t, done.True())
|
|
||||||
|
func TestForEachWithContext(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
|
var done int32
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
ForEach(func(source chan<- interface{}) {
|
||||||
|
for i := 0; i < defaultWorkers*2; i++ {
|
||||||
|
source <- i
|
||||||
|
}
|
||||||
|
atomic.AddInt32(&done, 1)
|
||||||
|
}, func(item interface{}) {
|
||||||
|
i := item.(int)
|
||||||
|
if i == defaultWorkers/2 {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}, WithContext(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapReduceWithContext(t *testing.T) {
|
func TestMapReduceWithContext(t *testing.T) {
|
||||||
defer goleak.VerifyNone(t)
|
defer goleak.VerifyNone(t)
|
||||||
|
|
||||||
var done syncx.AtomicBool
|
var done int32
|
||||||
var result []int
|
var result []int
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
err := MapReduceVoid(func(source chan<- interface{}) {
|
err := MapReduceVoid(func(source chan<- interface{}) {
|
||||||
for i := 0; i < defaultWorkers*2; i++ {
|
for i := 0; i < defaultWorkers*2; i++ {
|
||||||
source <- i
|
source <- i
|
||||||
}
|
}
|
||||||
done.Set(true)
|
atomic.AddInt32(&done, 1)
|
||||||
}, func(item interface{}, writer Writer, c func(error)) {
|
}, func(item interface{}, writer Writer, c func(error)) {
|
||||||
i := item.(int)
|
i := item.(int)
|
||||||
if i == defaultWorkers/2 {
|
if i == defaultWorkers/2 {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/mr"
|
"github.com/zeromicro/go-zero/core/mr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/mr"
|
"github.com/zeromicro/go-zero/core/mr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
// +build linux darwin
|
||||||
|
|
||||||
package proc
|
package proc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
30
core/prof/runtime.go
Normal file
30
core/prof/runtime.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package prof
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultInterval = time.Second * 5
|
||||||
|
mega = 1024 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
func DisplayStats(interval ...time.Duration) {
|
||||||
|
duration := defaultInterval
|
||||||
|
for _, val := range interval {
|
||||||
|
duration = val
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(duration)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for range ticker.C {
|
||||||
|
var m runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&m)
|
||||||
|
fmt.Printf("Goroutines: %d, Alloc: %vm, TotalAlloc: %vm, Sys: %vm, NumGC: %v\n",
|
||||||
|
runtime.NumGoroutine(), m.Alloc/mega, m.TotalAlloc/mega, m.Sys/mega, m.NumGC)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
104
core/stores/cache/cache.go
vendored
104
core/stores/cache/cache.go
vendored
@@ -1,6 +1,8 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
@@ -13,13 +15,37 @@ import (
|
|||||||
type (
|
type (
|
||||||
// Cache interface is used to define the cache implementation.
|
// Cache interface is used to define the cache implementation.
|
||||||
Cache interface {
|
Cache interface {
|
||||||
|
// Del deletes cached values with keys.
|
||||||
Del(keys ...string) error
|
Del(keys ...string) error
|
||||||
Get(key string, v interface{}) error
|
// DelCtx deletes cached values with keys.
|
||||||
|
DelCtx(ctx context.Context, keys ...string) error
|
||||||
|
// Get gets the cache with key and fills into v.
|
||||||
|
Get(key string, val interface{}) error
|
||||||
|
// GetCtx gets the cache with key and fills into v.
|
||||||
|
GetCtx(ctx context.Context, key string, val interface{}) error
|
||||||
|
// IsNotFound checks if the given error is the defined errNotFound.
|
||||||
IsNotFound(err error) bool
|
IsNotFound(err error) bool
|
||||||
Set(key string, v interface{}) error
|
// Set sets the cache with key and v, using c.expiry.
|
||||||
SetWithExpire(key string, v interface{}, expire time.Duration) error
|
Set(key string, val interface{}) error
|
||||||
Take(v interface{}, key string, query func(v interface{}) error) error
|
// SetCtx sets the cache with key and v, using c.expiry.
|
||||||
TakeWithExpire(v interface{}, key string, query func(v interface{}, expire time.Duration) error) error
|
SetCtx(ctx context.Context, key string, val interface{}) error
|
||||||
|
// SetWithExpire sets the cache with key and v, using given expire.
|
||||||
|
SetWithExpire(key string, val interface{}, expire time.Duration) error
|
||||||
|
// SetWithExpireCtx sets the cache with key and v, using given expire.
|
||||||
|
SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error
|
||||||
|
// Take takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using c.expiry, then return the result.
|
||||||
|
Take(val interface{}, key string, query func(val interface{}) error) error
|
||||||
|
// TakeCtx takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using c.expiry, then return the result.
|
||||||
|
TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error
|
||||||
|
// TakeWithExpire takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using given expire, then return the result.
|
||||||
|
TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error
|
||||||
|
// TakeWithExpireCtx takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using given expire, then return the result.
|
||||||
|
TakeWithExpireCtx(ctx context.Context, val interface{}, key string,
|
||||||
|
query func(val interface{}, expire time.Duration) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheCluster struct {
|
cacheCluster struct {
|
||||||
@@ -51,7 +77,13 @@ func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Del deletes cached values with keys.
|
||||||
func (cc cacheCluster) Del(keys ...string) error {
|
func (cc cacheCluster) Del(keys ...string) error {
|
||||||
|
return cc.DelCtx(context.Background(), keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelCtx deletes cached values with keys.
|
||||||
|
func (cc cacheCluster) DelCtx(ctx context.Context, keys ...string) error {
|
||||||
switch len(keys) {
|
switch len(keys) {
|
||||||
case 0:
|
case 0:
|
||||||
return nil
|
return nil
|
||||||
@@ -62,7 +94,7 @@ func (cc cacheCluster) Del(keys ...string) error {
|
|||||||
return cc.errNotFound
|
return cc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.(Cache).Del(key)
|
return c.(Cache).DelCtx(ctx, key)
|
||||||
default:
|
default:
|
||||||
var be errorx.BatchError
|
var be errorx.BatchError
|
||||||
nodes := make(map[interface{}][]string)
|
nodes := make(map[interface{}][]string)
|
||||||
@@ -76,7 +108,7 @@ func (cc cacheCluster) Del(keys ...string) error {
|
|||||||
nodes[c] = append(nodes[c], key)
|
nodes[c] = append(nodes[c], key)
|
||||||
}
|
}
|
||||||
for c, ks := range nodes {
|
for c, ks := range nodes {
|
||||||
if err := c.(Cache).Del(ks...); err != nil {
|
if err := c.(Cache).DelCtx(ctx, ks...); err != nil {
|
||||||
be.Add(err)
|
be.Add(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,52 +117,86 @@ func (cc cacheCluster) Del(keys ...string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc cacheCluster) Get(key string, v interface{}) error {
|
// Get gets the cache with key and fills into v.
|
||||||
|
func (cc cacheCluster) Get(key string, val interface{}) error {
|
||||||
|
return cc.GetCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCtx gets the cache with key and fills into v.
|
||||||
|
func (cc cacheCluster) GetCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
c, ok := cc.dispatcher.Get(key)
|
c, ok := cc.dispatcher.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return cc.errNotFound
|
return cc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.(Cache).Get(key, v)
|
return c.(Cache).GetCtx(ctx, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNotFound checks if the given error is the defined errNotFound.
|
||||||
func (cc cacheCluster) IsNotFound(err error) bool {
|
func (cc cacheCluster) IsNotFound(err error) bool {
|
||||||
return err == cc.errNotFound
|
return errors.Is(err, cc.errNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc cacheCluster) Set(key string, v interface{}) error {
|
// Set sets the cache with key and v, using c.expiry.
|
||||||
|
func (cc cacheCluster) Set(key string, val interface{}) error {
|
||||||
|
return cc.SetCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCtx sets the cache with key and v, using c.expiry.
|
||||||
|
func (cc cacheCluster) SetCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
c, ok := cc.dispatcher.Get(key)
|
c, ok := cc.dispatcher.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return cc.errNotFound
|
return cc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.(Cache).Set(key, v)
|
return c.(Cache).SetCtx(ctx, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc cacheCluster) SetWithExpire(key string, v interface{}, expire time.Duration) error {
|
// SetWithExpire sets the cache with key and v, using given expire.
|
||||||
|
func (cc cacheCluster) SetWithExpire(key string, val interface{}, expire time.Duration) error {
|
||||||
|
return cc.SetWithExpireCtx(context.Background(), key, val, expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWithExpireCtx sets the cache with key and v, using given expire.
|
||||||
|
func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
|
||||||
c, ok := cc.dispatcher.Get(key)
|
c, ok := cc.dispatcher.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return cc.errNotFound
|
return cc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.(Cache).SetWithExpire(key, v, expire)
|
return c.(Cache).SetWithExpireCtx(ctx, key, val, expire)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc cacheCluster) Take(v interface{}, key string, query func(v interface{}) error) error {
|
// Take takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using c.expiry, then return the result.
|
||||||
|
func (cc cacheCluster) Take(val interface{}, key string, query func(val interface{}) error) error {
|
||||||
|
return cc.TakeCtx(context.Background(), val, key, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TakeCtx takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using c.expiry, then return the result.
|
||||||
|
func (cc cacheCluster) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
|
||||||
c, ok := cc.dispatcher.Get(key)
|
c, ok := cc.dispatcher.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return cc.errNotFound
|
return cc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.(Cache).Take(v, key, query)
|
return c.(Cache).TakeCtx(ctx, val, key, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc cacheCluster) TakeWithExpire(v interface{}, key string,
|
// TakeWithExpire takes the result from cache first, if not found,
|
||||||
query func(v interface{}, expire time.Duration) error) error {
|
// query from DB and set cache using given expire, then return the result.
|
||||||
|
func (cc cacheCluster) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
|
||||||
|
return cc.TakeWithExpireCtx(context.Background(), val, key, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TakeWithExpireCtx takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using given expire, then return the result.
|
||||||
|
func (cc cacheCluster) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
|
||||||
c, ok := cc.dispatcher.Get(key)
|
c, ok := cc.dispatcher.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return cc.errNotFound
|
return cc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.(Cache).TakeWithExpire(v, key, query)
|
return c.(Cache).TakeWithExpireCtx(ctx, val, key, query)
|
||||||
}
|
}
|
||||||
|
|||||||
102
core/stores/cache/cache_test.go
vendored
102
core/stores/cache/cache_test.go
vendored
@@ -1,7 +1,9 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -16,12 +18,18 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/syncx"
|
"github.com/zeromicro/go-zero/core/syncx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ Cache = (*mockedNode)(nil)
|
||||||
|
|
||||||
type mockedNode struct {
|
type mockedNode struct {
|
||||||
vals map[string][]byte
|
vals map[string][]byte
|
||||||
errNotFound error
|
errNotFound error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) Del(keys ...string) error {
|
func (mc *mockedNode) Del(keys ...string) error {
|
||||||
|
return mc.DelCtx(context.Background(), keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockedNode) DelCtx(_ context.Context, keys ...string) error {
|
||||||
var be errorx.BatchError
|
var be errorx.BatchError
|
||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
@@ -35,21 +43,29 @@ func (mc *mockedNode) Del(keys ...string) error {
|
|||||||
return be.Err()
|
return be.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) Get(key string, v interface{}) error {
|
func (mc *mockedNode) Get(key string, val interface{}) error {
|
||||||
|
return mc.GetCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockedNode) GetCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
bs, ok := mc.vals[key]
|
bs, ok := mc.vals[key]
|
||||||
if ok {
|
if ok {
|
||||||
return json.Unmarshal(bs, v)
|
return json.Unmarshal(bs, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mc.errNotFound
|
return mc.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) IsNotFound(err error) bool {
|
func (mc *mockedNode) IsNotFound(err error) bool {
|
||||||
return err == mc.errNotFound
|
return errors.Is(err, mc.errNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) Set(key string, v interface{}) error {
|
func (mc *mockedNode) Set(key string, val interface{}) error {
|
||||||
data, err := json.Marshal(v)
|
return mc.SetCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockedNode) SetCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
|
data, err := json.Marshal(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -58,25 +74,37 @@ func (mc *mockedNode) Set(key string, v interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) SetWithExpire(key string, v interface{}, expire time.Duration) error {
|
func (mc *mockedNode) SetWithExpire(key string, val interface{}, expire time.Duration) error {
|
||||||
return mc.Set(key, v)
|
return mc.SetWithExpireCtx(context.Background(), key, val, expire)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) Take(v interface{}, key string, query func(v interface{}) error) error {
|
func (mc *mockedNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
|
||||||
|
return mc.Set(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockedNode) Take(val interface{}, key string, query func(val interface{}) error) error {
|
||||||
|
return mc.TakeCtx(context.Background(), val, key, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockedNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
|
||||||
if _, ok := mc.vals[key]; ok {
|
if _, ok := mc.vals[key]; ok {
|
||||||
return mc.Get(key, v)
|
return mc.GetCtx(ctx, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := query(v); err != nil {
|
if err := query(val); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return mc.Set(key, v)
|
return mc.SetCtx(ctx, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mockedNode) TakeWithExpire(v interface{}, key string, query func(v interface{}, expire time.Duration) error) error {
|
func (mc *mockedNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
|
||||||
return mc.Take(v, key, func(v interface{}) error {
|
return mc.TakeWithExpireCtx(context.Background(), val, key, query)
|
||||||
return query(v, 0)
|
}
|
||||||
|
|
||||||
|
func (mc *mockedNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
|
||||||
|
return mc.Take(val, key, func(val interface{}) error {
|
||||||
|
return query(val, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,18 +141,18 @@ func TestCache_SetDel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
var v int
|
var val int
|
||||||
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &v))
|
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &val))
|
||||||
assert.Equal(t, i, v)
|
assert.Equal(t, i, val)
|
||||||
}
|
}
|
||||||
assert.Nil(t, c.Del())
|
assert.Nil(t, c.Del())
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
|
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
|
||||||
}
|
}
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
var v int
|
var val int
|
||||||
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &v)))
|
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &val)))
|
||||||
assert.Equal(t, 0, v)
|
assert.Equal(t, 0, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,18 +179,18 @@ func TestCache_OneNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
var v int
|
var val int
|
||||||
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &v))
|
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &val))
|
||||||
assert.Equal(t, i, v)
|
assert.Equal(t, i, val)
|
||||||
}
|
}
|
||||||
assert.Nil(t, c.Del())
|
assert.Nil(t, c.Del())
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
|
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
|
||||||
}
|
}
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
var v int
|
var val int
|
||||||
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &v)))
|
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &val)))
|
||||||
assert.Equal(t, 0, v)
|
assert.Equal(t, 0, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,9 +230,9 @@ func TestCache_Balance(t *testing.T) {
|
|||||||
assert.True(t, entropy > .95, fmt.Sprintf("entropy should be greater than 0.95, but got %.2f", entropy))
|
assert.True(t, entropy > .95, fmt.Sprintf("entropy should be greater than 0.95, but got %.2f", entropy))
|
||||||
|
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
var v int
|
var val int
|
||||||
assert.Nil(t, c.Get(strconv.Itoa(i), &v))
|
assert.Nil(t, c.Get(strconv.Itoa(i), &val))
|
||||||
assert.Equal(t, i, v)
|
assert.Equal(t, i, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < total/10; i++ {
|
for i := 0; i < total/10; i++ {
|
||||||
@@ -216,14 +244,14 @@ func TestCache_Balance(t *testing.T) {
|
|||||||
for i := 0; i < total/10; i++ {
|
for i := 0; i < total/10; i++ {
|
||||||
var val int
|
var val int
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(v interface{}) error {
|
assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(val interface{}) error {
|
||||||
*v.(*int) = i
|
*val.(*int) = i
|
||||||
count++
|
count++
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(v interface{}, expire time.Duration) error {
|
assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(val interface{}, expire time.Duration) error {
|
||||||
*v.(*int) = i
|
*val.(*int) = i
|
||||||
count++
|
count++
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
@@ -244,10 +272,10 @@ func TestCacheNoNode(t *testing.T) {
|
|||||||
assert.NotNil(t, c.Get("foo", nil))
|
assert.NotNil(t, c.Get("foo", nil))
|
||||||
assert.NotNil(t, c.Set("foo", nil))
|
assert.NotNil(t, c.Set("foo", nil))
|
||||||
assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second))
|
assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second))
|
||||||
assert.NotNil(t, c.Take(nil, "foo", func(v interface{}) error {
|
assert.NotNil(t, c.Take(nil, "foo", func(val interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(v interface{}, duration time.Duration) error {
|
assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(val interface{}, duration time.Duration) error {
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -255,8 +283,8 @@ func TestCacheNoNode(t *testing.T) {
|
|||||||
func calcEntropy(m map[int]int, total int) float64 {
|
func calcEntropy(m map[int]int, total int) float64 {
|
||||||
var entropy float64
|
var entropy float64
|
||||||
|
|
||||||
for _, v := range m {
|
for _, val := range m {
|
||||||
proba := float64(v) / float64(total)
|
proba := float64(val) / float64(total)
|
||||||
entropy -= proba * math.Log2(proba)
|
entropy -= proba * math.Log2(proba)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
105
core/stores/cache/cachenode.go
vendored
105
core/stores/cache/cachenode.go
vendored
@@ -1,6 +1,7 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -61,30 +62,39 @@ func NewNode(rds *redis.Redis, barrier syncx.SingleFlight, st *Stat,
|
|||||||
|
|
||||||
// Del deletes cached values with keys.
|
// Del deletes cached values with keys.
|
||||||
func (c cacheNode) Del(keys ...string) error {
|
func (c cacheNode) Del(keys ...string) error {
|
||||||
|
return c.DelCtx(context.Background(), keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelCtx deletes cached values with keys.
|
||||||
|
func (c cacheNode) DelCtx(ctx context.Context, keys ...string) error {
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger := logx.WithContext(ctx)
|
||||||
if len(keys) > 1 && c.rds.Type == redis.ClusterType {
|
if len(keys) > 1 && c.rds.Type == redis.ClusterType {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if _, err := c.rds.Del(key); err != nil {
|
if _, err := c.rds.DelCtx(ctx, key); err != nil {
|
||||||
logx.Errorf("failed to clear cache with key: %q, error: %v", key, err)
|
logger.Errorf("failed to clear cache with key: %q, error: %v", key, err)
|
||||||
c.asyncRetryDelCache(key)
|
c.asyncRetryDelCache(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if _, err := c.rds.DelCtx(ctx, keys...); err != nil {
|
||||||
if _, err := c.rds.Del(keys...); err != nil {
|
logger.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err)
|
||||||
logx.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err)
|
|
||||||
c.asyncRetryDelCache(keys...)
|
c.asyncRetryDelCache(keys...)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get gets the cache with key and fills into v.
|
// Get gets the cache with key and fills into v.
|
||||||
func (c cacheNode) Get(key string, v interface{}) error {
|
func (c cacheNode) Get(key string, val interface{}) error {
|
||||||
err := c.doGetCache(key, v)
|
return c.GetCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCtx gets the cache with key and fills into v.
|
||||||
|
func (c cacheNode) GetCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
|
err := c.doGetCache(ctx, key, val)
|
||||||
if err == errPlaceholder {
|
if err == errPlaceholder {
|
||||||
return c.errNotFound
|
return c.errNotFound
|
||||||
}
|
}
|
||||||
@@ -94,22 +104,32 @@ func (c cacheNode) Get(key string, v interface{}) error {
|
|||||||
|
|
||||||
// IsNotFound checks if the given error is the defined errNotFound.
|
// IsNotFound checks if the given error is the defined errNotFound.
|
||||||
func (c cacheNode) IsNotFound(err error) bool {
|
func (c cacheNode) IsNotFound(err error) bool {
|
||||||
return err == c.errNotFound
|
return errors.Is(err, c.errNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the cache with key and v, using c.expiry.
|
// Set sets the cache with key and v, using c.expiry.
|
||||||
func (c cacheNode) Set(key string, v interface{}) error {
|
func (c cacheNode) Set(key string, val interface{}) error {
|
||||||
return c.SetWithExpire(key, v, c.aroundDuration(c.expiry))
|
return c.SetCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCtx sets the cache with key and v, using c.expiry.
|
||||||
|
func (c cacheNode) SetCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
|
return c.SetWithExpireCtx(ctx, key, val, c.aroundDuration(c.expiry))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWithExpire sets the cache with key and v, using given expire.
|
// SetWithExpire sets the cache with key and v, using given expire.
|
||||||
func (c cacheNode) SetWithExpire(key string, v interface{}, expire time.Duration) error {
|
func (c cacheNode) SetWithExpire(key string, val interface{}, expire time.Duration) error {
|
||||||
data, err := jsonx.Marshal(v)
|
return c.SetWithExpireCtx(context.Background(), key, val, expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWithExpireCtx sets the cache with key and v, using given expire.
|
||||||
|
func (c cacheNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
|
||||||
|
data, err := jsonx.Marshal(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.rds.Setex(key, string(data), int(expire.Seconds()))
|
return c.rds.SetexCtx(ctx, key, string(data), int(expire.Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string that represents the cacheNode.
|
// String returns a string that represents the cacheNode.
|
||||||
@@ -119,21 +139,32 @@ func (c cacheNode) String() string {
|
|||||||
|
|
||||||
// Take takes the result from cache first, if not found,
|
// Take takes the result from cache first, if not found,
|
||||||
// query from DB and set cache using c.expiry, then return the result.
|
// query from DB and set cache using c.expiry, then return the result.
|
||||||
func (c cacheNode) Take(v interface{}, key string, query func(v interface{}) error) error {
|
func (c cacheNode) Take(val interface{}, key string, query func(val interface{}) error) error {
|
||||||
return c.doTake(v, key, query, func(v interface{}) error {
|
return c.TakeCtx(context.Background(), val, key, query)
|
||||||
return c.Set(key, v)
|
}
|
||||||
|
|
||||||
|
// TakeCtx takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using c.expiry, then return the result.
|
||||||
|
func (c cacheNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
|
||||||
|
return c.doTake(ctx, val, key, query, func(v interface{}) error {
|
||||||
|
return c.SetCtx(ctx, key, v)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TakeWithExpire takes the result from cache first, if not found,
|
// TakeWithExpire takes the result from cache first, if not found,
|
||||||
// query from DB and set cache using given expire, then return the result.
|
// query from DB and set cache using given expire, then return the result.
|
||||||
func (c cacheNode) TakeWithExpire(v interface{}, key string, query func(v interface{},
|
func (c cacheNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
|
||||||
expire time.Duration) error) error {
|
return c.TakeWithExpireCtx(context.Background(), val, key, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TakeWithExpireCtx takes the result from cache first, if not found,
|
||||||
|
// query from DB and set cache using given expire, then return the result.
|
||||||
|
func (c cacheNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
|
||||||
expire := c.aroundDuration(c.expiry)
|
expire := c.aroundDuration(c.expiry)
|
||||||
return c.doTake(v, key, func(v interface{}) error {
|
return c.doTake(ctx, val, key, func(v interface{}) error {
|
||||||
return query(v, expire)
|
return query(v, expire)
|
||||||
}, func(v interface{}) error {
|
}, func(v interface{}) error {
|
||||||
return c.SetWithExpire(key, v, expire)
|
return c.SetWithExpireCtx(ctx, key, v, expire)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +179,9 @@ func (c cacheNode) asyncRetryDelCache(keys ...string) {
|
|||||||
}, keys...)
|
}, keys...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cacheNode) doGetCache(key string, v interface{}) error {
|
func (c cacheNode) doGetCache(ctx context.Context, key string, v interface{}) error {
|
||||||
c.stat.IncrementTotal()
|
c.stat.IncrementTotal()
|
||||||
data, err := c.rds.Get(key)
|
data, err := c.rds.GetCtx(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.stat.IncrementMiss()
|
c.stat.IncrementMiss()
|
||||||
return err
|
return err
|
||||||
@@ -166,13 +197,14 @@ func (c cacheNode) doGetCache(key string, v interface{}) error {
|
|||||||
return errPlaceholder
|
return errPlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.processCache(key, data, v)
|
return c.processCache(ctx, key, data, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) error,
|
func (c cacheNode) doTake(ctx context.Context, v interface{}, key string,
|
||||||
cacheVal func(v interface{}) error) error {
|
query func(v interface{}) error, cacheVal func(v interface{}) error) error {
|
||||||
|
logger := logx.WithContext(ctx)
|
||||||
val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) {
|
val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) {
|
||||||
if err := c.doGetCache(key, v); err != nil {
|
if err := c.doGetCache(ctx, key, v); err != nil {
|
||||||
if err == errPlaceholder {
|
if err == errPlaceholder {
|
||||||
return nil, c.errNotFound
|
return nil, c.errNotFound
|
||||||
} else if err != c.errNotFound {
|
} else if err != c.errNotFound {
|
||||||
@@ -183,8 +215,8 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = query(v); err == c.errNotFound {
|
if err = query(v); err == c.errNotFound {
|
||||||
if err = c.setCacheWithNotFound(key); err != nil {
|
if err = c.setCacheWithNotFound(ctx, key); err != nil {
|
||||||
logx.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, c.errNotFound
|
return nil, c.errNotFound
|
||||||
@@ -194,7 +226,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = cacheVal(v); err != nil {
|
if err = cacheVal(v); err != nil {
|
||||||
logx.Error(err)
|
logger.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +246,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
|
|||||||
return jsonx.Unmarshal(val.([]byte), v)
|
return jsonx.Unmarshal(val.([]byte), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cacheNode) processCache(key, data string, v interface{}) error {
|
func (c cacheNode) processCache(ctx context.Context, key, data string, v interface{}) error {
|
||||||
err := jsonx.Unmarshal([]byte(data), v)
|
err := jsonx.Unmarshal([]byte(data), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -222,10 +254,11 @@ func (c cacheNode) processCache(key, data string, v interface{}) error {
|
|||||||
|
|
||||||
report := fmt.Sprintf("unmarshal cache, node: %s, key: %s, value: %s, error: %v",
|
report := fmt.Sprintf("unmarshal cache, node: %s, key: %s, value: %s, error: %v",
|
||||||
c.rds.Addr, key, data, err)
|
c.rds.Addr, key, data, err)
|
||||||
logx.Error(report)
|
logger := logx.WithContext(ctx)
|
||||||
|
logger.Error(report)
|
||||||
stat.Report(report)
|
stat.Report(report)
|
||||||
if _, e := c.rds.Del(key); e != nil {
|
if _, e := c.rds.DelCtx(ctx, key); e != nil {
|
||||||
logx.Errorf("delete invalid cache, node: %s, key: %s, value: %s, error: %v",
|
logger.Errorf("delete invalid cache, node: %s, key: %s, value: %s, error: %v",
|
||||||
c.rds.Addr, key, data, e)
|
c.rds.Addr, key, data, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +266,6 @@ func (c cacheNode) processCache(key, data string, v interface{}) error {
|
|||||||
return c.errNotFound
|
return c.errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cacheNode) setCacheWithNotFound(key string) error {
|
func (c cacheNode) setCacheWithNotFound(ctx context.Context, key string) error {
|
||||||
return c.rds.Setex(key, notFoundPlaceholder, int(c.aroundDuration(c.notFoundExpiry).Seconds()))
|
return c.rds.SetexCtx(ctx, key, notFoundPlaceholder, int(c.aroundDuration(c.notFoundExpiry).Seconds()))
|
||||||
}
|
}
|
||||||
|
|||||||
83
core/stores/redis/hook.go
Normal file
83
core/stores/redis/hook.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
red "github.com/go-redis/redis/v8"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/core/mapping"
|
||||||
|
"github.com/zeromicro/go-zero/core/timex"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
startTimeKey = contextKey("startTime")
|
||||||
|
durationHook = hook{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
contextKey string
|
||||||
|
hook struct{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h hook) BeforeProcess(ctx context.Context, _ red.Cmder) (context.Context, error) {
|
||||||
|
return context.WithValue(ctx, startTimeKey, timex.Now()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h hook) AfterProcess(ctx context.Context, cmd red.Cmder) error {
|
||||||
|
val := ctx.Value(startTimeKey)
|
||||||
|
if val == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
start, ok := val.(time.Duration)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := timex.Since(start)
|
||||||
|
if duration > slowThreshold.Load() {
|
||||||
|
logDuration(ctx, cmd, duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h hook) BeforeProcessPipeline(ctx context.Context, _ []red.Cmder) (context.Context, error) {
|
||||||
|
return context.WithValue(ctx, startTimeKey, timex.Now()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h hook) AfterProcessPipeline(ctx context.Context, cmds []red.Cmder) error {
|
||||||
|
if len(cmds) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
val := ctx.Value(startTimeKey)
|
||||||
|
if val == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
start, ok := val.(time.Duration)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := timex.Since(start)
|
||||||
|
if duration > slowThreshold.Load()*time.Duration(len(cmds)) {
|
||||||
|
logDuration(ctx, cmds[0], duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func logDuration(ctx context.Context, cmd red.Cmder, duration time.Duration) {
|
||||||
|
var buf strings.Builder
|
||||||
|
for i, arg := range cmd.Args() {
|
||||||
|
if i > 0 {
|
||||||
|
buf.WriteByte(' ')
|
||||||
|
}
|
||||||
|
buf.WriteString(mapping.Repr(arg))
|
||||||
|
}
|
||||||
|
logx.WithContext(ctx).WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
|
||||||
|
}
|
||||||
137
core/stores/redis/hook_test.go
Normal file
137
core/stores/redis/hook_test.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
red "github.com/go-redis/redis/v8"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHookProcessCase1(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx, err := durationHook.BeforeProcess(context.Background(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
|
||||||
|
assert.False(t, strings.Contains(buf.String(), "slow"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessCase2(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx, err := durationHook.BeforeProcess(context.Background(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(slowThreshold.Load() + time.Millisecond)
|
||||||
|
|
||||||
|
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background(), "foo", "bar")))
|
||||||
|
assert.True(t, strings.Contains(buf.String(), "slow"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessCase3(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
assert.Nil(t, durationHook.AfterProcess(context.Background(), red.NewCmd(context.Background())))
|
||||||
|
assert.True(t, buf.Len() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessCase4(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
|
||||||
|
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
|
||||||
|
assert.True(t, buf.Len() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessPipelineCase1(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
|
||||||
|
red.NewCmd(context.Background()),
|
||||||
|
}))
|
||||||
|
assert.False(t, strings.Contains(buf.String(), "slow"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessPipelineCase2(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(slowThreshold.Load() + time.Millisecond)
|
||||||
|
|
||||||
|
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
|
||||||
|
red.NewCmd(context.Background(), "foo", "bar"),
|
||||||
|
}))
|
||||||
|
assert.True(t, strings.Contains(buf.String(), "slow"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessPipelineCase3(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
assert.Nil(t, durationHook.AfterProcessPipeline(context.Background(), []red.Cmder{
|
||||||
|
red.NewCmd(context.Background()),
|
||||||
|
}))
|
||||||
|
assert.True(t, buf.Len() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessPipelineCase4(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
|
||||||
|
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
|
||||||
|
red.NewCmd(context.Background()),
|
||||||
|
}))
|
||||||
|
assert.True(t, buf.Len() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookProcessPipelineCase5(t *testing.T) {
|
||||||
|
writer := log.Writer()
|
||||||
|
var buf strings.Builder
|
||||||
|
log.SetOutput(&buf)
|
||||||
|
defer log.SetOutput(writer)
|
||||||
|
|
||||||
|
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
|
||||||
|
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, nil))
|
||||||
|
assert.True(t, buf.Len() == 0)
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package redis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
red "github.com/go-redis/redis"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
"github.com/zeromicro/go-zero/core/mapping"
|
|
||||||
"github.com/zeromicro/go-zero/core/timex"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkDuration(proc func(red.Cmder) error) func(red.Cmder) error {
|
|
||||||
return func(cmd red.Cmder) error {
|
|
||||||
start := timex.Now()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
duration := timex.Since(start)
|
|
||||||
if duration > slowThreshold.Load() {
|
|
||||||
var buf strings.Builder
|
|
||||||
for i, arg := range cmd.Args() {
|
|
||||||
if i > 0 {
|
|
||||||
buf.WriteByte(' ')
|
|
||||||
}
|
|
||||||
buf.WriteString(mapping.Repr(arg))
|
|
||||||
}
|
|
||||||
logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return proc(cmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
package redis
|
package redis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
@@ -9,8 +10,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alicebob/miniredis/v2"
|
"github.com/alicebob/miniredis/v2"
|
||||||
red "github.com/go-redis/redis"
|
red "github.com/go-redis/redis/v8"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -963,13 +965,14 @@ func TestRedis_SortedSet(t *testing.T) {
|
|||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
client.Zadd("second", 2, "aa")
|
client.Zadd("second", 2, "aa")
|
||||||
client.Zadd("third", 3, "bbb")
|
client.Zadd("third", 3, "bbb")
|
||||||
val, err = client.Zunionstore("union", ZStore{
|
val, err = client.Zunionstore("union", &ZStore{
|
||||||
|
Keys: []string{"second", "third"},
|
||||||
Weights: []float64{1, 2},
|
Weights: []float64{1, 2},
|
||||||
Aggregate: "SUM",
|
Aggregate: "SUM",
|
||||||
}, "second", "third")
|
})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(2), val)
|
assert.Equal(t, int64(2), val)
|
||||||
_, err = New(client.Addr, badType()).Zunionstore("union", ZStore{})
|
_, err = New(client.Addr, badType()).Zunionstore("union", &ZStore{})
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
vals, err = client.Zrange("union", 0, 10000)
|
vals, err = client.Zrange("union", 0, 10000)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
@@ -987,9 +990,9 @@ func TestRedis_Pipelined(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
err := client.Pipelined(
|
err := client.Pipelined(
|
||||||
func(pipe Pipeliner) error {
|
func(pipe Pipeliner) error {
|
||||||
pipe.Incr("pipelined_counter")
|
pipe.Incr(context.Background(), "pipelined_counter")
|
||||||
pipe.Expire("pipelined_counter", time.Hour)
|
pipe.Expire(context.Background(), "pipelined_counter", time.Hour)
|
||||||
pipe.ZAdd("zadd", Z{Score: 12, Member: "zadd"})
|
pipe.ZAdd(context.Background(), "zadd", &Z{Score: 12, Member: "zadd"})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -1135,6 +1138,8 @@ func TestRedis_WithPass(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runOnRedis(t *testing.T, fn func(client *Redis)) {
|
func runOnRedis(t *testing.T, fn func(client *Redis)) {
|
||||||
|
logx.Disable()
|
||||||
|
|
||||||
s, err := miniredis.Run()
|
s, err := miniredis.Run()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -1153,6 +1158,8 @@ func runOnRedis(t *testing.T, fn func(client *Redis)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runOnRedisTLS(t *testing.T, fn func(client *Redis)) {
|
func runOnRedisTLS(t *testing.T, fn func(client *Redis)) {
|
||||||
|
logx.Disable()
|
||||||
|
|
||||||
s, err := miniredis.RunTLS(&tls.Config{
|
s, err := miniredis.RunTLS(&tls.Config{
|
||||||
Certificates: make([]tls.Certificate, 1),
|
Certificates: make([]tls.Certificate, 1),
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
@@ -1182,6 +1189,6 @@ type mockedNode struct {
|
|||||||
RedisNode
|
RedisNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n mockedNode) BLPop(timeout time.Duration, keys ...string) *red.StringSliceCmd {
|
func (n mockedNode) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *red.StringSliceCmd {
|
||||||
return red.NewStringSliceCmd("foo", "bar")
|
return red.NewStringSliceCmd(context.Background(), "foo", "bar")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package redis
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
red "github.com/go-redis/redis"
|
red "github.com/go-redis/redis/v8"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
red "github.com/go-redis/redis"
|
red "github.com/go-redis/redis/v8"
|
||||||
"github.com/zeromicro/go-zero/core/syncx"
|
"github.com/zeromicro/go-zero/core/syncx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,7 +32,8 @@ func getClient(r *Redis) (*red.Client, error) {
|
|||||||
MinIdleConns: idleConns,
|
MinIdleConns: idleConns,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
})
|
})
|
||||||
store.WrapProcess(checkDuration)
|
store.AddHook(durationHook)
|
||||||
|
|
||||||
return store, nil
|
return store, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
red "github.com/go-redis/redis"
|
red "github.com/go-redis/redis/v8"
|
||||||
"github.com/zeromicro/go-zero/core/syncx"
|
"github.com/zeromicro/go-zero/core/syncx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
|
|||||||
MinIdleConns: idleConns,
|
MinIdleConns: idleConns,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
})
|
})
|
||||||
store.WrapProcess(checkDuration)
|
store.AddHook(durationHook)
|
||||||
|
|
||||||
return store, nil
|
return store, nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
red "github.com/go-redis/redis"
|
red "github.com/go-redis/redis/v8"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ func CreateRedis() (r *redis.Redis, clean func(), err error) {
|
|||||||
|
|
||||||
return redis.New(mr.Addr()), func() {
|
return redis.New(mr.Addr()), func() {
|
||||||
ch := make(chan lang.PlaceholderType)
|
ch := make(chan lang.PlaceholderType)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
mr.Close()
|
mr.Close()
|
||||||
close(ch)
|
close(ch)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ch:
|
case <-ch:
|
||||||
case <-time.After(time.Second):
|
case <-time.After(time.Second):
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScriptCache(t *testing.T) {
|
func TestScriptCache(t *testing.T) {
|
||||||
|
logx.Disable()
|
||||||
|
|
||||||
cache := GetScriptCache()
|
cache := GetScriptCache()
|
||||||
cache.SetSha("foo", "bar")
|
cache.SetSha("foo", "bar")
|
||||||
cache.SetSha("bla", "blabla")
|
cache.SetSha("bla", "blabla")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlc
|
package sqlc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -18,19 +19,27 @@ var (
|
|||||||
ErrNotFound = sqlx.ErrNotFound
|
ErrNotFound = sqlx.ErrNotFound
|
||||||
|
|
||||||
// can't use one SingleFlight per conn, because multiple conns may share the same cache key.
|
// can't use one SingleFlight per conn, because multiple conns may share the same cache key.
|
||||||
exclusiveCalls = syncx.NewSingleFlight()
|
singleFlights = syncx.NewSingleFlight()
|
||||||
stats = cache.NewStat("sqlc")
|
stats = cache.NewStat("sqlc")
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// ExecFn defines the sql exec method.
|
// ExecFn defines the sql exec method.
|
||||||
ExecFn func(conn sqlx.SqlConn) (sql.Result, error)
|
ExecFn func(conn sqlx.SqlConn) (sql.Result, error)
|
||||||
|
// ExecCtxFn defines the sql exec method.
|
||||||
|
ExecCtxFn func(ctx context.Context, conn sqlx.SqlConn) (sql.Result, error)
|
||||||
// IndexQueryFn defines the query method that based on unique indexes.
|
// IndexQueryFn defines the query method that based on unique indexes.
|
||||||
IndexQueryFn func(conn sqlx.SqlConn, v interface{}) (interface{}, error)
|
IndexQueryFn func(conn sqlx.SqlConn, v interface{}) (interface{}, error)
|
||||||
|
// IndexQueryCtxFn defines the query method that based on unique indexes.
|
||||||
|
IndexQueryCtxFn func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (interface{}, error)
|
||||||
// PrimaryQueryFn defines the query method that based on primary keys.
|
// PrimaryQueryFn defines the query method that based on primary keys.
|
||||||
PrimaryQueryFn func(conn sqlx.SqlConn, v, primary interface{}) error
|
PrimaryQueryFn func(conn sqlx.SqlConn, v, primary interface{}) error
|
||||||
|
// PrimaryQueryCtxFn defines the query method that based on primary keys.
|
||||||
|
PrimaryQueryCtxFn func(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error
|
||||||
// QueryFn defines the query method.
|
// QueryFn defines the query method.
|
||||||
QueryFn func(conn sqlx.SqlConn, v interface{}) error
|
QueryFn func(conn sqlx.SqlConn, v interface{}) error
|
||||||
|
// QueryCtxFn defines the query method.
|
||||||
|
QueryCtxFn func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error
|
||||||
|
|
||||||
// A CachedConn is a DB connection with cache capability.
|
// A CachedConn is a DB connection with cache capability.
|
||||||
CachedConn struct {
|
CachedConn struct {
|
||||||
@@ -41,7 +50,7 @@ type (
|
|||||||
|
|
||||||
// NewConn returns a CachedConn with a redis cluster cache.
|
// NewConn returns a CachedConn with a redis cluster cache.
|
||||||
func NewConn(db sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) CachedConn {
|
func NewConn(db sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) CachedConn {
|
||||||
cc := cache.New(c, exclusiveCalls, stats, sql.ErrNoRows, opts...)
|
cc := cache.New(c, singleFlights, stats, sql.ErrNoRows, opts...)
|
||||||
return NewConnWithCache(db, cc)
|
return NewConnWithCache(db, cc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,28 +64,46 @@ func NewConnWithCache(db sqlx.SqlConn, c cache.Cache) CachedConn {
|
|||||||
|
|
||||||
// NewNodeConn returns a CachedConn with a redis node cache.
|
// NewNodeConn returns a CachedConn with a redis node cache.
|
||||||
func NewNodeConn(db sqlx.SqlConn, rds *redis.Redis, opts ...cache.Option) CachedConn {
|
func NewNodeConn(db sqlx.SqlConn, rds *redis.Redis, opts ...cache.Option) CachedConn {
|
||||||
c := cache.NewNode(rds, exclusiveCalls, stats, sql.ErrNoRows, opts...)
|
c := cache.NewNode(rds, singleFlights, stats, sql.ErrNoRows, opts...)
|
||||||
return NewConnWithCache(db, c)
|
return NewConnWithCache(db, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelCache deletes cache with keys.
|
// DelCache deletes cache with keys.
|
||||||
func (cc CachedConn) DelCache(keys ...string) error {
|
func (cc CachedConn) DelCache(keys ...string) error {
|
||||||
return cc.cache.Del(keys...)
|
return cc.DelCacheCtx(context.Background(), keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelCacheCtx deletes cache with keys.
|
||||||
|
func (cc CachedConn) DelCacheCtx(ctx context.Context, keys ...string) error {
|
||||||
|
return cc.cache.DelCtx(ctx, keys...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCache unmarshals cache with given key into v.
|
// GetCache unmarshals cache with given key into v.
|
||||||
func (cc CachedConn) GetCache(key string, v interface{}) error {
|
func (cc CachedConn) GetCache(key string, v interface{}) error {
|
||||||
return cc.cache.Get(key, v)
|
return cc.GetCacheCtx(context.Background(), key, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCacheCtx unmarshals cache with given key into v.
|
||||||
|
func (cc CachedConn) GetCacheCtx(ctx context.Context, key string, v interface{}) error {
|
||||||
|
return cc.cache.GetCtx(ctx, key, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec runs given exec on given keys, and returns execution result.
|
// Exec runs given exec on given keys, and returns execution result.
|
||||||
func (cc CachedConn) Exec(exec ExecFn, keys ...string) (sql.Result, error) {
|
func (cc CachedConn) Exec(exec ExecFn, keys ...string) (sql.Result, error) {
|
||||||
res, err := exec(cc.db)
|
execCtx := func(_ context.Context, conn sqlx.SqlConn) (sql.Result, error) {
|
||||||
|
return exec(conn)
|
||||||
|
}
|
||||||
|
return cc.ExecCtx(context.Background(), execCtx, keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecCtx runs given exec on given keys, and returns execution result.
|
||||||
|
func (cc CachedConn) ExecCtx(ctx context.Context, exec ExecCtxFn, keys ...string) (sql.Result, error) {
|
||||||
|
res, err := exec(ctx, cc.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cc.DelCache(keys...); err != nil {
|
if err := cc.DelCacheCtx(ctx, keys...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,30 +112,60 @@ func (cc CachedConn) Exec(exec ExecFn, keys ...string) (sql.Result, error) {
|
|||||||
|
|
||||||
// ExecNoCache runs exec with given sql statement, without affecting cache.
|
// ExecNoCache runs exec with given sql statement, without affecting cache.
|
||||||
func (cc CachedConn) ExecNoCache(q string, args ...interface{}) (sql.Result, error) {
|
func (cc CachedConn) ExecNoCache(q string, args ...interface{}) (sql.Result, error) {
|
||||||
return cc.db.Exec(q, args...)
|
return cc.ExecNoCacheCtx(context.Background(), q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecNoCacheCtx runs exec with given sql statement, without affecting cache.
|
||||||
|
func (cc CachedConn) ExecNoCacheCtx(ctx context.Context, q string, args ...interface{}) (
|
||||||
|
sql.Result, error) {
|
||||||
|
return cc.db.ExecCtx(ctx, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRow unmarshals into v with given key and query func.
|
// QueryRow unmarshals into v with given key and query func.
|
||||||
func (cc CachedConn) QueryRow(v interface{}, key string, query QueryFn) error {
|
func (cc CachedConn) QueryRow(v interface{}, key string, query QueryFn) error {
|
||||||
return cc.cache.Take(v, key, func(v interface{}) error {
|
queryCtx := func(_ context.Context, conn sqlx.SqlConn, v interface{}) error {
|
||||||
return query(cc.db, v)
|
return query(conn, v)
|
||||||
|
}
|
||||||
|
return cc.QueryRowCtx(context.Background(), v, key, queryCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRowCtx unmarshals into v with given key and query func.
|
||||||
|
func (cc CachedConn) QueryRowCtx(ctx context.Context, v interface{}, key string, query QueryCtxFn) error {
|
||||||
|
return cc.cache.TakeCtx(ctx, v, key, func(v interface{}) error {
|
||||||
|
return query(ctx, cc.db, v)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRowIndex unmarshals into v with given key.
|
// QueryRowIndex unmarshals into v with given key.
|
||||||
func (cc CachedConn) QueryRowIndex(v interface{}, key string, keyer func(primary interface{}) string,
|
func (cc CachedConn) QueryRowIndex(v interface{}, key string, keyer func(primary interface{}) string,
|
||||||
indexQuery IndexQueryFn, primaryQuery PrimaryQueryFn) error {
|
indexQuery IndexQueryFn, primaryQuery PrimaryQueryFn) error {
|
||||||
|
indexQueryCtx := func(_ context.Context, conn sqlx.SqlConn, v interface{}) (interface{}, error) {
|
||||||
|
return indexQuery(conn, v)
|
||||||
|
}
|
||||||
|
primaryQueryCtx := func(_ context.Context, conn sqlx.SqlConn, v, primary interface{}) error {
|
||||||
|
return primaryQuery(conn, v, primary)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cc.QueryRowIndexCtx(context.Background(), v, key, keyer, indexQueryCtx, primaryQueryCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRowIndexCtx unmarshals into v with given key.
|
||||||
|
func (cc CachedConn) QueryRowIndexCtx(ctx context.Context, v interface{}, key string,
|
||||||
|
keyer func(primary interface{}) string, indexQuery IndexQueryCtxFn,
|
||||||
|
primaryQuery PrimaryQueryCtxFn) error {
|
||||||
var primaryKey interface{}
|
var primaryKey interface{}
|
||||||
var found bool
|
var found bool
|
||||||
|
|
||||||
if err := cc.cache.TakeWithExpire(&primaryKey, key, func(val interface{}, expire time.Duration) (err error) {
|
if err := cc.cache.TakeWithExpireCtx(ctx, &primaryKey, key,
|
||||||
primaryKey, err = indexQuery(cc.db, v)
|
func(val interface{}, expire time.Duration) (err error) {
|
||||||
|
primaryKey, err = indexQuery(ctx, cc.db, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
found = true
|
found = true
|
||||||
return cc.cache.SetWithExpire(keyer(primaryKey), v, expire+cacheSafeGapBetweenIndexAndPrimary)
|
return cc.cache.SetWithExpireCtx(ctx, keyer(primaryKey), v,
|
||||||
|
expire+cacheSafeGapBetweenIndexAndPrimary)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -117,28 +174,54 @@ func (cc CachedConn) QueryRowIndex(v interface{}, key string, keyer func(primary
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return cc.cache.Take(v, keyer(primaryKey), func(v interface{}) error {
|
return cc.cache.TakeCtx(ctx, v, keyer(primaryKey), func(v interface{}) error {
|
||||||
return primaryQuery(cc.db, v, primaryKey)
|
return primaryQuery(ctx, cc.db, v, primaryKey)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRowNoCache unmarshals into v with given statement.
|
// QueryRowNoCache unmarshals into v with given statement.
|
||||||
func (cc CachedConn) QueryRowNoCache(v interface{}, q string, args ...interface{}) error {
|
func (cc CachedConn) QueryRowNoCache(v interface{}, q string, args ...interface{}) error {
|
||||||
return cc.db.QueryRow(v, q, args...)
|
return cc.QueryRowNoCacheCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRowNoCacheCtx unmarshals into v with given statement.
|
||||||
|
func (cc CachedConn) QueryRowNoCacheCtx(ctx context.Context, v interface{}, q string,
|
||||||
|
args ...interface{}) error {
|
||||||
|
return cc.db.QueryRowCtx(ctx, v, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryRowsNoCache unmarshals into v with given statement.
|
// QueryRowsNoCache unmarshals into v with given statement.
|
||||||
// It doesn't use cache, because it might cause consistency problem.
|
// It doesn't use cache, because it might cause consistency problem.
|
||||||
func (cc CachedConn) QueryRowsNoCache(v interface{}, q string, args ...interface{}) error {
|
func (cc CachedConn) QueryRowsNoCache(v interface{}, q string, args ...interface{}) error {
|
||||||
return cc.db.QueryRows(v, q, args...)
|
return cc.QueryRowsNoCacheCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRowsNoCacheCtx unmarshals into v with given statement.
|
||||||
|
// It doesn't use cache, because it might cause consistency problem.
|
||||||
|
func (cc CachedConn) QueryRowsNoCacheCtx(ctx context.Context, v interface{}, q string,
|
||||||
|
args ...interface{}) error {
|
||||||
|
return cc.db.QueryRowsCtx(ctx, v, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCache sets v into cache with given key.
|
// SetCache sets v into cache with given key.
|
||||||
func (cc CachedConn) SetCache(key string, v interface{}) error {
|
func (cc CachedConn) SetCache(key string, val interface{}) error {
|
||||||
return cc.cache.Set(key, v)
|
return cc.SetCacheCtx(context.Background(), key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCacheCtx sets v into cache with given key.
|
||||||
|
func (cc CachedConn) SetCacheCtx(ctx context.Context, key string, val interface{}) error {
|
||||||
|
return cc.cache.SetCtx(ctx, key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transact runs given fn in transaction mode.
|
// Transact runs given fn in transaction mode.
|
||||||
func (cc CachedConn) Transact(fn func(sqlx.Session) error) error {
|
func (cc CachedConn) Transact(fn func(sqlx.Session) error) error {
|
||||||
return cc.db.Transact(fn)
|
fnCtx := func(_ context.Context, session sqlx.Session) error {
|
||||||
|
return fn(session)
|
||||||
|
}
|
||||||
|
return cc.TransactCtx(context.Background(), fnCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransactCtx runs given fn in transaction mode.
|
||||||
|
func (cc CachedConn) TransactCtx(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
|
||||||
|
return cc.db.TransactCtx(ctx, fn)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlc
|
package sqlc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -568,7 +569,7 @@ func TestNewConnWithCache(t *testing.T) {
|
|||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
var conn trackedConn
|
var conn trackedConn
|
||||||
c := NewConnWithCache(&conn, cache.NewNode(r, exclusiveCalls, stats, sql.ErrNoRows))
|
c := NewConnWithCache(&conn, cache.NewNode(r, singleFlights, stats, sql.ErrNoRows))
|
||||||
_, err = c.ExecNoCache("delete from user_table where id='kevin'")
|
_, err = c.ExecNoCache("delete from user_table where id='kevin'")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.True(t, conn.execValue)
|
assert.True(t, conn.execValue)
|
||||||
@@ -585,6 +586,30 @@ type dummySqlConn struct {
|
|||||||
queryRow func(interface{}, string, ...interface{}) error
|
queryRow func(interface{}, string, ...interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) ExecCtx(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) PrepareCtx(ctx context.Context, query string) (sqlx.StmtSession, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) QueryRowPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) QueryRowsCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) QueryRowsPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) TransactCtx(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d dummySqlConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
func (d dummySqlConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -594,6 +619,10 @@ func (d dummySqlConn) Prepare(query string) (sqlx.StmtSession, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d dummySqlConn) QueryRow(v interface{}, query string, args ...interface{}) error {
|
func (d dummySqlConn) QueryRow(v interface{}, query string, args ...interface{}) error {
|
||||||
|
return d.QueryRowCtx(context.Background(), v, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummySqlConn) QueryRowCtx(_ context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
if d.queryRow != nil {
|
if d.queryRow != nil {
|
||||||
return d.queryRow(v, query, args...)
|
return d.queryRow(v, query, args...)
|
||||||
}
|
}
|
||||||
@@ -628,13 +657,21 @@ type trackedConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *trackedConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
func (c *trackedConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return c.ExecCtx(context.Background(), query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *trackedConn) ExecCtx(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||||
c.execValue = true
|
c.execValue = true
|
||||||
return c.dummySqlConn.Exec(query, args...)
|
return c.dummySqlConn.ExecCtx(ctx, query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *trackedConn) QueryRows(v interface{}, query string, args ...interface{}) error {
|
func (c *trackedConn) QueryRows(v interface{}, query string, args ...interface{}) error {
|
||||||
|
return c.QueryRowsCtx(context.Background(), v, query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *trackedConn) QueryRowsCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
c.queryRowsValue = true
|
c.queryRowsValue = true
|
||||||
return c.dummySqlConn.QueryRows(v, query, args...)
|
return c.dummySqlConn.QueryRowsCtx(ctx, v, query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *trackedConn) RawDB() (*sql.DB, error) {
|
func (c *trackedConn) RawDB() (*sql.DB, error) {
|
||||||
@@ -642,6 +679,12 @@ func (c *trackedConn) RawDB() (*sql.DB, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *trackedConn) Transact(fn func(session sqlx.Session) error) error {
|
func (c *trackedConn) Transact(fn func(session sqlx.Session) error) error {
|
||||||
c.transactValue = true
|
return c.TransactCtx(context.Background(), func(_ context.Context, session sqlx.Session) error {
|
||||||
return c.dummySqlConn.Transact(fn)
|
return fn(session)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *trackedConn) TransactCtx(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
|
||||||
|
c.transactValue = true
|
||||||
|
return c.dummySqlConn.TransactCtx(ctx, fn)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -17,12 +18,40 @@ type mockedConn struct {
|
|||||||
execErr error
|
execErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockedConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
func (c *mockedConn) ExecCtx(_ context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||||
c.query = query
|
c.query = query
|
||||||
c.args = args
|
c.args = args
|
||||||
return nil, c.execErr
|
return nil, c.execErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) PrepareCtx(ctx context.Context, query string) (StmtSession, error) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) QueryRowCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) QueryRowPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) QueryRowsCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) QueryRowsPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) TransactCtx(ctx context.Context, fn func(context.Context, Session) error) error {
|
||||||
|
panic("should not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockedConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return c.ExecCtx(context.Background(), query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *mockedConn) Prepare(query string) (StmtSession, error) {
|
func (c *mockedConn) Prepare(query string) (StmtSession, error) {
|
||||||
panic("should not called")
|
panic("should not called")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -16,7 +17,7 @@ func TestUnmarshalRowBool(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value bool
|
var value bool
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.True(t, value)
|
assert.True(t, value)
|
||||||
@@ -29,7 +30,7 @@ func TestUnmarshalRowBoolNotSettable(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value bool
|
var value bool
|
||||||
assert.NotNil(t, query(db, func(rows *sql.Rows) error {
|
assert.NotNil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(value, rows, true)
|
return unmarshalRow(value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
})
|
})
|
||||||
@@ -41,7 +42,7 @@ func TestUnmarshalRowInt(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value int
|
var value int
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, 2, value)
|
assert.EqualValues(t, 2, value)
|
||||||
@@ -54,7 +55,7 @@ func TestUnmarshalRowInt8(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value int8
|
var value int8
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, int8(3), value)
|
assert.EqualValues(t, int8(3), value)
|
||||||
@@ -67,7 +68,7 @@ func TestUnmarshalRowInt16(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value int16
|
var value int16
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.Equal(t, int16(4), value)
|
assert.Equal(t, int16(4), value)
|
||||||
@@ -80,7 +81,7 @@ func TestUnmarshalRowInt32(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value int32
|
var value int32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.Equal(t, int32(5), value)
|
assert.Equal(t, int32(5), value)
|
||||||
@@ -93,7 +94,7 @@ func TestUnmarshalRowInt64(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value int64
|
var value int64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, int64(6), value)
|
assert.EqualValues(t, int64(6), value)
|
||||||
@@ -106,7 +107,7 @@ func TestUnmarshalRowUint(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value uint
|
var value uint
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, uint(2), value)
|
assert.EqualValues(t, uint(2), value)
|
||||||
@@ -119,7 +120,7 @@ func TestUnmarshalRowUint8(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value uint8
|
var value uint8
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, uint8(3), value)
|
assert.EqualValues(t, uint8(3), value)
|
||||||
@@ -132,7 +133,7 @@ func TestUnmarshalRowUint16(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value uint16
|
var value uint16
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, uint16(4), value)
|
assert.EqualValues(t, uint16(4), value)
|
||||||
@@ -145,7 +146,7 @@ func TestUnmarshalRowUint32(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value uint32
|
var value uint32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, uint32(5), value)
|
assert.EqualValues(t, uint32(5), value)
|
||||||
@@ -158,7 +159,7 @@ func TestUnmarshalRowUint64(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value uint64
|
var value uint64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, uint16(6), value)
|
assert.EqualValues(t, uint16(6), value)
|
||||||
@@ -171,7 +172,7 @@ func TestUnmarshalRowFloat32(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value float32
|
var value float32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, float32(7), value)
|
assert.EqualValues(t, float32(7), value)
|
||||||
@@ -184,7 +185,7 @@ func TestUnmarshalRowFloat64(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value float64
|
var value float64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, float64(8), value)
|
assert.EqualValues(t, float64(8), value)
|
||||||
@@ -198,7 +199,7 @@ func TestUnmarshalRowString(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value string
|
var value string
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&value, rows, true)
|
return unmarshalRow(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -215,7 +216,7 @@ func TestUnmarshalRowStruct(t *testing.T) {
|
|||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("liao,5")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("liao,5")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(value, rows, true)
|
return unmarshalRow(value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
assert.Equal(t, "liao", value.Name)
|
assert.Equal(t, "liao", value.Name)
|
||||||
@@ -233,7 +234,7 @@ func TestUnmarshalRowStructWithTags(t *testing.T) {
|
|||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("liao,5")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("liao,5")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(value, rows, true)
|
return unmarshalRow(value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
assert.Equal(t, "liao", value.Name)
|
assert.Equal(t, "liao", value.Name)
|
||||||
@@ -251,7 +252,7 @@ func TestUnmarshalRowStructWithTagsWrongColumns(t *testing.T) {
|
|||||||
rs := sqlmock.NewRows([]string{"name"}).FromCSVString("liao")
|
rs := sqlmock.NewRows([]string{"name"}).FromCSVString("liao")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
assert.NotNil(t, query(db, func(rows *sql.Rows) error {
|
assert.NotNil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(value, rows, true)
|
return unmarshalRow(value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
})
|
})
|
||||||
@@ -264,7 +265,7 @@ func TestUnmarshalRowsBool(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []bool
|
var value []bool
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -278,7 +279,7 @@ func TestUnmarshalRowsInt(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []int
|
var value []int
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -292,7 +293,7 @@ func TestUnmarshalRowsInt8(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []int8
|
var value []int8
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -306,7 +307,7 @@ func TestUnmarshalRowsInt16(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []int16
|
var value []int16
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -320,7 +321,7 @@ func TestUnmarshalRowsInt32(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []int32
|
var value []int32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -334,7 +335,7 @@ func TestUnmarshalRowsInt64(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []int64
|
var value []int64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -348,7 +349,7 @@ func TestUnmarshalRowsUint(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []uint
|
var value []uint
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -362,7 +363,7 @@ func TestUnmarshalRowsUint8(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []uint8
|
var value []uint8
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -376,7 +377,7 @@ func TestUnmarshalRowsUint16(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []uint16
|
var value []uint16
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -390,7 +391,7 @@ func TestUnmarshalRowsUint32(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []uint32
|
var value []uint32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -404,7 +405,7 @@ func TestUnmarshalRowsUint64(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []uint64
|
var value []uint64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -418,7 +419,7 @@ func TestUnmarshalRowsFloat32(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []float32
|
var value []float32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -432,7 +433,7 @@ func TestUnmarshalRowsFloat64(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []float64
|
var value []float64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -446,7 +447,7 @@ func TestUnmarshalRowsString(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []string
|
var value []string
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -462,7 +463,7 @@ func TestUnmarshalRowsBoolPtr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*bool
|
var value []*bool
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -478,7 +479,7 @@ func TestUnmarshalRowsIntPtr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*int
|
var value []*int
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -494,7 +495,7 @@ func TestUnmarshalRowsInt8Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*int8
|
var value []*int8
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -510,7 +511,7 @@ func TestUnmarshalRowsInt16Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*int16
|
var value []*int16
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -526,7 +527,7 @@ func TestUnmarshalRowsInt32Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*int32
|
var value []*int32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -542,7 +543,7 @@ func TestUnmarshalRowsInt64Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*int64
|
var value []*int64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -558,7 +559,7 @@ func TestUnmarshalRowsUintPtr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*uint
|
var value []*uint
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -574,7 +575,7 @@ func TestUnmarshalRowsUint8Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*uint8
|
var value []*uint8
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -590,7 +591,7 @@ func TestUnmarshalRowsUint16Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*uint16
|
var value []*uint16
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -606,7 +607,7 @@ func TestUnmarshalRowsUint32Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*uint32
|
var value []*uint32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -622,7 +623,7 @@ func TestUnmarshalRowsUint64Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*uint64
|
var value []*uint64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -638,7 +639,7 @@ func TestUnmarshalRowsFloat32Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*float32
|
var value []*float32
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -654,7 +655,7 @@ func TestUnmarshalRowsFloat64Ptr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*float64
|
var value []*float64
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -670,7 +671,7 @@ func TestUnmarshalRowsStringPtr(t *testing.T) {
|
|||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
|
|
||||||
var value []*string
|
var value []*string
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select value from users where user=?", "anyone"))
|
}, "select value from users where user=?", "anyone"))
|
||||||
assert.EqualValues(t, expect, value)
|
assert.EqualValues(t, expect, value)
|
||||||
@@ -699,7 +700,7 @@ func TestUnmarshalRowsStruct(t *testing.T) {
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -739,7 +740,7 @@ func TestUnmarshalRowsStructWithNullStringType(t *testing.T) {
|
|||||||
rs := sqlmock.NewRows([]string{"name", "value"}).AddRow(
|
rs := sqlmock.NewRows([]string{"name", "value"}).AddRow(
|
||||||
"first", "firstnullstring").AddRow("second", nil)
|
"first", "firstnullstring").AddRow("second", nil)
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -773,7 +774,7 @@ func TestUnmarshalRowsStructWithTags(t *testing.T) {
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -814,7 +815,7 @@ func TestUnmarshalRowsStructAndEmbeddedAnonymousStructWithTags(t *testing.T) {
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age", "value"}).FromCSVString("first,2,3\nsecond,3,4")
|
rs := sqlmock.NewRows([]string{"name", "age", "value"}).FromCSVString("first,2,3\nsecond,3,4")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age, value from users where user=?", "anyone"))
|
}, "select name, age, value from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -856,7 +857,7 @@ func TestUnmarshalRowsStructAndEmbeddedStructPtrAnonymousWithTags(t *testing.T)
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age", "value"}).FromCSVString("first,2,3\nsecond,3,4")
|
rs := sqlmock.NewRows([]string{"name", "age", "value"}).FromCSVString("first,2,3\nsecond,3,4")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age, value from users where user=?", "anyone"))
|
}, "select name, age, value from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -890,7 +891,7 @@ func TestUnmarshalRowsStructPtr(t *testing.T) {
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -923,7 +924,7 @@ func TestUnmarshalRowsStructWithTagsPtr(t *testing.T) {
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -956,7 +957,7 @@ func TestUnmarshalRowsStructWithTagsPtrWithInnerPtr(t *testing.T) {
|
|||||||
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
runOrmTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
|
||||||
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
rs := sqlmock.NewRows([]string{"name", "age"}).FromCSVString("first,2\nsecond,3")
|
||||||
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
mock.ExpectQuery("select (.+) from users where user=?").WithArgs("anyone").WillReturnRows(rs)
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(&value, rows, true)
|
return unmarshalRows(&value, rows, true)
|
||||||
}, "select name, age from users where user=?", "anyone"))
|
}, "select name, age from users where user=?", "anyone"))
|
||||||
|
|
||||||
@@ -976,7 +977,7 @@ func TestCommonSqlConn_QueryRowOptional(t *testing.T) {
|
|||||||
User string `db:"user"`
|
User string `db:"user"`
|
||||||
Age int `db:"age"`
|
Age int `db:"age"`
|
||||||
}
|
}
|
||||||
assert.Nil(t, query(db, func(rows *sql.Rows) error {
|
assert.Nil(t, query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(&r, rows, false)
|
return unmarshalRow(&r, rows, false)
|
||||||
}, "select age from users where user=?", "anyone"))
|
}, "select age from users where user=?", "anyone"))
|
||||||
assert.Empty(t, r.User)
|
assert.Empty(t, r.User)
|
||||||
@@ -1027,7 +1028,7 @@ func TestUnmarshalRowError(t *testing.T) {
|
|||||||
User string `db:"user"`
|
User string `db:"user"`
|
||||||
Age int `db:"age"`
|
Age int `db:"age"`
|
||||||
}
|
}
|
||||||
test.validate(query(db, func(rows *sql.Rows) error {
|
test.validate(query(context.Background(), db, func(rows *sql.Rows) error {
|
||||||
scanner := mockedScanner{
|
scanner := mockedScanner{
|
||||||
colErr: test.colErr,
|
colErr: test.colErr,
|
||||||
scanErr: test.scanErr,
|
scanErr: test.scanErr,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/breaker"
|
"github.com/zeromicro/go-zero/core/breaker"
|
||||||
@@ -14,11 +15,17 @@ type (
|
|||||||
// Session stands for raw connections or transaction sessions
|
// Session stands for raw connections or transaction sessions
|
||||||
Session interface {
|
Session interface {
|
||||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||||
|
ExecCtx(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||||
Prepare(query string) (StmtSession, error)
|
Prepare(query string) (StmtSession, error)
|
||||||
|
PrepareCtx(ctx context.Context, query string) (StmtSession, error)
|
||||||
QueryRow(v interface{}, query string, args ...interface{}) error
|
QueryRow(v interface{}, query string, args ...interface{}) error
|
||||||
|
QueryRowCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error
|
||||||
QueryRowPartial(v interface{}, query string, args ...interface{}) error
|
QueryRowPartial(v interface{}, query string, args ...interface{}) error
|
||||||
|
QueryRowPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error
|
||||||
QueryRows(v interface{}, query string, args ...interface{}) error
|
QueryRows(v interface{}, query string, args ...interface{}) error
|
||||||
|
QueryRowsCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error
|
||||||
QueryRowsPartial(v interface{}, query string, args ...interface{}) error
|
QueryRowsPartial(v interface{}, query string, args ...interface{}) error
|
||||||
|
QueryRowsPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// SqlConn only stands for raw connections, so Transact method can be called.
|
// SqlConn only stands for raw connections, so Transact method can be called.
|
||||||
@@ -27,7 +34,8 @@ type (
|
|||||||
// RawDB is for other ORM to operate with, use it with caution.
|
// RawDB is for other ORM to operate with, use it with caution.
|
||||||
// Notice: don't close it.
|
// Notice: don't close it.
|
||||||
RawDB() (*sql.DB, error)
|
RawDB() (*sql.DB, error)
|
||||||
Transact(func(session Session) error) error
|
Transact(fn func(Session) error) error
|
||||||
|
TransactCtx(ctx context.Context, fn func(context.Context, Session) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// SqlOption defines the method to customize a sql connection.
|
// SqlOption defines the method to customize a sql connection.
|
||||||
@@ -37,10 +45,15 @@ type (
|
|||||||
StmtSession interface {
|
StmtSession interface {
|
||||||
Close() error
|
Close() error
|
||||||
Exec(args ...interface{}) (sql.Result, error)
|
Exec(args ...interface{}) (sql.Result, error)
|
||||||
|
ExecCtx(ctx context.Context, args ...interface{}) (sql.Result, error)
|
||||||
QueryRow(v interface{}, args ...interface{}) error
|
QueryRow(v interface{}, args ...interface{}) error
|
||||||
|
QueryRowCtx(ctx context.Context, v interface{}, args ...interface{}) error
|
||||||
QueryRowPartial(v interface{}, args ...interface{}) error
|
QueryRowPartial(v interface{}, args ...interface{}) error
|
||||||
|
QueryRowPartialCtx(ctx context.Context, v interface{}, args ...interface{}) error
|
||||||
QueryRows(v interface{}, args ...interface{}) error
|
QueryRows(v interface{}, args ...interface{}) error
|
||||||
|
QueryRowsCtx(ctx context.Context, v interface{}, args ...interface{}) error
|
||||||
QueryRowsPartial(v interface{}, args ...interface{}) error
|
QueryRowsPartial(v interface{}, args ...interface{}) error
|
||||||
|
QueryRowsPartialCtx(ctx context.Context, v interface{}, args ...interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread-safe
|
// thread-safe
|
||||||
@@ -58,7 +71,9 @@ type (
|
|||||||
|
|
||||||
sessionConn interface {
|
sessionConn interface {
|
||||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||||
|
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
statement struct {
|
statement struct {
|
||||||
@@ -68,7 +83,9 @@ type (
|
|||||||
|
|
||||||
stmtConn interface {
|
stmtConn interface {
|
||||||
Exec(args ...interface{}) (sql.Result, error)
|
Exec(args ...interface{}) (sql.Result, error)
|
||||||
|
ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error)
|
||||||
Query(args ...interface{}) (*sql.Rows, error)
|
Query(args ...interface{}) (*sql.Rows, error)
|
||||||
|
QueryContext(ctx context.Context, args ...interface{}) (*sql.Rows, error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -112,6 +129,11 @@ func NewSqlConnFromDB(db *sql.DB, opts ...SqlOption) SqlConn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result, err error) {
|
func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result, err error) {
|
||||||
|
return db.ExecCtx(context.Background(), q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) ExecCtx(ctx context.Context, q string, args ...interface{}) (
|
||||||
|
result sql.Result, err error) {
|
||||||
err = db.brk.DoWithAcceptable(func() error {
|
err = db.brk.DoWithAcceptable(func() error {
|
||||||
var conn *sql.DB
|
var conn *sql.DB
|
||||||
conn, err = db.connProv()
|
conn, err = db.connProv()
|
||||||
@@ -120,7 +142,7 @@ func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err = exec(conn, q, args...)
|
result, err = exec(ctx, conn, q, args...)
|
||||||
return err
|
return err
|
||||||
}, db.acceptable)
|
}, db.acceptable)
|
||||||
|
|
||||||
@@ -128,6 +150,10 @@ func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) {
|
func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) {
|
||||||
|
return db.PrepareCtx(context.Background(), query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) PrepareCtx(ctx context.Context, query string) (stmt StmtSession, err error) {
|
||||||
err = db.brk.DoWithAcceptable(func() error {
|
err = db.brk.DoWithAcceptable(func() error {
|
||||||
var conn *sql.DB
|
var conn *sql.DB
|
||||||
conn, err = db.connProv()
|
conn, err = db.connProv()
|
||||||
@@ -136,7 +162,7 @@ func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
st, err := conn.Prepare(query)
|
st, err := conn.PrepareContext(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -152,25 +178,45 @@ func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) QueryRow(v interface{}, q string, args ...interface{}) error {
|
func (db *commonSqlConn) QueryRow(v interface{}, q string, args ...interface{}) error {
|
||||||
return db.queryRows(func(rows *sql.Rows) error {
|
return db.QueryRowCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) QueryRowCtx(ctx context.Context, v interface{}, q string,
|
||||||
|
args ...interface{}) error {
|
||||||
|
return db.queryRows(ctx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(v, rows, true)
|
return unmarshalRow(v, rows, true)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
func (db *commonSqlConn) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
||||||
return db.queryRows(func(rows *sql.Rows) error {
|
return db.QueryRowPartialCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) QueryRowPartialCtx(ctx context.Context, v interface{},
|
||||||
|
q string, args ...interface{}) error {
|
||||||
|
return db.queryRows(ctx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(v, rows, false)
|
return unmarshalRow(v, rows, false)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) QueryRows(v interface{}, q string, args ...interface{}) error {
|
func (db *commonSqlConn) QueryRows(v interface{}, q string, args ...interface{}) error {
|
||||||
return db.queryRows(func(rows *sql.Rows) error {
|
return db.QueryRowsCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) QueryRowsCtx(ctx context.Context, v interface{}, q string,
|
||||||
|
args ...interface{}) error {
|
||||||
|
return db.queryRows(ctx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(v, rows, true)
|
return unmarshalRows(v, rows, true)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
func (db *commonSqlConn) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
||||||
return db.queryRows(func(rows *sql.Rows) error {
|
return db.QueryRowsPartialCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) QueryRowsPartialCtx(ctx context.Context, v interface{},
|
||||||
|
q string, args ...interface{}) error {
|
||||||
|
return db.queryRows(ctx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(v, rows, false)
|
return unmarshalRows(v, rows, false)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
@@ -180,13 +226,19 @@ func (db *commonSqlConn) RawDB() (*sql.DB, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) Transact(fn func(Session) error) error {
|
func (db *commonSqlConn) Transact(fn func(Session) error) error {
|
||||||
|
return db.TransactCtx(context.Background(), func(_ context.Context, session Session) error {
|
||||||
|
return fn(session)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *commonSqlConn) TransactCtx(ctx context.Context, fn func(context.Context, Session) error) error {
|
||||||
return db.brk.DoWithAcceptable(func() error {
|
return db.brk.DoWithAcceptable(func() error {
|
||||||
return transact(db, db.beginTx, fn)
|
return transact(ctx, db, db.beginTx, fn)
|
||||||
}, db.acceptable)
|
}, db.acceptable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) acceptable(err error) bool {
|
func (db *commonSqlConn) acceptable(err error) bool {
|
||||||
ok := err == nil || err == sql.ErrNoRows || err == sql.ErrTxDone
|
ok := err == nil || err == sql.ErrNoRows || err == sql.ErrTxDone || err == context.Canceled
|
||||||
if db.accept == nil {
|
if db.accept == nil {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
@@ -194,7 +246,8 @@ func (db *commonSqlConn) acceptable(err error) bool {
|
|||||||
return ok || db.accept(err)
|
return ok || db.accept(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *commonSqlConn) queryRows(scanner func(*sql.Rows) error, q string, args ...interface{}) error {
|
func (db *commonSqlConn) queryRows(ctx context.Context, scanner func(*sql.Rows) error,
|
||||||
|
q string, args ...interface{}) error {
|
||||||
var qerr error
|
var qerr error
|
||||||
return db.brk.DoWithAcceptable(func() error {
|
return db.brk.DoWithAcceptable(func() error {
|
||||||
conn, err := db.connProv()
|
conn, err := db.connProv()
|
||||||
@@ -203,7 +256,7 @@ func (db *commonSqlConn) queryRows(scanner func(*sql.Rows) error, q string, args
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return query(conn, func(rows *sql.Rows) error {
|
return query(ctx, conn, func(rows *sql.Rows) error {
|
||||||
qerr = scanner(rows)
|
qerr = scanner(rows)
|
||||||
return qerr
|
return qerr
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
@@ -217,29 +270,49 @@ func (s statement) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s statement) Exec(args ...interface{}) (sql.Result, error) {
|
func (s statement) Exec(args ...interface{}) (sql.Result, error) {
|
||||||
return execStmt(s.stmt, s.query, args...)
|
return s.ExecCtx(context.Background(), args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s statement) ExecCtx(ctx context.Context, args ...interface{}) (sql.Result, error) {
|
||||||
|
return execStmt(ctx, s.stmt, s.query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s statement) QueryRow(v interface{}, args ...interface{}) error {
|
func (s statement) QueryRow(v interface{}, args ...interface{}) error {
|
||||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
return s.QueryRowCtx(context.Background(), v, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s statement) QueryRowCtx(ctx context.Context, v interface{}, args ...interface{}) error {
|
||||||
|
return queryStmt(ctx, s.stmt, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(v, rows, true)
|
return unmarshalRow(v, rows, true)
|
||||||
}, s.query, args...)
|
}, s.query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s statement) QueryRowPartial(v interface{}, args ...interface{}) error {
|
func (s statement) QueryRowPartial(v interface{}, args ...interface{}) error {
|
||||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
return s.QueryRowPartialCtx(context.Background(), v, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s statement) QueryRowPartialCtx(ctx context.Context, v interface{}, args ...interface{}) error {
|
||||||
|
return queryStmt(ctx, s.stmt, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(v, rows, false)
|
return unmarshalRow(v, rows, false)
|
||||||
}, s.query, args...)
|
}, s.query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s statement) QueryRows(v interface{}, args ...interface{}) error {
|
func (s statement) QueryRows(v interface{}, args ...interface{}) error {
|
||||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
return s.QueryRowsCtx(context.Background(), v, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s statement) QueryRowsCtx(ctx context.Context, v interface{}, args ...interface{}) error {
|
||||||
|
return queryStmt(ctx, s.stmt, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(v, rows, true)
|
return unmarshalRows(v, rows, true)
|
||||||
}, s.query, args...)
|
}, s.query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s statement) QueryRowsPartial(v interface{}, args ...interface{}) error {
|
func (s statement) QueryRowsPartial(v interface{}, args ...interface{}) error {
|
||||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
return s.QueryRowsPartialCtx(context.Background(), v, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s statement) QueryRowsPartialCtx(ctx context.Context, v interface{}, args ...interface{}) error {
|
||||||
|
return queryStmt(ctx, s.stmt, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(v, rows, false)
|
return unmarshalRows(v, rows, false)
|
||||||
}, s.query, args...)
|
}, s.query, args...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -18,64 +19,65 @@ func SetSlowThreshold(threshold time.Duration) {
|
|||||||
slowThreshold.Set(threshold)
|
slowThreshold.Set(threshold)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exec(conn sessionConn, q string, args ...interface{}) (sql.Result, error) {
|
func exec(ctx context.Context, conn sessionConn, q string, args ...interface{}) (sql.Result, error) {
|
||||||
stmt, err := format(q, args...)
|
stmt, err := format(q, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := timex.Now()
|
startTime := timex.Now()
|
||||||
result, err := conn.Exec(q, args...)
|
result, err := conn.ExecContext(ctx, q, args...)
|
||||||
duration := timex.Since(startTime)
|
duration := timex.Since(startTime)
|
||||||
if duration > slowThreshold.Load() {
|
if duration > slowThreshold.Load() {
|
||||||
logx.WithDuration(duration).Slowf("[SQL] exec: slowcall - %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Slowf("[SQL] exec: slowcall - %s", stmt)
|
||||||
} else {
|
} else {
|
||||||
logx.WithDuration(duration).Infof("sql exec: %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Infof("sql exec: %s", stmt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logSqlError(stmt, err)
|
logSqlError(ctx, stmt, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func execStmt(conn stmtConn, q string, args ...interface{}) (sql.Result, error) {
|
func execStmt(ctx context.Context, conn stmtConn, q string, args ...interface{}) (sql.Result, error) {
|
||||||
stmt, err := format(q, args...)
|
stmt, err := format(q, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := timex.Now()
|
startTime := timex.Now()
|
||||||
result, err := conn.Exec(args...)
|
result, err := conn.ExecContext(ctx, args...)
|
||||||
duration := timex.Since(startTime)
|
duration := timex.Since(startTime)
|
||||||
if duration > slowThreshold.Load() {
|
if duration > slowThreshold.Load() {
|
||||||
logx.WithDuration(duration).Slowf("[SQL] execStmt: slowcall - %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Slowf("[SQL] execStmt: slowcall - %s", stmt)
|
||||||
} else {
|
} else {
|
||||||
logx.WithDuration(duration).Infof("sql execStmt: %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Infof("sql execStmt: %s", stmt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logSqlError(stmt, err)
|
logSqlError(ctx, stmt, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func query(conn sessionConn, scanner func(*sql.Rows) error, q string, args ...interface{}) error {
|
func query(ctx context.Context, conn sessionConn, scanner func(*sql.Rows) error,
|
||||||
|
q string, args ...interface{}) error {
|
||||||
stmt, err := format(q, args...)
|
stmt, err := format(q, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := timex.Now()
|
startTime := timex.Now()
|
||||||
rows, err := conn.Query(q, args...)
|
rows, err := conn.QueryContext(ctx, q, args...)
|
||||||
duration := timex.Since(startTime)
|
duration := timex.Since(startTime)
|
||||||
if duration > slowThreshold.Load() {
|
if duration > slowThreshold.Load() {
|
||||||
logx.WithDuration(duration).Slowf("[SQL] query: slowcall - %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Slowf("[SQL] query: slowcall - %s", stmt)
|
||||||
} else {
|
} else {
|
||||||
logx.WithDuration(duration).Infof("sql query: %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Infof("sql query: %s", stmt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logSqlError(stmt, err)
|
logSqlError(ctx, stmt, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
@@ -83,22 +85,23 @@ func query(conn sessionConn, scanner func(*sql.Rows) error, q string, args ...in
|
|||||||
return scanner(rows)
|
return scanner(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryStmt(conn stmtConn, scanner func(*sql.Rows) error, q string, args ...interface{}) error {
|
func queryStmt(ctx context.Context, conn stmtConn, scanner func(*sql.Rows) error,
|
||||||
|
q string, args ...interface{}) error {
|
||||||
stmt, err := format(q, args...)
|
stmt, err := format(q, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := timex.Now()
|
startTime := timex.Now()
|
||||||
rows, err := conn.Query(args...)
|
rows, err := conn.QueryContext(ctx, args...)
|
||||||
duration := timex.Since(startTime)
|
duration := timex.Since(startTime)
|
||||||
if duration > slowThreshold.Load() {
|
if duration > slowThreshold.Load() {
|
||||||
logx.WithDuration(duration).Slowf("[SQL] queryStmt: slowcall - %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Slowf("[SQL] queryStmt: slowcall - %s", stmt)
|
||||||
} else {
|
} else {
|
||||||
logx.WithDuration(duration).Infof("sql queryStmt: %s", stmt)
|
logx.WithContext(ctx).WithDuration(duration).Infof("sql queryStmt: %s", stmt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logSqlError(stmt, err)
|
logSqlError(ctx, stmt, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -57,7 +58,7 @@ func TestStmt_exec(t *testing.T) {
|
|||||||
test := test
|
test := test
|
||||||
fns := []func(args ...interface{}) (sql.Result, error){
|
fns := []func(args ...interface{}) (sql.Result, error){
|
||||||
func(args ...interface{}) (sql.Result, error) {
|
func(args ...interface{}) (sql.Result, error) {
|
||||||
return exec(&mockedSessionConn{
|
return exec(context.Background(), &mockedSessionConn{
|
||||||
lastInsertId: test.lastInsertId,
|
lastInsertId: test.lastInsertId,
|
||||||
rowsAffected: test.rowsAffected,
|
rowsAffected: test.rowsAffected,
|
||||||
err: test.err,
|
err: test.err,
|
||||||
@@ -65,7 +66,7 @@ func TestStmt_exec(t *testing.T) {
|
|||||||
}, test.query, args...)
|
}, test.query, args...)
|
||||||
},
|
},
|
||||||
func(args ...interface{}) (sql.Result, error) {
|
func(args ...interface{}) (sql.Result, error) {
|
||||||
return execStmt(&mockedStmtConn{
|
return execStmt(context.Background(), &mockedStmtConn{
|
||||||
lastInsertId: test.lastInsertId,
|
lastInsertId: test.lastInsertId,
|
||||||
rowsAffected: test.rowsAffected,
|
rowsAffected: test.rowsAffected,
|
||||||
err: test.err,
|
err: test.err,
|
||||||
@@ -137,7 +138,7 @@ func TestStmt_query(t *testing.T) {
|
|||||||
test := test
|
test := test
|
||||||
fns := []func(args ...interface{}) error{
|
fns := []func(args ...interface{}) error{
|
||||||
func(args ...interface{}) error {
|
func(args ...interface{}) error {
|
||||||
return query(&mockedSessionConn{
|
return query(context.Background(), &mockedSessionConn{
|
||||||
err: test.err,
|
err: test.err,
|
||||||
delay: test.delay,
|
delay: test.delay,
|
||||||
}, func(rows *sql.Rows) error {
|
}, func(rows *sql.Rows) error {
|
||||||
@@ -145,7 +146,7 @@ func TestStmt_query(t *testing.T) {
|
|||||||
}, test.query, args...)
|
}, test.query, args...)
|
||||||
},
|
},
|
||||||
func(args ...interface{}) error {
|
func(args ...interface{}) error {
|
||||||
return queryStmt(&mockedStmtConn{
|
return queryStmt(context.Background(), &mockedStmtConn{
|
||||||
err: test.err,
|
err: test.err,
|
||||||
delay: test.delay,
|
delay: test.delay,
|
||||||
}, func(rows *sql.Rows) error {
|
}, func(rows *sql.Rows) error {
|
||||||
@@ -185,6 +186,10 @@ type mockedSessionConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockedSessionConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
func (m *mockedSessionConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return m.ExecContext(context.Background(), query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockedSessionConn) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||||
if m.delay {
|
if m.delay {
|
||||||
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
||||||
}
|
}
|
||||||
@@ -195,6 +200,10 @@ func (m *mockedSessionConn) Exec(query string, args ...interface{}) (sql.Result,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockedSessionConn) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
func (m *mockedSessionConn) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||||
|
return m.QueryContext(context.Background(), query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockedSessionConn) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
||||||
if m.delay {
|
if m.delay {
|
||||||
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
||||||
}
|
}
|
||||||
@@ -214,6 +223,10 @@ type mockedStmtConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockedStmtConn) Exec(args ...interface{}) (sql.Result, error) {
|
func (m *mockedStmtConn) Exec(args ...interface{}) (sql.Result, error) {
|
||||||
|
return m.ExecContext(context.Background(), args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockedStmtConn) ExecContext(_ context.Context, _ ...interface{}) (sql.Result, error) {
|
||||||
if m.delay {
|
if m.delay {
|
||||||
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
||||||
}
|
}
|
||||||
@@ -224,6 +237,10 @@ func (m *mockedStmtConn) Exec(args ...interface{}) (sql.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockedStmtConn) Query(args ...interface{}) (*sql.Rows, error) {
|
func (m *mockedStmtConn) Query(args ...interface{}) (*sql.Rows, error) {
|
||||||
|
return m.QueryContext(context.Background(), args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockedStmtConn) QueryContext(_ context.Context, _ ...interface{}) (*sql.Rows, error) {
|
||||||
if m.delay {
|
if m.delay {
|
||||||
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
time.Sleep(defaultSlowThreshold + time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
@@ -26,11 +27,19 @@ func NewSessionFromTx(tx *sql.Tx) Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t txSession) Exec(q string, args ...interface{}) (sql.Result, error) {
|
func (t txSession) Exec(q string, args ...interface{}) (sql.Result, error) {
|
||||||
return exec(t.Tx, q, args...)
|
return t.ExecCtx(context.Background(), q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t txSession) ExecCtx(ctx context.Context, q string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return exec(ctx, t.Tx, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t txSession) Prepare(q string) (StmtSession, error) {
|
func (t txSession) Prepare(q string) (StmtSession, error) {
|
||||||
stmt, err := t.Tx.Prepare(q)
|
return t.PrepareCtx(context.Background(), q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t txSession) PrepareCtx(ctx context.Context, q string) (StmtSession, error) {
|
||||||
|
stmt, err := t.Tx.PrepareContext(ctx, q)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -42,25 +51,43 @@ func (t txSession) Prepare(q string) (StmtSession, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t txSession) QueryRow(v interface{}, q string, args ...interface{}) error {
|
func (t txSession) QueryRow(v interface{}, q string, args ...interface{}) error {
|
||||||
return query(t.Tx, func(rows *sql.Rows) error {
|
return t.QueryRowCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t txSession) QueryRowCtx(ctx context.Context, v interface{}, q string, args ...interface{}) error {
|
||||||
|
return query(ctx, t.Tx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(v, rows, true)
|
return unmarshalRow(v, rows, true)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t txSession) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
func (t txSession) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
||||||
return query(t.Tx, func(rows *sql.Rows) error {
|
return t.QueryRowPartialCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t txSession) QueryRowPartialCtx(ctx context.Context, v interface{}, q string,
|
||||||
|
args ...interface{}) error {
|
||||||
|
return query(ctx, t.Tx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRow(v, rows, false)
|
return unmarshalRow(v, rows, false)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t txSession) QueryRows(v interface{}, q string, args ...interface{}) error {
|
func (t txSession) QueryRows(v interface{}, q string, args ...interface{}) error {
|
||||||
return query(t.Tx, func(rows *sql.Rows) error {
|
return t.QueryRowsCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t txSession) QueryRowsCtx(ctx context.Context, v interface{}, q string, args ...interface{}) error {
|
||||||
|
return query(ctx, t.Tx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(v, rows, true)
|
return unmarshalRows(v, rows, true)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t txSession) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
func (t txSession) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
||||||
return query(t.Tx, func(rows *sql.Rows) error {
|
return t.QueryRowsPartialCtx(context.Background(), v, q, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t txSession) QueryRowsPartialCtx(ctx context.Context, v interface{}, q string,
|
||||||
|
args ...interface{}) error {
|
||||||
|
return query(ctx, t.Tx, func(rows *sql.Rows) error {
|
||||||
return unmarshalRows(v, rows, false)
|
return unmarshalRows(v, rows, false)
|
||||||
}, q, args...)
|
}, q, args...)
|
||||||
}
|
}
|
||||||
@@ -76,17 +103,19 @@ func begin(db *sql.DB) (trans, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func transact(db *commonSqlConn, b beginnable, fn func(Session) error) (err error) {
|
func transact(ctx context.Context, db *commonSqlConn, b beginnable,
|
||||||
|
fn func(context.Context, Session) error) (err error) {
|
||||||
conn, err := db.connProv()
|
conn, err := db.connProv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.onError(err)
|
db.onError(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return transactOnConn(conn, b, fn)
|
return transactOnConn(ctx, conn, b, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func transactOnConn(conn *sql.DB, b beginnable, fn func(Session) error) (err error) {
|
func transactOnConn(ctx context.Context, conn *sql.DB, b beginnable,
|
||||||
|
fn func(context.Context, Session) error) (err error) {
|
||||||
var tx trans
|
var tx trans
|
||||||
tx, err = b(conn)
|
tx, err = b(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -96,18 +125,18 @@ func transactOnConn(conn *sql.DB, b beginnable, fn func(Session) error) (err err
|
|||||||
defer func() {
|
defer func() {
|
||||||
if p := recover(); p != nil {
|
if p := recover(); p != nil {
|
||||||
if e := tx.Rollback(); e != nil {
|
if e := tx.Rollback(); e != nil {
|
||||||
err = fmt.Errorf("recover from %#v, rollback failed: %s", p, e)
|
err = fmt.Errorf("recover from %#v, rollback failed: %w", p, e)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("recoveer from %#v", p)
|
err = fmt.Errorf("recoveer from %#v", p)
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
if e := tx.Rollback(); e != nil {
|
if e := tx.Rollback(); e != nil {
|
||||||
err = fmt.Errorf("transaction failed: %s, rollback failed: %s", err, e)
|
err = fmt.Errorf("transaction failed: %s, rollback failed: %w", err, e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return fn(tx)
|
return fn(ctx, tx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -26,26 +27,50 @@ func (mt *mockTx) Exec(q string, args ...interface{}) (sql.Result, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mt *mockTx) ExecCtx(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mt *mockTx) Prepare(query string) (StmtSession, error) {
|
func (mt *mockTx) Prepare(query string) (StmtSession, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mt *mockTx) PrepareCtx(ctx context.Context, query string) (StmtSession, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mt *mockTx) QueryRow(v interface{}, q string, args ...interface{}) error {
|
func (mt *mockTx) QueryRow(v interface{}, q string, args ...interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mt *mockTx) QueryRowCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mt *mockTx) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
func (mt *mockTx) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mt *mockTx) QueryRowPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mt *mockTx) QueryRows(v interface{}, q string, args ...interface{}) error {
|
func (mt *mockTx) QueryRows(v interface{}, q string, args ...interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mt *mockTx) QueryRowsCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mt *mockTx) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
func (mt *mockTx) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mt *mockTx) QueryRowsPartialCtx(ctx context.Context, v interface{}, query string, args ...interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mt *mockTx) Rollback() error {
|
func (mt *mockTx) Rollback() error {
|
||||||
mt.status |= mockRollback
|
mt.status |= mockRollback
|
||||||
return nil
|
return nil
|
||||||
@@ -59,7 +84,8 @@ func beginMock(mock *mockTx) beginnable {
|
|||||||
|
|
||||||
func TestTransactCommit(t *testing.T) {
|
func TestTransactCommit(t *testing.T) {
|
||||||
mock := &mockTx{}
|
mock := &mockTx{}
|
||||||
err := transactOnConn(nil, beginMock(mock), func(Session) error {
|
err := transactOnConn(context.Background(), nil, beginMock(mock),
|
||||||
|
func(context.Context, Session) error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
assert.Equal(t, mockCommit, mock.status)
|
assert.Equal(t, mockCommit, mock.status)
|
||||||
@@ -68,7 +94,8 @@ func TestTransactCommit(t *testing.T) {
|
|||||||
|
|
||||||
func TestTransactRollback(t *testing.T) {
|
func TestTransactRollback(t *testing.T) {
|
||||||
mock := &mockTx{}
|
mock := &mockTx{}
|
||||||
err := transactOnConn(nil, beginMock(mock), func(Session) error {
|
err := transactOnConn(context.Background(), nil, beginMock(mock),
|
||||||
|
func(context.Context, Session) error {
|
||||||
return errors.New("rollback")
|
return errors.New("rollback")
|
||||||
})
|
})
|
||||||
assert.Equal(t, mockRollback, mock.status)
|
assert.Equal(t, mockRollback, mock.status)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlx
|
package sqlx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -109,9 +110,9 @@ func logInstanceError(datasource string, err error) {
|
|||||||
logx.Errorf("Error on getting sql instance of %s: %v", datasource, err)
|
logx.Errorf("Error on getting sql instance of %s: %v", datasource, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logSqlError(stmt string, err error) {
|
func logSqlError(ctx context.Context, stmt string, err error) {
|
||||||
if err != nil && err != ErrNotFound {
|
if err != nil && err != ErrNotFound {
|
||||||
logx.Errorf("stmt: %s, error: %s", stmt, err.Error())
|
logx.WithContext(ctx).Errorf("stmt: %s, error: %s", stmt, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/lang"
|
"github.com/zeromicro/go-zero/core/lang"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// errTimeout indicates a timeout.
|
||||||
|
var errTimeout = errors.New("timeout")
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Ticker interface wraps the Chan and Stop methods.
|
// Ticker interface wraps the Chan and Stop methods.
|
||||||
Ticker interface {
|
Ticker interface {
|
||||||
@@ -70,7 +73,7 @@ func (ft *fakeTicker) Tick() {
|
|||||||
func (ft *fakeTicker) Wait(d time.Duration) error {
|
func (ft *fakeTicker) Wait(d time.Duration) error {
|
||||||
select {
|
select {
|
||||||
case <-time.After(d):
|
case <-time.After(d):
|
||||||
return errors.New("timeout")
|
return errTimeout
|
||||||
case <-ft.done:
|
case <-ft.done:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
17
go.mod
17
go.mod
@@ -7,7 +7,6 @@ require (
|
|||||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||||
github.com/alicebob/miniredis/v2 v2.17.0
|
github.com/alicebob/miniredis/v2 v2.17.0
|
||||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
|
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
|
||||||
github.com/go-redis/redis v6.15.9+incompatible
|
|
||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0
|
github.com/golang-jwt/jwt/v4 v4.2.0
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
@@ -18,8 +17,8 @@ require (
|
|||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/spaolacci/murmur3 v1.1.0
|
github.com/spaolacci/murmur3 v1.1.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
go.etcd.io/etcd/api/v3 v3.5.1
|
go.etcd.io/etcd/api/v3 v3.5.2
|
||||||
go.etcd.io/etcd/client/v3 v3.5.1
|
go.etcd.io/etcd/client/v3 v3.5.2
|
||||||
go.opentelemetry.io/otel v1.3.0
|
go.opentelemetry.io/otel v1.3.0
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.3.0
|
go.opentelemetry.io/otel/exporters/jaeger v1.3.0
|
||||||
go.opentelemetry.io/otel/exporters/zipkin v1.3.0
|
go.opentelemetry.io/otel/exporters/zipkin v1.3.0
|
||||||
@@ -28,7 +27,7 @@ require (
|
|||||||
go.uber.org/automaxprocs v1.4.0
|
go.uber.org/automaxprocs v1.4.0
|
||||||
go.uber.org/goleak v1.1.12
|
go.uber.org/goleak v1.1.12
|
||||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
|
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
|
||||||
google.golang.org/grpc v1.43.0
|
google.golang.org/grpc v1.44.0
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||||
gopkg.in/h2non/gock.v1 v1.1.2
|
gopkg.in/h2non/gock.v1 v1.1.2
|
||||||
@@ -42,10 +41,14 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.10.0 // indirect
|
github.com/fatih/color v1.10.0 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/go-redis/redis/v8 v8.11.4
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||||
github.com/openzipkin/zipkin-go v0.4.0 // indirect
|
github.com/openzipkin/zipkin-go v0.4.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
|
go.uber.org/multierr v1.8.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2 // indirect
|
go.uber.org/zap v1.21.0 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7 // indirect
|
||||||
k8s.io/klog/v2 v2.40.1 // indirect
|
k8s.io/klog/v2 v2.40.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
57
go.sum
57
go.sum
@@ -37,7 +37,6 @@ github.com/ClickHouse/clickhouse-go v1.5.1/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHg
|
|||||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
|
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
|
||||||
@@ -53,6 +52,7 @@ github.com/alicebob/miniredis/v2 v2.17.0 h1:EwLdrIS50uczw71Jc7iVSxZluTKj5nfSP8n7
|
|||||||
github.com/alicebob/miniredis/v2 v2.17.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I=
|
github.com/alicebob/miniredis/v2 v2.17.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
@@ -60,10 +60,9 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
@@ -73,7 +72,6 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h
|
|||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
@@ -87,6 +85,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
@@ -100,7 +100,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
@@ -142,8 +141,8 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9
|
|||||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
@@ -352,7 +351,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
@@ -381,10 +379,16 @@ github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5u
|
|||||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM=
|
go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.2 h1:tXok5yLlKyuQ/SXSjtqHc4uzNaMqZi2XsoSPr/LlJXI=
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.2 h1:4hzqQ6hIb3blLyQ8usCU4h3NghkqcsohEQ3o3VetYxE=
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.1 h1:oImGuV5LGKjCqXdjkMHCyWa5OO1gYKCnC/1sgdfj1Uk=
|
go.etcd.io/etcd/client/v3 v3.5.1 h1:oImGuV5LGKjCqXdjkMHCyWa5OO1gYKCnC/1sgdfj1Uk=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
|
go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.2 h1:WdnejrUtQC4nCxK0/dLTMqKOB+U5TP/2Ya0BJL+1otA=
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
@@ -402,14 +406,21 @@ go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKu
|
|||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
||||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||||
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||||
|
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
|
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
|
||||||
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@@ -486,8 +497,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -548,10 +561,14 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -647,8 +664,10 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG
|
|||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2 h1:z+R4M/SuyaRsj1zu3WC+nIQyfSrSIpuDcY01/R3uCtg=
|
google.golang.org/genproto v0.0.0-20220211171837-173942840c17 h1:2X+CNIheCutWRyKRte8szGxrE5ggtV4U+NKAbh/oLhg=
|
||||||
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7 h1:ntPPoHzFW6Xp09ueznmahONZufyoSakK/piXnr2BU3I=
|
||||||
|
google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
@@ -660,10 +679,9 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
|
||||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||||
google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
|
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
|
||||||
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -719,7 +737,6 @@ k8s.io/client-go v0.20.12 h1:U75SxTC31BHT9i7CbX/hL4v+U1Wkzy/E1vt5ClDPp3I=
|
|||||||
k8s.io/client-go v0.20.12/go.mod h1:NBJj6Evp73Xy/4v/O/RDRaH0+3JoxNfjRxkyRgrdbsA=
|
k8s.io/client-go v0.20.12/go.mod h1:NBJj6Evp73Xy/4v/O/RDRaH0+3JoxNfjRxkyRgrdbsA=
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
|
|
||||||
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4=
|
k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4=
|
||||||
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
|
|||||||
34
readme-cn.md
34
readme-cn.md
@@ -11,7 +11,17 @@
|
|||||||
[](https://github.com/zeromicro/go-zero)
|
[](https://github.com/zeromicro/go-zero)
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
**注意:为了满足开源基金会要求,go-zero 从好未来(tal-tech)组织下迁移至中立的 GitHub 组织(zeromicro)。**
|
> ***缩短从需求到上线的距离***
|
||||||
|
|
||||||
|
**为了满足开源基金会要求,go-zero 从好未来(tal-tech)组织下迁移至中立的 GitHub 组织(zeromicro)。**
|
||||||
|
|
||||||
|
> ***注意:***
|
||||||
|
>
|
||||||
|
> 从 v1.3.0 之前版本升级请执行以下命令:
|
||||||
|
>
|
||||||
|
> GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
|
||||||
|
>
|
||||||
|
> goctl migrate —verbose —version v1.3.0
|
||||||
|
|
||||||
## 0. go-zero 介绍
|
## 0. go-zero 介绍
|
||||||
|
|
||||||
@@ -87,7 +97,7 @@ go-zero 是一个集成了各种工程实践的包含 web 和 rpc 框架,有
|
|||||||
在项目目录下通过如下命令安装:
|
在项目目录下通过如下命令安装:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero
|
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. Quick Start
|
## 5. Quick Start
|
||||||
@@ -104,10 +114,10 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Go 1.15 及之前版本
|
# Go 1.15 及之前版本
|
||||||
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl@latest
|
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero/tools/goctl@latest
|
||||||
|
|
||||||
# Go 1.16 及以后版本
|
# Go 1.16 及以后版本
|
||||||
GOPROXY=https://goproxy.cn/,direct go install github.com/tal-tech/go-zero/tools/goctl@latest
|
GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
确保 goctl 可执行
|
确保 goctl 可执行
|
||||||
@@ -232,12 +242,16 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
|
|||||||
>46. 上海游族网络
|
>46. 上海游族网络
|
||||||
>47. 深信服
|
>47. 深信服
|
||||||
>48. 中免日上科技互联有限公司
|
>48. 中免日上科技互联有限公司
|
||||||
>48. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED
|
>49. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED
|
||||||
>48. 馨科智(深圳)科技有限公司
|
>50. 馨科智(深圳)科技有限公司
|
||||||
>48. 成都松珀科技有限公司
|
>51. 成都松珀科技有限公司
|
||||||
>48. 亿景智联
|
>52. 亿景智联
|
||||||
>48. 上海扩博智能技术有限公司
|
>53. 上海扩博智能技术有限公司
|
||||||
>48. 一犀科技成都有限公司
|
>54. 一犀科技成都有限公司
|
||||||
|
>55. 北京术杰科技有限公司
|
||||||
|
>56. 时代脉搏网络科技(云浮市)有限公司
|
||||||
|
>57. 店有帮
|
||||||
|
>58. 七牛云
|
||||||
|
|
||||||
如果贵公司也已使用 go-zero,欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。
|
如果贵公司也已使用 go-zero,欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。
|
||||||
|
|
||||||
|
|||||||
18
readme.md
18
readme.md
@@ -9,9 +9,19 @@ English | [简体中文](readme-cn.md)
|
|||||||
[](https://goreportcard.com/report/github.com/zeromicro/go-zero)
|
[](https://goreportcard.com/report/github.com/zeromicro/go-zero)
|
||||||
[](https://github.com/zeromicro/go-zero)
|
[](https://github.com/zeromicro/go-zero)
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
[](https://discord.gg/4JQvC5A4Fe)
|
||||||
|
<a href="https://www.producthunt.com/posts/go-zero?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-go-zero" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=334030&theme=light" alt="go-zero - A web & rpc framework written in Go. | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||||
|
|
||||||
**Note: To meet the requirements of Open Source Foundation, we moved go-zero from tal-tech to zeromicro (a neutral GitHub organization).**
|
**Note: To meet the requirements of Open Source Foundation, we moved go-zero from tal-tech to zeromicro (a neutral GitHub organization).**
|
||||||
|
|
||||||
|
> ***Important!***
|
||||||
|
>
|
||||||
|
> To upgrade from previous versions, run the following commands.
|
||||||
|
>
|
||||||
|
> `go install github.com/zeromicro/go-zero/tools/goctl@latest`
|
||||||
|
>
|
||||||
|
> `goctl migrate —verbose —version v1.3.0`
|
||||||
|
|
||||||
## 0. what is go-zero
|
## 0. what is go-zero
|
||||||
|
|
||||||
go-zero (listed in CNCF Landscape: [https://landscape.cncf.io/?selected=go-zero](https://landscape.cncf.io/?selected=go-zero)) is a web and rpc framework with lots of builtin engineering practices. It’s born to ensure the stability of the busy services with resilience design and has been serving sites with tens of millions of users for years.
|
go-zero (listed in CNCF Landscape: [https://landscape.cncf.io/?selected=go-zero](https://landscape.cncf.io/?selected=go-zero)) is a web and rpc framework with lots of builtin engineering practices. It’s born to ensure the stability of the busy services with resilience design and has been serving sites with tens of millions of users for years.
|
||||||
@@ -90,7 +100,7 @@ As below, go-zero protects the system with a couple of layers and mechanisms:
|
|||||||
Run the following command under your project:
|
Run the following command under your project:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
go get -u github.com/tal-tech/go-zero
|
go get -u github.com/zeromicro/go-zero
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. Quick Start
|
## 6. Quick Start
|
||||||
@@ -107,10 +117,10 @@ go get -u github.com/tal-tech/go-zero
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
# for Go 1.15 and earlier
|
# for Go 1.15 and earlier
|
||||||
GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl@latest
|
GO111MODULE=on go get -u github.com/zeromicro/go-zero/tools/goctl@latest
|
||||||
|
|
||||||
# for Go 1.16 and later
|
# for Go 1.16 and later
|
||||||
go install github.com/tal-tech/go-zero/tools/goctl@latest
|
go install github.com/zeromicro/go-zero/tools/goctl@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
make sure goctl is executable.
|
make sure goctl is executable.
|
||||||
@@ -221,7 +231,7 @@ go get -u github.com/tal-tech/go-zero
|
|||||||
|
|
||||||
## 9. Chat group
|
## 9. Chat group
|
||||||
|
|
||||||
Join the chat via https://join.slack.com/t/go-zero/shared_invite/zt-10ruju779-BE4y6lQNB_R21samtyKTgA
|
Join the chat via https://discord.gg/4JQvC5A4Fe
|
||||||
|
|
||||||
## 10. Cloud Native Landscape
|
## 10. Cloud Native Landscape
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/rest/handler"
|
"github.com/zeromicro/go-zero/rest/handler"
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
"github.com/zeromicro/go-zero/rest/internal"
|
"github.com/zeromicro/go-zero/rest/internal"
|
||||||
|
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// use 1000m to represent 100%
|
// use 1000m to represent 100%
|
||||||
@@ -154,6 +155,27 @@ func (ng *engine) getShedder(priority bool) load.Shedder {
|
|||||||
return ng.shedder
|
return ng.shedder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// notFoundHandler returns a middleware that handles 404 not found requests.
|
||||||
|
func (ng *engine) notFoundHandler(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
chain := alice.New(
|
||||||
|
handler.TracingHandler(ng.conf.Name, ""),
|
||||||
|
ng.getLogHandler(),
|
||||||
|
)
|
||||||
|
|
||||||
|
var h http.Handler
|
||||||
|
if next != nil {
|
||||||
|
h = chain.Then(next)
|
||||||
|
} else {
|
||||||
|
h = chain.Then(http.NotFoundHandler())
|
||||||
|
}
|
||||||
|
|
||||||
|
cw := response.NewHeaderOnceResponseWriter(w)
|
||||||
|
h.ServeHTTP(cw, r)
|
||||||
|
cw.WriteHeader(http.StatusNotFound)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (ng *engine) setTlsConfig(cfg *tls.Config) {
|
func (ng *engine) setTlsConfig(cfg *tls.Config) {
|
||||||
ng.tlsConfig = cfg
|
ng.tlsConfig = cfg
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package rest
|
package rest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/zeromicro/go-zero/core/conf"
|
"github.com/zeromicro/go-zero/core/conf"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewEngine(t *testing.T) {
|
func TestNewEngine(t *testing.T) {
|
||||||
@@ -190,6 +194,75 @@ func TestEngine_checkedTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEngine_notFoundHandler(t *testing.T) {
|
||||||
|
logx.Disable()
|
||||||
|
|
||||||
|
ng := newEngine(RestConf{})
|
||||||
|
ts := httptest.NewServer(ng.notFoundHandler(nil))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
client := ts.Client()
|
||||||
|
err := func(ctx context.Context) error {
|
||||||
|
req, err := http.NewRequest("GET", ts.URL+"/bad", nil)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
res, err := client.Do(req)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
|
return res.Body.Close()
|
||||||
|
}(context.Background())
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEngine_notFoundHandlerNotNil(t *testing.T) {
|
||||||
|
logx.Disable()
|
||||||
|
|
||||||
|
ng := newEngine(RestConf{})
|
||||||
|
var called int32
|
||||||
|
ts := httptest.NewServer(ng.notFoundHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
atomic.AddInt32(&called, 1)
|
||||||
|
})))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
client := ts.Client()
|
||||||
|
err := func(ctx context.Context) error {
|
||||||
|
req, err := http.NewRequest("GET", ts.URL+"/bad", nil)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
res, err := client.Do(req)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
|
return res.Body.Close()
|
||||||
|
}(context.Background())
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, int32(1), atomic.LoadInt32(&called))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEngine_notFoundHandlerNotNilWriteHeader(t *testing.T) {
|
||||||
|
logx.Disable()
|
||||||
|
|
||||||
|
ng := newEngine(RestConf{})
|
||||||
|
var called int32
|
||||||
|
ts := httptest.NewServer(ng.notFoundHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
atomic.AddInt32(&called, 1)
|
||||||
|
w.WriteHeader(http.StatusExpectationFailed)
|
||||||
|
})))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
client := ts.Client()
|
||||||
|
err := func(ctx context.Context) error {
|
||||||
|
req, err := http.NewRequest("GET", ts.URL+"/bad", nil)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
res, err := client.Do(req)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, http.StatusExpectationFailed, res.StatusCode)
|
||||||
|
return res.Body.Close()
|
||||||
|
}(context.Background())
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, int32(1), atomic.LoadInt32(&called))
|
||||||
|
}
|
||||||
|
|
||||||
type mockedRouter struct{}
|
type mockedRouter struct{}
|
||||||
|
|
||||||
func (m mockedRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
func (m mockedRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||||
"github.com/zeromicro/go-zero/rest/token"
|
"github.com/zeromicro/go-zero/rest/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,7 +104,7 @@ func detailAuthLog(r *http.Request, reason string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback UnauthorizedCallback) {
|
func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback UnauthorizedCallback) {
|
||||||
writer := newGuardedResponseWriter(w)
|
writer := response.NewHeaderOnceResponseWriter(w)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
detailAuthLog(r, err.Error())
|
detailAuthLog(r, err.Error())
|
||||||
@@ -121,47 +120,3 @@ func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback Un
|
|||||||
// if user not setting HTTP header, we set header with 401
|
// if user not setting HTTP header, we set header with 401
|
||||||
writer.WriteHeader(http.StatusUnauthorized)
|
writer.WriteHeader(http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
type guardedResponseWriter struct {
|
|
||||||
writer http.ResponseWriter
|
|
||||||
wroteHeader bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGuardedResponseWriter(w http.ResponseWriter) *guardedResponseWriter {
|
|
||||||
return &guardedResponseWriter{
|
|
||||||
writer: w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (grw *guardedResponseWriter) Flush() {
|
|
||||||
if flusher, ok := grw.writer.(http.Flusher); ok {
|
|
||||||
flusher.Flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (grw *guardedResponseWriter) Header() http.Header {
|
|
||||||
return grw.writer.Header()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hijack implements the http.Hijacker interface.
|
|
||||||
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
|
|
||||||
func (grw *guardedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
||||||
if hijacked, ok := grw.writer.(http.Hijacker); ok {
|
|
||||||
return hijacked.Hijack()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil, errors.New("server doesn't support hijacking")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (grw *guardedResponseWriter) Write(body []byte) (int, error) {
|
|
||||||
return grw.writer.Write(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (grw *guardedResponseWriter) WriteHeader(statusCode int) {
|
|
||||||
if grw.wroteHeader {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
grw.wroteHeader = true
|
|
||||||
grw.writer.WriteHeader(statusCode)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,26 +90,6 @@ func TestAuthHandler_NilError(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthHandler_Flush(t *testing.T) {
|
|
||||||
resp := httptest.NewRecorder()
|
|
||||||
handler := newGuardedResponseWriter(resp)
|
|
||||||
handler.Flush()
|
|
||||||
assert.True(t, resp.Flushed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAuthHandler_Hijack(t *testing.T) {
|
|
||||||
resp := httptest.NewRecorder()
|
|
||||||
writer := newGuardedResponseWriter(resp)
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
writer.Hijack()
|
|
||||||
})
|
|
||||||
|
|
||||||
writer = newGuardedResponseWriter(mockedHijackable{resp})
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
writer.Hijack()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildToken(secretKey string, payloads map[string]interface{}, seconds int64) (string, error) {
|
func buildToken(secretKey string, payloads map[string]interface{}, seconds int64) (string, error) {
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
claims := make(jwt.MapClaims)
|
claims := make(jwt.MapClaims)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/core/stat"
|
"github.com/zeromicro/go-zero/core/stat"
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
"github.com/zeromicro/go-zero/rest/internal/security"
|
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
const breakerSeparator = "://"
|
const breakerSeparator = "://"
|
||||||
@@ -28,7 +28,7 @@ func BreakerHandler(method, path string, metrics *stat.Metrics) func(http.Handle
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cw := &security.WithCodeResponseWriter{Writer: w}
|
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||||
defer func() {
|
defer func() {
|
||||||
if cw.Code < http.StatusInternalServerError {
|
if cw.Code < http.StatusInternalServerError {
|
||||||
promise.Accept()
|
promise.Accept()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/metric"
|
"github.com/zeromicro/go-zero/core/metric"
|
||||||
"github.com/zeromicro/go-zero/core/prometheus"
|
"github.com/zeromicro/go-zero/core/prometheus"
|
||||||
"github.com/zeromicro/go-zero/core/timex"
|
"github.com/zeromicro/go-zero/core/timex"
|
||||||
"github.com/zeromicro/go-zero/rest/internal/security"
|
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
const serverNamespace = "http_server"
|
const serverNamespace = "http_server"
|
||||||
@@ -41,7 +41,7 @@ func PrometheusHandler(path string) func(http.Handler) http.Handler {
|
|||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
startTime := timex.Now()
|
startTime := timex.Now()
|
||||||
cw := &security.WithCodeResponseWriter{Writer: w}
|
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||||
defer func() {
|
defer func() {
|
||||||
metricServerReqDur.Observe(int64(timex.Since(startTime)/time.Millisecond), path)
|
metricServerReqDur.Observe(int64(timex.Since(startTime)/time.Millisecond), path)
|
||||||
metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code))
|
metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"github.com/zeromicro/go-zero/core/stat"
|
"github.com/zeromicro/go-zero/core/stat"
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
"github.com/zeromicro/go-zero/rest/internal/security"
|
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
const serviceType = "api"
|
const serviceType = "api"
|
||||||
@@ -41,7 +41,7 @@ func SheddingHandler(shedder load.Shedder, metrics *stat.Metrics) func(http.Hand
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cw := &security.WithCodeResponseWriter{Writer: w}
|
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||||
defer func() {
|
defer func() {
|
||||||
if cw.Code == http.StatusServiceUnavailable {
|
if cw.Code == http.StatusServiceUnavailable {
|
||||||
promise.Fail()
|
promise.Fail()
|
||||||
|
|||||||
@@ -18,12 +18,16 @@ func TracingHandler(serviceName, path string) func(http.Handler) http.Handler {
|
|||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||||
|
spanName := path
|
||||||
|
if len(spanName) == 0 {
|
||||||
|
spanName = r.URL.Path
|
||||||
|
}
|
||||||
spanCtx, span := tracer.Start(
|
spanCtx, span := tracer.Start(
|
||||||
ctx,
|
ctx,
|
||||||
path,
|
spanName,
|
||||||
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
|
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
|
||||||
oteltrace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest(
|
oteltrace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest(
|
||||||
serviceName, path, r)...),
|
serviceName, spanName, r)...),
|
||||||
)
|
)
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/justinas/alice"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
ztrace "github.com/zeromicro/go-zero/core/trace"
|
ztrace "github.com/zeromicro/go-zero/core/trace"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
@@ -21,13 +22,15 @@ func TestOtelHandler(t *testing.T) {
|
|||||||
Sampler: 1.0,
|
Sampler: 1.0,
|
||||||
})
|
})
|
||||||
|
|
||||||
ts := httptest.NewServer(
|
for _, test := range []string{"", "bar"} {
|
||||||
|
t.Run(test, func(t *testing.T) {
|
||||||
|
h := alice.New(TracingHandler("foo", test)).Then(
|
||||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||||
spanCtx := trace.SpanContextFromContext(ctx)
|
spanCtx := trace.SpanContextFromContext(ctx)
|
||||||
assert.Equal(t, true, spanCtx.IsValid())
|
assert.True(t, spanCtx.IsValid())
|
||||||
}),
|
}))
|
||||||
)
|
ts := httptest.NewServer(h)
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
|
|
||||||
client := ts.Client()
|
client := ts.Client()
|
||||||
@@ -39,10 +42,11 @@ func TestOtelHandler(t *testing.T) {
|
|||||||
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
|
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
|
||||||
|
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
assert.Equal(t, err, nil)
|
assert.Nil(t, err)
|
||||||
_ = res.Body.Close()
|
return res.Body.Close()
|
||||||
return nil
|
|
||||||
}(context.Background())
|
}(context.Background())
|
||||||
|
|
||||||
assert.Equal(t, err, nil)
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package cors
|
package cors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -30,7 +29,7 @@ const (
|
|||||||
// At most one origin can be specified, other origins are ignored if given, default to be *.
|
// At most one origin can be specified, other origins are ignored if given, default to be *.
|
||||||
func NotAllowedHandler(fn func(w http.ResponseWriter), origins ...string) http.Handler {
|
func NotAllowedHandler(fn func(w http.ResponseWriter), origins ...string) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
gw := &guardedResponseWriter{w: w}
|
gw := response.NewHeaderOnceResponseWriter(w)
|
||||||
checkAndSetHeaders(gw, r, origins)
|
checkAndSetHeaders(gw, r, origins)
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
fn(gw)
|
fn(gw)
|
||||||
@@ -62,44 +61,6 @@ func Middleware(fn func(w http.Header), origins ...string) func(http.HandlerFunc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type guardedResponseWriter struct {
|
|
||||||
w http.ResponseWriter
|
|
||||||
wroteHeader bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *guardedResponseWriter) Flush() {
|
|
||||||
if flusher, ok := w.w.(http.Flusher); ok {
|
|
||||||
flusher.Flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *guardedResponseWriter) Header() http.Header {
|
|
||||||
return w.w.Header()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hijack implements the http.Hijacker interface.
|
|
||||||
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
|
|
||||||
func (w *guardedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
||||||
if hijacked, ok := w.w.(http.Hijacker); ok {
|
|
||||||
return hijacked.Hijack()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil, errors.New("server doesn't support hijacking")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *guardedResponseWriter) Write(bytes []byte) (int, error) {
|
|
||||||
return w.w.Write(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *guardedResponseWriter) WriteHeader(code int) {
|
|
||||||
if w.wroteHeader {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.w.WriteHeader(code)
|
|
||||||
w.wroteHeader = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAndSetHeaders(w http.ResponseWriter, r *http.Request, origins []string) {
|
func checkAndSetHeaders(w http.ResponseWriter, r *http.Request, origins []string) {
|
||||||
setVaryHeaders(w, r)
|
setVaryHeaders(w, r)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package cors
|
package cors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -131,48 +129,3 @@ func TestCorsHandlerWithOrigins(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGuardedResponseWriter_Flush(t *testing.T) {
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
|
|
||||||
handler := NotAllowedHandler(func(w http.ResponseWriter) {
|
|
||||||
w.Header().Set("X-Test", "test")
|
|
||||||
w.WriteHeader(http.StatusServiceUnavailable)
|
|
||||||
_, err := w.Write([]byte("content"))
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
flusher, ok := w.(http.Flusher)
|
|
||||||
assert.True(t, ok)
|
|
||||||
flusher.Flush()
|
|
||||||
}, "foo.com")
|
|
||||||
|
|
||||||
resp := httptest.NewRecorder()
|
|
||||||
handler.ServeHTTP(resp, req)
|
|
||||||
assert.Equal(t, http.StatusServiceUnavailable, resp.Code)
|
|
||||||
assert.Equal(t, "test", resp.Header().Get("X-Test"))
|
|
||||||
assert.Equal(t, "content", resp.Body.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGuardedResponseWriter_Hijack(t *testing.T) {
|
|
||||||
resp := httptest.NewRecorder()
|
|
||||||
writer := &guardedResponseWriter{
|
|
||||||
w: resp,
|
|
||||||
}
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
writer.Hijack()
|
|
||||||
})
|
|
||||||
|
|
||||||
writer = &guardedResponseWriter{
|
|
||||||
w: mockedHijackable{resp},
|
|
||||||
}
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
writer.Hijack()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockedHijackable struct {
|
|
||||||
*httptest.ResponseRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockedHijackable) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
||||||
return nil, nil, nil
|
|
||||||
}
|
|
||||||
|
|||||||
57
rest/internal/response/headeronceresponsewriter.go
Normal file
57
rest/internal/response/headeronceresponsewriter.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HeaderOnceResponseWriter is a http.ResponseWriter implementation
|
||||||
|
// that only the first WriterHeader takes effect.
|
||||||
|
type HeaderOnceResponseWriter struct {
|
||||||
|
w http.ResponseWriter
|
||||||
|
wroteHeader bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHeaderOnceResponseWriter returns a HeaderOnceResponseWriter.
|
||||||
|
func NewHeaderOnceResponseWriter(w http.ResponseWriter) http.ResponseWriter {
|
||||||
|
return &HeaderOnceResponseWriter{w: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush flushes the response writer.
|
||||||
|
func (w *HeaderOnceResponseWriter) Flush() {
|
||||||
|
if flusher, ok := w.w.(http.Flusher); ok {
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header returns the http header.
|
||||||
|
func (w *HeaderOnceResponseWriter) Header() http.Header {
|
||||||
|
return w.w.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hijack implements the http.Hijacker interface.
|
||||||
|
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
|
||||||
|
func (w *HeaderOnceResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
if hijacked, ok := w.w.(http.Hijacker); ok {
|
||||||
|
return hijacked.Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil, errors.New("server doesn't support hijacking")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes bytes into w.
|
||||||
|
func (w *HeaderOnceResponseWriter) Write(bytes []byte) (int, error) {
|
||||||
|
return w.w.Write(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeader writes code into w, and not sealing the writer.
|
||||||
|
func (w *HeaderOnceResponseWriter) WriteHeader(code int) {
|
||||||
|
if w.wroteHeader {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.w.WriteHeader(code)
|
||||||
|
w.wroteHeader = true
|
||||||
|
}
|
||||||
58
rest/internal/response/headeronceresponsewriter_test.go
Normal file
58
rest/internal/response/headeronceresponsewriter_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHeaderOnceResponseWriter_Flush(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
cw := NewHeaderOnceResponseWriter(w)
|
||||||
|
cw.Header().Set("X-Test", "test")
|
||||||
|
cw.WriteHeader(http.StatusServiceUnavailable)
|
||||||
|
cw.WriteHeader(http.StatusExpectationFailed)
|
||||||
|
_, err := cw.Write([]byte("content"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
flusher, ok := cw.(http.Flusher)
|
||||||
|
assert.True(t, ok)
|
||||||
|
flusher.Flush()
|
||||||
|
})
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(resp, req)
|
||||||
|
assert.Equal(t, http.StatusServiceUnavailable, resp.Code)
|
||||||
|
assert.Equal(t, "test", resp.Header().Get("X-Test"))
|
||||||
|
assert.Equal(t, "content", resp.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeaderOnceResponseWriter_Hijack(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
writer := &HeaderOnceResponseWriter{
|
||||||
|
w: resp,
|
||||||
|
}
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
writer.Hijack()
|
||||||
|
})
|
||||||
|
|
||||||
|
writer = &HeaderOnceResponseWriter{
|
||||||
|
w: mockedHijackable{resp},
|
||||||
|
}
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
writer.Hijack()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockedHijackable struct {
|
||||||
|
*httptest.ResponseRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockedHijackable) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package security
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@@ -27,7 +28,11 @@ func (w *WithCodeResponseWriter) Header() http.Header {
|
|||||||
// Hijack implements the http.Hijacker interface.
|
// Hijack implements the http.Hijacker interface.
|
||||||
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
|
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
|
||||||
func (w *WithCodeResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
func (w *WithCodeResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
return w.Writer.(http.Hijacker).Hijack()
|
if hijacked, ok := w.Writer.(http.Hijacker); ok {
|
||||||
|
return hijacked.Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil, errors.New("server doesn't support hijacking")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes bytes into w.
|
// Write writes bytes into w.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package security
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -31,3 +31,20 @@ func TestWithCodeResponseWriter(t *testing.T) {
|
|||||||
assert.Equal(t, "test", resp.Header().Get("X-Test"))
|
assert.Equal(t, "test", resp.Header().Get("X-Test"))
|
||||||
assert.Equal(t, "content", resp.Body.String())
|
assert.Equal(t, "content", resp.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWithCodeResponseWriter_Hijack(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
writer := &WithCodeResponseWriter{
|
||||||
|
Writer: resp,
|
||||||
|
}
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
writer.Hijack()
|
||||||
|
})
|
||||||
|
|
||||||
|
writer = &WithCodeResponseWriter{
|
||||||
|
Writer: mockedHijackable{resp},
|
||||||
|
}
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
writer.Hijack()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ func NewServer(c RestConf, opts ...RunOption) (*Server, error) {
|
|||||||
router: router.NewRouter(),
|
router: router.NewRouter(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts = append([]RunOption{WithNotFoundHandler(nil)}, opts...)
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(server)
|
opt(server)
|
||||||
}
|
}
|
||||||
@@ -163,7 +164,8 @@ func WithMiddleware(middleware Middleware, rs ...Route) []Route {
|
|||||||
// WithNotFoundHandler returns a RunOption with not found handler set to given handler.
|
// WithNotFoundHandler returns a RunOption with not found handler set to given handler.
|
||||||
func WithNotFoundHandler(handler http.Handler) RunOption {
|
func WithNotFoundHandler(handler http.Handler) RunOption {
|
||||||
return func(server *Server) {
|
return func(server *Server) {
|
||||||
server.router.SetNotFoundHandler(handler)
|
notFoundHandler := server.ngin.notFoundHandler(handler)
|
||||||
|
server.router.SetNotFoundHandler(notFoundHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/logrusorgru/aurora"
|
"github.com/logrusorgru/aurora"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiTemplate = `
|
const apiTemplate = `
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package apigen
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/logx"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DartCommand create dart network request code
|
// DartCommand create dart network request code
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiTemplate = `import 'api.dart';
|
const apiTemplate = `import 'api.dart';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dataTemplate = `// --{{with .Info}}{{.Title}}{{end}}--
|
const dataTemplate = `// --{{with .Info}}{{.Title}}{{end}}--
|
||||||
@@ -19,12 +19,12 @@ class {{.Name}}{
|
|||||||
});
|
});
|
||||||
factory {{.Name}}.fromJson(Map<String,dynamic> m) {
|
factory {{.Name}}.fromJson(Map<String,dynamic> m) {
|
||||||
return {{.Name}}({{range .Members}}
|
return {{.Name}}({{range .Members}}
|
||||||
{{lowCamelCase .Name}}: {{if isDirectType .Type.Name}}m['{{tagGet .Tag "json"}}']{{else if isClassListType .Type.Name}}(m['{{tagGet .Tag "json"}}'] as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)){{else}}{{.Type.Name}}.fromJson(m['{{tagGet .Tag "json"}}']){{end}},{{end}}
|
{{lowCamelCase .Name}}: {{if isDirectType .Type.Name}}m['{{getPropertyFromMember .}}']{{else if isClassListType .Type.Name}}(m['{{getPropertyFromMember .}}'] as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)){{else}}{{.Type.Name}}.fromJson(m['{{getPropertyFromMember .}}']){{end}},{{end}}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Map<String,dynamic> toJson() {
|
Map<String,dynamic> toJson() {
|
||||||
return { {{range .Members}}
|
return { {{range .Members}}
|
||||||
'{{tagGet .Tag "json"}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
|
'{{getPropertyFromMember .}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
"github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func lowCamelCase(s string) string {
|
func lowCamelCase(s string) string {
|
||||||
@@ -34,18 +34,12 @@ func pathToFuncName(path string) string {
|
|||||||
return util.ToLower(camel[:1]) + camel[1:]
|
return util.ToLower(camel[:1]) + camel[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagGet(tag, k string) string {
|
func getPropertyFromMember(member spec.Member) string {
|
||||||
tags, err := spec.Parse(tag)
|
name, err := member.GetPropertyName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(k + " not exist")
|
panic(fmt.Sprintf("cannot get property name of %q", member.Name))
|
||||||
}
|
}
|
||||||
|
return name
|
||||||
v, err := tags.Get(k)
|
|
||||||
if err != nil {
|
|
||||||
panic(k + " value not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
return v.Name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isDirectType(s string) bool {
|
func isDirectType(s string) bool {
|
||||||
|
|||||||
39
tools/goctl/api/dartgen/util_test.go
Normal file
39
tools/goctl/api/dartgen/util_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package dartgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_getPropertyFromMember(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
member spec.Member
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "json tag should be ok",
|
||||||
|
member: spec.Member{
|
||||||
|
Tag: "`json:\"foo\"`",
|
||||||
|
Name: "Foo",
|
||||||
|
},
|
||||||
|
want: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "form tag should be ok",
|
||||||
|
member: spec.Member{
|
||||||
|
Tag: "`form:\"bar\"`",
|
||||||
|
Name: "Bar",
|
||||||
|
},
|
||||||
|
want: "bar",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := getPropertyFromMember(tt.member); got != tt.want {
|
||||||
|
t.Errorf("getPropertyFromMember() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package dartgen
|
|||||||
import "text/template"
|
import "text/template"
|
||||||
|
|
||||||
var funcMap = template.FuncMap{
|
var funcMap = template.FuncMap{
|
||||||
"tagGet": tagGet,
|
"getPropertyFromMember": getPropertyFromMember,
|
||||||
"isDirectType": isDirectType,
|
"isDirectType": isDirectType,
|
||||||
"isClassListType": isClassListType,
|
"isClassListType": isClassListType,
|
||||||
"getCoreType": getCoreType,
|
"getCoreType": getCoreType,
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
|
"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
"github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DocCommand generate markdown doc file
|
// DocCommand generate Markdown doc file
|
||||||
func DocCommand(c *cli.Context) error {
|
func DocCommand(c *cli.Context) error {
|
||||||
dir := c.String("dir")
|
dir := c.String("dir")
|
||||||
if len(dir) == 0 {
|
if len(dir) == 0 {
|
||||||
@@ -45,7 +45,7 @@ func DocCommand(c *cli.Context) error {
|
|||||||
for _, p := range files {
|
for _, p := range files {
|
||||||
api, err := parser.Parse(p)
|
api, err := parser.Parse(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parse file: %s, err: %s", p, err.Error())
|
return fmt.Errorf("parse file: %s, err: %w", p, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
api.Service = api.Service.JoinPrefix()
|
api.Service = api.Service.JoinPrefix()
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/errorx"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/core/errorx"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -39,5 +39,5 @@ service A-api {
|
|||||||
func TestFormat(t *testing.T) {
|
func TestFormat(t *testing.T) {
|
||||||
r, err := apiFormat(notFormattedStr)
|
r, err := apiFormat(notFormattedStr)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, r, formattedStr)
|
assert.Equal(t, formattedStr, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/logrusorgru/aurora"
|
"github.com/logrusorgru/aurora"
|
||||||
"github.com/tal-tech/go-zero/core/logx"
|
|
||||||
apiformat "github.com/tal-tech/go-zero/tools/goctl/api/format"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
|
||||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
apiformat "github.com/zeromicro/go-zero/tools/goctl/api/format"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
|
||||||
|
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tmpFile = "%s-%d"
|
const tmpFile = "%s-%d"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testApiTemplate = `
|
const testApiTemplate = `
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
|
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
"github.com/zeromicro/go-zero/tools/goctl/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -34,7 +34,7 @@ func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
|
{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
|
||||||
{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}req{{end}})
|
{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.Error(w, err)
|
httpx.Error(w, err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
const logicTemplate = `package {{.pkgName}}
|
const logicTemplate = `package {{.pkgName}}
|
||||||
@@ -26,8 +26,8 @@ type {{.logic}} struct {
|
|||||||
svcCtx *svc.ServiceContext
|
svcCtx *svc.ServiceContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) {{.logic}} {
|
func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) *{{.logic}} {
|
||||||
return {{.logic}}{
|
return &{{.logic}}{
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
svcCtx: svcCtx,
|
svcCtx: svcCtx,
|
||||||
@@ -73,7 +73,7 @@ func genLogicByRoute(dir, rootPkg string, cfg *config.Config, group spec.Group,
|
|||||||
returnString = "return nil"
|
returnString = "return nil"
|
||||||
}
|
}
|
||||||
if len(route.RequestTypeName()) > 0 {
|
if len(route.RequestTypeName()) > 0 {
|
||||||
requestString = "req " + requestGoTypeName(route, typesPacket)
|
requestString = "req *" + requestGoTypeName(route, typesPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
subDir := getLogicFolderPath(group, route)
|
subDir := getLogicFolderPath(group, route)
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
const mainTemplate = `package main
|
const mainTemplate = `package main
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package gogen
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
var middlewareImplementCode = `
|
var middlewareImplementCode = `
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/collection"
|
"github.com/zeromicro/go-zero/core/collection"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
"github.com/zeromicro/go-zero/tools/goctl/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
"github.com/zeromicro/go-zero/tools/goctl/util/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package gogen
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenTemplates(t *testing.T) {
|
func TestGenTemplates(t *testing.T) {
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/collection"
|
"github.com/zeromicro/go-zero/core/collection"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
"github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fileGenConfig struct {
|
type fileGenConfig struct {
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/logrusorgru/aurora"
|
"github.com/logrusorgru/aurora"
|
||||||
"github.com/tal-tech/go-zero/core/logx"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JavaCommand the generate java code command entrance
|
// JavaCommand the generate java code command entrance
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
"github.com/zeromicro/go-zero/tools/goctl/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
|
||||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
"github.com/zeromicro/go-zero/tools/goctl/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const packetTemplate = `package com.xhb.logic.http.packet.{{.packet}};
|
const packetTemplate = `package com.xhb.logic.http.packet.{{.packet}};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user