blob: 0bb0258f3711194fabd4e7eabff1550b669887f0 [file] [log] [blame]
Jian Li49109b52019-01-22 00:17:28 +09001/*
2 * Copyright 2019-present Open Networking Foundation
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 */
16package org.onosproject.k8snode.impl;
17
18import com.google.common.collect.Lists;
19import com.google.common.util.concurrent.MoreExecutors;
20import org.junit.After;
21import org.junit.Before;
22import org.junit.Test;
23import org.onlab.junit.TestUtils;
24import org.onlab.packet.ChassisId;
25import org.onlab.packet.IpAddress;
26import org.onosproject.cluster.ClusterServiceAdapter;
27import org.onosproject.cluster.LeadershipServiceAdapter;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreServiceAdapter;
30import org.onosproject.core.DefaultApplicationId;
31import org.onosproject.event.Event;
32import org.onosproject.k8snode.api.DefaultK8sNode;
33import org.onosproject.k8snode.api.K8sNode;
34import org.onosproject.k8snode.api.K8sNodeEvent;
35import org.onosproject.k8snode.api.K8sNodeListener;
36import org.onosproject.k8snode.api.K8sNodeState;
37import org.onosproject.net.DefaultDevice;
38import org.onosproject.net.Device;
39import org.onosproject.net.DeviceId;
40import org.onosproject.net.provider.ProviderId;
41import org.onosproject.store.service.TestStorageService;
42
43import java.util.List;
44
45import static org.junit.Assert.assertEquals;
46import static org.junit.Assert.assertNotNull;
47import static org.junit.Assert.assertNull;
48import static org.junit.Assert.assertTrue;
49import static org.onosproject.k8snode.api.K8sNode.Type.MINION;
50import static org.onosproject.k8snode.api.K8sNodeEvent.Type.K8S_NODE_COMPLETE;
51import static org.onosproject.k8snode.api.K8sNodeEvent.Type.K8S_NODE_CREATED;
52import static org.onosproject.k8snode.api.K8sNodeEvent.Type.K8S_NODE_INCOMPLETE;
53import static org.onosproject.k8snode.api.K8sNodeEvent.Type.K8S_NODE_REMOVED;
54import static org.onosproject.k8snode.api.K8sNodeEvent.Type.K8S_NODE_UPDATED;
55import static org.onosproject.k8snode.api.K8sNodeState.COMPLETE;
56import static org.onosproject.k8snode.api.K8sNodeState.INCOMPLETE;
57import static org.onosproject.k8snode.api.K8sNodeState.INIT;
58import static org.onosproject.net.Device.Type.SWITCH;
59
60/**
61 * Unit tests for Kubernetes node manager.
62 */
63public class K8sNodeManagerTest {
64
65 private static final ApplicationId TEST_APP_ID = new DefaultApplicationId(1, "test");
66
67 private static final String ERR_SIZE = "Number of nodes did not match";
68 private static final String ERR_NOT_MATCH = "Node did not match";
69 private static final String ERR_NOT_FOUND = "Node did not exist";
70
Jian Lie2a04ce2020-07-01 19:07:02 +090071 private static final String CLUSTER_NAME = "kubernetes";
72
Jian Li49109b52019-01-22 00:17:28 +090073 private static final String MINION_1_HOSTNAME = "minion_1";
74 private static final String MINION_2_HOSTNAME = "minion_2";
75 private static final String MINION_3_HOSTNAME = "minion_3";
76
77 private static final Device MINION_1_INTG_DEVICE = createDevice(1);
78 private static final Device MINION_2_INTG_DEVICE = createDevice(2);
79 private static final Device MINION_3_INTG_DEVICE = createDevice(3);
80
Jian Libf562c22019-04-15 18:07:14 +090081 private static final Device MINION_1_EXT_DEVICE = createDevice(4);
82 private static final Device MINION_2_EXT_DEVICE = createDevice(5);
83 private static final Device MINION_3_EXT_DEVICE = createDevice(6);
84
Jian Li1a2eb5d2019-08-27 02:07:05 +090085 private static final Device MINION_1_LOCAL_DEVICE = createDevice(7);
86 private static final Device MINION_2_LOCAL_DEVICE = createDevice(8);
87 private static final Device MINION_3_LOCAL_DEVICE = createDevice(9);
88
Jian Lie2a04ce2020-07-01 19:07:02 +090089 private static final Device MINION_1_TUN_DEVICE = createDevice(10);
90 private static final Device MINION_2_TUN_DEVICE = createDevice(11);
91 private static final Device MINION_3_TUN_DEVICE = createDevice(12);
92
Jian Li1a2eb5d2019-08-27 02:07:05 +090093
Jian Li49109b52019-01-22 00:17:28 +090094 private static final K8sNode MINION_1 = createNode(
Jian Lie2a04ce2020-07-01 19:07:02 +090095 CLUSTER_NAME,
Jian Li49109b52019-01-22 00:17:28 +090096 MINION_1_HOSTNAME,
97 MINION,
98 MINION_1_INTG_DEVICE,
Jian Libf562c22019-04-15 18:07:14 +090099 MINION_1_EXT_DEVICE,
Jian Li1a2eb5d2019-08-27 02:07:05 +0900100 MINION_1_LOCAL_DEVICE,
Jian Lie2a04ce2020-07-01 19:07:02 +0900101 MINION_1_TUN_DEVICE,
Jian Li49109b52019-01-22 00:17:28 +0900102 IpAddress.valueOf("10.100.0.1"),
103 INIT
104 );
105 private static final K8sNode MINION_2 = createNode(
Jian Lie2a04ce2020-07-01 19:07:02 +0900106 CLUSTER_NAME,
Jian Li49109b52019-01-22 00:17:28 +0900107 MINION_2_HOSTNAME,
108 MINION,
109 MINION_2_INTG_DEVICE,
Jian Libf562c22019-04-15 18:07:14 +0900110 MINION_2_EXT_DEVICE,
Jian Li1a2eb5d2019-08-27 02:07:05 +0900111 MINION_2_LOCAL_DEVICE,
Jian Lie2a04ce2020-07-01 19:07:02 +0900112 MINION_2_TUN_DEVICE,
Jian Li49109b52019-01-22 00:17:28 +0900113 IpAddress.valueOf("10.100.0.2"),
114 INIT
115 );
116 private static final K8sNode MINION_3 = createNode(
Jian Lie2a04ce2020-07-01 19:07:02 +0900117 CLUSTER_NAME,
Jian Li49109b52019-01-22 00:17:28 +0900118 MINION_3_HOSTNAME,
119 MINION,
120 MINION_3_INTG_DEVICE,
Jian Libf562c22019-04-15 18:07:14 +0900121 MINION_3_EXT_DEVICE,
Jian Li1a2eb5d2019-08-27 02:07:05 +0900122 MINION_3_LOCAL_DEVICE,
Jian Lie2a04ce2020-07-01 19:07:02 +0900123 MINION_3_TUN_DEVICE,
Jian Li49109b52019-01-22 00:17:28 +0900124 IpAddress.valueOf("10.100.0.3"),
125 COMPLETE
126 );
127
128 private final TestK8sNodeListener testListener = new TestK8sNodeListener();
129
130 private K8sNodeManager target;
131 private DistributedK8sNodeStore nodeStore;
132
133 /**
134 * Initial setup for this unit test.
135 */
136 @Before
137 public void setUp() {
138 nodeStore = new DistributedK8sNodeStore();
139 TestUtils.setField(nodeStore, "coreService", new TestCoreService());
140 TestUtils.setField(nodeStore, "storageService", new TestStorageService());
141 TestUtils.setField(nodeStore, "eventExecutor", MoreExecutors.newDirectExecutorService());
142 nodeStore.activate();
143
144 nodeStore.createNode(MINION_2);
145 nodeStore.createNode(MINION_3);
146
147 target = new K8sNodeManager();
148 target.storageService = new TestStorageService();
149 target.coreService = new TestCoreService();
150 target.clusterService = new TestClusterService();
151 target.leadershipService = new TestLeadershipService();
152 target.nodeStore = nodeStore;
153 target.addListener(testListener);
154 target.activate();
155 testListener.events.clear();
156 }
157
158 /**
159 * Clean up unit test.
160 */
161 @After
162 public void tearDown() {
163 target.removeListener(testListener);
164 target.deactivate();
165 nodeStore.deactivate();
166 nodeStore = null;
167 target = null;
168 }
169
170 /**
171 * Checks if creating and removing a node work well with proper events.
172 */
173 @Test
174 public void testCreateAndRemoveNode() {
175 target.createNode(MINION_1);
176 assertEquals(ERR_SIZE, 3, target.nodes().size());
177 assertNotNull(target.node(MINION_1_HOSTNAME));
178
179 target.removeNode(MINION_1_HOSTNAME);
180 assertEquals(ERR_SIZE, 2, target.nodes().size());
181 assertNull(target.node(MINION_1_HOSTNAME));
182
183 validateEvents(K8S_NODE_CREATED, K8S_NODE_REMOVED);
184 }
185
186 /**
187 * Checks if creating null node fails with proper exception.
188 */
189 @Test(expected = NullPointerException.class)
190 public void testCreateNullNode() {
191 target.createNode(null);
192 }
193
194 /**
195 * Checks if creating a duplicated node fails with proper exception.
196 */
197 @Test(expected = IllegalArgumentException.class)
198 public void testCreateDuplicateNode() {
199 target.createNode(MINION_1);
200 target.createNode(MINION_1);
201 }
202
203 /**
204 * Checks if removing null node fails with proper exception.
205 */
206 @Test(expected = IllegalArgumentException.class)
207 public void testRemoveNullNode() {
208 target.removeNode(null);
209 }
210
211 /**
212 * Checks if updating a node works well with proper event.
213 */
214 @Test
215 public void testUpdateNode() {
216 K8sNode updated = DefaultK8sNode.from(MINION_2)
217 .dataIp(IpAddress.valueOf("10.200.0.100"))
218 .build();
219 target.updateNode(updated);
220 assertEquals(ERR_NOT_MATCH, updated, target.node(MINION_2_INTG_DEVICE.id()));
221 validateEvents(K8S_NODE_UPDATED);
222 }
223
224 /**
225 * Checks if updating a node state to complete generates proper events.
226 */
227 @Test
228 public void testUpdateNodeStateComplete() {
229 K8sNode updated = DefaultK8sNode.from(MINION_2)
230 .state(COMPLETE)
231 .build();
232 target.updateNode(updated);
233 assertEquals(ERR_NOT_MATCH, updated, target.node(MINION_2_HOSTNAME));
234 validateEvents(K8S_NODE_UPDATED, K8S_NODE_COMPLETE);
235 }
236
237 /**
238 * Checks if updating a node state to incomplete generates proper events.
239 */
240 @Test
241 public void testUpdateNodeStateIncomplete() {
242 K8sNode updated = DefaultK8sNode.from(MINION_3)
243 .state(INCOMPLETE)
244 .build();
245 target.updateNode(updated);
246 assertEquals(ERR_NOT_MATCH, updated, target.node(MINION_3_HOSTNAME));
247 validateEvents(K8S_NODE_UPDATED, K8S_NODE_INCOMPLETE);
248 }
249
250 /**
251 * Checks if updating a null node fails with proper exception.
252 */
253 @Test(expected = NullPointerException.class)
254 public void testUpdateNullNode() {
255 target.updateNode(null);
256 }
257
258 /**
259 * Checks if updating not existing node fails with proper exception.
260 */
Jian Li1cee9882019-02-13 11:25:25 +0900261 @Test(expected = NullPointerException.class)
Jian Li49109b52019-01-22 00:17:28 +0900262 public void testUpdateNotExistingNode() {
263 target.updateNode(MINION_1);
264 }
265
266 /**
267 * Checks if getting all nodes method returns correct set of nodes.
268 */
269 @Test
270 public void testGetAllNodes() {
271 assertEquals(ERR_SIZE, 2, target.nodes().size());
272 assertTrue(ERR_NOT_FOUND, target.nodes().contains(MINION_2));
273 assertTrue(ERR_NOT_FOUND, target.nodes().contains(MINION_3));
274 }
275
276 /**
277 * Checks if getting complete nodes method returns correct set of nodes.
278 */
279 @Test
280 public void testGetCompleteNodes() {
281 assertEquals(ERR_SIZE, 1, target.completeNodes().size());
282 assertTrue(ERR_NOT_FOUND, target.completeNodes().contains(MINION_3));
283 }
284
285 /**
286 * Checks if getting nodes by type method returns correct set of nodes.
287 */
288 @Test
289 public void testGetNodesByType() {
290 assertEquals(ERR_SIZE, 2, target.nodes(MINION).size());
291 assertTrue(ERR_NOT_FOUND, target.nodes(MINION).contains(MINION_2));
292 assertTrue(ERR_NOT_FOUND, target.nodes(MINION).contains(MINION_3));
293 }
294
295 /**
296 * Checks if getting a node by hostname returns correct node.
297 */
298 @Test
299 public void testGetNodeByHostname() {
300 assertEquals(ERR_NOT_FOUND, target.node(MINION_2_HOSTNAME), MINION_2);
301 assertEquals(ERR_NOT_FOUND, target.node(MINION_3_HOSTNAME), MINION_3);
302 }
303
304 private void validateEvents(Enum... types) {
305 int i = 0;
306 assertEquals("Number of events did not match", types.length, testListener.events.size());
307 for (Event event : testListener.events) {
308 assertEquals("Incorrect event received", types[i], event.type());
309 i++;
310 }
311 testListener.events.clear();
312 }
313
314 private static Device createDevice(long devIdNum) {
315 return new DefaultDevice(new ProviderId("of", "foo"),
316 DeviceId.deviceId(String.format("of:%016d", devIdNum)),
317 SWITCH,
318 "manufacturer",
319 "hwVersion",
320 "swVersion",
321 "serialNumber",
322 new ChassisId(1));
323 }
324
325 private static class TestK8sNodeListener implements K8sNodeListener {
326 private List<K8sNodeEvent> events = Lists.newArrayList();
327
328 @Override
329 public void event(K8sNodeEvent event) {
330 events.add(event);
331 }
332 }
333
334 private static class TestCoreService extends CoreServiceAdapter {
335 @Override
336 public ApplicationId registerApplication(String name) {
337 return TEST_APP_ID;
338 }
339 }
340
341 private class TestClusterService extends ClusterServiceAdapter {
342
343 }
344
345 private static class TestLeadershipService extends LeadershipServiceAdapter {
346
347 }
348
Jian Lie2a04ce2020-07-01 19:07:02 +0900349 private static K8sNode createNode(String clusterName, String hostname, K8sNode.Type type,
Jian Libf562c22019-04-15 18:07:14 +0900350 Device intgBridge, Device extBridge,
Jian Lie2a04ce2020-07-01 19:07:02 +0900351 Device localBridge, Device tunBridge,
352 IpAddress ipAddr, K8sNodeState state) {
Jian Li49109b52019-01-22 00:17:28 +0900353 return DefaultK8sNode.builder()
354 .hostname(hostname)
Jian Lie2a04ce2020-07-01 19:07:02 +0900355 .clusterName(clusterName)
Jian Li49109b52019-01-22 00:17:28 +0900356 .type(type)
357 .intgBridge(intgBridge.id())
Jian Libf562c22019-04-15 18:07:14 +0900358 .extBridge(extBridge.id())
Jian Li1a2eb5d2019-08-27 02:07:05 +0900359 .localBridge(localBridge.id())
Jian Lie2a04ce2020-07-01 19:07:02 +0900360 .tunBridge(tunBridge.id())
Jian Li49109b52019-01-22 00:17:28 +0900361 .managementIp(ipAddr)
362 .dataIp(ipAddr)
363 .state(state)
364 .build();
365 }
366}