Skip to content

Commit ab0d3c4

Browse files
committed
Added trace validation logic
1 parent 57d717c commit ab0d3c4

File tree

9 files changed

+204
-80
lines changed

9 files changed

+204
-80
lines changed

validator/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ dependencies {
4141
// yaml reader
4242
compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.11.1'
4343

44+
// json reader
45+
compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1'
46+
47+
// json flattener
48+
compile group: 'com.github.wnameless', name: 'json-flattener', version: '0.1.0'
49+
4450
// command cli
4551
compile 'info.picocli:picocli:4.3.2'
4652

validator/src/main/java/com/amazon/aoc/callers/HttpCaller.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class HttpCaller implements ICaller {
2020

2121
public HttpCaller(String endpoint, String path) {
2222
this.url = endpoint + path;
23+
log.info("validator is testing {} path", this.url);
2324
}
2425

2526
@Override
@@ -29,7 +30,7 @@ public SampleAppResponse callSampleApp() throws Exception {
2930

3031
AtomicReference<SampleAppResponse> sampleAppResponseAtomicReference = new AtomicReference<>();
3132
RetryHelper.retry(
32-
60,
33+
3,
3334
() -> {
3435
try (Response response = client.newCall(request).execute()) {
3536
String responseBody = response.body().string();

validator/src/main/java/com/amazon/aoc/exception/ExceptionCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public enum ExceptionCode {
2525

2626
// validating errors
2727
TRACE_ID_NOT_MATCHED(50001, "trace id not matched"),
28+
DATA_MODEL_NOT_MATCHED(50006, "trace id not matched"),
2829
TRACE_SPAN_LIST_NOT_MATCHED(50002, "trace span list has different length"),
2930
TRACE_SPAN_NOT_MATCHED(50003, "trace span not matched"),
3031
TRACE_LIST_NOT_MATCHED(50004, "trace list has different length"),

validator/src/main/java/com/amazon/aoc/fileconfigs/ExpectedTrace.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
@Getter
2121
public enum ExpectedTrace implements FileConfig {
2222
DEFAULT_EXPECTED_TRACE("/expected-data-template/defaultExpectedTrace.mustache"),
23+
AWSSDK_EXPECTED_TRACE("/expected-data-template/expectedAWSSDKTrace.json"),
24+
HTTP_EXPECTED_TRACE("/expected-data-template/expectedHTTPTrace.json")
2325
;
2426

2527
private String path;

validator/src/main/java/com/amazon/aoc/helpers/RetryHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public static void retry(int retryCount, int sleepInMilliSeconds, Retryable retr
3636
throws Exception {
3737
while (retryCount-- > 0) {
3838
try {
39-
log.info("still can retry for {} times", retryCount);
39+
log.info("retry attempt left : {} ", retryCount);
4040
retryable.execute();
4141
return;
4242
} catch (Exception ex) {

validator/src/main/java/com/amazon/aoc/validators/TraceValidator.java

Lines changed: 80 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -19,97 +19,99 @@
1919
import com.amazon.aoc.exception.BaseException;
2020
import com.amazon.aoc.exception.ExceptionCode;
2121
import com.amazon.aoc.fileconfigs.FileConfig;
22-
import com.amazon.aoc.helpers.MustacheHelper;
23-
import com.amazon.aoc.helpers.RetryHelper;
2422
import com.amazon.aoc.models.Context;
2523
import com.amazon.aoc.models.SampleAppResponse;
2624
import com.amazon.aoc.services.XRayService;
2725
import com.amazonaws.services.xray.model.Trace;
26+
import com.github.wnameless.json.flattener.JsonFlattener;
2827
import lombok.extern.log4j.Log4j2;
28+
import org.json.simple.JSONObject;
29+
import org.json.simple.parser.JSONParser;
2930

30-
import java.util.Arrays;
31-
import java.util.Comparator;
32-
import java.util.List;
33-
import java.util.stream.Collectors;
31+
import java.io.FileReader;
32+
import java.util.*;
33+
import java.util.concurrent.TimeUnit;
3434

3535
@Log4j2
3636
public class TraceValidator implements IValidator {
37-
private MustacheHelper mustacheHelper = new MustacheHelper();
38-
private static int MAX_RETRY_COUNT = 60;
39-
private Context context;
37+
private static int MAX_RETRY_COUNT = 3;
4038
private XRayService xrayService;
4139
private ICaller caller;
4240
private FileConfig expectedTrace;
4341

44-
@Override
45-
public void init(Context context, ICaller caller, FileConfig expectedTrace) throws Exception {
46-
this.context = context;
47-
this.xrayService = new XRayService(context.getRegion());
48-
this.caller = caller;
49-
this.expectedTrace = expectedTrace;
50-
}
51-
52-
@Override
53-
public void validate() throws Exception {
54-
List<Trace> expectedTraceList = this.getExpectedTrace();
55-
expectedTraceList.sort(Comparator.comparing(Trace::getId));
56-
RetryHelper.retry(
57-
MAX_RETRY_COUNT,
58-
() -> {
59-
List<Trace> traceList =
60-
xrayService.listTraceByIds(
61-
expectedTraceList.stream()
62-
.map(trace -> trace.getId())
63-
.collect(Collectors.toList()));
64-
65-
traceList.sort(Comparator.comparing(Trace::getId));
66-
67-
log.info("expectedTraceList: {}", expectedTraceList);
68-
log.info("traceList got from backend: {}", traceList);
69-
if (expectedTraceList.size() != traceList.size()) {
70-
throw new BaseException(ExceptionCode.TRACE_LIST_NOT_MATCHED);
71-
}
72-
73-
for (int i = 0; i != expectedTraceList.size(); ++i) {
74-
Trace trace = traceList.get(i);
75-
compareTwoTraces(expectedTraceList.get(i), trace);
76-
}
77-
});
78-
}
79-
80-
private void compareTwoTraces(Trace trace1, Trace trace2) throws BaseException {
81-
// check trace id
82-
if (!trace1.getId().equals(trace2.getId())) {
83-
throw new BaseException(ExceptionCode.TRACE_ID_NOT_MATCHED);
42+
@Override
43+
public void init(Context context, ICaller caller, FileConfig expectedTrace) throws Exception {
44+
this.xrayService = new XRayService(context.getRegion());
45+
this.caller = caller;
46+
this.expectedTrace = expectedTrace;
8447
}
8548

86-
/*
87-
if (trace1.getSegments().size() != trace2.getSegments().size()) {
88-
throw new BaseException(ExceptionCode.TRACE_SPAN_LIST_NOT_MATCHED);
49+
@Override
50+
public void validate() throws Exception {
51+
// get stored trace
52+
Map<String, Object> storedTrace = this.getStoredTrace();
53+
54+
// create trace id list to retrieve trace from x-ray service
55+
String traceId = (String) storedTrace.get("trace_id");
56+
List<String> traceIdList = Collections.singletonList(traceId);
57+
58+
// get retrieved trace from x-ray service
59+
Map<String, Object> retrievedTrace = this.getRetrievedTrace(traceIdList);
60+
61+
// validation of trace id
62+
if (!storedTrace.get("trace_id").equals(retrievedTrace.get("trace_id"))) {
63+
throw new BaseException(ExceptionCode.TRACE_ID_NOT_MATCHED);
64+
}
65+
66+
// data model validation of other fields of segment document
67+
for (Map.Entry<String, Object> entry : storedTrace.entrySet()) {
68+
if (!entry.getValue().equals(retrievedTrace.get(entry.getKey()))) {
69+
log.info("mis matched data model field list");
70+
log.info("value of stored trace map: {}", entry.getValue());
71+
log.info("value of retrieved map: {}",retrievedTrace.get(entry.getKey()));
72+
log.info("==========================================");
73+
throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED);
74+
}
75+
}
8976
}
90-
trace1.getSegments().sort(Comparator.comparing(Segment::getId));
91-
trace2.getSegments().sort(Comparator.comparing(Segment::getId));
92-
93-
for (int i = 0; i != trace1.getSegments().size(); ++i) {
94-
// check span id
95-
if (!trace1.getSegments().get(i).getId()
96-
.equals(trace2.getSegments().get(i).getId())) {
97-
throw new BaseException(ExceptionCode.TRACE_SPAN_NOT_MATCHED);
98-
}
99-
}*/
100-
}
101-
102-
// this endpoint will be a http endpoint including the path with get method
103-
private List<Trace> getExpectedTrace() throws Exception {
104-
SampleAppResponse sampleAppResponse = this.caller.callSampleApp();
105-
106-
// convert the trace data into xray format
107-
Trace trace = new Trace();
108-
trace.setId(sampleAppResponse.getTraceId());
109-
110-
// todo: construct the trace data from the template file
111-
112-
// we can support multi expected trace id to validate if need
113-
return Arrays.asList(trace);
114-
}
115-
}
77+
78+
// this method will hit get trace from x-ray service and get retrieved trace
79+
private Map<String, Object> getRetrievedTrace(List<String> traceIdList) throws Exception {
80+
Map<String, Object> flattenedJsonMapForRetrievedTrace = null;
81+
82+
// retrieve trace from x-ray service
83+
TimeUnit.SECONDS.sleep(15);
84+
List<Trace> retrieveTraceList = xrayService.listTraceByIds(traceIdList);
85+
86+
try {
87+
// flattened JSON object to a map
88+
flattenedJsonMapForRetrievedTrace = JsonFlattener.flattenAsMap(retrieveTraceList.get(0).getSegments().get(0).getDocument());
89+
} catch (Exception e) {
90+
e.printStackTrace();
91+
}
92+
93+
return flattenedJsonMapForRetrievedTrace;
94+
}
95+
96+
// this method will hit a http endpoints of sample web apps and get stored trace
97+
private Map<String, Object> getStoredTrace() throws Exception {
98+
String PATH = "src/main/resources";
99+
Map<String, Object> flattenedJsonMapForStoredTraces = null;
100+
101+
SampleAppResponse sampleAppResponse = this.caller.callSampleApp();
102+
103+
JSONParser parser = new JSONParser();
104+
try {
105+
Object obj = parser.parse(new FileReader(PATH + this.expectedTrace.getPath()));
106+
JSONObject jsonObject = (JSONObject) obj;
107+
108+
// flattened JSON object to a map
109+
flattenedJsonMapForStoredTraces = JsonFlattener.flattenAsMap(jsonObject.toString());
110+
flattenedJsonMapForStoredTraces.put("trace_id", sampleAppResponse.getTraceId());
111+
} catch (Exception e) {
112+
e.printStackTrace();
113+
}
114+
115+
return flattenedJsonMapForStoredTraces;
116+
}
117+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"name": "/aws-sdk-call",
3+
"fault": false,
4+
"error": false,
5+
"throttle": false,
6+
"http": {
7+
"request": {
8+
"url": "http://127.0.0.1:8080/aws-sdk-call",
9+
"method": "GET"
10+
},
11+
"response": {
12+
"status": 200
13+
}
14+
},
15+
"subsegments": [
16+
{
17+
"name": "DemoController.awssdkCall",
18+
"fault": false,
19+
"error": false,
20+
"throttle": false,
21+
"subsegments": [
22+
{
23+
"name": "S3",
24+
"fault": false,
25+
"error": false,
26+
"throttle": false,
27+
"http": {
28+
"request": {
29+
"url": "https://s3.us-west-2.amazonaws.com/",
30+
"method": "GET"
31+
},
32+
"response": {
33+
"status": 200
34+
}
35+
},
36+
"namespace": "aws",
37+
"subsegments": [
38+
{
39+
"name": "s3.us-west-2.amazonaws.com",
40+
"fault": false,
41+
"error": false,
42+
"throttle": false,
43+
"http": {
44+
"request": {
45+
"url": "https://s3.us-west-2.amazonaws.com/",
46+
"method": "GET",
47+
},
48+
"response": {
49+
"status": 200
50+
}
51+
},
52+
"namespace": "remote"
53+
}
54+
]
55+
}
56+
]
57+
}
58+
]
59+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "/outgoing-http-call",
3+
"fault": false,
4+
"error": false,
5+
"throttle": false,
6+
"http": {
7+
"request": {
8+
"url": "http://127.0.0.1:8080/outgoing-http-call",
9+
"method": "GET"
10+
},
11+
"response": {
12+
"status": 200
13+
}
14+
},
15+
"subsegments": [
16+
{
17+
"name": "DemoController.httpCall",
18+
"fault": false,
19+
"error": false,
20+
"throttle": false,
21+
"subsegments": [
22+
{
23+
"name": "aws.amazon.com",
24+
"fault": false,
25+
"error": false,
26+
"throttle": false,
27+
"http": {
28+
"request": {
29+
"url": "https://aws.amazon.com/",
30+
"method": "GET"
31+
},
32+
"response": {
33+
"status": 200
34+
}
35+
},
36+
"namespace": "remote"
37+
}
38+
]
39+
}
40+
]
41+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-
2+
validationType: "trace"
3+
httpPath: "/outgoing-http-call"
4+
httpMethod: "get"
5+
callingType: "http"
6+
expectedTraceTemplate: "HTTP_EXPECTED_TRACE"
7+
-
8+
validationType: "trace"
9+
httpPath: "/aws-sdk-call"
10+
httpMethod: "get"
11+
callingType: "http"
12+
expectedTraceTemplate: "AWSSDK_EXPECTED_TRACE"

0 commit comments

Comments
 (0)