blob: b5e5829f02a7ed45634cb1b39ec62b59ec4aeb52 [file] [log] [blame]
Claudine Chiufb8b8162016-04-01 23:50:51 +00001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Claudine Chiufb8b8162016-04-01 23:50:51 +00003 *
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
17package org.onosproject.rest.resources;
18
19import com.eclipsesource.json.Json;
20import com.eclipsesource.json.JsonArray;
21import com.eclipsesource.json.JsonObject;
22import com.google.common.collect.ImmutableSet;
23import org.glassfish.jersey.client.ClientProperties;
24import org.hamcrest.Description;
25import org.hamcrest.Matchers;
26import org.hamcrest.TypeSafeMatcher;
27import org.junit.Before;
28import org.junit.Test;
29import org.onlab.osgi.ServiceDirectory;
30import org.onlab.osgi.TestServiceDirectory;
Claudine Chiufb8b8162016-04-01 23:50:51 +000031import org.onosproject.codec.CodecService;
32import org.onosproject.codec.impl.CodecManager;
33import org.onosproject.incubator.net.virtual.TenantId;
34import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
35
36import javax.ws.rs.BadRequestException;
Jian Li70773462020-02-05 16:23:53 +090037import javax.ws.rs.InternalServerErrorException;
Claudine Chiufb8b8162016-04-01 23:50:51 +000038import javax.ws.rs.NotFoundException;
39import javax.ws.rs.client.Entity;
40import javax.ws.rs.client.WebTarget;
41import javax.ws.rs.core.MediaType;
42import javax.ws.rs.core.Response;
43import java.io.InputStream;
44import java.net.HttpURLConnection;
45import java.util.HashSet;
46
Ray Milkey094a1352018-01-22 14:03:54 -080047import static org.easymock.EasyMock.anyObject;
48import static org.easymock.EasyMock.createMock;
49import static org.easymock.EasyMock.expect;
50import static org.easymock.EasyMock.expectLastCall;
51import static org.easymock.EasyMock.replay;
52import static org.easymock.EasyMock.verify;
53import static org.hamcrest.Matchers.containsString;
54import static org.hamcrest.Matchers.hasSize;
55import static org.hamcrest.Matchers.is;
56import static org.hamcrest.Matchers.notNullValue;
57import static org.junit.Assert.assertEquals;
58import static org.junit.Assert.assertThat;
59import static org.junit.Assert.fail;
Claudine Chiufb8b8162016-04-01 23:50:51 +000060
61/**
62 * Unit tests for tenant REST APIs.
63 */
64public class TenantWebResourceTest extends ResourceTest {
65
66 private final VirtualNetworkAdminService mockVnetAdminService = createMock(VirtualNetworkAdminService.class);
67
68 final HashSet<TenantId> tenantIdSet = new HashSet<>();
69
70 private static final String ID = "id";
71
72 private final TenantId tenantId1 = TenantId.tenantId("TenantId1");
73 private final TenantId tenantId2 = TenantId.tenantId("TenantId2");
74 private final TenantId tenantId3 = TenantId.tenantId("TenantId3");
75 private final TenantId tenantId4 = TenantId.tenantId("TenantId4");
76
77 /**
78 * Sets up the global values for all the tests.
79 */
80 @Before
81 public void setUpTest() {
82 // Register the services needed for the test
83 CodecManager codecService = new CodecManager();
84 codecService.activate();
85 ServiceDirectory testDirectory =
86 new TestServiceDirectory()
87 .add(VirtualNetworkAdminService.class, mockVnetAdminService)
88 .add(CodecService.class, codecService);
89
Ray Milkey094a1352018-01-22 14:03:54 -080090 setServiceDirectory(testDirectory);
Claudine Chiufb8b8162016-04-01 23:50:51 +000091 }
92
93 /**
94 * Hamcrest matcher to check that a tenant id representation in JSON matches
95 * the actual tenant id.
96 */
97 public static class TenantIdJsonMatcher extends TypeSafeMatcher<JsonObject> {
98 private final TenantId tenantId;
99 private String reason = "";
100
101 public TenantIdJsonMatcher(TenantId tenantIdValue) {
102 tenantId = tenantIdValue;
103 }
104
105 @Override
106 public boolean matchesSafely(JsonObject jsonHost) {
107 // Check the tenant id
108 final String jsonId = jsonHost.get(ID).asString();
109 if (!jsonId.equals(tenantId.id())) {
110 reason = ID + " " + tenantId.id();
111 return false;
112 }
113
114 return true;
115 }
116
117 @Override
118 public void describeTo(Description description) {
119 description.appendText(reason);
120 }
121 }
122
123 /**
124 * Factory to allocate a tenant id array matcher.
125 *
126 * @param tenantId tenant id object we are looking for
127 * @return matcher
128 */
129 private static TenantIdJsonMatcher matchesTenantId(TenantId tenantId) {
130 return new TenantIdJsonMatcher(tenantId);
131 }
132
133 /**
134 * Hamcrest matcher to check that a tenant id is represented properly in a JSON
135 * array of tenant ids.
136 */
137 public static class TenantIdJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
138 private final TenantId tenantId;
139 private String reason = "";
140
141 public TenantIdJsonArrayMatcher(TenantId tenantIdValue) {
142 tenantId = tenantIdValue;
143 }
144
145 @Override
146 public boolean matchesSafely(JsonArray json) {
147 boolean tenantIdFound = false;
148 final int expectedAttributes = 1;
149 for (int tenantIdIndex = 0; tenantIdIndex < json.size();
150 tenantIdIndex++) {
151
152 final JsonObject jsonHost = json.get(tenantIdIndex).asObject();
153
154 // Only 1 attribute - ID.
155 if (jsonHost.names().size() < expectedAttributes) {
156 reason = "Found a tenant id with the wrong number of attributes";
157 return false;
158 }
159
160 final String jsonDeviceKeyId = jsonHost.get(ID).asString();
161 if (jsonDeviceKeyId.equals(tenantId.id())) {
162 tenantIdFound = true;
163
164 // We found the correct tenant id, check the tenant id attribute values
165 assertThat(jsonHost, matchesTenantId(tenantId));
166 }
167 }
168 if (!tenantIdFound) {
169 reason = "Tenant id " + tenantId.id() + " was not found";
170 return false;
171 }
172 return true;
173 }
174
175 @Override
176 public void describeTo(Description description) {
177 description.appendText(reason);
178 }
179 }
180
181 /**
182 * Factory to allocate a tenant id array matcher.
183 *
184 * @param tenantId tenant id object we are looking for
185 * @return matcher
186 */
187 private static TenantIdJsonArrayMatcher hasTenantId(TenantId tenantId) {
188 return new TenantIdJsonArrayMatcher(tenantId);
189 }
190
191 /**
192 * Tests the result of the REST API GET when there are no tenant ids.
193 */
194 @Test
195 public void testGetTenantsEmptyArray() {
196 expect(mockVnetAdminService.getTenantIds()).andReturn(ImmutableSet.of()).anyTimes();
197 replay(mockVnetAdminService);
198
199 WebTarget wt = target();
200 String response = wt.path("tenants").request().get(String.class);
201 assertThat(response, is("{\"tenants\":[]}"));
202
203 verify(mockVnetAdminService);
204 }
205
206 /**
207 * Tests the result of the REST API GET when tenant ids are defined.
208 */
209 @Test
210 public void testGetTenantIdsArray() {
211 tenantIdSet.add(tenantId1);
212 tenantIdSet.add(tenantId2);
213 tenantIdSet.add(tenantId3);
214 tenantIdSet.add(tenantId4);
215 expect(mockVnetAdminService.getTenantIds()).andReturn(tenantIdSet).anyTimes();
216 replay(mockVnetAdminService);
217
218 WebTarget wt = target();
219 String response = wt.path("tenants").request().get(String.class);
220 assertThat(response, containsString("{\"tenants\":["));
221
222 final JsonObject result = Json.parse(response).asObject();
223 assertThat(result, notNullValue());
224
225 assertThat(result.names(), hasSize(1));
226 assertThat(result.names().get(0), is("tenants"));
227
228 final JsonArray tenantIds = result.get("tenants").asArray();
229 assertThat(tenantIds, notNullValue());
230 assertEquals("Device keys array is not the correct size.",
231 tenantIdSet.size(), tenantIds.size());
232
233 tenantIdSet.forEach(tenantId -> assertThat(tenantIds, hasTenantId(tenantId)));
234
235 verify(mockVnetAdminService);
236 }
237
238 /**
239 * Tests adding of new tenant id using POST via JSON stream.
240 */
241 @Test
242 public void testPost() {
243 mockVnetAdminService.registerTenantId(anyObject());
244 tenantIdSet.add(tenantId2);
245 expect(mockVnetAdminService.getTenantIds()).andReturn(tenantIdSet).anyTimes();
246 expectLastCall();
247
248 replay(mockVnetAdminService);
249
250 WebTarget wt = target();
251 InputStream jsonStream = TenantWebResourceTest.class
252 .getResourceAsStream("post-tenant.json");
253
254 Response response = wt.path("tenants").request(MediaType.APPLICATION_JSON_TYPE)
255 .post(Entity.json(jsonStream));
256 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
257
258 String location = response.getLocation().getPath();
259 assertThat(location, Matchers.startsWith("/tenants/" + tenantId2));
260
261 verify(mockVnetAdminService);
262 }
263
264 /**
265 * Tests adding of a null tenant id using POST via JSON stream.
266 */
267 @Test
268 public void testPostNullTenantId() {
269
270 replay(mockVnetAdminService);
271
272 WebTarget wt = target();
273 try {
274 String response = wt.path("tenants")
275 .request(MediaType.APPLICATION_JSON_TYPE)
276 .post(Entity.json(null), String.class);
277 fail("POST of null tenant id did not throw an exception");
278 } catch (BadRequestException ex) {
279 assertThat(ex.getMessage(), containsString("HTTP 400 Bad Request"));
Jian Li70773462020-02-05 16:23:53 +0900280 } catch (InternalServerErrorException ex) {
281 assertThat(ex.getMessage(), containsString("HTTP 500 Internal Server Error"));
Claudine Chiufb8b8162016-04-01 23:50:51 +0000282 }
283
284 verify(mockVnetAdminService);
285 }
286
287 /**
288 * Tests removing a tenant id with DELETE request.
289 */
290 @Test
291 public void testDelete() {
292 expect(mockVnetAdminService.getTenantIds())
293 .andReturn(ImmutableSet.of(tenantId2)).anyTimes();
294 mockVnetAdminService.unregisterTenantId(anyObject());
295 expectLastCall();
296 replay(mockVnetAdminService);
297
298 WebTarget wt = target()
299 .property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
300 Response response = wt.path("tenants/" + tenantId2)
301 .request(MediaType.APPLICATION_JSON_TYPE)
302 .delete();
303
Jian Lic2a542b2016-05-10 11:48:19 -0700304 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
Claudine Chiufb8b8162016-04-01 23:50:51 +0000305
306 verify(mockVnetAdminService);
307 }
308
309 /**
Claudine Chiufb8b8162016-04-01 23:50:51 +0000310 * Tests that a DELETE of a non-existent tenant id throws an exception.
311 */
312 @Test
313 public void testDeleteNonExistentDeviceKey() {
314 expect(mockVnetAdminService.getTenantIds())
315 .andReturn(ImmutableSet.of())
316 .anyTimes();
317 expectLastCall();
318
319 replay(mockVnetAdminService);
320
321 WebTarget wt = target();
322
323 try {
324 wt.path("tenants/" + "NON_EXISTENT_TENANT_ID")
325 .request()
326 .delete(String.class);
327 fail("Delete of a non-existent tenant did not throw an exception");
328 } catch (NotFoundException ex) {
329 assertThat(ex.getMessage(), containsString("HTTP 404 Not Found"));
330 }
331
332 verify(mockVnetAdminService);
333 }
334}