2222import com .fasterxml .jackson .databind .ObjectMapper ;
2323import org .junit .Test ;
2424
25+ import static org .junit .Assert .assertFalse ;
2526import static org .junit .Assert .assertEquals ;
2627import static org .junit .Assert .assertNotNull ;
2728import static org .junit .Assert .assertTrue ;
2829
2930public class TestSentinelBatchReader {
30- private ObjectMapper mapper = new ObjectMapper ();
31+ private final ObjectMapper mapper = new ObjectMapper ();
3132
3233 @ Test
3334 public void testParseSimpleSecurityAlertResponse () throws Exception {
@@ -67,15 +68,29 @@ public void testParseSimpleSecurityAlertResponse() throws Exception {
6768 assertEquals ("AlertName" , firstColumn .get ("name" ).asText ());
6869 assertEquals ("string" , firstColumn .get ("type" ).asText ());
6970
71+ // Verify column order
72+ assertEquals ("AlertName" , columns .get (0 ).get ("name" ).asText ());
73+ assertEquals ("Severity" , columns .get (1 ).get ("name" ).asText ());
74+ assertEquals ("Count" , columns .get (2 ).get ("name" ).asText ());
75+ assertEquals ("Active" , columns .get (3 ).get ("name" ).asText ());
76+
77+ // Verify first row data
7078 JsonNode firstRow = rows .get (0 );
7179 assertEquals ("Alert1" , firstRow .get (0 ).asText ());
7280 assertEquals ("High" , firstRow .get (1 ).asText ());
7381 assertEquals (5 , firstRow .get (2 ).asLong ());
7482 assertTrue (firstRow .get (3 ).asBoolean ());
83+
84+ // Verify second row data
85+ JsonNode secondRow = rows .get (1 );
86+ assertEquals ("Alert2" , secondRow .get (0 ).asText ());
87+ assertEquals ("Medium" , secondRow .get (1 ).asText ());
88+ assertEquals (3 , secondRow .get (2 ).asLong ());
89+ assertFalse (secondRow .get (3 ).asBoolean ());
7590 }
7691
7792 @ Test
78- public void testParseTypeMappings () throws Exception {
93+ public void testParseAllKqlTypeMappings () throws Exception {
7994 String jsonResponse = "{\n " +
8095 " \" tables\" : [\n " +
8196 " {\n " +
@@ -97,10 +112,22 @@ public void testParseTypeMappings() throws Exception {
97112 JsonNode root = mapper .readTree (jsonResponse );
98113 JsonNode columns = root .get ("tables" ).get (0 ).get ("columns" );
99114
115+ String [] expectedNames = {"StringCol" , "IntCol" , "LongCol" , "RealCol" , "BoolCol" , "DatetimeCol" };
100116 String [] expectedTypes = {"string" , "int" , "long" , "real" , "bool" , "datetime" };
117+
101118 for (int i = 0 ; i < expectedTypes .length ; i ++) {
119+ assertEquals (expectedNames [i ], columns .get (i ).get ("name" ).asText ());
102120 assertEquals (expectedTypes [i ], columns .get (i ).get ("type" ).asText ());
103121 }
122+
123+ // Verify row values match types
124+ JsonNode row = root .get ("tables" ).get (0 ).get ("rows" ).get (0 );
125+ assertEquals ("value" , row .get (0 ).asText ());
126+ assertEquals (42 , row .get (1 ).asInt ());
127+ assertEquals (1000 , row .get (2 ).asLong ());
128+ assertTrue (Math .abs (3.14 - row .get (3 ).asDouble ()) < 0.01 );
129+ assertTrue (row .get (4 ).asBoolean ());
130+ assertTrue (row .get (5 ).asText ().contains ("2026-04-26" ));
104131 }
105132
106133 @ Test
@@ -117,8 +144,14 @@ public void testParseEmptyResult() throws Exception {
117144 "}" ;
118145
119146 JsonNode root = mapper .readTree (jsonResponse );
147+ JsonNode columns = root .get ("tables" ).get (0 ).get ("columns" );
120148 JsonNode rows = root .get ("tables" ).get (0 ).get ("rows" );
121149
150+ // Should have column metadata even with empty rows
151+ assertEquals (1 , columns .size ());
152+ assertEquals ("Column1" , columns .get (0 ).get ("name" ).asText ());
153+
154+ // But no data rows
122155 assertEquals (0 , rows .size ());
123156 }
124157
@@ -142,7 +175,12 @@ public void testParseNullValues() throws Exception {
142175 JsonNode root = mapper .readTree (jsonResponse );
143176 JsonNode rows = root .get ("tables" ).get (0 ).get ("rows" );
144177
178+ // First row: null string, 123 int
145179 assertTrue (rows .get (0 ).get (0 ).isNull ());
180+ assertEquals (123 , rows .get (0 ).get (1 ).asInt ());
181+
182+ // Second row: "value" string, null int
183+ assertEquals ("value" , rows .get (1 ).get (0 ).asText ());
146184 assertTrue (rows .get (1 ).get (1 ).isNull ());
147185 }
148186
@@ -162,9 +200,27 @@ public void testParsePaginationLink() throws Exception {
162200 JsonNode nextLink = root .get ("@odata.nextLink" );
163201
164202 assertNotNull (nextLink );
203+ assertTrue (nextLink .asText ().contains ("api.loganalytics.io" ));
165204 assertTrue (nextLink .asText ().contains ("skip=1000" ));
166205 }
167206
207+ @ Test
208+ public void testParseNoPaginationLink () throws Exception {
209+ String jsonResponse = "{\n " +
210+ " \" tables\" : [\n " +
211+ " {\n " +
212+ " \" columns\" : [{\" name\" : \" Col1\" , \" type\" : \" string\" }],\n " +
213+ " \" rows\" : [[\" value1\" ]]\n " +
214+ " }\n " +
215+ " ]\n " +
216+ "}" ;
217+
218+ JsonNode root = mapper .readTree (jsonResponse );
219+ JsonNode nextLink = root .get ("@odata.nextLink" );
220+
221+ assertTrue (nextLink == null || nextLink .isNull ());
222+ }
223+
168224 @ Test
169225 public void testParseLargeNumbers () throws Exception {
170226 String jsonResponse = "{\n " +
@@ -182,6 +238,27 @@ public void testParseLargeNumbers() throws Exception {
182238 assertEquals (9223372036854775807L , value );
183239 }
184240
241+ @ Test
242+ public void testParseNegativeNumbers () throws Exception {
243+ String jsonResponse = "{\n " +
244+ " \" tables\" : [\n " +
245+ " {\n " +
246+ " \" columns\" : [\n " +
247+ " {\" name\" : \" IntVal\" , \" type\" : \" int\" },\n " +
248+ " {\" name\" : \" RealVal\" , \" type\" : \" real\" }\n " +
249+ " ],\n " +
250+ " \" rows\" : [[-42, -3.14]]\n " +
251+ " }\n " +
252+ " ]\n " +
253+ "}" ;
254+
255+ JsonNode root = mapper .readTree (jsonResponse );
256+ JsonNode row = root .get ("tables" ).get (0 ).get ("rows" ).get (0 );
257+
258+ assertEquals (-42 , row .get (0 ).asInt ());
259+ assertTrue (Math .abs (-3.14 - row .get (1 ).asDouble ()) < 0.01 );
260+ }
261+
185262 @ Test
186263 public void testParseDecimalNumbers () throws Exception {
187264 String jsonResponse = "{\n " +
@@ -202,7 +279,40 @@ public void testParseDecimalNumbers() throws Exception {
202279 double realValue = row .get (0 ).asDouble ();
203280 double decimalValue = row .get (1 ).asDouble ();
204281
205- assertEquals (1.5 , realValue , 0.01 );
206- assertEquals (2.7 , decimalValue , 0.01 );
282+ assertTrue (Math .abs (1.5 - realValue ) < 0.01 );
283+ assertTrue (Math .abs (2.7 - decimalValue ) < 0.01 );
284+ }
285+
286+ @ Test
287+ public void testParseMultipleRows () throws Exception {
288+ String jsonResponse = "{\n " +
289+ " \" tables\" : [\n " +
290+ " {\n " +
291+ " \" columns\" : [\n " +
292+ " {\" name\" : \" Name\" , \" type\" : \" string\" },\n " +
293+ " {\" name\" : \" Value\" , \" type\" : \" int\" }\n " +
294+ " ],\n " +
295+ " \" rows\" : [\n " +
296+ " [\" Alert1\" , 10],\n " +
297+ " [\" Alert2\" , 20],\n " +
298+ " [\" Alert3\" , 30]\n " +
299+ " ]\n " +
300+ " }\n " +
301+ " ]\n " +
302+ "}" ;
303+
304+ JsonNode root = mapper .readTree (jsonResponse );
305+ JsonNode rows = root .get ("tables" ).get (0 ).get ("rows" );
306+
307+ assertEquals (3 , rows .size ());
308+
309+ assertEquals ("Alert1" , rows .get (0 ).get (0 ).asText ());
310+ assertEquals (10 , rows .get (0 ).get (1 ).asInt ());
311+
312+ assertEquals ("Alert2" , rows .get (1 ).get (0 ).asText ());
313+ assertEquals (20 , rows .get (1 ).get (1 ).asInt ());
314+
315+ assertEquals ("Alert3" , rows .get (2 ).get (0 ).asText ());
316+ assertEquals (30 , rows .get (2 ).get (1 ).asInt ());
207317 }
208318}
0 commit comments