1 package civitas.bboard.server.controllers.tests;
2
3 import static org.junit.jupiter.api.Assertions.assertThrows;
4 import static org.mockito.Mockito.times;
5 import static org.mockito.Mockito.verify;
6 import static org.mockito.Mockito.verifyNoInteractions;
7
8 import java.io.IOException;
9 import java.util.ArrayList;
10
11 import org.bouncycastle.crypto.CryptoException;
12 import org.junit.jupiter.api.DisplayName;
13 import org.junit.jupiter.api.Test;
14 import org.mockito.InjectMocks;
15 import org.mockito.Mock;
16
17 import civitas.bboard.server.BoardRepository;
18 import civitas.bboard.server.GetBoardForId;
19 import civitas.bboard.server.controllers.CloseBoardController;
20 import civitas.bboard.server.controllers.CommunicableException;
21 import civitas.common.board.BoardClosedContentCommitment;
22 import civitas.common.board.tests.BoardClosedContentCommitmentTestData;
23 import civitas.common.tests.EnvironmentState;
24 import civitas.common.tests.RandomAwareTestBase;
25 import civitas.crypto.messagedigest.CryptoHash;
26 import civitas.crypto.rsapublickey.VerifyPublicKeySignature;
27 import civitas.crypto.signature.tests.SignatureTestData;
28
29 class CloseBoardControllerTest extends RandomAwareTestBase
30 implements BoardClosedContentCommitmentTestData, SignatureTestData {
31
32 @InjectMocks
33 CloseBoardController closeBoardController;
34
35 @Mock
36 GetBoardForId getBoardForId;
37
38 @Mock
39 VerifyPublicKeySignature verifyPublicKeySignature;
40
41 @Mock
42 BoardRepository boardRepository;
43
44 @Mock
45 CryptoHash cryptoHash;
46
47 @Test
48 @DisplayName(
49 """
50 closes the board
51 - verifies the signature based on the owner key stored for the bulletin board
52 - marks the board closed
53 - calculates the BoardClosedContentCommitment for all voter block
54 - posts the BoardClosedContentCommitment for the election master
55 """)
56 void test() throws CommunicableException, CryptoException {
57 closeBoardController.apply(BULLETIN_BOARD_ID, ELECTION_ID, NUM_VOTER_BLOCKS, SIGNATURE_OF_AUTH_NONCE_WITH_KEY);
58 verify(getBoardForId).apply(BULLETIN_BOARD_ID, true);
59 verify(verifyPublicKeySignature).apply(SIGNATURE_OF_AUTH_NONCE_WITH_KEY, PUBLIC_KEY, BULLETIN_BOARD_ID);
60 verify(boardRepository).save(BULLETIN_BOARD);
61 verify(cryptoHash).apply(BULLETIN_BOARD_ID.getBytes(), "voterSubmission-voterBlock0".getBytes());
62 verify(cryptoHash).apply(BULLETIN_BOARD_ID.getBytes(), "voterSubmission-voterBlock1".getBytes());
63 verify(GetRestTemplateStub.restTemplate)
64 .postForObject(ELECTION_ID.uriBase() + "/post", BOARD_CLOSED_CONTENT_COMMITMENT, Boolean.class);
65 }
66
67 @Test
68 @DisplayName("if the signature does not verify, does nothing")
69 void test2() throws CommunicableException {
70 closeBoardController.apply(BULLETIN_BOARD_ID, ELECTION_ID, NUM_VOTER_BLOCKS, SIGNATURE_OF_AUTH_NONCE_WITH_KEY2);
71 verify(boardRepository, times(0)).save(BULLETIN_BOARD);
72 verifyNoInteractions(cryptoHash);
73 verifyNoInteractions(GetRestTemplateStub.restTemplate);
74 }
75
76 @Test
77 @DisplayName("if the election is null, a NullPointerException is thrown")
78 void test3() {
79 assertThrows(
80 NullPointerException.class,
81 () -> closeBoardController.apply(
82 BULLETIN_BOARD_ID, null, NUM_VOTER_BLOCKS, SIGNATURE_OF_AUTH_NONCE_WITH_KEY));
83 }
84
85 @Test
86 @DisplayName("if the signature is null, a NullPointerException is thrown")
87 void test4() {
88 assertThrows(
89 NullPointerException.class,
90 () -> closeBoardController.apply(BULLETIN_BOARD_ID, ELECTION_ID, NUM_VOTER_BLOCKS, null));
91 }
92
93 @Test
94 @DisplayName("if the number of voter blocks is negative, an IllegalArgumentException is thrown")
95 void test5() {
96 assertThrows(
97 IllegalArgumentException.class,
98 () -> closeBoardController.apply(BULLETIN_BOARD_ID, ELECTION_ID, -1, SIGNATURE_OF_AUTH_NONCE_WITH_KEY));
99 }
100
101 @Test
102 @DisplayName("if the number of voter blocks is zero, the BoardClosedContentCommitment posted has empty hashes")
103 void test6() throws CommunicableException {
104 closeBoardController.apply(BULLETIN_BOARD_ID, ELECTION_ID, 0, SIGNATURE_OF_AUTH_NONCE_WITH_KEY);
105 verify(GetRestTemplateStub.restTemplate)
106 .postForObject(
107 ELECTION_ID.uriBase() + "/post",
108 new BoardClosedContentCommitment(ELECTION_ID, BULLETIN_BOARD_ID, new ArrayList<>()),
109 Boolean.class);
110 }
111
112 @Test
113 @DisplayName("if the election server is unreachable, an IOException is thrown and the board is not closed")
114 void test7() {
115 given(EnvironmentState.ELECTION_SERVER_IS_UNREACHEABLE);
116 assertThrows(
117 IOException.class,
118 () -> closeBoardController.apply(BULLETIN_BOARD_ID, ELECTION_ID, 0, SIGNATURE_OF_AUTH_NONCE_WITH_KEY));
119 verify(boardRepository, times(0)).save(BULLETIN_BOARD);
120 }
121 }