|
25 | 25 | import com.amazon.aoc.models.SampleAppResponse; |
26 | 26 | import com.amazon.aoc.models.ValidationConfig; |
27 | 27 | import com.amazon.aoc.services.XRayService; |
| 28 | +import com.amazonaws.services.xray.model.Segment; |
28 | 29 | import com.amazonaws.services.xray.model.Trace; |
| 30 | +import com.fasterxml.jackson.databind.ObjectMapper; |
29 | 31 | import com.github.wnameless.json.flattener.JsonFlattener; |
30 | 32 | import lombok.extern.log4j.Log4j2; |
31 | 33 |
|
32 | | -import java.util.*; |
| 34 | +import java.util.Collections; |
| 35 | +import java.util.List; |
| 36 | +import java.util.Map; |
33 | 37 | import java.util.concurrent.atomic.AtomicReference; |
34 | 38 |
|
35 | 39 | @Log4j2 |
36 | 40 | public class TraceValidator implements IValidator { |
37 | | - private MustacheHelper mustacheHelper = new MustacheHelper(); |
38 | | - private XRayService xrayService; |
39 | | - private ICaller caller; |
40 | | - private Context context; |
41 | | - private FileConfig expectedTrace; |
42 | | - |
43 | | - @Override |
44 | | - public void init(Context context, ValidationConfig validationConfig, ICaller caller, FileConfig expectedTrace) throws Exception { |
45 | | - this.xrayService = new XRayService(context.getRegion()); |
46 | | - this.caller = caller; |
47 | | - this.context = context; |
48 | | - this.expectedTrace = expectedTrace; |
| 41 | + private MustacheHelper mustacheHelper = new MustacheHelper(); |
| 42 | + private XRayService xrayService; |
| 43 | + private ICaller caller; |
| 44 | + private Context context; |
| 45 | + private FileConfig expectedTrace; |
| 46 | + |
| 47 | + @Override |
| 48 | + public void init( |
| 49 | + Context context, ValidationConfig validationConfig, ICaller caller, FileConfig expectedTrace) |
| 50 | + throws Exception { |
| 51 | + this.xrayService = new XRayService(context.getRegion()); |
| 52 | + this.caller = caller; |
| 53 | + this.context = context; |
| 54 | + this.expectedTrace = expectedTrace; |
| 55 | + } |
| 56 | + |
| 57 | + @Override |
| 58 | + public void validate() throws Exception { |
| 59 | + // get stored trace |
| 60 | + Map<String, Object> storedTrace = this.getStoredTrace(); |
| 61 | + |
| 62 | + // create trace id list to retrieve trace from x-ray service |
| 63 | + String traceId = (String) storedTrace.get("[0].trace_id"); |
| 64 | + List<String> traceIdList = Collections.singletonList(traceId); |
| 65 | + |
| 66 | + // get retrieved trace from x-ray service |
| 67 | + Map<String, Object> retrievedTrace = this.getRetrievedTrace(traceIdList); |
| 68 | + |
| 69 | + // data model validation of other fields of segment document |
| 70 | + for (Map.Entry<String, Object> entry : storedTrace.entrySet()) { |
| 71 | + if (!entry.getValue().equals(retrievedTrace.get(entry.getKey()))) { |
| 72 | + log.error("data model validation failed"); |
| 73 | + log.info("mis matched data model field list"); |
| 74 | + log.info("value of stored trace map: {}", entry.getValue()); |
| 75 | + log.info("value of retrieved map: {}", retrievedTrace.get(entry.getKey())); |
| 76 | + log.info("=========================================="); |
| 77 | + throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED); |
| 78 | + } |
49 | 79 | } |
50 | 80 |
|
51 | | - @Override |
52 | | - public void validate() throws Exception { |
53 | | - // get stored trace |
54 | | - Map<String, Object> storedTrace = this.getStoredTrace(); |
| 81 | + log.info("validation is passed for path {}", caller.getCallingPath()); |
| 82 | + } |
55 | 83 |
|
56 | | - // create trace id list to retrieve trace from x-ray service |
57 | | - String traceId = (String) storedTrace.get("trace_id"); |
58 | | - List<String> traceIdList = Collections.singletonList(traceId); |
| 84 | + // this method will hit get trace from x-ray service and get retrieved trace |
| 85 | + private Map<String, Object> getRetrievedTrace(List<String> traceIdList) throws Exception { |
| 86 | + AtomicReference<List<Trace>> retrieveTraceListAtomicReference = new AtomicReference<>(); |
| 87 | + RetryHelper.retry( |
| 88 | + 3, |
| 89 | + () -> { |
| 90 | + List<Trace> retrieveTraceList = null; |
| 91 | + retrieveTraceList = xrayService.listTraceByIds(traceIdList); |
| 92 | + retrieveTraceListAtomicReference.set(retrieveTraceList); |
59 | 93 |
|
60 | | - // get retrieved trace from x-ray service |
61 | | - Map<String, Object> retrievedTrace = this.getRetrievedTrace(traceIdList); |
62 | | - |
63 | | - // validation of trace id |
64 | | - if (!storedTrace.get("trace_id").equals(retrievedTrace.get("trace_id"))) { |
65 | | - log.error("trace id validation failed"); |
66 | | - throw new BaseException(ExceptionCode.TRACE_ID_NOT_MATCHED); |
67 | | - } |
68 | | - |
69 | | - // data model validation of other fields of segment document |
70 | | - for (Map.Entry<String, Object> entry : storedTrace.entrySet()) { |
71 | | - if (!entry.getValue().equals(retrievedTrace.get(entry.getKey()))) { |
72 | | - log.error("data model validation failed"); |
73 | | - log.info("mis matched data model field list"); |
74 | | - log.info("value of stored trace map: {}", entry.getValue()); |
75 | | - log.info("value of retrieved map: {}",retrievedTrace.get(entry.getKey())); |
76 | | - log.info("=========================================="); |
77 | | - throw new BaseException(ExceptionCode.DATA_MODEL_NOT_MATCHED); |
78 | | - } |
79 | | - } |
80 | | - } |
81 | | - |
82 | | - // this method will hit get trace from x-ray service and get retrieved trace |
83 | | - private Map<String, Object> getRetrievedTrace(List<String> traceIdList) throws Exception { |
84 | | - Map<String, Object> flattenedJsonMapForRetrievedTrace = null; |
85 | | - AtomicReference<List<Trace>> retrieveTraceListAtomicReference = new AtomicReference<>(); |
86 | | - int MAX_RETRY_COUNT = 3; |
87 | | - |
88 | | - RetryHelper.retry(MAX_RETRY_COUNT, () -> { |
89 | | - List<Trace> retrieveTraceList = null; |
90 | | - retrieveTraceList = xrayService.listTraceByIds(traceIdList); |
91 | | - retrieveTraceListAtomicReference.set(retrieveTraceList); |
92 | | - |
93 | | - if (retrieveTraceList == null || retrieveTraceList.isEmpty()) { |
94 | | - throw new BaseException(ExceptionCode.EMPTY_LIST); |
95 | | - } |
| 94 | + if (retrieveTraceList == null || retrieveTraceList.isEmpty()) { |
| 95 | + throw new BaseException(ExceptionCode.EMPTY_LIST); |
| 96 | + } |
96 | 97 | }); |
97 | 98 |
|
98 | | - // flattened JSON object to a map |
99 | | - if (retrieveTraceListAtomicReference.get() != null && !retrieveTraceListAtomicReference.get().isEmpty()) { |
100 | | - try { |
101 | | - flattenedJsonMapForRetrievedTrace = JsonFlattener.flattenAsMap(retrieveTraceListAtomicReference.get().get(0).getSegments().get(0).getDocument()); |
102 | | - } catch (Exception e) { |
103 | | - log.error("exception while flattening the retrieved trace: " + e.getMessage()); |
104 | | - e.printStackTrace(); |
105 | | - } |
106 | | - } else { |
107 | | - log.error("retrieved trace list is empty or null"); |
108 | | - throw new BaseException(ExceptionCode.EMPTY_LIST); |
| 99 | + // flattened JSON object to a map |
| 100 | + Map<String, Object> flattenedJsonMapForRetrievedTrace = null; |
| 101 | + if (retrieveTraceListAtomicReference.get() != null |
| 102 | + && !retrieveTraceListAtomicReference.get().isEmpty()) { |
| 103 | + try { |
| 104 | + List<Segment> segmentList = retrieveTraceListAtomicReference.get().get(0).getSegments(); |
| 105 | + // have to sort the segments by start_time because |
| 106 | + // 1. we can not get span id from xraysdk today, |
| 107 | + // 2. the segments come out with different order everytime |
| 108 | + segmentList.sort( |
| 109 | + (segment1, segment2) -> { |
| 110 | + try { |
| 111 | + Map<String, Object> map1 = |
| 112 | + new ObjectMapper().readValue(segment1.getDocument(), Map.class); |
| 113 | + Map<String, Object> map2 = |
| 114 | + new ObjectMapper().readValue(segment2.getDocument(), Map.class); |
| 115 | + return map1.get("start_time") |
| 116 | + .toString() |
| 117 | + .compareTo(map2.get("start_time").toString()); |
| 118 | + } catch (Exception ex) { |
| 119 | + log.error(ex); |
| 120 | + return 0; |
| 121 | + } |
| 122 | + }); |
| 123 | + |
| 124 | + // build the segment's document as a jsonarray and flatten it for easy comparison |
| 125 | + StringBuilder segmentsJson = new StringBuilder("["); |
| 126 | + for (Segment segment : segmentList) { |
| 127 | + segmentsJson.append(segment.getDocument()); |
| 128 | + segmentsJson.append(","); |
109 | 129 | } |
110 | | - |
111 | | - return flattenedJsonMapForRetrievedTrace; |
| 130 | + segmentsJson.replace(segmentsJson.length() - 1, segmentsJson.length(), "]"); |
| 131 | + flattenedJsonMapForRetrievedTrace = JsonFlattener.flattenAsMap(segmentsJson.toString()); |
| 132 | + } catch (Exception e) { |
| 133 | + log.error("exception while flattening the retrieved trace: " + e.getMessage()); |
| 134 | + } |
| 135 | + } else { |
| 136 | + log.error("retrieved trace list is empty or null"); |
| 137 | + throw new BaseException(ExceptionCode.EMPTY_LIST); |
112 | 138 | } |
113 | 139 |
|
114 | | - // this method will hit a http endpoints of sample web apps and get stored trace |
115 | | - private Map<String, Object> getStoredTrace() throws Exception { |
116 | | - Map<String, Object> flattenedJsonMapForStoredTraces = null; |
| 140 | + return flattenedJsonMapForRetrievedTrace; |
| 141 | + } |
117 | 142 |
|
118 | | - SampleAppResponse sampleAppResponse = this.caller.callSampleApp(); |
| 143 | + // this method will hit a http endpoints of sample web apps and get stored trace |
| 144 | + private Map<String, Object> getStoredTrace() throws Exception { |
| 145 | + Map<String, Object> flattenedJsonMapForStoredTraces = null; |
119 | 146 |
|
120 | | - String jsonExpectedTrace = mustacheHelper.render(this.expectedTrace, context); |
| 147 | + SampleAppResponse sampleAppResponse = this.caller.callSampleApp(); |
121 | 148 |
|
122 | | - try { |
123 | | - // flattened JSON object to a map |
124 | | - flattenedJsonMapForStoredTraces = JsonFlattener.flattenAsMap(jsonExpectedTrace); |
125 | | - flattenedJsonMapForStoredTraces.put("trace_id", sampleAppResponse.getTraceId()); |
126 | | - } catch (Exception e) { |
127 | | - e.printStackTrace(); |
128 | | - } |
| 149 | + String jsonExpectedTrace = mustacheHelper.render(this.expectedTrace, context); |
129 | 150 |
|
130 | | - return flattenedJsonMapForStoredTraces; |
| 151 | + try { |
| 152 | + // flattened JSON object to a map |
| 153 | + flattenedJsonMapForStoredTraces = JsonFlattener.flattenAsMap(jsonExpectedTrace); |
| 154 | + flattenedJsonMapForStoredTraces.put("[0].trace_id", sampleAppResponse.getTraceId()); |
| 155 | + } catch (Exception e) { |
| 156 | + e.printStackTrace(); |
131 | 157 | } |
| 158 | + |
| 159 | + return flattenedJsonMapForStoredTraces; |
| 160 | + } |
132 | 161 | } |
0 commit comments