1 /*
2  * Copyright 2018 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "fcp/secagg/client/secagg_client_r3_unmasking_state.h"
18 
19 #include <memory>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "fcp/base/monitoring.h"
27 #include "fcp/secagg/client/secagg_client_aborted_state.h"
28 #include "fcp/secagg/client/secagg_client_completed_state.h"
29 #include "fcp/secagg/shared/secagg_messages.pb.h"
30 #include "fcp/secagg/shared/secagg_vector.h"
31 #include "fcp/secagg/shared/shamir_secret_sharing.h"
32 #include "fcp/secagg/testing/mock_send_to_server_interface.h"
33 #include "fcp/secagg/testing/mock_state_transition_listener.h"
34 #include "fcp/testing/testing.h"
35 
36 namespace fcp {
37 namespace secagg {
38 namespace {
39 
40 using ::testing::Eq;
41 using ::testing::Pointee;
42 using ::testing::StrEq;
43 
44 static const ShamirShare test_pairwise_share = {"test pairwise share"};
45 static const ShamirShare test_self_share = {"test self share"};
46 
TEST(SecAggClientR3UnmaskingStateTest,IsAbortedReturnsFalse)47 TEST(SecAggClientR3UnmaskingStateTest, IsAbortedReturnsFalse) {
48   MockSendToServerInterface* sender = new MockSendToServerInterface();
49   MockStateTransitionListener* transition_listener =
50       new MockStateTransitionListener();
51   SecAggClientR3UnmaskingState r3_state(
52       0, 4, 4, 4, std::make_unique<std::vector<OtherClientState> >(4),
53       std::make_unique<std::vector<ShamirShare> >(4),
54       std::make_unique<std::vector<ShamirShare> >(4),
55       std::unique_ptr<SendToServerInterface>(sender),
56       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
57   EXPECT_THAT(r3_state.IsAborted(), Eq(false));
58 }
59 
TEST(SecAggClientR3UnmaskingStateTest,IsCompletedSuccessfullyReturnsFalse)60 TEST(SecAggClientR3UnmaskingStateTest, IsCompletedSuccessfullyReturnsFalse) {
61   MockSendToServerInterface* sender = new MockSendToServerInterface();
62   MockStateTransitionListener* transition_listener =
63       new MockStateTransitionListener();
64   SecAggClientR3UnmaskingState r3_state(
65       0, 4, 4, 4, std::make_unique<std::vector<OtherClientState> >(4),
66       std::make_unique<std::vector<ShamirShare> >(4),
67       std::make_unique<std::vector<ShamirShare> >(4),
68       std::unique_ptr<SendToServerInterface>(sender),
69       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
70   EXPECT_THAT(r3_state.IsCompletedSuccessfully(), Eq(false));
71 }
72 
TEST(SecAggClientR3UnmaskingStateTest,StartRaisesErrorStatus)73 TEST(SecAggClientR3UnmaskingStateTest, StartRaisesErrorStatus) {
74   MockSendToServerInterface* sender = new MockSendToServerInterface();
75   MockStateTransitionListener* transition_listener =
76       new MockStateTransitionListener();
77   SecAggClientR3UnmaskingState r3_state(
78       0, 4, 4, 4, std::make_unique<std::vector<OtherClientState> >(4),
79       std::make_unique<std::vector<ShamirShare> >(4),
80       std::make_unique<std::vector<ShamirShare> >(4),
81       std::unique_ptr<SendToServerInterface>(sender),
82       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
83   EXPECT_THAT(r3_state.Start().ok(), Eq(false));
84 }
85 
TEST(SecAggClientR3UnmaskingStateTest,SetInputRaisesErrorStatus)86 TEST(SecAggClientR3UnmaskingStateTest, SetInputRaisesErrorStatus) {
87   MockSendToServerInterface* sender = new MockSendToServerInterface();
88   MockStateTransitionListener* transition_listener =
89       new MockStateTransitionListener();
90   SecAggClientR3UnmaskingState r3_state(
91       0, 4, 4, 4, std::make_unique<std::vector<OtherClientState> >(4),
92       std::make_unique<std::vector<ShamirShare> >(4),
93       std::make_unique<std::vector<ShamirShare> >(4),
94       std::unique_ptr<SendToServerInterface>(sender),
95       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
96   EXPECT_THAT(r3_state.SetInput(std::make_unique<SecAggVectorMap>()).ok(),
97               Eq(false));
98 }
99 
TEST(SecAggClientR3UnmaskingStateTest,ErrorMessageRaisesErrorStatus)100 TEST(SecAggClientR3UnmaskingStateTest, ErrorMessageRaisesErrorStatus) {
101   MockSendToServerInterface* sender = new MockSendToServerInterface();
102   MockStateTransitionListener* transition_listener =
103       new MockStateTransitionListener();
104   SecAggClientR3UnmaskingState r3_state(
105       0, 4, 4, 4, std::make_unique<std::vector<OtherClientState> >(4),
106       std::make_unique<std::vector<ShamirShare> >(4),
107       std::make_unique<std::vector<ShamirShare> >(4),
108       std::unique_ptr<SendToServerInterface>(sender),
109       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
110   EXPECT_THAT(r3_state.ErrorMessage().ok(), Eq(false));
111 }
112 
TEST(SecAggClientR3UnmaskingStateTest,AbortReturnsValidAbortStateAndNotifiesServer)113 TEST(SecAggClientR3UnmaskingStateTest,
114      AbortReturnsValidAbortStateAndNotifiesServer) {
115   MockSendToServerInterface* sender = new MockSendToServerInterface();
116   MockStateTransitionListener* transition_listener =
117       new MockStateTransitionListener();
118 
119   std::string error_string =
120       "Abort upon external request for reason <Abort reason>.";
121 
122   ClientToServerWrapperMessage expected_message;
123   expected_message.mutable_abort()->set_diagnostic_info(error_string);
124   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
125 
126   SecAggClientR3UnmaskingState r3_state(
127       0, 4, 4, 4, std::make_unique<std::vector<OtherClientState> >(4),
128       std::make_unique<std::vector<ShamirShare> >(4),
129       std::make_unique<std::vector<ShamirShare> >(4),
130       std::unique_ptr<SendToServerInterface>(sender),
131       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
132   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
133       r3_state.Abort("Abort reason");
134   ASSERT_THAT(new_state.ok(), Eq(true));
135   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
136   EXPECT_THAT(new_state.value()->ErrorMessage().value(), StrEq(error_string));
137 }
138 
TEST(SecAggClientR3UnmaskingStateTest,AbortFailureMessageCausesAbortWithoutNotifyingServer)139 TEST(SecAggClientR3UnmaskingStateTest,
140      AbortFailureMessageCausesAbortWithoutNotifyingServer) {
141   MockSendToServerInterface* sender = new MockSendToServerInterface();
142   MockStateTransitionListener* transition_listener =
143       new MockStateTransitionListener();
144   SecAggClientR3UnmaskingState r3_state(
145       1,  // client_id
146       6,  // number_of_alive_neighbors
147       4,  // minimum_surviving_neighbors_for_reconstruction
148       6,  // number_of_neighbors
149       std::make_unique<std::vector<OtherClientState> >(
150           6, OtherClientState::kAlive),
151       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
152       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
153       std::unique_ptr<SendToServerInterface>(sender),
154       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
155 
156   EXPECT_CALL(*sender, Send(::testing::_)).Times(0);
157   ServerToClientWrapperMessage abort_message;
158   abort_message.mutable_abort()->set_early_success(false);
159 
160   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
161       r3_state.HandleMessage(abort_message);
162   ASSERT_TRUE(new_state.ok());
163   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
164   EXPECT_THAT(new_state.value()->ErrorMessage().value(),
165               StrEq("Aborting because of abort message from the server."));
166 }
167 
TEST(SecAggClientR3UnmaskingStateTest,EarlySuccessMessageCausesTransitionToCompletedState)168 TEST(SecAggClientR3UnmaskingStateTest,
169      EarlySuccessMessageCausesTransitionToCompletedState) {
170   MockSendToServerInterface* sender = new MockSendToServerInterface();
171   MockStateTransitionListener* transition_listener =
172       new MockStateTransitionListener();
173   SecAggClientR3UnmaskingState r3_state(
174       1,  // client_id
175       6,  // number_of_alive_neighbors
176       4,  // minimum_surviving_neighbors_for_reconstruction
177       6,  // number_of_neighbors
178       std::make_unique<std::vector<OtherClientState> >(
179           6, OtherClientState::kAlive),
180       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
181       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
182       std::unique_ptr<SendToServerInterface>(sender),
183       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
184 
185   EXPECT_CALL(*sender, Send(::testing::_)).Times(0);
186   ServerToClientWrapperMessage abort_message;
187   abort_message.mutable_abort()->set_early_success(true);
188 
189   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
190       r3_state.HandleMessage(abort_message);
191   ASSERT_TRUE(new_state.ok());
192   EXPECT_THAT(new_state.value()->StateName(), StrEq("COMPLETED"));
193 }
194 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestIsCorrectlyHandledWhenNoClientsDie)195 TEST(SecAggClientR3UnmaskingStateTest,
196      UnmaskingRequestIsCorrectlyHandledWhenNoClientsDie) {
197   // In this test, this is client id 1. There are 6 clients, and none of them
198   // drop out.
199   MockSendToServerInterface* sender = new MockSendToServerInterface();
200   MockStateTransitionListener* transition_listener =
201       new MockStateTransitionListener();
202   SecAggClientR3UnmaskingState r3_state(
203       1,  // client_id
204       6,  // number_of_alive_neighbors
205       4,  // minimum_surviving_neighbors_for_reconstruction
206       6,  // number_of_neighbors
207       std::make_unique<std::vector<OtherClientState> >(
208           6, OtherClientState::kAlive),
209       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
210       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
211       std::unique_ptr<SendToServerInterface>(sender),
212       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
213 
214   ClientToServerWrapperMessage expected_message;
215   for (int i = 0; i < 6; i++) {
216     expected_message.mutable_unmasking_response()
217         ->add_noise_or_prf_key_shares()
218         ->set_prf_sk_share("test self share");
219   }
220   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
221 
222   ServerToClientWrapperMessage request;
223   request.mutable_unmasking_request();
224   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
225       r3_state.HandleMessage(request);
226   ASSERT_TRUE(new_state.ok());
227   EXPECT_THAT(new_state.value()->StateName(), StrEq("COMPLETED"));
228 }
229 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestIsCorrectlyHandledWhenFewClientsDie)230 TEST(SecAggClientR3UnmaskingStateTest,
231      UnmaskingRequestIsCorrectlyHandledWhenFewClientsDie) {
232   // In this test, this is client id 1. Client 3 already died at round 2, and
233   // client 5 dies in round 3.
234   MockSendToServerInterface* sender = new MockSendToServerInterface();
235   MockStateTransitionListener* transition_listener =
236       new MockStateTransitionListener();
237   std::vector<OtherClientState> other_clients_states{
238       OtherClientState::kAlive, OtherClientState::kAlive,
239       OtherClientState::kAlive, OtherClientState::kDeadAtRound2,
240       OtherClientState::kAlive, OtherClientState::kAlive};
241 
242   SecAggClientR3UnmaskingState r3_state(
243       1,  // client_id
244       5,  // number_of_alive_neighbors
245       4,  // minimum_surviving_neighbors_for_reconstruction
246       6,  // number_of_neighbors
247       std::make_unique<std::vector<OtherClientState> >(other_clients_states),
248       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
249       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
250       std::unique_ptr<SendToServerInterface>(sender),
251       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
252 
253   ClientToServerWrapperMessage expected_message;
254   for (int i = 0; i < 6; i++) {
255     if (i == 3) {
256       expected_message.mutable_unmasking_response()
257           ->add_noise_or_prf_key_shares();
258     } else if (i == 5) {
259       expected_message.mutable_unmasking_response()
260           ->add_noise_or_prf_key_shares()
261           ->set_noise_sk_share("test pairwise share");
262     } else {
263       expected_message.mutable_unmasking_response()
264           ->add_noise_or_prf_key_shares()
265           ->set_prf_sk_share("test self share");
266     }
267   }
268   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
269 
270   ServerToClientWrapperMessage request;
271   // TODO(team): 6 -> 5 below, once backwards compatibility not needed.
272   request.mutable_unmasking_request()->add_dead_3_client_ids(6);
273   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
274       r3_state.HandleMessage(request);
275   ASSERT_TRUE(new_state.ok());
276   EXPECT_THAT(new_state.value()->StateName(), StrEq("COMPLETED"));
277 }
278 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestCausesAbortWhenTooManyClientsDie)279 TEST(SecAggClientR3UnmaskingStateTest,
280      UnmaskingRequestCausesAbortWhenTooManyClientsDie) {
281   // In this test, this is client id 1. Client 3 already died at round 2, and
282   // clients 4 and 5 die in round 3. This should cause a transition to an abort
283   // state and an abort message to be sent to the server.
284   MockSendToServerInterface* sender = new MockSendToServerInterface();
285   MockStateTransitionListener* transition_listener =
286       new MockStateTransitionListener();
287   std::vector<OtherClientState> other_clients_states{
288       OtherClientState::kAlive, OtherClientState::kAlive,
289       OtherClientState::kAlive, OtherClientState::kDeadAtRound2,
290       OtherClientState::kAlive, OtherClientState::kAlive};
291 
292   SecAggClientR3UnmaskingState r3_state(
293       1,  // client_id
294       5,  // number_of_alive_neighbors
295       4,  // minimum_surviving_neighbors_for_reconstruction
296       6,  // number_of_neighbors
297       std::make_unique<std::vector<OtherClientState> >(other_clients_states),
298       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
299       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
300       std::unique_ptr<SendToServerInterface>(sender),
301       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
302 
303   std::string error_string =
304       "Not enough clients survived. The server should not have sent this "
305       "UnmaskingRequest.";
306   ClientToServerWrapperMessage expected_message;
307   expected_message.mutable_abort()->set_diagnostic_info(error_string);
308   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
309 
310   ServerToClientWrapperMessage request;
311   // TODO(team): 5 -> 4 below, once backwards compatibility not needed.
312   request.mutable_unmasking_request()->add_dead_3_client_ids(5);
313   // TODO(team): 6 -> 5 below, once backwards compatibility not needed.
314   request.mutable_unmasking_request()->add_dead_3_client_ids(6);
315   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
316       r3_state.HandleMessage(request);
317   ASSERT_TRUE(new_state.ok());
318   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
319   EXPECT_THAT(new_state.value()->ErrorMessage().value(), StrEq(error_string));
320 }
321 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestCausesAbortIfServerListsThisClientAsDead)322 TEST(SecAggClientR3UnmaskingStateTest,
323      UnmaskingRequestCausesAbortIfServerListsThisClientAsDead) {
324   // In this test, this is client id 1, but the server lists client 1 as dead.
325   // This should cause a transition to an abort state and an abort message to be
326   // sent to the server.
327   MockSendToServerInterface* sender = new MockSendToServerInterface();
328   MockStateTransitionListener* transition_listener =
329       new MockStateTransitionListener();
330 
331   SecAggClientR3UnmaskingState r3_state(
332       1,  // client_id
333       6,  // number_of_alive_neighbors
334       4,  // minimum_surviving_neighbors_for_reconstruction
335       6,  // number_of_neighbors
336       std::make_unique<std::vector<OtherClientState> >(
337           6, OtherClientState::kAlive),
338       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
339       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
340       std::unique_ptr<SendToServerInterface>(sender),
341       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
342 
343   std::string error_string =
344       "The received UnmaskingRequest states this client has aborted, but this "
345       "client had not yet aborted.";
346   ClientToServerWrapperMessage expected_message;
347   expected_message.mutable_abort()->set_diagnostic_info(error_string);
348   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
349 
350   ServerToClientWrapperMessage request;
351   // TODO(team): 2 -> 1 below, once backwards compatibility not needed.
352   request.mutable_unmasking_request()->add_dead_3_client_ids(2);
353   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
354       r3_state.HandleMessage(request);
355   ASSERT_TRUE(new_state.ok());
356   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
357   EXPECT_THAT(new_state.value()->ErrorMessage().value(), StrEq(error_string));
358 }
359 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestCausesAbortIfServerListsNonexistentClientAsDead)360 TEST(SecAggClientR3UnmaskingStateTest,
361      UnmaskingRequestCausesAbortIfServerListsNonexistentClientAsDead) {
362   // In this test, there are 6 clients (labeled 0-5), but the server lists
363   // client 6 as dead. This should cause a transition to an abort state and an
364   // abort message to be sent to the server.
365   MockSendToServerInterface* sender = new MockSendToServerInterface();
366   MockStateTransitionListener* transition_listener =
367       new MockStateTransitionListener();
368 
369   SecAggClientR3UnmaskingState r3_state(
370       1,  // client_id
371       6,  // number_of_alive_neighbors
372       4,  // minimum_surviving_neighbors_for_reconstruction
373       6,  // number_of_neighbors
374       std::make_unique<std::vector<OtherClientState> >(
375           6, OtherClientState::kAlive),
376       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
377       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
378       std::unique_ptr<SendToServerInterface>(sender),
379       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
380 
381   std::string error_string =
382       "The received UnmaskingRequest contains a client id that does not "
383       "correspond to any client.";
384   ClientToServerWrapperMessage expected_message;
385   expected_message.mutable_abort()->set_diagnostic_info(error_string);
386   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
387 
388   ServerToClientWrapperMessage request;
389   // TODO(team): 7 -> 6 below, once backwards compatibility not needed.
390   request.mutable_unmasking_request()->add_dead_3_client_ids(7);
391   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
392       r3_state.HandleMessage(request);
393   ASSERT_TRUE(new_state.ok());
394   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
395   EXPECT_THAT(new_state.value()->ErrorMessage().value(), StrEq(error_string));
396 }
397 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestCausesAbortIfServerListsClientThatAlreadyDied)398 TEST(SecAggClientR3UnmaskingStateTest,
399      UnmaskingRequestCausesAbortIfServerListsClientThatAlreadyDied) {
400   // In this test, client 3 died at round 1, but the server lists client 3 as
401   // dead at round 3. This should cause a transition to an abort state and an
402   // abort message to be sent to the server.
403   MockSendToServerInterface* sender = new MockSendToServerInterface();
404   MockStateTransitionListener* transition_listener =
405       new MockStateTransitionListener();
406   std::vector<OtherClientState> other_clients_states{
407       OtherClientState::kAlive, OtherClientState::kAlive,
408       OtherClientState::kAlive, OtherClientState::kDeadAtRound1,
409       OtherClientState::kAlive, OtherClientState::kAlive};
410 
411   SecAggClientR3UnmaskingState r3_state(
412       1,  // client_id
413       5,  // number_of_alive_neighbors
414       4,  // minimum_surviving_neighbors_for_reconstruction
415       6,  // number_of_neighbors
416       std::make_unique<std::vector<OtherClientState> >(other_clients_states),
417       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
418       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
419       std::unique_ptr<SendToServerInterface>(sender),
420       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
421 
422   std::string error_string =
423       "The received UnmaskingRequest considers a client dead in round 3 "
424       "that was already considered dead.";
425   ClientToServerWrapperMessage expected_message;
426   expected_message.mutable_abort()->set_diagnostic_info(error_string);
427   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
428 
429   ServerToClientWrapperMessage request;
430   // TODO(team): 4 -> 3 below, once backwards compatibility not needed.
431   request.mutable_unmasking_request()->add_dead_3_client_ids(4);
432   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
433       r3_state.HandleMessage(request);
434   ASSERT_TRUE(new_state.ok());
435   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
436   EXPECT_THAT(new_state.value()->ErrorMessage().value(), StrEq(error_string));
437 }
438 
TEST(SecAggClientR3UnmaskingStateTest,UnmaskingRequestCausesAbortIfServerListsSameClientTwice)439 TEST(SecAggClientR3UnmaskingStateTest,
440      UnmaskingRequestCausesAbortIfServerListsSameClientTwice) {
441   // In this test, the server lists client 5 as dead at round 3 twice. This
442   // should cause a transition to an abort state and an abort message to be sent
443   // to the server.
444   MockSendToServerInterface* sender = new MockSendToServerInterface();
445   MockStateTransitionListener* transition_listener =
446       new MockStateTransitionListener();
447 
448   SecAggClientR3UnmaskingState r3_state(
449       1,  // client_id
450       6,  // number_of_alive_neighbors
451       4,  // minimum_surviving_neighbors_for_reconstruction
452       6,  // number_of_neighbors
453       std::make_unique<std::vector<OtherClientState> >(
454           6, OtherClientState::kAlive),
455       std::make_unique<std::vector<ShamirShare> >(6, test_pairwise_share),
456       std::make_unique<std::vector<ShamirShare> >(6, test_self_share),
457       std::unique_ptr<SendToServerInterface>(sender),
458       std::unique_ptr<StateTransitionListenerInterface>(transition_listener));
459 
460   std::string error_string =
461       "The received UnmaskingRequest repeated a client more than once as a "
462       "dead client.";
463   ClientToServerWrapperMessage expected_message;
464   expected_message.mutable_abort()->set_diagnostic_info(error_string);
465   EXPECT_CALL(*sender, Send(Pointee(EqualsProto(expected_message))));
466 
467   ServerToClientWrapperMessage request;
468   // TODO(team): 6 -> 5 below, once backwards compatibility not needed.
469   request.mutable_unmasking_request()->add_dead_3_client_ids(6);
470   request.mutable_unmasking_request()->add_dead_3_client_ids(6);
471   StatusOr<std::unique_ptr<SecAggClientState> > new_state =
472       r3_state.HandleMessage(request);
473   ASSERT_TRUE(new_state.ok());
474   EXPECT_THAT(new_state.value()->StateName(), StrEq("ABORTED"));
475   EXPECT_THAT(new_state.value()->ErrorMessage().value(), StrEq(error_string));
476 }
477 
478 }  // namespace
479 }  // namespace secagg
480 }  // namespace fcp
481