BUG-9145: rework singleton service group state tracking
[mdsal.git] / singleton-service / mdsal-singleton-dom-impl / src / test / java / org / opendaylight / mdsal / singleton / dom / impl / DOMClusterSingletonServiceProviderImplTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.mdsal.singleton.dom.impl;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.mockito.Mockito.atLeastOnce;
14 import static org.mockito.Mockito.never;
15 import static org.mockito.Mockito.times;
16 import static org.mockito.Mockito.verify;
17
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
21 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
22 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
23
24 /**
25  * Synchronous test suite.
26  */
27 public class DOMClusterSingletonServiceProviderImplTest extends AbstractDOMClusterServiceProviderTest {
28     /**
29      * Initialization functionality for every Tests in this suite.
30      *
31      * @throws CandidateAlreadyRegisteredException if the condition does not meet
32      */
33     @Override
34     @Before
35     public void setup() throws CandidateAlreadyRegisteredException {
36         super.setup();
37     }
38
39     /**
40      * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}.
41      *
42      * @throws Exception if the condition does not meet
43      */
44     @Test
45     public void takeDoubleLeadershipClusterSingletonServiceTest() throws Exception {
46         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
47                 .registerClusterSingletonService(clusterSingletonService);
48         assertNotNull(reg);
49         verify(mockEos).registerCandidate(ENTITY);
50         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
51         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
52         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
53         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
54         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
55         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
56         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
57         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
58         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
59         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
60         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
61         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
62         verify(mockEosDoubleEntityListReg, never()).close();
63         verify(mockEosEntityListReg, never()).close();
64         verify(mockEntityCandReg, never()).close();
65         verify(mockDoubleEntityCandReg).close();
66     }
67
68     /**
69      * Test checks unexpected change for MASTER-TO-SLAVE double Candidate role change.
70      *
71      * @throws Exception if the condition does not meet
72      */
73     @Test
74     public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception {
75         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
76                 .registerClusterSingletonService(clusterSingletonService);
77         assertNotNull(reg);
78         verify(mockEos).registerCandidate(ENTITY);
79         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
80         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
81         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
82         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
83         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
84         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
85         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
86         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
87         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
88         verify(mockEosDoubleEntityListReg, never()).close();
89         verify(mockEntityCandReg, never()).close();
90         verify(mockDoubleEntityCandReg, never()).close();
91         reg.close();
92         verify(mockEosEntityListReg, never()).close();
93         verify(mockEosDoubleEntityListReg, never()).close();
94         verify(mockEntityCandReg, atLeastOnce()).close();
95         verify(mockDoubleEntityCandReg, never()).close();
96         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
97         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
98         verify(mockEntityCandReg, atLeastOnce()).close();
99         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
100         verify(mockEosDoubleEntityListReg, never()).close();
101     }
102
103     /**
104      * Test checks inJeopardy Cluster Node state for Master Instance.
105      *
106      * @throws Exception if the condition does not meet
107      */
108     @Test
109     public void inJeopardyMasterTest() throws Exception {
110         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
111                 .registerClusterSingletonService(clusterSingletonService);
112         assertNotNull(reg);
113         verify(mockEos).registerCandidate(ENTITY);
114         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
115         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
116         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
117         clusterSingletonServiceProvider.ownershipChanged(getInitDoubleEntityToSlave());
118         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
119         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
120         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
121         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToJeopardy());
122         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
123         verify(mockEosEntityListReg, never()).close();
124         verify(mockEosDoubleEntityListReg, never()).close();
125         verify(mockEntityCandReg, never()).close();
126         verify(mockDoubleEntityCandReg, never()).close();
127     }
128
129     /**
130      * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
131      *
132      * @throws Exception if the condition does not meet
133      */
134     @Test
135     public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception {
136         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
137                 .registerClusterSingletonService(clusterSingletonService);
138         assertNotNull(reg);
139         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
140         verify(mockEos).registerCandidate(ENTITY);
141         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
142         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
143         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
144         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
145         reg.close();
146         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
147         verify(mockEosEntityListReg, never()).close();
148         verify(mockEosDoubleEntityListReg, never()).close();
149         verify(mockEntityCandReg).close();
150         verify(mockDoubleEntityCandReg).close();
151         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
152     }
153
154     /**
155      * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
156      *
157      * @throws Exception if the condition does not meet
158      */
159     @Test
160     public void closeClusterSingletonServiceRegistrationMasterCloseWithNotificationTimesTest() throws Exception {
161         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
162                 .registerClusterSingletonService(clusterSingletonService);
163         assertNotNull(reg);
164         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
165         verify(mockEos).registerCandidate(ENTITY);
166         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
167         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
168         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
169         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
170         reg.close();
171         verify(mockEosEntityListReg, never()).close();
172         verify(mockEosDoubleEntityListReg, never()).close();
173         verify(mockEntityCandReg, atLeastOnce()).close();
174         verify(mockDoubleEntityCandReg, never()).close();
175         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
176         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
177         verify(mockEntityCandReg, atLeastOnce()).close();
178         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
179         verify(mockEosDoubleEntityListReg, never()).close();
180         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
181     }
182
183     /**
184      * Test checks close processing for {@link ClusterSingletonServiceRegistration}.
185      *
186      * @throws Exception if the condition does not meet
187      */
188     @Test
189     public void closeClusterSingletonServiceRegistrationMasterCloseCoupleTimesTest() throws Exception {
190         final ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
191                 .registerClusterSingletonService(clusterSingletonService);
192         assertNotNull(reg);
193         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
194         verify(mockEos).registerCandidate(ENTITY);
195         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
196         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
197         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
198         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
199         reg.close();
200         reg.close();
201         verify(mockEosEntityListReg, never()).close();
202         verify(mockEosDoubleEntityListReg, never()).close();
203         verify(mockEntityCandReg, atLeastOnce()).close();
204         verify(mockDoubleEntityCandReg, never()).close();
205         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
206         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
207         verify(mockEntityCandReg, atLeastOnce()).close();
208         verify(mockDoubleEntityCandReg, atLeastOnce()).close();
209         verify(mockEosDoubleEntityListReg, never()).close();
210         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
211     }
212
213
214     /**
215      * Verify that closing a group does not prevent next incarnation of it to be registered and the next incarnation
216      * will become active once the old incarnation finishes cleaning up.
217      */
218     @Test
219     public void testTwoIncarnations() throws Exception {
220         ClusterSingletonServiceRegistration reg = clusterSingletonServiceProvider
221                 .registerClusterSingletonService(clusterSingletonService);
222         assertNotNull(reg);
223         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState());
224         verify(mockEos).registerCandidate(ENTITY);
225         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
226         verify(mockEos).registerCandidate(DOUBLE_ENTITY);
227         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
228         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState());
229
230         // Close, triggers unregistration, but we will not continue with it.
231         reg.close();
232         verify(mockEosEntityListReg, never()).close();
233         verify(mockEosDoubleEntityListReg, never()).close();
234         verify(mockEntityCandReg).close();
235         verify(mockDoubleEntityCandReg, never()).close();
236
237         // Instantiate the next incarnation
238         reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService2);
239         verify(mockEos).registerCandidate(ENTITY);
240         assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState());
241
242         // Drive the old incarnation to closure, resetting mocks as needed
243         clusterSingletonServiceProvider.ownershipChanged(getEntityToSlave());
244         verify(mockEntityCandReg).close();
245         verify(mockDoubleEntityCandReg).close();
246         verify(mockEosDoubleEntityListReg, never()).close();
247         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
248
249         // Reset mocks for reuse. The next change should see the previous group terminate and the next incarnation
250         // to start coming up
251         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToSlave());
252         verify(mockEos, times(2)).registerCandidate(ENTITY);
253         clusterSingletonServiceProvider.ownershipChanged(getEntityToMaster());
254         verify(mockEos, times(2)).registerCandidate(DOUBLE_ENTITY);
255         clusterSingletonServiceProvider.ownershipChanged(getDoubleEntityToMaster());
256         assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState());
257
258         // Check for potential service mixup
259         assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState());
260
261         verify(mockEosEntityListReg, never()).close();
262         verify(mockEosDoubleEntityListReg, never()).close();
263     }
264 }