@@ -191,6 +191,10 @@ func TestWriter(t *testing.T) {
191
191
scenario : "test write message with writer data" ,
192
192
function : testWriteMessageWithWriterData ,
193
193
},
194
+ {
195
+ scenario : "test no new partition writers after close" ,
196
+ function : testWriterNoNewPartitionWritersAfterClose ,
197
+ },
194
198
}
195
199
196
200
for _ , test := range tests {
@@ -1030,6 +1034,46 @@ func testWriterOverrideConfigStats(t *testing.T) {
1030
1034
}
1031
1035
}
1032
1036
1037
+ func testWriterNoNewPartitionWritersAfterClose (t * testing.T ) {
1038
+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
1039
+ defer cancel ()
1040
+ topic1 := makeTopic ()
1041
+ createTopic (t , topic1 , 1 )
1042
+ defer deleteTopic (t , topic1 )
1043
+
1044
+ w := newTestWriter (WriterConfig {
1045
+ Topic : topic1 ,
1046
+ })
1047
+ defer w .Close () // try and close anyway after test finished
1048
+
1049
+ // using balancer to close writer right between first mutex is released and second mutex is taken to make map of partition writers
1050
+ w .Balancer = mockBalancerFunc (func (m Message , i ... int ) int {
1051
+ go w .Close () // close is blocking so run in goroutine
1052
+ for { // wait until writer is marked as closed
1053
+ w .mutex .Lock ()
1054
+ if w .closed {
1055
+ w .mutex .Unlock ()
1056
+ break
1057
+ }
1058
+ w .mutex .Unlock ()
1059
+ }
1060
+ return 0
1061
+ })
1062
+
1063
+ msg := Message {Value : []byte ("Hello World" )} // no topic
1064
+
1065
+ if err := w .WriteMessages (ctx , msg ); ! errors .Is (err , io .ErrClosedPipe ) {
1066
+ t .Errorf ("expected error: %v got: %v" , io .ErrClosedPipe , err )
1067
+ return
1068
+ }
1069
+ }
1070
+
1071
+ type mockBalancerFunc func (msg Message , partitions ... int ) (partition int )
1072
+
1073
+ func (b mockBalancerFunc ) Balance (msg Message , partitions ... int ) int {
1074
+ return b (msg , partitions ... )
1075
+ }
1076
+
1033
1077
type staticBalancer struct {
1034
1078
partition int
1035
1079
}
0 commit comments