Openstatus www.openstatus.dev

๐Ÿค— Some test should fail ๐Ÿค— (#1281)

* ๐Ÿค—

* ci: apply automated fixes

* ๐Ÿค—

* ci: apply automated fixes

* ๐Ÿš€

* ci: apply automated fixes

* ๐Ÿ˜ญ

* ci: apply automated fixes

* ๐Ÿ˜ญ

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

authored by

Thibault Le Ouay
autofix-ci[bot]
and committed by
GitHub
51c97cc4 b79b2068

+155 -57
+1 -1
apps/checker/handlers/ping.go
··· 146 146 return nil 147 147 } 148 148 if err := backoff.Retry(op, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3)); err != nil { 149 - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"}) 149 + c.JSON(http.StatusOK, gin.H{"message": "url not reachable"}) 150 150 151 151 return 152 152 }
+1 -1
apps/checker/handlers/tcp.go
··· 331 331 } 332 332 333 333 if err := backoff.Retry(op, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3)); err != nil { 334 - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"}) 334 + c.JSON(http.StatusOK, gin.H{"message": "uri not reachable"}) 335 335 336 336 return 337 337 }
+8
apps/web/src/app/api/checker/test/tcp/schema.ts
··· 26 26 latency: z.number().optional(), 27 27 }); 28 28 29 + export const TCPResponseTest = TCPResponse.extend({ 30 + state: z.literal("success").default("success"), 31 + }).or( 32 + z.object({ 33 + type: z.literal("tcp").default("tcp"), 34 + state: z.literal("error").default("error"), 35 + }), 36 + ); 29 37 export type tcpPayload = z.infer<typeof tcpPayload>;
+21 -17
apps/web/src/app/play/checker/_components/checker-form.tsx
··· 172 172 setResult(currentResult); 173 173 174 174 if (_result) { 175 - toast.loading( 176 - `Checking ${regionFormatter(_result[0].region, "long")} (${latencyFormatter(_result[0].latency)})`, 177 - { 178 - id: toastId, 179 - }, 180 - ); 175 + if (_result[0].state === "success") { 176 + toast.loading( 177 + `Checking ${regionFormatter(_result[0].region, "long")} (${latencyFormatter(_result[0].latency)})`, 178 + { 179 + id: toastId, 180 + }, 181 + ); 182 + } 181 183 } 182 184 } 183 185 } ··· 360 362 </TableHeader> 361 363 <TableBody> 362 364 {result.length > 0 ? ( 363 - result.map((item) => ( 364 - <TableRow key={item.region}> 365 - <TableCell className="flex items-center gap-2 font-medium"> 366 - {regionFormatter(item.region, "long")} 367 - <StatusDot value={item.status} /> 368 - </TableCell> 369 - <TableCell className="text-right"> 370 - {latencyFormatter(item.latency)} 371 - </TableCell> 372 - </TableRow> 373 - )) 365 + result 366 + .filter((item) => item.state === "success") 367 + .map((item) => ( 368 + <TableRow key={item.region}> 369 + <TableCell className="flex items-center gap-2 font-medium"> 370 + {regionFormatter(item.region, "long")} 371 + <StatusDot value={item.status} /> 372 + </TableCell> 373 + <TableCell className="text-right"> 374 + {latencyFormatter(item.latency)} 375 + </TableCell> 376 + </TableRow> 377 + )) 374 378 ) : ( 375 379 <TableRow> 376 380 <TableCell
+71 -1
apps/web/src/app/play/checker/api/mock.ts
··· 3 3 import type { Region } from "@openstatus/db/src/schema/constants"; 4 4 5 5 export async function mockCheckRegion(region: Region) { 6 - const response = data.checks.find((check) => check.region === region); 6 + const response = data.checks 7 + .filter((i) => i.state === "success") 8 + .find((check) => check.region === region); 7 9 8 10 if (!response) { 9 11 throw new Error("Region not found"); ··· 58 60 { 59 61 type: "http", 60 62 status: 200, 63 + state: "success", 64 + 61 65 latency: 1602, 62 66 headers: { 63 67 Age: "0", ··· 95 99 { 96 100 type: "http", 97 101 status: 200, 102 + state: "success", 103 + 98 104 latency: 823, 99 105 headers: { 100 106 Age: "0", ··· 131 137 }, 132 138 { 133 139 type: "http", 140 + state: "success", 141 + 134 142 status: 200, 135 143 latency: 1198, 136 144 headers: { ··· 168 176 }, 169 177 { 170 178 type: "http", 179 + state: "success", 180 + 171 181 status: 200, 172 182 latency: 1423, 173 183 headers: { ··· 205 215 }, 206 216 { 207 217 type: "http", 218 + state: "success", 219 + 208 220 status: 200, 209 221 latency: 1134, 210 222 headers: { ··· 242 254 }, 243 255 { 244 256 type: "http", 257 + state: "success", 258 + 245 259 status: 200, 246 260 latency: 812, 247 261 headers: { ··· 279 293 }, 280 294 { 281 295 type: "http", 296 + state: "success", 297 + 282 298 status: 200, 283 299 latency: 1081, 284 300 headers: { ··· 316 332 }, 317 333 { 318 334 type: "http", 335 + state: "success", 336 + 319 337 status: 200, 320 338 latency: 1329, 321 339 headers: { ··· 353 371 }, 354 372 { 355 373 type: "http", 374 + state: "success", 375 + 356 376 status: 200, 357 377 latency: 380, 358 378 headers: { ··· 390 410 }, 391 411 { 392 412 type: "http", 413 + state: "success", 414 + 393 415 status: 200, 394 416 latency: 802, 395 417 headers: { ··· 427 449 }, 428 450 { 429 451 type: "http", 452 + state: "success", 453 + 430 454 status: 200, 431 455 latency: 615, 432 456 headers: { ··· 463 487 }, 464 488 { 465 489 type: "http", 490 + state: "success", 491 + 466 492 status: 200, 467 493 latency: 1481, 468 494 headers: { ··· 500 526 }, 501 527 { 502 528 type: "http", 529 + state: "success", 530 + 503 531 status: 200, 504 532 latency: 768, 505 533 headers: { ··· 537 565 }, 538 566 { 539 567 type: "http", 568 + state: "success", 569 + 540 570 status: 200, 541 571 latency: 662, 542 572 headers: { ··· 574 604 }, 575 605 { 576 606 type: "http", 607 + state: "success", 608 + 577 609 status: 200, 578 610 latency: 1543, 579 611 headers: { ··· 611 643 }, 612 644 { 613 645 type: "http", 646 + state: "success", 647 + 614 648 status: 200, 615 649 latency: 369, 616 650 headers: { ··· 648 682 }, 649 683 { 650 684 type: "http", 685 + state: "success", 686 + 651 687 status: 200, 652 688 latency: 1264, 653 689 headers: { ··· 685 721 }, 686 722 { 687 723 type: "http", 724 + state: "success", 725 + 688 726 status: 200, 689 727 latency: 642, 690 728 headers: { ··· 722 760 }, 723 761 { 724 762 type: "http", 763 + state: "success", 764 + 725 765 status: 200, 726 766 latency: 627, 727 767 headers: { ··· 759 799 }, 760 800 { 761 801 type: "http", 802 + state: "success", 803 + 762 804 status: 200, 763 805 latency: 951, 764 806 headers: { ··· 796 838 }, 797 839 { 798 840 type: "http", 841 + state: "success", 842 + 799 843 status: 200, 800 844 latency: 808, 801 845 headers: { ··· 833 877 }, 834 878 { 835 879 type: "http", 880 + state: "success", 881 + 836 882 status: 200, 837 883 latency: 1301, 838 884 headers: { ··· 870 916 }, 871 917 { 872 918 type: "http", 919 + state: "success", 920 + 873 921 status: 200, 874 922 latency: 1079, 875 923 headers: { ··· 907 955 }, 908 956 { 909 957 type: "http", 958 + state: "success", 959 + 910 960 status: 200, 911 961 latency: 1349, 912 962 headers: { ··· 943 993 }, 944 994 { 945 995 type: "http", 996 + state: "success", 997 + 946 998 status: 200, 947 999 latency: 970, 948 1000 headers: { ··· 980 1032 }, 981 1033 { 982 1034 type: "http", 1035 + state: "success", 1036 + 983 1037 status: 200, 984 1038 latency: 1539, 985 1039 headers: { ··· 1017 1071 }, 1018 1072 { 1019 1073 type: "http", 1074 + state: "success", 1075 + 1020 1076 status: 200, 1021 1077 latency: 1347, 1022 1078 headers: { ··· 1054 1110 }, 1055 1111 { 1056 1112 type: "http", 1113 + state: "success", 1114 + 1057 1115 status: 200, 1058 1116 latency: 400, 1059 1117 headers: { ··· 1091 1149 }, 1092 1150 { 1093 1151 type: "http", 1152 + state: "success", 1153 + 1094 1154 status: 200, 1095 1155 latency: 883, 1096 1156 headers: { ··· 1128 1188 }, 1129 1189 { 1130 1190 type: "http", 1191 + state: "success", 1192 + 1131 1193 status: 200, 1132 1194 latency: 825, 1133 1195 headers: { ··· 1165 1227 }, 1166 1228 { 1167 1229 type: "http", 1230 + state: "success", 1231 + 1168 1232 status: 200, 1169 1233 latency: 526, 1170 1234 headers: { ··· 1202 1266 }, 1203 1267 { 1204 1268 type: "http", 1269 + state: "success", 1270 + 1205 1271 status: 200, 1206 1272 latency: 869, 1207 1273 headers: { ··· 1238 1304 }, 1239 1305 { 1240 1306 type: "http", 1307 + state: "success", 1308 + 1241 1309 status: 200, 1242 1310 latency: 1133, 1243 1311 headers: { ··· 1275 1343 }, 1276 1344 { 1277 1345 type: "http", 1346 + state: "success", 1347 + 1278 1348 status: 200, 1279 1349 latency: 447, 1280 1350 headers: {
+3 -1
apps/web/src/app/play/checker/api/route.ts
··· 31 31 check.body = undefined; // Drop the body to avoid storing it in Redis Cache 32 32 } 33 33 34 - storeCheckerData({ check, id }); 34 + if (check.state === "success") { 35 + storeCheckerData({ check, id }); 36 + } 35 37 36 38 return encoder.encode( 37 39 `${JSON.stringify({
+5 -4
apps/web/src/components/data-table/monitor/data-table-row-actions.tsx
··· 31 31 import { toast, toastAction } from "@/lib/toast"; 32 32 import { api } from "@/trpc/client"; 33 33 34 - import type { TCPResponse } from "@/app/api/checker/test/tcp/schema"; 34 + import type { TCPResponseTest } from "@/app/api/checker/test/tcp/schema"; 35 35 import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"; 36 36 37 37 interface DataTableRowActionsProps<TData> { ··· 79 79 }); 80 80 const data = (await res.json()) as 81 81 | RegionChecker 82 - | z.infer<typeof TCPResponse>; 82 + | z.infer<typeof TCPResponseTest>; 83 83 84 84 // FIXME: assertions 85 + // it's getting ๐Ÿ˜ญ 85 86 const success = 86 - data.type === "http" 87 + data.state === "success" && data.type === "http" 87 88 ? data.status >= 200 && data.status < 300 88 - : !data.error; 89 + : data.state === "success" && data.type === "tcp" && !data.error; 89 90 90 91 if (success) { 91 92 toastAction("test-success");
+20 -17
apps/web/src/components/forms/monitor/form.tsx
··· 229 229 const _headers: Record<string, string> = {}; 230 230 // biome-ignore lint/suspicious/noAssignInExpressions: <explanation> 231 231 res.headers.forEach((value, key) => (_headers[key] = value)); 232 - 233 - if (as.length > 0) { 234 - for (const a of as) { 235 - const { success, message } = a.assert({ 236 - body: data.body ?? "", 237 - header: data.headers ?? {}, 238 - status: data.status, 239 - }); 240 - if (!success) { 241 - return { data, error: `Assertion error: ${message}` }; 232 + if (data.state === "success") { 233 + if (as.length > 0) { 234 + for (const a of as) { 235 + const { success, message } = a.assert({ 236 + body: data.body ?? "", 237 + header: data.headers ?? {}, 238 + status: data.status, 239 + }); 240 + if (!success) { 241 + return { data, error: `Assertion error: ${message}` }; 242 + } 243 + } 244 + } else { 245 + // default assertion if no assertions are provided 246 + if (res.status < 200 || res.status >= 300) { 247 + return { 248 + data, 249 + error: `Assertion error: The response status was not 2XX: ${data.status}.`, 250 + }; 242 251 } 243 252 } 244 253 } else { 245 - // default assertion if no assertions are provided 246 - if (res.status < 200 || res.status >= 300) { 247 - return { 248 - data, 249 - error: `Assertion error: The response status was not 2XX: ${data.status}.`, 250 - }; 251 - } 254 + return { data, error: `Request error: ${data}` }; 252 255 } 253 256 254 257 return { data, error: undefined };
+2 -2
apps/web/src/components/forms/monitor/request-test-button.tsx
··· 135 135 <DialogHeader> 136 136 <DialogTitle>Response</DialogTitle> 137 137 </DialogHeader> 138 - {check ? ( 138 + {check?.data.state === "success" ? ( 139 139 <div className="grid gap-8"> 140 140 <RegionInfo check={check.data} error={check.error} /> 141 - {check.data.type === "http" ? ( 141 + {check.data.state === "success" && check.data.type === "http" ? ( 142 142 <ResponseDetailTabs 143 143 timing={check.data.timing} 144 144 headers={check.data.headers}
+2 -8
apps/web/src/components/ping-response-analysis/columns.tsx
··· 1 1 "use client"; 2 2 3 3 import type { ColumnDef } from "@tanstack/react-table"; 4 - import { 5 - type RegionChecker, 6 - continentFormatter, 7 - latencyFormatter, 8 - regionFormatter, 9 - } from "./utils"; 4 + import { type RegionChecker, latencyFormatter, regionFormatter } from "./utils"; 10 5 11 6 import { flyRegionsDict } from "@openstatus/utils"; 12 - import { format } from "date-fns"; 13 - import { utcToZonedTime } from "date-fns-tz"; 7 + 14 8 import { DataTableColumnHeader } from "../data-table/data-table-column-header"; 15 9 import { StatusCodeBadge } from "../monitor/status-code-badge"; 16 10
+21 -5
apps/web/src/components/ping-response-analysis/utils.ts
··· 101 101 102 102 export const checkerSchema = z.object({ 103 103 type: z.literal("http").default("http"), 104 + state: z.literal("success").default("success"), 104 105 status: z.number(), 105 106 latency: z.number(), 106 107 headers: z.record(z.string()), ··· 116 117 checks: checkerSchema.extend({ region: monitorFlyRegionSchema }).array(), 117 118 }); 118 119 120 + const errorRequest = z.object({ 121 + message: z.string(), 122 + state: z.literal("error").default("error"), 123 + }); 124 + 119 125 export const regionCheckerSchema = checkerSchema.extend({ 120 126 region: monitorFlyRegionSchema, 127 + state: z.literal("success").default("success"), 121 128 }); 122 129 130 + export const regionCheckerSchemaResponse = regionCheckerSchema.or( 131 + errorRequest.extend({ 132 + region: monitorFlyRegionSchema, 133 + }), 134 + ); 123 135 export type Timing = z.infer<typeof timingSchema>; 124 136 export type Checker = z.infer<typeof checkerSchema>; 125 137 // FIXME: does not include TCP! 126 138 export type RegionChecker = z.infer<typeof regionCheckerSchema>; 139 + export type RegionCheckerResponse = z.infer<typeof regionCheckerSchemaResponse>; 127 140 export type Method = 128 141 | "GET" 129 142 | "HEAD" ··· 136 149 | "TRACE"; 137 150 export type CachedRegionChecker = z.infer<typeof cachedCheckerSchema>; 138 151 152 + export type ErrorRequest = z.infer<typeof errorRequest>; 139 153 export async function checkRegion( 140 154 url: string, 141 155 region: MonitorFlyRegion, ··· 144 158 headers?: { value: string; key: string }[]; 145 159 body?: string; 146 160 }, 147 - ): Promise<RegionChecker> { 161 + ): Promise<RegionCheckerResponse> { 148 162 // 149 163 const res = await fetch(`https://checker.openstatus.dev/ping/${region}`, { 150 164 headers: { ··· 172 186 173 187 const json = await res.json(); 174 188 175 - const data = checkerSchema.safeParse(json); 189 + const data = checkerSchema.or(errorRequest).safeParse(json); 176 190 177 191 if (!data.success) { 178 - console.error(res); 192 + console.error(JSON.stringify(res)); 179 193 console.error(JSON.stringify(json)); 180 194 console.error( 181 195 `something went wrong with request to ${url} error ${data.error.message}`, ··· 197 211 return await Promise.all( 198 212 flyRegions.map(async (region) => { 199 213 const check = await checkRegion(url, region, opts); 200 - // REMINDER: dropping the body to avoid storing it within Redis Cache (Err max request size exceeded) 201 - check.body = undefined; 214 + if (check.state === "success") { 215 + // REMINDER: dropping the body to avoid storing it within Redis Cache (Err max request size exceeded) 216 + check.body = undefined; 217 + } 202 218 return check; 203 219 }), 204 220 );