Skip to content

Commit 468c8af

Browse files
authored
enable race unit-tests (#708)
1 parent b88ab0c commit 468c8af

File tree

10 files changed

+99
-15
lines changed

10 files changed

+99
-15
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
runs-on: ubuntu-latest
3434
strategy:
3535
matrix:
36-
tests: [unit-tests]
36+
tests: [unit-tests-race]
3737

3838
steps:
3939
- name: Checkout code

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ run-optl:
4949

5050

5151
.PHONY: unit-tests-race
52-
unit-tests-race:
52+
unit-tests-race: testing-docker-images
5353
@export GORACE=history_size=7; export FAB_BINS=$(FAB_BINS); go test -race -cover $(shell go list ./... | grep -v '/integration/')
54-
cd integration/nwo/; export FAB_BINS=$(FAB_BINS); go test -cover ./...
54+
cd integration/nwo/; export FAB_BINS=$(FAB_BINS); go test -race -cover ./...
5555

5656
.PHONY: docker-images
5757
docker-images: fabric-docker-images weaver-docker-images orion-server-images monitoring-docker-images testing-docker-images

platform/common/utils/lazy/holder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type lazyHolder[V any] struct {
3737
func (h *lazyHolder[V]) Get() (V, error) {
3838
h.mu.RLock()
3939
if h.set {
40-
h.mu.RUnlock()
40+
defer h.mu.RUnlock()
4141
return h.v, nil
4242
}
4343
h.mu.RUnlock()
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package lazy
8+
9+
import (
10+
"errors"
11+
"io"
12+
"sync"
13+
"testing"
14+
"time"
15+
)
16+
17+
type dummyCloser struct {
18+
mu sync.Mutex
19+
v int
20+
}
21+
22+
func (d *dummyCloser) Close() error {
23+
d.mu.Lock()
24+
defer d.mu.Unlock()
25+
d.v = 0
26+
return nil
27+
}
28+
29+
func TestLazyHolderRaceCondition(t *testing.T) {
30+
// Provider function for the lazyHolder.
31+
provider := func() (*dummyCloser, error) {
32+
time.Sleep(10 * time.Millisecond) // Simulate some delay
33+
return &dummyCloser{v: 42}, nil
34+
}
35+
36+
// Test for race conditions
37+
holder := NewCloserHolder(provider)
38+
39+
var wg sync.WaitGroup
40+
41+
// Concurrently call Get.
42+
for i := 0; i < 10; i++ {
43+
wg.Add(1)
44+
go func() {
45+
defer wg.Done()
46+
v, err := holder.Get()
47+
if err != nil {
48+
t.Errorf("Get() error: %v", err)
49+
}
50+
if v == nil {
51+
t.Errorf("Get() returned nil value")
52+
}
53+
}()
54+
}
55+
56+
// Concurrently call Reset.
57+
for i := 0; i < 5; i++ {
58+
wg.Add(1)
59+
go func() {
60+
defer wg.Done()
61+
err := holder.Reset()
62+
if err != nil && !errors.Is(err, io.EOF) {
63+
t.Errorf("Reset() error: %v", err)
64+
}
65+
}()
66+
}
67+
68+
wg.Wait()
69+
}

platform/fabric/core/generic/chaincode/discovery.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,10 @@ func (d *Discovery) Response() (discovery.Response, error) {
132132
// Do we have a response already?
133133
d.chaincode.discoveryResultsCacheLock.RLock()
134134
responseBoxed, err := d.chaincode.discoveryResultsCache.Get(key)
135+
d.chaincode.discoveryResultsCacheLock.RUnlock()
135136
if responseBoxed != nil && err == nil {
136-
d.chaincode.discoveryResultsCacheLock.RUnlock()
137137
return responseBoxed.(discovery.Response), nil
138138
}
139-
d.chaincode.discoveryResultsCacheLock.RUnlock()
140139

141140
d.chaincode.discoveryResultsCacheLock.Lock()
142141
defer d.chaincode.discoveryResultsCacheLock.Unlock()

platform/fabric/core/generic/chaincode/manager.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,10 @@ func NewManager(
6767
func (c *Manager) Chaincode(name string) driver.Chaincode {
6868
c.ChaincodesLock.RLock()
6969
ch, ok := c.Chaincodes[name]
70+
c.ChaincodesLock.RUnlock()
7071
if ok {
71-
c.ChaincodesLock.RUnlock()
7272
return ch
7373
}
74-
c.ChaincodesLock.RUnlock()
7574

7675
c.ChaincodesLock.Lock()
7776
defer c.ChaincodesLock.Unlock()

platform/fabric/events_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,24 @@ import (
2020

2121
type mockSubscriber struct {
2222
listener events.Listener
23-
sync.RWMutex
23+
m sync.RWMutex
2424
}
2525

2626
func (m *mockSubscriber) Subscribe(chaincodeName string, listener events.Listener) {
27+
m.m.Lock()
28+
defer m.m.Unlock()
2729
m.listener = listener
2830
}
2931

3032
func (m *mockSubscriber) Unsubscribe(chaincodeName string, listener events.Listener) {
33+
m.m.Lock()
34+
defer m.m.Unlock()
3135
m.listener = nil
3236
}
3337

3438
func (m *mockSubscriber) Publish(chaincodeName string, event *committer.ChaincodeEvent) {
39+
m.m.RLock()
40+
defer m.m.RUnlock()
3541
if m.listener != nil {
3642
m.listener.OnReceive(event)
3743
}

platform/view/services/comm/host/rest/websocket/stream_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,18 @@ func TestWriter(t *testing.T) {
7777
assert.NoError(t, stream.Close())
7878

7979
output := make([][]byte, 0, len(input))
80+
m := sync.RWMutex{}
8081
go func() {
8182
for written := range conn.WrittenValues() {
83+
m.Lock()
8284
output = append(output, written)
85+
m.Unlock()
8386
}
8487
}()
8588

8689
assert.Eventually(t, func() bool {
90+
m.RLock()
91+
defer m.RUnlock()
8792
return len(input) == len(output)
8893
}, 5*time.Second, time.Second)
8994
}

platform/view/services/comm/session.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ type NetworkStreamSession struct {
2828
incoming chan *view.Message
2929
streams map[*streamHandler]struct{}
3030
closed bool
31-
mutex sync.Mutex
31+
mutex sync.RWMutex
3232
}
3333

3434
func (n *NetworkStreamSession) Info() view.SessionInfo {
35-
n.mutex.Lock()
35+
n.mutex.RLock()
36+
defer n.mutex.RUnlock()
3637
ret := view.SessionInfo{
3738
ID: n.sessionID,
3839
Caller: n.caller,
@@ -41,7 +42,6 @@ func (n *NetworkStreamSession) Info() view.SessionInfo {
4142
EndpointPKID: n.endpointID,
4243
Closed: n.closed,
4344
}
44-
n.mutex.Unlock()
4545
return ret
4646
}
4747

@@ -111,20 +111,25 @@ func (n *NetworkStreamSession) closeInternal() {
111111
}
112112

113113
func (n *NetworkStreamSession) sendWithStatus(ctx context.Context, payload []byte, status int32) error {
114+
n.mutex.RLock()
114115
info := host.StreamInfo{
115116
RemotePeerID: string(n.endpointID),
116117
RemotePeerAddress: n.endpointAddress,
117118
ContextID: n.contextID,
118119
SessionID: n.sessionID,
119120
}
120-
err := n.node.sendTo(ctx, info, &ViewPacket{
121+
packet := &ViewPacket{
121122
ContextID: n.contextID,
122123
SessionID: n.sessionID,
123124
Caller: n.callerViewID,
124125
Status: status,
125126
Payload: payload,
126-
})
127+
}
128+
n.mutex.RUnlock()
129+
130+
err := n.node.sendTo(ctx, info, packet)
127131
if logger.IsEnabledFor(zapcore.DebugLevel) {
132+
n.mutex.RLock()
128133
logger.Debugf(
129134
"sent message [len:%d] to [%s:%s] from [%s] with err [%s]",
130135
len(payload),
@@ -144,6 +149,7 @@ func (n *NetworkStreamSession) sendWithStatus(ctx context.Context, payload []byt
144149
debug.Stack(),
145150
)
146151
}
152+
n.mutex.RUnlock()
147153
}
148154
return err
149155
}

platform/view/services/kvs/kvs_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func testParallelWrites(t *testing.T, driver driver.Driver, cp kvs.ConfigProvide
134134
assert.NoError(t, err)
135135
for i := 0; i < n; i++ {
136136
go func(i int) {
137-
err = kvstore.Put(k1, &stuff{"santa", 1})
137+
err := kvstore.Put(k1, &stuff{"santa", 1})
138138
assert.NoError(t, err)
139139
defer wg.Done()
140140
}(i)

0 commit comments

Comments
 (0)