Compare commits

..

33 Commits

Author SHA1 Message Date
Kevin Wan
4878f90546 chore: update goctl version to 1.5.6 (#3593) 2023-09-27 22:55:50 +08:00
Kevin Wan
421e6617b1 chore: add more tests (#3592) 2023-09-27 22:33:27 +08:00
Kevin Wan
0ee7a271d3 fix: avoid float overflow in mapping.Unmarshal (#3590) 2023-09-26 13:46:34 +00:00
dependabot[bot]
af022b9655 chore(deps): bump google.golang.org/grpc from 1.58.1 to 1.58.2 in /tools/goctl (#3584) 2023-09-25 16:23:29 +08:00
dependabot[bot]
98d46261d9 chore(deps): bump google.golang.org/grpc from 1.58.1 to 1.58.2 (#3585)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 23:27:02 +08:00
Kevin Wan
4222fd97bc chore: add test for logging rotate size (#3587) 2023-09-24 22:28:03 +08:00
dependabot[bot]
814852f0b8 chore(deps): bump github.com/fullstorydev/grpcurl from 1.8.7 to 1.8.8 (#3586)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 19:04:34 +08:00
Kevin Wan
ded2888759 fix: avoid integer overflow in mapping.Unmarshal (#3582) 2023-09-21 14:22:33 +00:00
Kevin Wan
18d66a795d chore: add more tests (#3578) 2023-09-20 23:52:10 +08:00
Kevin Wan
4211672bfd chore: add more tests (#3577) 2023-09-20 00:01:26 +08:00
Kevin Wan
68df0c3620 chore: add more tests (#3575) 2023-09-18 11:01:46 +08:00
xt-inking
5e435b6a76 fix: avoid losing logs before closing (#3573) 2023-09-17 11:38:53 +00:00
Kevin Wan
0dcede6457 chore: refactor log limit in rest (#3572) 2023-09-16 22:33:30 +08:00
Awadabang
cc21f5fae2 update: limit logBrief http body size (#3498)
Co-authored-by: 常公征 <changgz@yealink.com>
2023-09-16 11:58:21 +00:00
dependabot[bot]
b22ad50d59 chore(deps): bump google.golang.org/grpc from 1.58.0 to 1.58.1 in /tools/goctl (#3568)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-16 16:52:01 +08:00
Kevin Wan
974252980c chore: upgrade grpc (#3570) 2023-09-15 23:21:22 +08:00
dependabot[bot]
8d83986d27 chore(deps): bump google.golang.org/grpc from 1.57.0 to 1.58.0 in /tools/goctl (#3546) 2023-09-12 20:00:52 +08:00
Kevin Wan
6821b0a7dd chore: upgrade grpc (#3558) 2023-09-12 10:30:26 +08:00
Kevin Wan
1ba1724c65 chore: refactor (#3545) 2023-09-06 22:36:43 +08:00
Xinwei Xiong
ca5a7df5b0 feat: Optimize Encoding Functions and Add Descriptive Comments (#3543) 2023-09-06 14:19:50 +00:00
dependabot[bot]
69a3024853 chore(deps): bump golang.org/x/net from 0.14.0 to 0.15.0 (#3544)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 20:28:03 +08:00
dependabot[bot]
fd3abf3717 chore(deps): bump golang.org/x/text from 0.12.0 to 0.13.0 in /tools/goctl (#3542)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2023-09-06 20:20:12 +08:00
dependabot[bot]
99b3750d10 chore(deps): bump golang.org/x/sys from 0.11.0 to 0.12.0 (#3541)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 00:02:00 +08:00
POABOB
33f6d7ebb8 fix: goctl pg gen will extract all fields when the same table name exists in different schemas (#3496) (#3517) 2023-09-04 20:48:26 +08:00
kesonan
c4ef9ceb68 Add api version (#3536) 2023-09-02 01:45:48 +00:00
dependabot[bot]
e95861f28a chore(deps): bump github.com/pelletier/go-toml/v2 from 2.0.9 to 2.1.0 (#3532)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-31 22:52:23 +08:00
Kevin Wan
d3cd7b17c0 Revert "add:func() QueryRowsPartial,QueryRowPartial into cachedsql.go" (#3523) 2023-08-27 21:36:14 +08:00
liumin-go
a50515496c add:func() QueryRowsPartial,QueryRowPartial into cachedsql.go (#3512)
Co-authored-by: 刘敏 <liumin@liumindeMac-mini.local>
2023-08-27 08:05:02 +00:00
Kevin Wan
0423313d9b feat: support json:"-" in mapping (#3521) 2023-08-27 16:04:38 +08:00
dependabot[bot]
7bbe7de05f chore(deps): bump github.com/google/uuid from 1.3.0 to 1.3.1 (#3511)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 14:59:49 +08:00
dependabot[bot]
83a451f2f4 chore(deps): bump github.com/jhump/protoreflect from 1.15.1 to 1.15.2 (#3518)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 14:39:50 +08:00
Kevin Wan
d2a874f21d chore: upgrade go-zero, and update goctl version (#3509) 2023-08-21 09:09:51 +08:00
Kevin Wan
fd85b24b25 Update readme-cn.md 2023-08-20 23:38:39 +08:00
29 changed files with 2248 additions and 147 deletions

View File

@@ -29,6 +29,8 @@ func NewSafeMap() *SafeMap {
// Del deletes the value with the given key from m.
func (m *SafeMap) Del(key any) {
m.lock.Lock()
defer m.lock.Unlock()
if _, ok := m.dirtyOld[key]; ok {
delete(m.dirtyOld, key)
m.deletionOld++
@@ -52,7 +54,6 @@ func (m *SafeMap) Del(key any) {
m.dirtyNew = make(map[any]any)
m.deletionNew = 0
}
m.lock.Unlock()
}
// Get gets the value with the given key from m.
@@ -89,6 +90,8 @@ func (m *SafeMap) Range(f func(key, val any) bool) {
// Set sets the value into m with the given key.
func (m *SafeMap) Set(key, value any) {
m.lock.Lock()
defer m.lock.Unlock()
if m.deletionOld <= maxDeletion {
if _, ok := m.dirtyNew[key]; ok {
delete(m.dirtyNew, key)
@@ -102,7 +105,6 @@ func (m *SafeMap) Set(key, value any) {
}
m.dirtyNew[key] = value
}
m.lock.Unlock()
}
// Size returns the size of m.

View File

@@ -147,3 +147,65 @@ func TestSafeMap_Range(t *testing.T) {
assert.Equal(t, m.dirtyNew, newMap.dirtyNew)
assert.Equal(t, m.dirtyOld, newMap.dirtyOld)
}
func TestSetManyTimes(t *testing.T) {
const iteration = maxDeletion * 2
m := NewSafeMap()
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
var count int
m.Range(func(k, v any) bool {
count++
return count < maxDeletion/2
})
assert.Equal(t, maxDeletion/2, count)
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
count = 0
m.Range(func(k, v any) bool {
count++
return count < maxDeletion
})
assert.Equal(t, maxDeletion, count)
}
func TestSetManyTimesNew(t *testing.T) {
m := NewSafeMap()
for i := 0; i < maxDeletion*3; i++ {
m.Set(i, i)
}
for i := 0; i < maxDeletion*2; i++ {
m.Del(i)
}
for i := 0; i < maxDeletion*3; i++ {
m.Set(i+maxDeletion*3, i+maxDeletion*3)
}
for i := 0; i < maxDeletion*2; i++ {
m.Del(i + maxDeletion*2)
}
for i := 0; i < maxDeletion-copyThreshold+1; i++ {
m.Del(i + maxDeletion*2)
}
assert.Equal(t, 0, len(m.dirtyNew))
}

View File

@@ -0,0 +1,12 @@
package iox
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNopCloser(t *testing.T) {
closer := NopCloser(nil)
assert.NoError(t, closer.Close())
}

View File

@@ -35,6 +35,16 @@ func KeepSpace() TextReadOption {
}
}
// LimitDupReadCloser returns two io.ReadCloser that read from the first will be written to the second.
// But the second io.ReadCloser is limited to up to n bytes.
// The first returned reader needs to be read first, because the content
// read from it will be written to the underlying buffer of the second reader.
func LimitDupReadCloser(reader io.ReadCloser, n int64) (io.ReadCloser, io.ReadCloser) {
var buf bytes.Buffer
tee := LimitTeeReader(reader, &buf, n)
return io.NopCloser(tee), io.NopCloser(&buf)
}
// ReadBytes reads exactly the bytes with the length of len(buf)
func ReadBytes(reader io.Reader, buf []byte) error {
var got int

View File

@@ -51,6 +51,11 @@ b`,
}
}
func TestReadTextError(t *testing.T) {
_, err := ReadText("not-exist")
assert.NotNil(t, err)
}
func TestReadTextLines(t *testing.T) {
text := `1
@@ -94,6 +99,11 @@ func TestReadTextLines(t *testing.T) {
}
}
func TestReadTextLinesError(t *testing.T) {
_, err := ReadTextLines("not-exist")
assert.NotNil(t, err)
}
func TestDupReadCloser(t *testing.T) {
input := "hello"
reader := io.NopCloser(bytes.NewBufferString(input))
@@ -108,6 +118,29 @@ func TestDupReadCloser(t *testing.T) {
verify(r2)
}
func TestLimitDupReadCloser(t *testing.T) {
input := "hello world"
limitBytes := int64(4)
reader := io.NopCloser(bytes.NewBufferString(input))
r1, r2 := LimitDupReadCloser(reader, limitBytes)
verify := func(r io.Reader) {
output, err := io.ReadAll(r)
assert.Nil(t, err)
assert.Equal(t, input, string(output))
}
verifyLimit := func(r io.Reader, limit int64) {
output, err := io.ReadAll(r)
if limit < int64(len(input)) {
input = input[:limit]
}
assert.Nil(t, err)
assert.Equal(t, input, string(output))
}
verify(r1)
verifyLimit(r2, limitBytes)
}
func TestReadBytes(t *testing.T) {
reader := io.NopCloser(bytes.NewBufferString("helloworld"))
buf := make([]byte, 5)

35
core/iox/tee.go Normal file
View File

@@ -0,0 +1,35 @@
package iox
import "io"
// LimitTeeReader returns a Reader that writes up to n bytes to w what it reads from r.
// First n bytes reads from r performed through it are matched with
// corresponding writes to w. There is no internal buffering -
// the write must complete before the first n bytes read completes.
// Any error encountered while writing is reported as a read error.
func LimitTeeReader(r io.Reader, w io.Writer, n int64) io.Reader {
return &limitTeeReader{r, w, n}
}
type limitTeeReader struct {
r io.Reader
w io.Writer
n int64 // limit bytes remaining
}
func (t *limitTeeReader) Read(p []byte) (n int, err error) {
n, err = t.r.Read(p)
if n > 0 && t.n > 0 {
limit := int64(n)
if limit > t.n {
limit = t.n
}
if n, err := t.w.Write(p[:limit]); err != nil {
return n, err
}
t.n -= limit
}
return
}

40
core/iox/tee_test.go Normal file
View File

@@ -0,0 +1,40 @@
package iox
import (
"bytes"
"io"
"testing"
"github.com/stretchr/testify/assert"
)
func TestLimitTeeReader(t *testing.T) {
limit := int64(4)
src := []byte("hello, world")
dst := make([]byte, len(src))
rb := bytes.NewBuffer(src)
wb := new(bytes.Buffer)
r := LimitTeeReader(rb, wb, limit)
if n, err := io.ReadFull(r, dst); err != nil || n != len(src) {
t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src))
}
if !bytes.Equal(dst, src) {
t.Errorf("bytes read = %q want %q", dst, src)
}
if !bytes.Equal(wb.Bytes(), src[:limit]) {
t.Errorf("bytes written = %q want %q", wb.Bytes(), src)
}
n, err := r.Read(dst)
assert.Equal(t, 0, n)
assert.Equal(t, io.EOF, err)
rb = bytes.NewBuffer(src)
pr, pw := io.Pipe()
if assert.NoError(t, pr.Close()) {
r = LimitTeeReader(rb, pw, limit)
n, err := io.ReadFull(r, dst)
assert.Equal(t, 0, n)
assert.Equal(t, io.ErrClosedPipe, err)
}
}

View File

@@ -2,6 +2,7 @@ package iox
import (
"bytes"
"errors"
"io"
"os"
)
@@ -26,7 +27,7 @@ func CountLines(file string) (int, error) {
count += bytes.Count(buf[:c], lineSep)
switch {
case err == io.EOF:
case errors.Is(err, io.EOF):
if noEol {
count++
}

View File

@@ -24,3 +24,8 @@ func TestCountLines(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 4, lines)
}
func TestCountLinesError(t *testing.T) {
_, err := CountLines("not-exist")
assert.NotNil(t, err)
}

View File

@@ -3,6 +3,7 @@ package iox
import (
"strings"
"testing"
"testing/iotest"
"github.com/stretchr/testify/assert"
)
@@ -22,3 +23,10 @@ func TestScanner(t *testing.T) {
}
assert.EqualValues(t, []string{"1", "2", "3", "4"}, lines)
}
func TestBadScanner(t *testing.T) {
scanner := NewTextLineScanner(iotest.ErrReader(iotest.ErrTimeout))
assert.False(t, scanner.Scan())
_, err := scanner.Line()
assert.ErrorIs(t, err, iotest.ErrTimeout)
}

View File

@@ -298,6 +298,7 @@ func (l *RotateLogger) initialize() error {
if l.fp, err = os.OpenFile(l.filename, os.O_APPEND|os.O_WRONLY, defaultFileMode); err != nil {
return err
}
l.currentSize = fileInfo.Size()
}
@@ -381,7 +382,15 @@ func (l *RotateLogger) startWorker() {
case event := <-l.channel:
l.write(event)
case <-l.done:
return
// avoid losing logs before closing.
for {
select {
case event := <-l.channel:
l.write(event)
default:
return
}
}
}
}
}()

View File

@@ -206,6 +206,27 @@ func TestRotateLoggerClose(t *testing.T) {
_, err := logger.Write([]byte("foo"))
assert.ErrorIs(t, err, ErrLogFileClosed)
})
t.Run("close without losing logs", func(t *testing.T) {
text := "foo"
filename, err := fs.TempFilenameWithText(text)
assert.Nil(t, err)
if len(filename) > 0 {
defer os.Remove(filename)
}
logger, err := NewLogger(filename, new(DailyRotateRule), false)
assert.Nil(t, err)
msg := []byte("foo")
n := 100
for i := 0; i < n; i++ {
_, err = logger.Write(msg)
assert.Nil(t, err)
}
assert.Nil(t, logger.Close())
bs, err := os.ReadFile(filename)
assert.Nil(t, err)
assert.Equal(t, len(msg)*n+len(text), len(bs))
})
}
func TestRotateLoggerGetBackupFilename(t *testing.T) {
@@ -496,6 +517,21 @@ func TestGzipFile(t *testing.T) {
})
}
func TestRotateLogger_WithExistingFile(t *testing.T) {
const body = "foo"
filename, err := fs.TempFilenameWithText(body)
assert.Nil(t, err)
if len(filename) > 0 {
defer os.Remove(filename)
}
rule := NewSizeLimitRotateRule(filename, "-", 1, 100, 3, false)
logger, err := NewLogger(filename, rule, false)
assert.Nil(t, err)
assert.Equal(t, int64(len(body)), logger.currentSize)
assert.Nil(t, logger.Close())
}
func BenchmarkRotateLogger(b *testing.B) {
filename := "./test.log"
filename2 := "./test2.log"

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"reflect"
"strconv"
"strings"
@@ -20,6 +21,7 @@ import (
const (
defaultKeyName = "key"
delimiter = '.'
ignoreKey = "-"
)
var (
@@ -437,6 +439,10 @@ func (u *Unmarshaler) processAnonymousField(field reflect.StructField, value ref
return err
}
if key == ignoreKey {
return nil
}
if options.optional() {
return u.processAnonymousFieldOptional(field, value, key, m, fullName)
}
@@ -604,25 +610,23 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(fieldType reflect.Type
target := reflect.New(Deref(fieldType)).Elem()
switch typeKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
iValue, err := v.Int64()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if err := setValueFromString(typeKind, target, v.String()); err != nil {
return err
}
case reflect.Float32:
fValue, err := v.Float64()
if err != nil {
return err
}
target.SetInt(iValue)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
iValue, err := v.Int64()
if err != nil {
return err
if fValue > math.MaxFloat32 {
return float32OverflowError(v.String())
}
if iValue < 0 {
return fmt.Errorf("unmarshal %q with bad value %q", fullName, v.String())
}
target.SetUint(uint64(iValue))
case reflect.Float32, reflect.Float64:
target.SetFloat(fValue)
case reflect.Float64:
fValue, err := v.Float64()
if err != nil {
return err
@@ -724,6 +728,10 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
return err
}
if key == ignoreKey {
return nil
}
fullName = join(fullName, key)
if opts != nil && len(opts.EnvVar) > 0 {
envVal := proc.Env(opts.EnvVar)

View File

@@ -569,6 +569,468 @@ func TestUnmarshalIntWithString(t *testing.T) {
})
}
func TestUnmarshalInt8WithOverflow(t *testing.T) {
t.Run("int8 from string", func(t *testing.T) {
type inner struct {
Value int8 `key:"int,string"`
}
m := map[string]any{
"int": "8589934592", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int8 from json.Number", func(t *testing.T) {
type inner struct {
Value int8 `key:"int"`
}
m := map[string]any{
"int": json.Number("8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int8 from json.Number", func(t *testing.T) {
type inner struct {
Value int8 `key:"int"`
}
m := map[string]any{
"int": json.Number("-8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int8 from int64", func(t *testing.T) {
type inner struct {
Value int8 `key:"int"`
}
m := map[string]any{
"int": int64(1) << 36, // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalInt16WithOverflow(t *testing.T) {
t.Run("int16 from string", func(t *testing.T) {
type inner struct {
Value int16 `key:"int,string"`
}
m := map[string]any{
"int": "8589934592", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int16 from json.Number", func(t *testing.T) {
type inner struct {
Value int16 `key:"int"`
}
m := map[string]any{
"int": json.Number("8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int16 from json.Number", func(t *testing.T) {
type inner struct {
Value int16 `key:"int"`
}
m := map[string]any{
"int": json.Number("-8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int16 from int64", func(t *testing.T) {
type inner struct {
Value int16 `key:"int"`
}
m := map[string]any{
"int": int64(1) << 36, // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalInt32WithOverflow(t *testing.T) {
t.Run("int32 from string", func(t *testing.T) {
type inner struct {
Value int32 `key:"int,string"`
}
m := map[string]any{
"int": "8589934592", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int32 from json.Number", func(t *testing.T) {
type inner struct {
Value int32 `key:"int"`
}
m := map[string]any{
"int": json.Number("8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int32 from json.Number", func(t *testing.T) {
type inner struct {
Value int32 `key:"int"`
}
m := map[string]any{
"int": json.Number("-8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int32 from int64", func(t *testing.T) {
type inner struct {
Value int32 `key:"int"`
}
m := map[string]any{
"int": int64(1) << 36, // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalInt64WithOverflow(t *testing.T) {
t.Run("int64 from string", func(t *testing.T) {
type inner struct {
Value int64 `key:"int,string"`
}
m := map[string]any{
"int": "18446744073709551616", // overflow, 1 << 64
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("int64 from json.Number", func(t *testing.T) {
type inner struct {
Value int64 `key:"int,string"`
}
m := map[string]any{
"int": json.Number("18446744073709551616"), // overflow, 1 << 64
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalUint8WithOverflow(t *testing.T) {
t.Run("uint8 from string", func(t *testing.T) {
type inner struct {
Value uint8 `key:"int,string"`
}
m := map[string]any{
"int": "8589934592", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint8 from json.Number", func(t *testing.T) {
type inner struct {
Value uint8 `key:"int"`
}
m := map[string]any{
"int": json.Number("8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint8 from json.Number with negative", func(t *testing.T) {
type inner struct {
Value uint8 `key:"int"`
}
m := map[string]any{
"int": json.Number("-1"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint8 from int64", func(t *testing.T) {
type inner struct {
Value uint8 `key:"int"`
}
m := map[string]any{
"int": int64(1) << 36, // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalUint16WithOverflow(t *testing.T) {
t.Run("uint16 from string", func(t *testing.T) {
type inner struct {
Value uint16 `key:"int,string"`
}
m := map[string]any{
"int": "8589934592", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint16 from json.Number", func(t *testing.T) {
type inner struct {
Value uint16 `key:"int"`
}
m := map[string]any{
"int": json.Number("8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint16 from json.Number with negative", func(t *testing.T) {
type inner struct {
Value uint16 `key:"int"`
}
m := map[string]any{
"int": json.Number("-1"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint16 from int64", func(t *testing.T) {
type inner struct {
Value uint16 `key:"int"`
}
m := map[string]any{
"int": int64(1) << 36, // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalUint32WithOverflow(t *testing.T) {
t.Run("uint32 from string", func(t *testing.T) {
type inner struct {
Value uint32 `key:"int,string"`
}
m := map[string]any{
"int": "8589934592", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint32 from json.Number", func(t *testing.T) {
type inner struct {
Value uint32 `key:"int"`
}
m := map[string]any{
"int": json.Number("8589934592"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint32 from json.Number with negative", func(t *testing.T) {
type inner struct {
Value uint32 `key:"int"`
}
m := map[string]any{
"int": json.Number("-1"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint32 from int64", func(t *testing.T) {
type inner struct {
Value uint32 `key:"int"`
}
m := map[string]any{
"int": int64(1) << 36, // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalUint64WithOverflow(t *testing.T) {
t.Run("uint64 from string", func(t *testing.T) {
type inner struct {
Value uint64 `key:"int,string"`
}
m := map[string]any{
"int": "18446744073709551616", // overflow, 1 << 64
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("uint64 from json.Number", func(t *testing.T) {
type inner struct {
Value uint64 `key:"int,string"`
}
m := map[string]any{
"int": json.Number("18446744073709551616"), // overflow, 1 << 64
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalFloat32WithOverflow(t *testing.T) {
t.Run("float32 from string greater than float64", func(t *testing.T) {
type inner struct {
Value float32 `key:"float,string"`
}
m := map[string]any{
"float": "1.79769313486231570814527423731704356798070e+309", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("float32 from string greater than float32", func(t *testing.T) {
type inner struct {
Value float32 `key:"float,string"`
}
m := map[string]any{
"float": "1.79769313486231570814527423731704356798070e+300", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("float32 from json.Number greater than float64", func(t *testing.T) {
type inner struct {
Value float32 `key:"float"`
}
m := map[string]any{
"float": json.Number("1.79769313486231570814527423731704356798070e+309"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("float32 from json.Number greater than float32", func(t *testing.T) {
type inner struct {
Value float32 `key:"float"`
}
m := map[string]any{
"float": json.Number("1.79769313486231570814527423731704356798070e+300"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalFloat64WithOverflow(t *testing.T) {
t.Run("float64 from string greater than float64", func(t *testing.T) {
type inner struct {
Value float64 `key:"float,string"`
}
m := map[string]any{
"float": "1.79769313486231570814527423731704356798070e+309", // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("float32 from json.Number greater than float64", func(t *testing.T) {
type inner struct {
Value float64 `key:"float"`
}
m := map[string]any{
"float": json.Number("1.79769313486231570814527423731704356798070e+309"), // overflow
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
}
func TestUnmarshalBoolSliceRequired(t *testing.T) {
type inner struct {
Bools []bool `key:"bools"`
@@ -795,16 +1257,20 @@ func TestUnmarshalFloat(t *testing.T) {
type inner struct {
Float32 float32 `key:"float32"`
Float32Str float32 `key:"float32str,string"`
Float32Num float32 `key:"float32num"`
Float64 float64 `key:"float64"`
Float64Str float64 `key:"float64str,string"`
Float64Num float64 `key:"float64num"`
DefaultFloat float32 `key:"defaultfloat,default=5.5"`
Optional float32 `key:",optional"`
}
m := map[string]any{
"float32": float32(1.5),
"float32str": "2.5",
"float64": float64(3.5),
"float32num": json.Number("2.6"),
"float64": 3.5,
"float64str": "4.5",
"float64num": json.Number("4.6"),
}
var in inner
@@ -812,8 +1278,10 @@ func TestUnmarshalFloat(t *testing.T) {
if ast.NoError(UnmarshalKey(m, &in)) {
ast.Equal(float32(1.5), in.Float32)
ast.Equal(float32(2.5), in.Float32Str)
ast.Equal(float32(2.6), in.Float32Num)
ast.Equal(3.5, in.Float64)
ast.Equal(4.5, in.Float64Str)
ast.Equal(4.6, in.Float64Num)
ast.Equal(float32(5.5), in.DefaultFloat)
}
}
@@ -5107,6 +5575,115 @@ func TestUnmarshalWithOpaqueKeys(t *testing.T) {
}
}
func TestUnmarshalWithIgnoreFields(t *testing.T) {
type (
Foo struct {
Value string
IgnoreString string `json:"-"`
IgnoreInt int `json:"-"`
}
Bar struct {
Foo1 Foo
Foo2 *Foo
Foo3 []Foo
Foo4 []*Foo
Foo5 map[string]Foo
Foo6 map[string]Foo
}
Bar1 struct {
Foo `json:"-"`
}
Bar2 struct {
*Foo `json:"-"`
}
)
var bar Bar
unmarshaler := NewUnmarshaler(jsonTagKey)
if assert.NoError(t, unmarshaler.Unmarshal(map[string]any{
"Foo1": map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
},
"Foo2": map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
},
"Foo3": []map[string]any{
{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
},
},
"Foo4": []map[string]any{
{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
},
},
"Foo5": map[string]any{
"key": map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
},
},
"Foo6": map[string]any{
"key": map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
},
},
}, &bar)) {
assert.Equal(t, "foo", bar.Foo1.Value)
assert.Empty(t, bar.Foo1.IgnoreString)
assert.Equal(t, 0, bar.Foo1.IgnoreInt)
assert.Equal(t, "foo", bar.Foo2.Value)
assert.Empty(t, bar.Foo2.IgnoreString)
assert.Equal(t, 0, bar.Foo2.IgnoreInt)
assert.Equal(t, "foo", bar.Foo3[0].Value)
assert.Empty(t, bar.Foo3[0].IgnoreString)
assert.Equal(t, 0, bar.Foo3[0].IgnoreInt)
assert.Equal(t, "foo", bar.Foo4[0].Value)
assert.Empty(t, bar.Foo4[0].IgnoreString)
assert.Equal(t, 0, bar.Foo4[0].IgnoreInt)
assert.Equal(t, "foo", bar.Foo5["key"].Value)
assert.Empty(t, bar.Foo5["key"].IgnoreString)
assert.Equal(t, 0, bar.Foo5["key"].IgnoreInt)
assert.Equal(t, "foo", bar.Foo6["key"].Value)
assert.Empty(t, bar.Foo6["key"].IgnoreString)
assert.Equal(t, 0, bar.Foo6["key"].IgnoreInt)
}
var bar1 Bar1
if assert.NoError(t, unmarshaler.Unmarshal(map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
}, &bar1)) {
assert.Empty(t, bar1.Value)
assert.Empty(t, bar1.IgnoreString)
assert.Equal(t, 0, bar1.IgnoreInt)
}
var bar2 Bar2
if assert.NoError(t, unmarshaler.Unmarshal(map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
}, &bar2)) {
assert.Nil(t, bar2.Foo)
}
}
func BenchmarkDefaultValue(b *testing.B) {
for i := 0; i < b.N; i++ {
var a struct {

View File

@@ -42,6 +42,10 @@ var (
)
type (
integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
optionsCacheValue struct {
key string
options *fieldOptions
@@ -103,21 +107,32 @@ func convertTypeFromString(kind reflect.Kind, str string) (any, error) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
intValue, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return 0, fmt.Errorf("the value %q cannot be parsed as int", str)
return 0, err
}
return intValue, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uintValue, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return 0, fmt.Errorf("the value %q cannot be parsed as uint", str)
return 0, err
}
return uintValue, nil
case reflect.Float32, reflect.Float64:
case reflect.Float32:
floatValue, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0, fmt.Errorf("the value %q cannot be parsed as float", str)
return 0, err
}
if floatValue > math.MaxFloat32 {
return 0, float32OverflowError(str)
}
return floatValue, nil
case reflect.Float64:
floatValue, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0, err
}
return floatValue, nil
@@ -215,6 +230,10 @@ func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
return false, nil
}
func intOverflowError[T integer](v T, kind reflect.Kind) error {
return fmt.Errorf("parsing \"%d\" as %s: value out of range", v, kind.String())
}
func isLeftInclude(b byte) (bool, error) {
switch b {
case '[':
@@ -237,6 +256,10 @@ func isRightInclude(b byte) (bool, error) {
}
}
func float32OverflowError(str string) error {
return fmt.Errorf("parsing %q as float32: value out of range", str)
}
func maybeNewValue(fieldType reflect.Type, value reflect.Value) {
if fieldType.Kind() == reflect.Ptr && value.IsNil() {
value.Set(reflect.New(value.Type().Elem()))
@@ -482,22 +505,61 @@ func parseSegments(val string) []string {
return segments
}
func setIntValue(value reflect.Value, v any, min, max int64) error {
iv := v.(int64)
if iv < min || iv > max {
return intOverflowError(iv, value.Kind())
}
value.SetInt(iv)
return nil
}
func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v any) error {
switch kind {
case reflect.Bool:
value.SetBool(v.(bool))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return nil
case reflect.Int: // int depends on int size, 32 or 64
return setIntValue(value, v, math.MinInt, math.MaxInt)
case reflect.Int8:
return setIntValue(value, v, math.MinInt8, math.MaxInt8)
case reflect.Int16:
return setIntValue(value, v, math.MinInt16, math.MaxInt16)
case reflect.Int32:
return setIntValue(value, v, math.MinInt32, math.MaxInt32)
case reflect.Int64:
value.SetInt(v.(int64))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return nil
case reflect.Uint: // uint depends on int size, 32 or 64
return setUintValue(value, v, math.MaxUint)
case reflect.Uint8:
return setUintValue(value, v, math.MaxUint8)
case reflect.Uint16:
return setUintValue(value, v, math.MaxUint16)
case reflect.Uint32:
return setUintValue(value, v, math.MaxUint32)
case reflect.Uint64:
value.SetUint(v.(uint64))
return nil
case reflect.Float32, reflect.Float64:
value.SetFloat(v.(float64))
return nil
case reflect.String:
value.SetString(v.(string))
return nil
default:
return errUnsupportedType
}
}
func setUintValue(value reflect.Value, v any, boundary uint64) error {
iv := v.(uint64)
if iv > boundary {
return intOverflowError(iv, value.Kind())
}
value.SetUint(iv)
return nil
}
@@ -575,7 +637,8 @@ func usingDifferentKeys(key string, field reflect.StructField) bool {
return false
}
func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string, opts *fieldOptionsWithContext) error {
func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string,
opts *fieldOptionsWithContext) error {
if !value.CanSet() {
return errValueNotSettable
}

View File

@@ -3,6 +3,8 @@ package redis
import (
"testing"
"github.com/alicebob/miniredis/v2"
red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
)
@@ -41,3 +43,17 @@ func TestSplitClusterAddrs(t *testing.T) {
})
}
}
func TestGetCluster(t *testing.T) {
r := miniredis.RunT(t)
defer r.Close()
c, err := getCluster(&Redis{
Addr: r.Addr(),
Type: ClusterType,
tls: true,
hooks: []red.Hook{durationHook},
})
if assert.NoError(t, err) {
assert.NotNil(t, c)
}
}

32
go.mod
View File

@@ -6,17 +6,17 @@ require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/alicebob/miniredis/v2 v2.30.5
github.com/fatih/color v1.15.0
github.com/fullstorydev/grpcurl v1.8.7
github.com/fullstorydev/grpcurl v1.8.8
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.0
github.com/google/uuid v1.3.1
github.com/jackc/pgx/v5 v5.4.3
github.com/jhump/protoreflect v1.15.1
github.com/jhump/protoreflect v1.15.2
github.com/olekukonko/tablewriter v0.0.5
github.com/pelletier/go-toml/v2 v2.0.9
github.com/pelletier/go-toml/v2 v2.1.0
github.com/prometheus/client_golang v1.16.0
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.8.4
@@ -33,11 +33,11 @@ require (
go.opentelemetry.io/otel/trace v1.14.0
go.uber.org/automaxprocs v1.5.3
go.uber.org/goleak v1.2.1
golang.org/x/net v0.14.0
golang.org/x/sys v0.11.0
golang.org/x/net v0.15.0
golang.org/x/sys v0.12.0
golang.org/x/time v0.3.0
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9
google.golang.org/grpc v1.57.0
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.1.2
@@ -51,7 +51,7 @@ require (
require (
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bufbuild/protocompile v0.4.0 // indirect
github.com/bufbuild/protocompile v0.6.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
@@ -103,14 +103,14 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/term v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.90.1 // indirect

1118
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -9,36 +9,27 @@ import (
"gopkg.in/yaml.v2"
)
// TomlToJson converts TOML data into its JSON representation.
func TomlToJson(data []byte) ([]byte, error) {
var val any
if err := toml.NewDecoder(bytes.NewReader(data)).Decode(&val); err != nil {
return nil, err
}
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
return encodeToJSON(val)
}
// YamlToJson converts YAML data into its JSON representation.
func YamlToJson(data []byte) ([]byte, error) {
var val any
if err := yaml.Unmarshal(data, &val); err != nil {
return nil, err
}
val = toStringKeyMap(val)
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
return encodeToJSON(toStringKeyMap(val))
}
// convertKeyToString ensures all keys of the map are of type string.
func convertKeyToString(in map[any]any) map[string]any {
res := make(map[string]any)
for k, v := range in {
@@ -47,10 +38,12 @@ func convertKeyToString(in map[any]any) map[string]any {
return res
}
// convertNumberToJsonNumber converts numbers into json.Number type for compatibility.
func convertNumberToJsonNumber(in any) json.Number {
return json.Number(lang.Repr(in))
}
// convertSlice processes slice items to ensure key compatibility.
func convertSlice(in []any) []any {
res := make([]any, len(in))
for i, v := range in {
@@ -59,6 +52,17 @@ func convertSlice(in []any) []any {
return res
}
// encodeToJSON encodes the given value into its JSON representation.
func encodeToJSON(val any) ([]byte, error) {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// toStringKeyMap processes the data to ensure that all map keys are of type string.
func toStringKeyMap(v any) any {
switch v := v.(type) {
case []any:

View File

@@ -295,6 +295,7 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>91. 宁波甬风信息科技有限公司
>92. 深圳市万佳安物联科技股份有限公司
>93. 武侯区编程之美软件开发工作室
>94. 西安交通大学智慧能源与碳中和研究中心
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -132,7 +132,7 @@ func (w *cryptionResponseWriter) flush(key []byte) {
body := base64.StdEncoding.EncodeToString(content)
if n, err := io.WriteString(w.ResponseWriter, body); err != nil {
logx.Errorf("write response failed, error: %s", err)
} else if n < len(content) {
logx.Errorf("actual bytes: %d, written bytes: %d", len(content), n)
} else if n < len(body) {
logx.Errorf("actual bytes: %d, written bytes: %d", len(body), n)
}
}

View File

@@ -2,15 +2,18 @@ package handler
import (
"bytes"
"crypto/rand"
"encoding/base64"
"io"
"math/rand"
"net/http"
"net/http/httptest"
"strings"
"testing"
"testing/iotest"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/codec"
"github.com/zeromicro/go-zero/core/logx/logtest"
)
const (
@@ -37,6 +40,19 @@ func TestCryptionHandlerGet(t *testing.T) {
assert.Equal(t, base64.StdEncoding.EncodeToString(expect), recorder.Body.String())
}
func TestCryptionHandlerGet_badKey(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
handler := CryptionHandler(append(aesKey, aesKey...))(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(respText))
w.Header().Set("X-Test", "test")
assert.Nil(t, err)
}))
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusInternalServerError, recorder.Code)
}
func TestCryptionHandlerPost(t *testing.T) {
var buf bytes.Buffer
enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
@@ -120,10 +136,110 @@ func TestCryptionHandler_ContentTooLong(t *testing.T) {
defer svr.Close()
body := make([]byte, maxBytes+1)
rand.Read(body)
_, err := rand.Read(body)
assert.NoError(t, err)
req, err := http.NewRequest(http.MethodPost, svr.URL, bytes.NewReader(body))
assert.Nil(t, err)
resp, err := http.DefaultClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
}
func TestCryptionHandler_BadBody(t *testing.T) {
req, err := http.NewRequest(http.MethodPost, "/foo", iotest.ErrReader(io.ErrUnexpectedEOF))
assert.Nil(t, err)
err = decryptBody(maxBytes, aesKey, req)
assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
}
func TestCryptionHandler_BadKey(t *testing.T) {
var buf bytes.Buffer
enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
assert.Nil(t, err)
buf.WriteString(base64.StdEncoding.EncodeToString(enc))
req := httptest.NewRequest(http.MethodPost, "/any", &buf)
err = decryptBody(maxBytes, append(aesKey, aesKey...), req)
assert.Error(t, err)
}
func TestCryptionResponseWriter_Flush(t *testing.T) {
body := []byte("hello, world!")
t.Run("half", func(t *testing.T) {
recorder := httptest.NewRecorder()
f := flushableResponseWriter{
writer: &halfWriter{recorder},
}
w := newCryptionResponseWriter(f)
_, err := w.Write(body)
assert.NoError(t, err)
w.flush(aesKey)
b, err := io.ReadAll(recorder.Body)
assert.NoError(t, err)
expected, err := codec.EcbEncrypt(aesKey, body)
assert.NoError(t, err)
assert.True(t, strings.HasPrefix(base64.StdEncoding.EncodeToString(expected), string(b)))
assert.True(t, len(string(b)) < len(base64.StdEncoding.EncodeToString(expected)))
})
t.Run("full", func(t *testing.T) {
recorder := httptest.NewRecorder()
f := flushableResponseWriter{
writer: recorder,
}
w := newCryptionResponseWriter(f)
_, err := w.Write(body)
assert.NoError(t, err)
w.flush(aesKey)
b, err := io.ReadAll(recorder.Body)
assert.NoError(t, err)
expected, err := codec.EcbEncrypt(aesKey, body)
assert.NoError(t, err)
assert.Equal(t, base64.StdEncoding.EncodeToString(expected), string(b))
})
t.Run("bad writer", func(t *testing.T) {
buf := logtest.NewCollector(t)
f := flushableResponseWriter{
writer: new(badWriter),
}
w := newCryptionResponseWriter(f)
_, err := w.Write(body)
assert.NoError(t, err)
w.flush(aesKey)
assert.True(t, strings.Contains(buf.Content(), io.ErrClosedPipe.Error()))
})
}
type flushableResponseWriter struct {
writer io.Writer
}
func (m flushableResponseWriter) Header() http.Header {
panic("implement me")
}
func (m flushableResponseWriter) Write(p []byte) (int, error) {
return m.writer.Write(p)
}
func (m flushableResponseWriter) WriteHeader(statusCode int) {
panic("implement me")
}
type halfWriter struct {
w io.Writer
}
func (t *halfWriter) Write(p []byte) (n int, err error) {
n = len(p) >> 1
return t.w.Write(p[0:n])
}
type badWriter struct {
}
func (b *badWriter) Write(p []byte) (n int, err error) {
return 0, io.ErrClosedPipe
}

View File

@@ -10,7 +10,6 @@ import (
"net/http"
"net/http/httputil"
"strconv"
"strings"
"time"
"github.com/zeromicro/go-zero/core/color"
@@ -39,7 +38,7 @@ func LogHandler(next http.Handler) http.Handler {
lrw := response.NewWithCodeResponseWriter(w)
var dup io.ReadCloser
r.Body, dup = iox.DupReadCloser(r.Body)
r.Body, dup = iox.LimitDupReadCloser(r.Body, limitBodyBytes)
next.ServeHTTP(lrw, r.WithContext(internal.WithLogCollector(r.Context(), logs)))
r.Body = dup
logBrief(r, lrw.Code, timer, logs)
@@ -136,14 +135,7 @@ func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *intern
ok := isOkResponse(code)
if !ok {
fullReq := dumpRequest(r)
limitReader := io.LimitReader(strings.NewReader(fullReq), limitBodyBytes)
body, err := io.ReadAll(limitReader)
if err != nil {
buf.WriteString(fmt.Sprintf("\n%s", fullReq))
} else {
buf.WriteString(fmt.Sprintf("\n%s", string(body)))
}
buf.WriteString(fmt.Sprintf("\n%s", dumpRequest(r)))
}
body := logs.Flush()

View File

@@ -1,3 +1,5 @@
syntax = "v1"
type Request {
Name string `path:"name,options=you|me"`
}

View File

@@ -15,15 +15,15 @@ require (
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
github.com/zeromicro/antlr v0.0.1
github.com/zeromicro/ddl-parser v1.0.5
github.com/zeromicro/go-zero v1.5.4
golang.org/x/text v0.12.0
google.golang.org/grpc v1.57.0
github.com/zeromicro/go-zero v1.5.6
golang.org/x/text v0.13.0
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
)
require (
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/alicebob/miniredis/v2 v2.30.4 // indirect
github.com/alicebob/miniredis/v2 v2.30.5 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
@@ -51,7 +51,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.4.2 // indirect
github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
@@ -63,7 +63,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
@@ -87,19 +87,19 @@ require (
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/automaxprocs v1.5.2 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.12.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@@ -38,8 +38,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo=
github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
github.com/alicebob/miniredis/v2 v2.30.5 h1:3r6kTHdKnuP4fkS8k2IrvSfxpxUTcW1SOL0wN7b7Dt0=
github.com/alicebob/miniredis/v2 v2.30.5/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
@@ -178,7 +178,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
@@ -199,8 +199,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg=
github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -241,8 +241,8 @@ github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -296,8 +296,8 @@ github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
github.com/zeromicro/ddl-parser v1.0.5 h1:LaVqHdzMTjasua1yYpIYaksxKqRzFrEukj2Wi2EbWaQ=
github.com/zeromicro/ddl-parser v1.0.5/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
github.com/zeromicro/go-zero v1.5.4 h1:kRvcYuxcHOkUZvg7887KQl77Qv4klGL7MqGkTBgkpS8=
github.com/zeromicro/go-zero v1.5.4/go.mod h1:x/aUyLmSwRECvOyjOf+lhwThBOilJIY+s3slmPAeboA=
github.com/zeromicro/go-zero v1.5.6 h1:vBzrLaj+xQySBAeMBA6vhPxNgasz0T3WE60s98H0Bb4=
github.com/zeromicro/go-zero v1.5.6/go.mod h1:FX2a2MQd5EvAYO7neJBm2GAmPU5XfFnj3JMM/qj+kpY=
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
@@ -334,8 +334,8 @@ go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJP
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
@@ -346,8 +346,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -407,16 +407,16 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -459,19 +459,19 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -580,12 +580,12 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
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.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -602,8 +602,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
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-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -6,7 +6,7 @@ import (
)
// BuildVersion is the version of goctl.
const BuildVersion = "1.5.4"
const BuildVersion = "1.5.6"
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}

View File

@@ -72,7 +72,8 @@ from (
t.typname AS type,
a.atttypmod AS lengthvar,
a.attnotnull AS not_null,
b.description AS comment
b.description AS comment,
(c.relnamespace::regnamespace)::varchar AS schema_name
FROM pg_class c,
pg_attribute a
LEFT OUTER JOIN pg_description b ON a.attrelid = b.objoid AND a.attnum = b.objsubid,
@@ -81,10 +82,11 @@ from (
and a.attnum > 0
and a.attrelid = c.oid
and a.atttypid = t.oid
GROUP BY a.attnum, c.relname, a.attname, t.typname, a.atttypmod, a.attnotnull, b.description
GROUP BY a.attnum, c.relname, a.attname, t.typname, a.atttypmod, a.attnotnull, b.description, c.relnamespace::regnamespace
ORDER BY a.attnum) AS t
left join information_schema.columns AS c on t.relname = c.table_name
and t.field = c.column_name and c.table_schema = $2`
left join information_schema.columns AS c on t.relname = c.table_name and t.schema_name = c.table_schema
and t.field = c.column_name
where c.table_schema = $2`
var reply []*PostgreColumn
err := m.conn.QueryRowsPartial(&reply, querySql, table, schema)

View File

@@ -147,3 +147,6 @@ func (m mockClientConn) UpdateAddresses(addresses []resolver.Address) {
func (m mockClientConn) Connect() {
}
func (m mockClientConn) Shutdown() {
}