commit 1da60bb4601ddd313012d7e9bc0e5d1deba2cbc3
parent 8ef51f83cdce8c580333e02797c6e0693be5205f
Author: francoispqt <francois@parquet.ninja>
Date: Tue, 1 May 2018 10:13:28 +0800
fix race condition in stream tests
Diffstat:
5 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,6 +1,6 @@
.PHONY: test
test:
- go test -run=^Test -v
+ go test -race -run=^Test -v
.PHONY: cover
cover:
diff --git a/encode_number.go b/encode_number.go
@@ -18,17 +18,45 @@ func (enc *Encoder) encodeInt(n int64) ([]byte, error) {
}
// EncodeFloat encodes a float64 to JSON
-func (enc *Encoder) EncodeFloat(n float64) ([]byte, error) {
+func (enc *Encoder) EncodeFloat(n float64) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
- return enc.encodeFloat(n)
+ _, err := enc.encodeFloat(n)
+ if err != nil {
+ return err
+ }
+ _, err = enc.write()
+ if err != nil {
+ return err
+ }
+ return nil
}
// encodeFloat encodes a float64 to JSON
func (enc *Encoder) encodeFloat(n float64) ([]byte, error) {
- s := strconv.FormatFloat(n, 'f', -1, 64)
- enc.writeString(s)
+ enc.buf = strconv.AppendFloat(enc.buf, float64(n), 'f', -1, 64)
+ return enc.buf, nil
+}
+
+// EncodeFloat encodes a float32 to JSON
+func (enc *Encoder) EncodeFloat32(n float32) error {
+ if enc.isPooled == 1 {
+ panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
+ }
+ _, err := enc.encodeFloat32(n)
+ if err != nil {
+ return err
+ }
+ _, err = enc.write()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (enc *Encoder) encodeFloat32(n float32) ([]byte, error) {
+ enc.buf = strconv.AppendFloat(enc.buf, float64(n), 'f', -1, 32)
return enc.buf, nil
}
diff --git a/encode_number_test.go b/encode_number_test.go
@@ -126,6 +126,6 @@ func TestEncoderFloatPooledError(t *testing.T) {
assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
}()
- _, _ = enc.EncodeFloat(v)
+ _ = enc.EncodeFloat(v)
assert.True(t, false, "should not be called as it should have panicked")
}
diff --git a/encode_stream.go b/encode_stream.go
@@ -71,9 +71,9 @@ func (s *StreamEncoder) NConsumer(n int) *StreamEncoder {
// If a decoder is used after calling Release
// a panic will be raised with an InvalidUsagePooledDecoderError error.
func (s *StreamEncoder) Release() {
+ s.Encoder.isPooled = 1
select {
case streamEncPool <- s:
- s.Encoder.isPooled = 1
default:
}
}
diff --git a/encode_stream_test.go b/encode_stream_test.go
@@ -57,7 +57,7 @@ func TestEncodeStreamSingleConsumer(t *testing.T) {
`{"testStr":"","testInt":0,"testInt64":0,"testInt32":0,"testInt16":0,"testInt8":0,"testUint64":0,"testUint32":0,"testUint16":0,"testUint8":0,"testFloat64":0,"testFloat32":0,"testBool":false}
`
// create our writer
- w := &TestWriter{target: 100, mux: &sync.Mutex{}}
+ w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
@@ -73,7 +73,7 @@ func TestEncodeStreamSingleConsumer(t *testing.T) {
}
func TestEncodeStreamSingleConsumerInt(t *testing.T) {
// create our writer
- w := &TestWriter{target: 100, mux: &sync.Mutex{}}
+ w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanInt(make(chan int))
@@ -86,7 +86,7 @@ func TestEncodeStreamSingleConsumerInt(t *testing.T) {
}
func TestEncodeStreamSingleConsumerFloat(t *testing.T) {
// create our writer
- w := &TestWriter{target: 100, mux: &sync.Mutex{}}
+ w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanFloat(make(chan float64))
@@ -99,7 +99,7 @@ func TestEncodeStreamSingleConsumerFloat(t *testing.T) {
}
func TestEncodeStreamSingleConsumerMarshalError(t *testing.T) {
// create our writer
- w := &TestWriter{target: 100, mux: &sync.Mutex{}}
+ w := &TestWriter{target: 100, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).LineDelimited()
w.enc = enc
s := StreamChanError(make(chan *testObject))
@@ -114,7 +114,7 @@ func TestEncodeStreamSingleConsumerCommaDelimited(t *testing.T) {
expectedStr :=
`{"testStr":"","testInt":0,"testInt64":0,"testInt32":0,"testInt16":0,"testInt8":0,"testUint64":0,"testUint32":0,"testUint16":0,"testUint8":0,"testFloat64":0,"testFloat32":0,"testBool":false},`
// create our writer
- w := &TestWriter{target: 5000, mux: &sync.Mutex{}}
+ w := &TestWriter{target: 5000, mux: &sync.RWMutex{}}
enc := Stream.BorrowEncoder(w).NConsumer(50).CommaDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
@@ -134,7 +134,7 @@ func TestEncodeStreamMultipleConsumer(t *testing.T) {
`{"testStr":"","testInt":0,"testInt64":0,"testInt32":0,"testInt16":0,"testInt8":0,"testUint64":0,"testUint32":0,"testUint16":0,"testUint8":0,"testFloat64":0,"testFloat32":0,"testBool":false}
`
// create our writer
- w := &TestWriter{target: 5000, mux: &sync.Mutex{}}
+ w := &TestWriter{target: 5000, mux: &sync.RWMutex{}}
enc := Stream.NewEncoder(w).NConsumer(50).LineDelimited()
w.enc = enc
s := StreamChanObject(make(chan *testObject))
@@ -155,17 +155,17 @@ type TestWriter struct {
target int
enc *StreamEncoder
result [][]byte
- mux *sync.Mutex
+ mux *sync.RWMutex
}
func (w *TestWriter) Write(b []byte) (int, error) {
if len(b) > 0 {
w.mux.Lock()
w.result = append(w.result, b)
- w.mux.Unlock()
if len(w.result) == w.target {
w.enc.Cancel(nil)
}
+ w.mux.Unlock()
}
return len(b), nil
}