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