Merge changes from topics "VID-14", "VID-13", "VID-12"
[vid.git] / vid-app-common / src / test / java / org / onap / vid / testUtils / TestUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.vid.testUtils;
22
23 import static com.fasterxml.jackson.module.kotlin.ExtensionsKt.jacksonObjectMapper;
24 import static java.util.function.Function.identity;
25 import static java.util.stream.Collectors.toList;
26 import static java.util.stream.Collectors.toMap;
27 import static org.apache.commons.beanutils.PropertyUtils.getPropertyDescriptors;
28 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
29 import static org.apache.commons.text.CharacterPredicates.DIGITS;
30 import static org.apache.commons.text.CharacterPredicates.LETTERS;
31 import static org.apache.http.HttpVersion.HTTP_1_1;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.Mockito.RETURNS_DEFAULTS;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.when;
36 import static org.mockito.Mockito.withSettings;
37 import static org.testng.Assert.fail;
38
39 import com.fasterxml.jackson.databind.DeserializationFeature;
40 import com.fasterxml.jackson.databind.ObjectMapper;
41 import com.google.code.beanmatchers.BeanMatchers;
42 import com.google.common.collect.ImmutableList;
43 import io.joshworks.restclient.http.HttpResponse;
44 import java.beans.PropertyDescriptor;
45 import java.io.ByteArrayInputStream;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.Serializable;
49 import java.lang.reflect.Field;
50 import java.net.URI;
51 import java.nio.charset.StandardCharsets;
52 import java.util.Arrays;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.function.Predicate;
56 import javax.ws.rs.client.Client;
57 import javax.ws.rs.client.Invocation;
58 import javax.ws.rs.client.WebTarget;
59 import javax.ws.rs.core.GenericType;
60 import javax.ws.rs.core.MediaType;
61 import javax.ws.rs.core.Response;
62 import org.apache.commons.beanutils.BeanUtils;
63 import org.apache.commons.io.IOUtils;
64 import org.apache.commons.lang3.exception.ExceptionUtils;
65 import org.apache.commons.lang3.reflect.FieldUtils;
66 import org.apache.commons.lang3.reflect.MethodUtils;
67 import org.apache.commons.text.RandomStringGenerator;
68 import org.apache.http.HttpResponseFactory;
69 import org.apache.http.entity.StringEntity;
70 import org.apache.http.impl.DefaultHttpResponseFactory;
71 import org.apache.http.message.BasicStatusLine;
72 import org.apache.log4j.LogManager;
73 import org.apache.log4j.Logger;
74 import org.json.JSONArray;
75 import org.json.JSONObject;
76 import org.junit.Assert;
77 import org.mockito.InjectMocks;
78 import org.mockito.Mock;
79 import org.mockito.MockSettings;
80 import org.mockito.Mockito;
81 import org.mockito.MockitoAnnotations;
82 import org.mockito.invocation.InvocationOnMock;
83 import org.mockito.stubbing.Answer;
84 import org.mockito.stubbing.OngoingStubbing;
85 import org.onap.portalsdk.core.util.SystemProperties;
86 import org.onap.vid.asdc.AsdcCatalogException;
87 import org.onap.vid.asdc.beans.Service;
88 import org.onap.vid.mso.model.CloudConfiguration;
89 import org.springframework.core.env.Environment;
90 import org.testng.annotations.DataProvider;
91
92 /**
93  * Created by Oren on 6/7/17.
94  */
95 public class TestUtils {
96
97     private static final Logger logger = LogManager.getLogger(TestUtils.class);
98
99     /**
100      * The method compares between two jsons. the function assert that the actual object does not reduce or change the functionallity/parsing of the expected json.
101      * This means that if the expected JSON has a key which is null or the JSON doesn't have a key which contained in the expected JSON the assert will succeed and the will pass.
102      * For example : For JSON expected = {a:null} and actual {a:3} the test will pass
103      * Other example : For JSON expected = {a:3} and actual {a:null} the test will fail
104      *
105      * @param expected JSON
106      * @param actual JSON
107      */
108     public static void assertJsonStringEqualsIgnoreNulls(String expected, String actual) {
109         if (expected == null || expected == JSONObject.NULL) {return;}
110
111         JSONObject expectedJSON = new JSONObject(expected);
112         JSONObject actualJSON = new JSONObject(actual);
113         Iterator<?> keys = expectedJSON.keys();
114
115         while( keys.hasNext() ) {
116             String key = (String)keys.next();
117             Object expectedValue = expectedJSON.get(key);
118             if (expectedValue == JSONObject.NULL){
119                 continue;
120             }
121
122             Object actualValue = actualJSON.get(key);
123
124             if (expectedValue instanceof JSONObject) {
125                 String expectedVal = expectedValue.toString();
126                 String actualVal = actualValue.toString();
127                 assertJsonStringEqualsIgnoreNulls(expectedVal, actualVal);
128             }
129             else if (expectedValue instanceof JSONArray) {
130                 if (actualValue instanceof JSONArray) {
131                     JSONArray expectedJSONArray = (JSONArray)expectedValue;
132                     JSONArray actualJSONArray = (JSONArray)actualValue;
133                     for (int i = 0; i < expectedJSONArray.length(); i++) {
134                         String expectedItem = expectedJSONArray.get(i).toString();
135                         String actualItem = actualJSONArray.get(i).toString();
136                         if (expectedValue instanceof JSONObject)
137                             assertJsonStringEqualsIgnoreNulls(expectedItem, actualItem);
138                     }
139                 }
140                 else {
141                     fail("expected: " + expectedValue + " got:" + actualValue);
142                 }
143             }
144             else {
145                 Assert.assertEquals("assertion fail for key:"+key, expectedValue, actualValue);
146             }
147         }
148     }
149
150     public static <T> T readJsonResourceFileAsObject(String pathInResource, Class<T> valueType) throws IOException {
151         return readJsonResourceFileAsObject(pathInResource, valueType, false);
152     }
153
154     public static <T> T readJsonResourceFileAsObject(String pathInResource, Class<T> valueType,
155         boolean failOnUnknownProperties)
156         throws IOException {
157         ObjectMapper objectMapper = jacksonObjectMapper()
158             .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, failOnUnknownProperties);
159         return objectMapper.readValue(
160             TestUtils.class.getResource(pathInResource),
161             valueType);
162     }
163
164     public static String readFileAsString(String pathInResource) {
165         try {
166             return IOUtils.toString(TestUtils.class.getResource(pathInResource), "UTF-8");
167         } catch (IOException e) {
168             throw new RuntimeException(e);
169         }
170     }
171
172     public static String[] allPropertiesOf(Class<?> aClass) {
173         return Arrays.stream(getPropertyDescriptors(aClass))
174             .map(PropertyDescriptor::getDisplayName)
175             .toArray(String[]::new);
176     }
177
178     private static <T> List<String> allStringPropertiesOf(T object) {
179         return Arrays.stream(getPropertyDescriptors(object.getClass()))
180             .filter(descriptor -> descriptor.getPropertyType().isAssignableFrom(String.class))
181             .map(PropertyDescriptor::getDisplayName)
182             .collect(toList());
183     }
184
185     private static List<Field> allMockitoFieldsOf(Object object) {
186         final Predicate<Field> hasMockAnnotation = field -> field.getAnnotation(Mock.class) != null;
187         final Predicate<Field> hasInjectMocksAnnotation = field -> field.getAnnotation(InjectMocks.class) != null;
188
189         return Arrays.stream(FieldUtils.getAllFields(object.getClass()))
190             .filter(hasMockAnnotation.or(hasInjectMocksAnnotation))
191             .collect(toList());
192     }
193
194     /**
195      * Calls MockitoAnnotations.initMocks after nullifying any field which is annotated @Mocke or @InjectMock.
196      * This makes a "hard rest" to any mocked state or instance. Expected to be invoked between any @Tests in class, by
197      * being called in TestNG's @BeforeMethod (or equivalently JUnit's @BeforeTest).
198      */
199     public static void initMockitoMocks(Object testClass) {
200         for (Field field : allMockitoFieldsOf(testClass)) {
201             try {
202                 // Write null to fields
203                 FieldUtils.writeField(field, testClass, null, true);
204             } catch (ReflectiveOperationException e) {
205                 ExceptionUtils.rethrow(e);
206             }
207         }
208
209         MockitoAnnotations.initMocks(testClass);
210     }
211
212     /**
213      * Sets each String property with a value equal to the name of
214      * the property; e.g.: { name: "name", city: "city" }
215      * @param object
216      * @param <T>
217      * @return The modified object
218      */
219     public static <T> T setStringsInStringProperties(T object) {
220         try {
221             final List<String> stringFields = allStringPropertiesOf(object);
222
223             BeanUtils.populate(object, stringFields.stream()
224                 .collect(toMap(identity(), identity())));
225
226             return object;
227         } catch (Exception e) {
228             throw new RuntimeException(e);
229         }
230     }
231
232     public static void registerCloudConfigurationValueGenerator() {
233         BeanMatchers.registerValueGenerator(() -> new CloudConfiguration(
234                 randomAlphabetic(7), randomAlphabetic(7), randomAlphabetic(7)
235             ), CloudConfiguration.class);
236     }
237
238     public static OngoingStubbing<InputStream> mockGetRawBodyWithStringBody(HttpResponse<String> httpResponse, String body) {
239         try {
240             return when(httpResponse.getRawBody()).thenReturn(IOUtils.toInputStream(body, StandardCharsets.UTF_8.name()));
241         } catch (IOException e) {
242             ExceptionUtils.rethrow(e);
243         }
244         return null; //never shall get here
245     }
246
247     public static HttpResponse<String> createTestHttpResponse(int statusCode, String entity) throws Exception {
248         HttpResponseFactory factory = new DefaultHttpResponseFactory();
249         org.apache.http.HttpResponse response = factory.newHttpResponse(new BasicStatusLine(HTTP_1_1, statusCode, null), null);
250         if (entity != null) {
251             response.setEntity(new StringEntity(entity));
252         }
253         return new HttpResponse<>(response, String.class, null);
254     }
255
256
257     public static class JavaxRsClientMocks {
258         private final javax.ws.rs.client.Client fakeClient;
259         private final javax.ws.rs.client.Invocation.Builder fakeBuilder;
260         private final javax.ws.rs.client.Invocation fakeInvocation;
261         private final Response fakeResponse;
262
263         public javax.ws.rs.client.Client getFakeClient() {
264             return fakeClient;
265         }
266
267         public javax.ws.rs.client.Invocation.Builder getFakeBuilder() {
268             return fakeBuilder;
269         }
270
271         public Response getFakeResponse() {
272             return fakeResponse;
273         }
274
275         public JavaxRsClientMocks() {
276             final MockSettings mockSettings = withSettings().defaultAnswer(new TriesToReturnMockByType());
277
278             fakeClient = mock(javax.ws.rs.client.Client.class, mockSettings);
279             fakeBuilder = mock(javax.ws.rs.client.Invocation.Builder.class, mockSettings);
280             fakeInvocation = mock(javax.ws.rs.client.Invocation.class, mockSettings);
281             fakeResponse = mock(Response.class, mockSettings);
282             final javax.ws.rs.client.WebTarget fakeWebTarget = mock(javax.ws.rs.client.WebTarget.class, mockSettings);
283
284             TriesToReturnMockByType.setAvailableMocks(
285                     fakeClient,
286                     fakeWebTarget,
287                     fakeBuilder,
288                     fakeInvocation,
289                     fakeResponse
290             );
291             Mockito.when(fakeBuilder.get(any(Class.class))).thenReturn(null);
292             Mockito.when(fakeBuilder.get(any(GenericType.class))).thenReturn(null);
293             Mockito.when(fakeResponse.getStatus()).thenReturn(200);
294             Mockito.when(fakeResponse.getStatusInfo()).thenReturn(Response.Status.OK);
295             Mockito.when(fakeResponse.readEntity(Service.class)).thenReturn(null);
296             Mockito.when(fakeResponse.readEntity(InputStream.class)).thenReturn(new ByteArrayInputStream(new byte[]{}));
297             Mockito.when(fakeResponse.readEntity(String.class)).thenReturn(null);
298         }
299     }
300
301     /*
302        inspired out from newer Mockito version
303         returns a mock from given list if it's a matching return-type
304     */
305     private static class TriesToReturnMockByType implements Answer<Object>, Serializable {
306         private final Answer<Object> defaultReturn = RETURNS_DEFAULTS;
307         private static List<Object> availableMocks = ImmutableList.of();
308
309         static void setAvailableMocks(Object... mocks) {
310             availableMocks = ImmutableList.copyOf(mocks);
311         }
312
313         public Object answer(InvocationOnMock invocation) throws Throwable {
314             Class<?> methodReturnType = invocation.getMethod().getReturnType();
315
316             return availableMocks.stream()
317                     .filter(mock -> methodReturnType.isAssignableFrom(mock.getClass()))
318                     //.peek(m -> logger.info("found a mock: " + m.getClass().getName()))
319                     .findFirst()
320                     .orElse(defaultReturn.answer(invocation));
321         }
322     }
323
324
325     //The method mocks only some methods used in my case
326     //You may add some other when for your test here
327     public static Response mockResponseForJavaxClient(Client javaxClientMock) {
328         Response  mockResponse = mock(Response.class);
329         WebTarget webTarget = mock(WebTarget.class);
330         Invocation.Builder builder = mock(Invocation.Builder.class);
331         when(javaxClientMock.target(any(URI.class))).thenReturn(webTarget);
332         when(webTarget.path(any())).thenReturn(webTarget);
333         when(webTarget.request(any(MediaType.class))).thenReturn(builder);
334         when(builder.headers(any())).thenReturn(builder);
335         when(builder.header(any(), any())).thenReturn(builder);
336         when(builder.get()).thenReturn(mockResponse);
337         return mockResponse;
338     }
339
340
341     public interface Test {
342
343         void apply() throws AsdcCatalogException;
344     }
345
346     public static void testWithSystemProperty(String key, String value, Test test) throws Exception {
347         SystemProperties systemProperties = new SystemProperties();
348         //use reflection to invoke protected method
349         Environment originalEnvironment = (Environment) MethodUtils
350             .invokeMethod(systemProperties, true, "getEnvironment");
351
352         try {
353             Environment environment = mock(Environment.class);
354             systemProperties.setEnvironment(environment);
355             when(environment.getRequiredProperty(key)).thenReturn(value);
356             when(environment.containsProperty(key)).thenReturn(true);
357             test.apply();
358         }
359         finally {
360             systemProperties.setEnvironment(originalEnvironment);
361         }
362     }
363
364     private static RandomStringGenerator generator = new RandomStringGenerator.Builder()
365             .withinRange('0', 'z')
366             .filteredBy(LETTERS, DIGITS)
367             .build();
368
369     public static String generateRandomAlphaNumeric(int length) {
370         return generator.generate(length);
371     }
372
373     @DataProvider
374     public static Object[][] trueAndFalse() {
375         return new Object[][]{{true}, {false}};
376     }
377
378 }