blob: 724075c70e5d49087eb67a928ceb0084e32dc440 [file] [log] [blame]
Jian Lif96d41f2016-05-03 09:49:12 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jian Lif96d41f2016-05-03 09:49:12 -07003 *
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.rest.resources;
17
18import com.eclipsesource.json.Json;
19import com.eclipsesource.json.JsonArray;
20import com.eclipsesource.json.JsonObject;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableSet;
23import org.apache.commons.lang3.StringUtils;
24import org.hamcrest.Description;
Jian Li0409b702016-05-03 18:21:37 -070025import org.hamcrest.Matchers;
Jian Lif96d41f2016-05-03 09:49:12 -070026import org.hamcrest.TypeSafeMatcher;
27import org.junit.Before;
28import org.junit.Test;
29import org.onlab.osgi.ServiceDirectory;
30import org.onlab.osgi.TestServiceDirectory;
31import org.onlab.rest.BaseResource;
32import org.onosproject.cluster.NodeId;
33import org.onosproject.cluster.RoleInfo;
34import org.onosproject.codec.CodecService;
35import org.onosproject.codec.impl.CodecManager;
36import org.onosproject.mastership.MastershipAdminService;
37import org.onosproject.mastership.MastershipService;
Kavitha Alagesan60093392016-10-26 17:04:26 +053038import org.onosproject.net.DefaultDevice;
39import org.onosproject.net.Device;
Jian Lif96d41f2016-05-03 09:49:12 -070040import org.onosproject.net.DeviceId;
41import org.onosproject.net.MastershipRole;
Kavitha Alagesan60093392016-10-26 17:04:26 +053042import org.onosproject.net.device.DeviceService;
Jian Lif96d41f2016-05-03 09:49:12 -070043
Jian Li0409b702016-05-03 18:21:37 -070044import javax.ws.rs.client.Entity;
Jian Lif96d41f2016-05-03 09:49:12 -070045import javax.ws.rs.client.WebTarget;
46import javax.ws.rs.core.Response;
Jian Li0409b702016-05-03 18:21:37 -070047import java.io.InputStream;
Jian Lif96d41f2016-05-03 09:49:12 -070048import java.net.HttpURLConnection;
49import java.util.List;
50import java.util.Set;
51
52import static org.easymock.EasyMock.anyObject;
53import static org.easymock.EasyMock.createMock;
54import static org.easymock.EasyMock.expect;
55import static org.easymock.EasyMock.expectLastCall;
56import static org.easymock.EasyMock.replay;
57import static org.hamcrest.Matchers.hasSize;
58import static org.hamcrest.Matchers.is;
59import static org.hamcrest.Matchers.notNullValue;
60import static org.junit.Assert.assertEquals;
61import static org.junit.Assert.assertThat;
62import static org.onosproject.net.MastershipRole.MASTER;
63
64/**
65 * Unit tests for Mastership REST APIs.
66 */
67public final class MastershipResourceTest extends ResourceTest {
68
69 private final MastershipService mockService = createMock(MastershipService.class);
Kavitha Alagesan60093392016-10-26 17:04:26 +053070 private final DeviceService mockDeviceService = createMock(DeviceService.class);
Jian Lif96d41f2016-05-03 09:49:12 -070071 private final MastershipAdminService mockAdminService =
72 createMock(MastershipAdminService.class);
73
74 private final DeviceId deviceId1 = DeviceId.deviceId("dev:1");
75 private final DeviceId deviceId2 = DeviceId.deviceId("dev:2");
76 private final DeviceId deviceId3 = DeviceId.deviceId("dev:3");
77
Kavitha Alagesan60093392016-10-26 17:04:26 +053078 final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.OTHER,
79 "", "", "", "", null);
Jian Lif96d41f2016-05-03 09:49:12 -070080 private final NodeId nodeId1 = NodeId.nodeId("node:1");
81 private final NodeId nodeId2 = NodeId.nodeId("node:2");
82 private final NodeId nodeId3 = NodeId.nodeId("node:3");
83 private final MastershipRole role1 = MASTER;
84
85 /**
86 * Creates a mock role info which is comprised of one master and three backups.
87 *
88 * @return a mock role info instance
89 */
90 private RoleInfo createMockRoleInfo() {
91 NodeId master = NodeId.nodeId("master");
92 List<NodeId> backups = ImmutableList.of(nodeId1, nodeId2, nodeId3);
93
94 return new RoleInfo(master, backups);
95 }
96
97 private static final class RoleInfoJsonMatcher extends TypeSafeMatcher<JsonObject> {
98 private final RoleInfo roleInfo;
99 private String reason = "";
100
101 private RoleInfoJsonMatcher(RoleInfo roleInfo) {
102 this.roleInfo = roleInfo;
103 }
104
105 @Override
106 protected boolean matchesSafely(JsonObject jsonNode) {
107
108 // check master node identifier
109 String jsonNodeId = jsonNode.get("master") != null ?
110 jsonNode.get("master").asString() : null;
111 String nodeId = roleInfo.master().id();
112 if (!StringUtils.equals(jsonNodeId, nodeId)) {
113 reason = "master's node id was " + jsonNodeId;
114 return false;
115 }
116
117 // check backup nodes size
118 final JsonArray jsonBackupNodeIds = jsonNode.get("backups").asArray();
119 if (jsonBackupNodeIds.size() != roleInfo.backups().size()) {
120 reason = "backup nodes size was " + jsonBackupNodeIds.size();
121 return false;
122 }
123
124 // check backup nodes' identifier
125 for (NodeId backupNodeId : roleInfo.backups()) {
126 boolean backupFound = false;
127 for (int idx = 0; idx < jsonBackupNodeIds.size(); idx++) {
128 if (backupNodeId.id().equals(jsonBackupNodeIds.get(idx).asString())) {
129 backupFound = true;
130 break;
131 }
132 }
133 if (!backupFound) {
134 reason = "backup not found " + backupNodeId.id();
135 return false;
136 }
137 }
138
139 return true;
140 }
141
142 @Override
143 public void describeTo(Description description) {
144 description.appendText(reason);
145 }
146 }
147
148 /**
149 * Factory to allocate a role info json matcher.
150 *
151 * @param roleInfo role info object we are looking for
152 * @return matcher
153 */
154 private static RoleInfoJsonMatcher matchesRoleInfo(RoleInfo roleInfo) {
155 return new RoleInfoJsonMatcher(roleInfo);
156 }
157
158 /**
159 * Sets up the global values for all the tests.
160 */
161 @Before
162 public void setUpTest() {
163
164 final CodecManager codecService = new CodecManager();
165 codecService.activate();
166 ServiceDirectory testDirectory =
167 new TestServiceDirectory()
168 .add(MastershipService.class, mockService)
169 .add(MastershipAdminService.class, mockAdminService)
Kavitha Alagesan60093392016-10-26 17:04:26 +0530170 .add(DeviceService.class, mockDeviceService)
Jian Lif96d41f2016-05-03 09:49:12 -0700171 .add(CodecService.class, codecService);
172
173 BaseResource.setServiceDirectory(testDirectory);
174 }
175
176 /**
177 * Tests the result of the REST API GET when there are active master roles.
178 */
179 @Test
180 public void testGetLocalRole() {
181 expect(mockService.getLocalRole(anyObject())).andReturn(role1).anyTimes();
182 replay(mockService);
183
184 final WebTarget wt = target();
185 final String response = wt.path("mastership/" + deviceId1.toString() +
186 "/local").request().get(String.class);
187 final JsonObject result = Json.parse(response).asObject();
188 assertThat(result, notNullValue());
189
190 assertThat(result.names(), hasSize(1));
191 assertThat(result.names().get(0), is("role"));
192
193 final String role = result.get("role").asString();
194 assertThat(role, notNullValue());
195 assertThat(role, is("MASTER"));
196 }
197
198 /**
199 * Tests the result of the REST API GET when there is no active master.
200 */
201 @Test
202 public void testGetMasterForNull() {
203 expect(mockService.getMasterFor(anyObject())).andReturn(null).anyTimes();
204 replay(mockService);
205
206 final WebTarget wt = target();
207 final Response response = wt.path("mastership/" + deviceId1.toString() +
208 "/master").request().get();
209 assertEquals(404, response.getStatus());
210 }
211
212 /**
213 * Tests the result of the REST API GET when there is active master.
214 */
215 @Test
216 public void testGetMasterFor() {
217 expect(mockService.getMasterFor(anyObject())).andReturn(nodeId1).anyTimes();
218 replay(mockService);
219
220 final WebTarget wt = target();
221 final String response = wt.path("mastership/" + deviceId1.toString() +
222 "/master").request().get(String.class);
223 final JsonObject result = Json.parse(response).asObject();
224 assertThat(result, notNullValue());
225
226 assertThat(result.names(), hasSize(1));
Jian Li0409b702016-05-03 18:21:37 -0700227 assertThat(result.names().get(0), is("nodeId"));
Jian Lif96d41f2016-05-03 09:49:12 -0700228
Jian Li0409b702016-05-03 18:21:37 -0700229 final String node = result.get("nodeId").asString();
Jian Lif96d41f2016-05-03 09:49:12 -0700230 assertThat(node, notNullValue());
231 assertThat(node, is("node:1"));
232 }
233
234 /**
235 * Tests the result of the REST API GET when there are no active nodes.
236 */
237 @Test
238 public void testGetNodesForNull() {
239 expect(mockService.getNodesFor(anyObject())).andReturn(null).anyTimes();
240 replay(mockService);
241
242 final WebTarget wt = target();
243 final Response response = wt.path("mastership/" + deviceId1.toString() +
244 "/role").request().get();
245 assertEquals(404, response.getStatus());
246 }
247
248 /**
249 * Tests the result of the REST API GET when there are active nodes.
250 */
251 @Test
252 public void testGetNodesFor() {
253 RoleInfo mockRoleInfo = createMockRoleInfo();
254 expect(mockService.getNodesFor(anyObject())).andReturn(mockRoleInfo).anyTimes();
255 replay(mockService);
256
257 final WebTarget wt = target();
258 final String response = wt.path("mastership/" + deviceId1.toString() +
259 "/role").request().get(String.class);
260 final JsonObject result = Json.parse(response).asObject();
261 assertThat(result, notNullValue());
262
263 assertThat(result, matchesRoleInfo(mockRoleInfo));
264 }
265
266 /**
267 * Tests the result of the REST API GET when there are active devices.
268 */
269 @Test
270 public void testGetDevicesOf() {
271 Set<DeviceId> deviceIds = ImmutableSet.of(deviceId1, deviceId2, deviceId3);
272 expect(mockService.getDevicesOf(anyObject())).andReturn(deviceIds).anyTimes();
273 replay(mockService);
274
275 final WebTarget wt = target();
276 final String response = wt.path("mastership/" + deviceId1.toString() +
277 "/device").request().get(String.class);
278 final JsonObject result = Json.parse(response).asObject();
279 assertThat(result, notNullValue());
280
281 assertThat(result.names(), hasSize(1));
Jian Li0409b702016-05-03 18:21:37 -0700282 assertThat(result.names().get(0), is("deviceIds"));
Jian Lif96d41f2016-05-03 09:49:12 -0700283
Jian Li0409b702016-05-03 18:21:37 -0700284 final JsonArray jsonDevices = result.get("deviceIds").asArray();
Jian Lif96d41f2016-05-03 09:49:12 -0700285 assertThat(jsonDevices, notNullValue());
286 assertThat(jsonDevices.size(), is(3));
287 }
288
289 /**
290 * Tests the result of the REST API GET for requesting mastership role.
291 */
292 @Test
293 public void testRequestRoleFor() {
Jian Li0409b702016-05-03 18:21:37 -0700294 expect(mockService.requestRoleForSync(anyObject())).andReturn(role1).anyTimes();
295 replay(mockService);
296
Kavitha Alagesan60093392016-10-26 17:04:26 +0530297 expect(mockDeviceService.getDevice(deviceId1)).andReturn(device1);
298 replay(mockDeviceService);
299
Jian Li0409b702016-05-03 18:21:37 -0700300 final WebTarget wt = target();
301 final String response = wt.path("mastership/" + deviceId1.toString() +
302 "/request").request().get(String.class);
303 final JsonObject result = Json.parse(response).asObject();
304 assertThat(result, notNullValue());
305
306 assertThat(result.names(), hasSize(1));
307 assertThat(result.names().get(0), is("role"));
308
309 final String role = result.get("role").asString();
310 assertThat(role, notNullValue());
311 assertThat(role, is("MASTER"));
Jian Lif96d41f2016-05-03 09:49:12 -0700312 }
313
314 /**
315 * Tests the result of the REST API GET for relinquishing mastership role.
316 */
317 @Test
318 public void testRelinquishMastership() {
Jian Li0409b702016-05-03 18:21:37 -0700319 mockService.relinquishMastershipSync(anyObject());
320 expectLastCall();
321 replay(mockService);
322
323 final WebTarget wt = target();
324 final Response response = wt.path("mastership/" + deviceId1.toString() +
325 "/relinquish").request().get();
326 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
327 String location = response.getLocation().toString();
328 assertThat(location, Matchers.startsWith(deviceId1.toString()));
Jian Lif96d41f2016-05-03 09:49:12 -0700329 }
330
331 /**
332 * Tests the result of the REST API PUT for setting role.
333 */
334 @Test
335 public void testSetRole() {
Jian Li0409b702016-05-03 18:21:37 -0700336 mockAdminService.setRoleSync(anyObject(), anyObject(), anyObject());
337 expectLastCall();
338 replay(mockAdminService);
339
340 final WebTarget wt = target();
341 final InputStream jsonStream = MetersResourceTest.class
342 .getResourceAsStream("put-set-roles.json");
343 final Response response = wt.path("mastership")
344 .request().put(Entity.json(jsonStream));
345 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
Jian Lif96d41f2016-05-03 09:49:12 -0700346 }
347
348 /**
349 * Tests the result of the REST API GET for balancing roles.
350 */
351 @Test
352 public void testBalanceRoles() {
353 mockAdminService.balanceRoles();
354 expectLastCall();
355 replay(mockAdminService);
356
357 final WebTarget wt = target();
358 final Response response = wt.path("mastership").request().get();
359 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
360 }
361}