@@ -158,6 +158,81 @@ func TestDuplicateMessagesAndMalformedInput(t *testing.T) {
158158 }
159159}
160160
161+ func TestDuplicateInboundPreAcceptAndAcceptDoNotQueueDuplicateRecords (t * testing.T ) {
162+ ref := InstanceRef {Replica : 1 , Instance : 1 , Conf : 1 }
163+ command := Command {ID : CommandID {Client : 10 , Sequence : 20 }, Payload : []byte ("duplicate-inbound" ), ConflictKeys : [][]byte {[]byte ("duplicate-key" )}}
164+ tests := []struct {
165+ name string
166+ msg Message
167+ wantStatus Status
168+ }{
169+ {
170+ name : "preaccept" ,
171+ msg : Message {
172+ Type : MsgPreAccept ,
173+ From : 1 ,
174+ To : 2 ,
175+ Ref : ref ,
176+ Ballot : Ballot {Replica : 1 },
177+ Seq : 1 ,
178+ Deps : []InstanceNum {0 , 0 , 0 },
179+ Command : command ,
180+ },
181+ wantStatus : StatusPreAccepted ,
182+ },
183+ {
184+ name : "accept" ,
185+ msg : Message {
186+ Type : MsgAccept ,
187+ From : 1 ,
188+ To : 2 ,
189+ Ref : ref ,
190+ Ballot : Ballot {Replica : 1 },
191+ Seq : 1 ,
192+ Deps : []InstanceNum {0 , 0 , 0 },
193+ Command : command ,
194+ },
195+ wantStatus : StatusAccepted ,
196+ },
197+ }
198+ for _ , tt := range tests {
199+ t .Run (tt .name , func (t * testing.T ) {
200+ store := NewMemoryStorage ()
201+ rn , err := NewRawNode (Config {ID : 2 , Voters : makeIDs (3 ), Storage : store })
202+ if err != nil {
203+ t .Fatal (err )
204+ }
205+ tt .msg .Checksum = ChecksumMessage (tt .msg )
206+
207+ if err := rn .Step (tt .msg ); err != nil {
208+ t .Fatalf ("first Step(%s) err=%v" , tt .msg .Type , err )
209+ }
210+ first := rn .Ready ()
211+ if len (first .Records ) != 1 || first .Records [0 ].Ref != ref || first .Records [0 ].Status != tt .wantStatus {
212+ t .Fatalf ("first duplicate target ready records = %#v, want exactly one %s record for %s" , first .Records , tt .wantStatus , ref )
213+ }
214+ if err := store .ApplyReady (first ); err != nil {
215+ t .Fatal (err )
216+ }
217+ advanceOK (t , rn , first )
218+
219+ if err := rn .Step (tt .msg ); err != nil {
220+ t .Fatalf ("duplicate Step(%s) err=%v" , tt .msg .Type , err )
221+ }
222+ duplicate := rn .Ready ()
223+ if len (duplicate .Records ) != 0 {
224+ t .Fatalf ("duplicate %s ready records = %#v, want no durable records for unchanged %s" , tt .msg .Type , duplicate .Records , ref )
225+ }
226+ if ! duplicate .Empty () {
227+ if err := store .ApplyReady (duplicate ); err != nil {
228+ t .Fatal (err )
229+ }
230+ advanceOK (t , rn , duplicate )
231+ }
232+ })
233+ }
234+ }
235+
161236func TestCodecChecksumZeroCopy (t * testing.T ) {
162237 m := Message {
163238 Type : MsgCommit ,
0 commit comments