Aharoni, Pavel (pa0916) | ca3cb01 | 2018-10-22 15:29:57 +0300 | [diff] [blame] | 1 | /*-
|
| 2 | * ============LICENSE_START=======================================================
|
| 3 | * OSAM
|
| 4 | * ================================================================================
|
| 5 | * Copyright (C) 2018 AT&T
|
| 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 |
|
| 22 |
|
| 23 | package org.onap.osam.mso.rest;
|
| 24 |
|
| 25 | import com.google.common.collect.ImmutableList;
|
| 26 | import org.apache.commons.lang3.reflect.FieldUtils;
|
| 27 | import org.mockito.ArgumentCaptor;
|
| 28 | import org.mockito.Captor;
|
| 29 | import org.mockito.InjectMocks;
|
| 30 | import org.mockito.Matchers;
|
| 31 | import org.mockito.Mockito;
|
| 32 | import org.mockito.MockitoAnnotations;
|
| 33 | import org.onap.osam.aai.util.AAIRestInterface;
|
| 34 | import org.onap.osam.filters.PromiseEcompRequestIdFilter;
|
| 35 | import org.onap.osam.mso.RestMsoImplementation;
|
| 36 | import org.onap.osam.mso.RestObject;
|
| 37 | import org.onap.osam.testUtils.TestUtils;
|
| 38 | import org.springframework.mock.web.MockHttpServletRequest;
|
| 39 | import org.springframework.web.context.request.RequestContextHolder;
|
| 40 | import org.springframework.web.context.request.ServletRequestAttributes;
|
| 41 | import org.testng.annotations.BeforeClass;
|
| 42 | import org.testng.annotations.BeforeMethod;
|
| 43 | import org.testng.annotations.DataProvider;
|
| 44 | import org.testng.annotations.Test;
|
| 45 |
|
| 46 | import javax.servlet.http.HttpServletRequest;
|
| 47 | import javax.ws.rs.client.Client;
|
| 48 | import javax.ws.rs.client.Invocation;
|
| 49 | import javax.ws.rs.core.MultivaluedMap;
|
| 50 | import java.util.Set;
|
| 51 | import java.util.function.Consumer;
|
| 52 | import java.util.stream.Collectors;
|
| 53 | import java.util.stream.Stream;
|
| 54 |
|
| 55 | import static org.hamcrest.MatcherAssert.assertThat;
|
| 56 | import static org.hamcrest.Matchers.allOf;
|
| 57 | import static org.hamcrest.Matchers.equalToIgnoringCase;
|
| 58 | import static org.hamcrest.Matchers.hasItem;
|
| 59 | import static org.hamcrest.Matchers.hasToString;
|
| 60 | import static org.hamcrest.Matchers.instanceOf;
|
| 61 | import static org.hamcrest.Matchers.matchesPattern;
|
| 62 |
|
| 63 |
|
| 64 | public class OutgoingRequestIdTest {
|
| 65 |
|
| 66 |
|
| 67 | @InjectMocks
|
| 68 | private RestMsoImplementation restMsoImplementation;
|
| 69 |
|
| 70 | @InjectMocks
|
| 71 | private AAIRestInterface aaiRestInterface;
|
| 72 |
|
| 73 |
|
| 74 | @Captor
|
| 75 | private ArgumentCaptor<MultivaluedMap<String, Object>> multivaluedMapArgumentCaptor;
|
| 76 |
|
| 77 | @BeforeClass
|
| 78 | public void initMocks() {
|
| 79 | MockitoAnnotations.initMocks(this);
|
| 80 | }
|
| 81 |
|
| 82 | @BeforeMethod
|
| 83 | private void putRequestInSpringContext() {
|
| 84 | RequestContextHolder.setRequestAttributes(new ServletRequestAttributes((HttpServletRequest) PromiseEcompRequestIdFilter.wrapIfNeeded(new MockHttpServletRequest())));
|
| 85 | }
|
| 86 |
|
| 87 | @DataProvider
|
| 88 | public Object[][] msoMethods() {
|
| 89 | return Stream.<ThrowingConsumer<RestMsoImplementation>>of(
|
| 90 |
|
| 91 | client -> client.Get(new Object(), "whatever source id", "/any path", new RestObject<>()),
|
| 92 | client -> client.GetForObject("whatever source id", "/any path", Object.class),
|
| 93 | client -> client.Post(new Object(), "some payload", "whatever source id", "/any path", new RestObject<>()),
|
| 94 | client -> client.PostForObject("some payload", "whatever source id", "/any path", Object.class),
|
| 95 | client -> client.Put(Object.class, new RequestDetailsWrapper(), "whatever source id", "/any path", new RestObject<>())
|
| 96 |
|
| 97 | ).map(l -> ImmutableList.of(l).toArray()).collect(Collectors.toList()).toArray(new Object[][]{});
|
| 98 | }
|
| 99 |
|
| 100 | @Test(dataProvider = "msoMethods")
|
| 101 | public void mso(Consumer<RestMsoImplementation> f) throws Exception {
|
| 102 | final TestUtils.JavaxRsClientMocks mocks = setAndGetMocksInsideRestImpl(restMsoImplementation);
|
| 103 |
|
| 104 | f.accept(restMsoImplementation);
|
| 105 |
|
| 106 | verifyRequestIdHeaderWasAdded(mocks.getFakeBuilder());
|
| 107 | }
|
| 108 |
|
| 109 | @DataProvider
|
| 110 | public Object[][] aaiMethods() {
|
| 111 | return Stream.<ThrowingConsumer<AAIRestInterface>>of(
|
| 112 |
|
| 113 | client -> client.RestGet("from app id", "some transId", "/any path", false),
|
| 114 | client -> client.Delete("whatever source id", "some transId", "/any path"),
|
| 115 | client -> client.RestPost("from app id", "/any path", "some payload", false),
|
| 116 | client -> client.RestPut("from app id", "/any path", "some payload", false)
|
| 117 |
|
| 118 | ).map(l -> ImmutableList.of(l).toArray()).collect(Collectors.toList()).toArray(new Object[][]{});
|
| 119 | }
|
| 120 |
|
| 121 | //@Test(dataProvider = "aaiMethods")
|
| 122 | public void aai(Consumer<AAIRestInterface> f) throws Exception {
|
| 123 | final TestUtils.JavaxRsClientMocks mocks = setAndGetMocksInsideRestImpl(aaiRestInterface);
|
| 124 |
|
| 125 | f.accept(aaiRestInterface);
|
| 126 |
|
| 127 | verifyRequestIdHeaderWasAdded(mocks.getFakeBuilder());
|
| 128 | }
|
| 129 |
|
| 130 | // @Test(dataProvider = "schedulerMethods")
|
| 131 | // public void scheduler(Consumer<AAIRestInterface> f) throws Exception {
|
| 132 | //
|
| 133 | // This test os not feasible in the wat acheduler is implemented today,
|
| 134 | // as Scheduler's client is rewritten in every call.
|
| 135 | //
|
| 136 | // :-(
|
| 137 | //
|
| 138 | // }
|
| 139 |
|
| 140 | private void verifyRequestIdHeaderWasAdded(Invocation.Builder fakeBuilder) {
|
| 141 | final String requestIdHeader = "x-ecomp-requestid";
|
| 142 | final String uuidRegex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
| 143 |
|
| 144 | // Checks that the builder was called with either one of header("x-ecomp-requestid", uuid)
|
| 145 | // or the plural brother: headers(Map.of("x-ecomp-requestid", Set.of(uuid))
|
| 146 |
|
| 147 | Object requestId;
|
| 148 | // The 'verify()' will capture the request id. If no match -- AssertionError will
|
| 149 | // catch for a second chance -- another 'verify()'.
|
| 150 | try {
|
| 151 | ArgumentCaptor<Object> argumentCaptor = ArgumentCaptor.forClass(Object.class);
|
| 152 | Mockito.verify(fakeBuilder)
|
| 153 | .header(
|
| 154 | Matchers.argThat(equalToIgnoringCase(requestIdHeader)),
|
| 155 | argumentCaptor.capture()
|
| 156 | );
|
| 157 | requestId = argumentCaptor.getValue();
|
| 158 |
|
| 159 | } catch (AssertionError e) {
|
| 160 | Mockito.verify(fakeBuilder).headers(multivaluedMapArgumentCaptor.capture());
|
| 161 |
|
| 162 | final MultivaluedMap<String, Object> headersMap = multivaluedMapArgumentCaptor.getValue();
|
| 163 | final String thisRequestIdHeader = getFromSetCaseInsensitive(headersMap.keySet(), requestIdHeader);
|
| 164 |
|
| 165 | assertThat(headersMap.keySet(), hasItem(thisRequestIdHeader));
|
| 166 | requestId = headersMap.getFirst(thisRequestIdHeader);
|
| 167 | }
|
| 168 |
|
| 169 | assertThat("header '" + requestIdHeader + "' should be a uuid", requestId,
|
| 170 | allOf(instanceOf(String.class), hasToString(matchesPattern(uuidRegex))));
|
| 171 | }
|
| 172 |
|
| 173 | private String getFromSetCaseInsensitive(Set<String> set, String key) {
|
| 174 | return set.stream()
|
| 175 | .filter(anotherString -> anotherString.equalsIgnoreCase(key))
|
| 176 | .findFirst()
|
| 177 | .orElse(key);
|
| 178 | }
|
| 179 |
|
| 180 | private TestUtils.JavaxRsClientMocks setAndGetMocksInsideRestImpl(Class<?> clazz) throws IllegalAccessException {
|
| 181 | TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks();
|
| 182 | Client fakeClient = mocks.getFakeClient();
|
| 183 |
|
| 184 | FieldUtils.writeStaticField(clazz, "client", fakeClient, true);
|
| 185 |
|
| 186 | return mocks;
|
| 187 | }
|
| 188 |
|
| 189 | private TestUtils.JavaxRsClientMocks setAndGetMocksInsideRestImpl(Object instance) throws IllegalAccessException {
|
| 190 | TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks();
|
| 191 | Client fakeClient = mocks.getFakeClient();
|
| 192 |
|
| 193 | FieldUtils.writeField(instance, "client", fakeClient, true);
|
| 194 |
|
| 195 | return mocks;
|
| 196 | }
|
| 197 |
|
| 198 | @FunctionalInterface
|
| 199 | public interface ThrowingConsumer<T> extends Consumer<T> {
|
| 200 | @Override
|
| 201 | default void accept(T t) {
|
| 202 | try {
|
| 203 | acceptThrows(t);
|
| 204 | } catch (Exception e) {
|
| 205 | throw new RuntimeException(e);
|
| 206 | }
|
| 207 | }
|
| 208 |
|
| 209 | void acceptThrows(T t) throws Exception;
|
| 210 | }
|
| 211 |
|
| 212 | }
|