run logging test for the error log as well
[vid.git] / vid-automation / src / test / java / org / onap / vid / more / LoggerFormatTest.java
1 package org.onap.vid.more;
2
3 import static java.util.Collections.reverse;
4 import static java.util.stream.Collectors.toList;
5 import static org.hamcrest.CoreMatchers.containsString;
6 import static org.hamcrest.CoreMatchers.is;
7 import static org.hamcrest.MatcherAssert.assertThat;
8 import static org.hamcrest.Matchers.allOf;
9 import static org.hamcrest.Matchers.contains;
10 import static org.hamcrest.Matchers.containsInAnyOrder;
11 import static org.hamcrest.Matchers.containsInRelativeOrder;
12 import static org.hamcrest.Matchers.either;
13 import static org.hamcrest.Matchers.emptyOrNullString;
14 import static org.hamcrest.Matchers.greaterThan;
15 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
16 import static org.hamcrest.Matchers.hasSize;
17 import static org.hamcrest.Matchers.matchesPattern;
18 import static vid.automation.test.services.SimulatorApi.retrieveRecordedRequests;
19
20 import com.fasterxml.jackson.databind.JsonNode;
21
22 import java.lang.reflect.Method;
23 import java.net.URI;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.Logger;
34 import org.jetbrains.annotations.NotNull;
35 import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetSubscribersGet;
36 import org.onap.vid.api.BaseApiTest;
37 import org.springframework.web.client.RestTemplate;
38 import org.testng.annotations.BeforeClass;
39 import org.testng.annotations.DataProvider;
40 import org.testng.annotations.Test;
41 import vid.automation.test.services.SimulatorApi;
42 import vid.automation.test.services.SimulatorApi.RecordedRequests;
43
44 public class LoggerFormatTest extends BaseApiTest {
45
46     private final static String logChecker = System.getProperty("EELF_LOG_CHECKER", "http://my-logchecker:8888/validate");
47     private final Logger logger = LogManager.getLogger(LoggerFormatTest.class);
48     private final int PRIORITY_LAST = 999;
49
50     public enum LogName {
51         audit2019, error, metrics2019, debug
52     }
53
54     @BeforeClass
55     public void login() {
56         super.login();
57     }
58
59     @BeforeClass
60     public void setAaiSubscribers() {
61         SimulatorApi.registerExpectationFromPreset(new PresetAAIGetSubscribersGet(), SimulatorApi.RegistrationStrategy.CLEAR_THEN_SET);
62     }
63
64     @DataProvider
65     public static Object[][] logsAndFormats(Method test) {
66         return new Object[][]{
67                 {LogName.debug, "debug", 0.95 },
68                 {LogName.metrics2019, "metric-ELS-2019.11", 0.95},
69                 {LogName.audit2019, "audit-ELS-2019.11", 0.95},
70                 {LogName.error, "error", 0.75 }
71         };
72     }
73
74
75     @Test(dataProvider = "logsAndFormats", priority = PRIORITY_LAST)
76     public void validateLogsAndFormat(LogName logName, String logCheckerFormat, Double expectedRank){
77         String logLines = validateLogsFormat(logName, logCheckerFormat, expectedRank);
78
79         if (logName == LogName.audit2019)
80         {
81             moreValidationsForAuditFormat(logLines);
82         }
83     }
84
85     //more validations for log format that logcheck doesn't verify
86     private void moreValidationsForAuditFormat (String logLines){
87         splitLogLines(logLines).forEach(line -> {
88             String[] records = line.split("\\|");
89             assertThat("server name shall be empty", records[5], emptyOrNullString());
90
91             //authenticated request shall logs with userId.
92             final String serviceName = records[6];
93             if (StringUtils.containsAny(serviceName, "aai", "mso")) {
94                 assertThat("Partner name shall be userId", records[7], matchesPattern("^[A-Za-z0-9]{4,15}$"));
95             }
96
97             assertThat("Severity shall be empty", records[13], emptyOrNullString());
98             assertThat("marker", records[21], either(is("ENTRY")).or(is("EXIT")));
99         });
100     }
101
102     private String validateLogsFormat (LogName logName, String logType){
103         return validateLogsFormat(logName, logType, 0.95);
104     }
105
106     private String validateLogsFormat (LogName logName, String logType,double score){
107
108         String logLines = getLogLines(logName);
109         logger.info("logLines are: " + logLines);
110         JsonNode response = getCheckerResults(logType, logLines);
111         logger.info("Response is:" + response.toString());
112
113         int total_records = response.path("summary").path("total_records").asInt();
114         int valid_records = response.path("summary").path("valid_records").asInt();
115
116         assertThat(total_records, greaterThan(30)); //make sure we have at least 30 total records
117         assertThat((double) valid_records / total_records, is(greaterThanOrEqualTo(score)));
118
119         return logLines;
120     }
121
122     private String getLogLines (LogName logname){
123         return getLogLines(logname, 5000, 30, restTemplate, uri);
124     }
125
126     public static String getLogLines (LogName logname,int maxRows, int minRows, RestTemplate restTemplate, URI uri){
127         String logLines = restTemplate.getForObject(uri + "/logger/" + logname.name() + "?limit={maxRows}", String.class, maxRows);
128         assertThat("expecting at least " + minRows + " rows in " + logname.name(),
129                 StringUtils.countMatches(logLines, '\n') + 1,
130                 is(greaterThanOrEqualTo(minRows)));
131         return logLines;
132     }
133
134     /**
135      * @return Chronological-ordered list of recent log-lines
136      */
137     public static List<String> getLogLinesAsList (LogName logname,int maxRows, int minRows, RestTemplate restTemplate, URI uri){
138         String logLines = LoggerFormatTest.getLogLines(logname, maxRows, minRows, restTemplate, uri);
139         List<String> lines = splitLogLines(logLines);
140
141         // Reverse
142         reverse(lines);
143
144         return lines;
145     }
146
147     @NotNull
148     private static List<String> splitLogLines (String logLines){
149         return new ArrayList<>(Arrays.asList(logLines.split("(\\r?\\n)")));
150     }
151
152
153     /**
154      * @return Chronological-ordered list of recent log-lines of a given requestId
155      */
156     public static List<String> getRequestLogLines (String requestId, LogName logname, RestTemplate restTemplate, URI uri){
157
158         List<String> lines = getLogLinesAsList(logname, 30, 1, restTemplate, uri);
159
160         //Filter
161         lines.removeIf(line -> !StringUtils.containsIgnoreCase(line, requestId));
162
163         return lines;
164     }
165
166     public static void verifyExistenceOfIncomingReqsInAuditLogs (RestTemplate restTemplate, URI uri, String requestId, String path){
167         List<String> logLines = getRequestLogLines(requestId, LogName.audit2019, restTemplate, uri);
168         String requestIdPrefix = "RequestID=";
169         assertThat("\nENTRY & EXIT logs are expected to include RequestId: " + requestId
170                         + " \nAnd request path: "
171                         + path +
172                         "\nin exactly two rows - inside the audit log matching lines:\n"
173                         + String.join("\n", logLines) + "\n",
174                 logLines,
175                 contains(
176                         allOf(
177                                 containsString(requestIdPrefix + requestId),
178                                 containsString("ENTRY"),
179                                 containsString(path)),
180                         allOf(
181                                 containsString(requestIdPrefix + requestId),
182                                 containsString("EXIT"),
183                                 containsString(path))
184                 ));
185     }
186
187     public static void assertHeadersAndMetricLogs (RestTemplate restTemplate, URI uri, String requestId, String path, int requestsSize){
188         List<String> logLines =
189                 getRequestLogLines(requestId, LogName.metrics2019, restTemplate, uri);
190
191         List<RecordedRequests> requests = retrieveRecordedRequests();
192         List<RecordedRequests> underTestRequests =
193                 requests.stream().filter(x -> x.path.contains(path)).collect(toList());
194
195         assertThat(underTestRequests, hasSize(requestsSize));
196
197         underTestRequests.forEach(request -> {
198             assertThat("X-ONAP-RequestID", request.headers.get("X-ONAP-RequestID"), contains(requestId));
199             assertThat("X-ECOMP-RequestID", request.headers.get("X-ECOMP-RequestID"), contains(requestId));
200             assertThat("X-ONAP-PartnerName", request.headers.get("X-ONAP-PartnerName"), contains("VID.VID"));
201         });
202
203         List<String> allInvocationIds = new LinkedList<>();
204
205         underTestRequests.forEach(request -> {
206
207             List<String> invocationIds = request.headers.get("X-InvocationID");
208             assertThat(invocationIds, hasSize(1));
209
210             String invocationId = invocationIds.get(0);
211             allInvocationIds.add(invocationId);
212
213             assertIdsInMetricsLog(logLines, requestId, invocationId);
214         });
215
216         //make sure no InvocationId is repeated twice
217         assertThat("expect all InvocationIds to be unique",
218                 allInvocationIds, containsInAnyOrder(new HashSet<>(allInvocationIds).toArray()));
219     }
220
221     public static void assertIdsInMetricsLog (List < String > logLines, String requestId, String invocationId){
222         assertThat("request id and invocation id must be found in exactly two rows in: \n" + String.join("\n", logLines),
223                 logLines,
224                 containsInRelativeOrder(
225                         allOf(
226                                 containsString("RequestID=" + requestId),
227                                 containsString("InvocationID=" + invocationId),
228                                 containsString("Invoke")),
229                         allOf(
230                                 containsString("RequestID=" + requestId),
231                                 containsString("InvocationID=" + invocationId),
232                                 containsString("InvokeReturn"))
233                 ));
234     }
235
236     private JsonNode getCheckerResults (String logtype, String logLines){
237         Map<String, String> params = new HashMap<>();
238         params.put("format", "raw");
239         params.put("type", logtype);
240         params.put("component", "vid");
241         params.put("data", logLines);
242
243         return restTemplate.postForObject(logChecker, params, JsonNode.class);
244     }
245 }