Repository: hyperjumptech/monika
Pull request #1130 (2023-10-03 08:10:34)

Fix: Monika Can not Send Alert to Symon
# Monika Pull Request (PR)

## What feature/issue does this PR add
Fix Monika can not send alert to Symon due to wrong alert ID.

## How did you implement / how did you fix it
1. Add method to get reserved `failed request assertion`
2. Log an error if there is no `failed request assertion`
3. Sanitized probe config to ensure it has failed request assertion (Monika mode)

## How to test
1. Connect Monika to Symon
2. Shutdown the probe target
3. Turn the probe target again

## Video

https://github.com/hyperjumptech/monika/assets/15191978/a35693cb-defc-44b2-913d-fbe970ca714d




codecov[bot]: ## [Codecov](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) Report
> Merging [#1130](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) (d23d999) into [main](https://app.codecov.io/gh/hyperjumptech/monika/commit/d6ae24171bde1aced323d26de075bac0e9bc2c3a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) (d6ae241) will **decrease** coverage by `0.26%`.
> The diff coverage is `78.84%`.

> :exclamation: Current head d23d999 differs from pull request most recent head 5fc465a. Consider uploading reports for the commit 5fc465a to get more accurate results

```diff
@@            Coverage Diff             @@
##             main    #1130      +/-   ##
==========================================
- Coverage   60.80%   60.55%   -0.26%     
==========================================
  Files         111      111              
  Lines        3217     3199      -18     
  Branches      633      630       -3     
==========================================
- Hits         1956     1937      -19     
- Misses        984      994      +10     
+ Partials      277      268       -9     
```


| [Files](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) | Coverage Δ | |
|---|---|---|
| [src/components/probe/prober/http/index.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvcHJvYmUvcHJvYmVyL2h0dHAvaW5kZXgudHM=) | `83.51% <100.00%> (+4.65%)` | :arrow_up: |
| [src/jobs/tls-check.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2pvYnMvdGxzLWNoZWNrLnRz) | `27.27% <ø> (-2.14%)` | :arrow_down: |
| [src/looper/index.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2xvb3Blci9pbmRleC50cw==) | `66.19% <88.88%> (-9.17%)` | :arrow_down: |
| [src/components/probe/prober/index.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvcHJvYmUvcHJvYmVyL2luZGV4LnRz) | `74.22% <61.53%> (-7.92%)` | :arrow_down: |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/hyperjumptech/monika/pull/1130/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech)


Patch:
diff --git a/.mocharc.json b/.mocharc.json
index 75d7db8d..3aa2c2fb 100644
--- a/.mocharc.json
+++ b/.mocharc.json
@@ -1,8 +1,5 @@
 {
   "require": ["ts-node/register"],
-  "watch-extensions": ["ts"],
-  "recursive": true,
-  "reporter": "spec",
   "timeout": 5000,
-  "bail": true
+  "exit": true
 }
diff --git a/src/components/probe/prober/http/index.ts b/src/components/probe/prober/http/index.ts
index 8376c7d0..a619339c 100644
--- a/src/components/probe/prober/http/index.ts
+++ b/src/components/probe/prober/http/index.ts
@@ -22,18 +22,11 @@
  * SOFTWARE.                                                                      *
  **********************************************************************************/
 
-import { v4 as uuid } from 'uuid'
 import { getContext } from '../../../../context'
 import events from '../../../../events'
 import { getEventEmitter } from '../../../../utils/events'
-import { log } from '../../../../utils/pino'
 import { httpRequest } from './request'
-import {
-  BaseProber,
-  NotificationType,
-  ProbeMessage,
-  failedRequestAssertion,
-} from '..'
+import { BaseProber, NotificationType } from '..'
 import {
   type ProbeRequestResponse,
   probeRequestResult,
@@ -45,10 +38,7 @@ import { logResponseTime } from '../../../logger/response-time-log'
 import { saveProbeRequestLog } from '../../../logger/history'
 import type { ValidatedResponse } from '../../../../plugins/validate-response'
 import { isSymonModeFrom } from '../../../config'
-import {
-  startDowntimeCounter,
-  stopDowntimeCounter,
-} from '../../../downtime-counter'
+import { startDowntimeCounter } from '../../../downtime-counter'
 
 type ProbeResultMessageParams = {
   request: RequestConfig
@@ -76,15 +66,23 @@ export class HTTPProber extends BaseProber {
     )
     if (hasFailedRequest) {
       if (this.hasIncident()) {
-        this.printLogMessage(
+        this.logMessage(
           false,
           getErrorMessage(hasFailedRequest.errMessage || 'Unknown error.')
         )
-        throw new Error(ProbeMessage.ProbeNotAccessible)
+        throw new Error('There is an ongoing incident.')
       }
 
-      this.handleFailedRequest(responses)
-      throw new Error(ProbeMessage.ProbeNotAccessible)
+      this.logMessage(
+        false,
+        getErrorMessage(hasFailedRequest.errMessage || 'Unknown error.'),
+        getNotificationMessage({ isIncident: true })
+      )
+
+      this.handleFailedProbe(
+        responses.map((requestResponse) => ({ requestResponse }))
+      )
+      throw new Error('Probe request is failed.')
     }
 
     for (const requestIndex of responses.keys()) {
@@ -101,7 +99,7 @@ export class HTTPProber extends BaseProber {
         const { alert } = triggeredAlertResponse
 
         if (this.hasIncident()) {
-          this.printLogMessage(false, getAssertionMessage(alert.assertion))
+          this.logMessage(false, getAssertionMessage(alert.assertion))
           throw new Error(alert.message)
         }
 
@@ -112,7 +110,10 @@ export class HTTPProber extends BaseProber {
 
     const isRecovery = this.hasIncident()
     if (isRecovery) {
-      this.handleIncidentRecovery(responses)
+      this.logMessage(true, getNotificationMessage({ isIncident: false }))
+      this.handleRecovery(
+        responses.map((requestResponse) => ({ requestResponse }))
+      )
     }
 
     for (const requestIndex of responses.keys()) {
@@ -123,7 +124,7 @@ export class HTTPProber extends BaseProber {
         response,
       })
 
-      this.printLogMessage(
+      this.logMessage(
         true,
         getProbeResultMessage({
           request: requests[requestIndex],
@@ -160,86 +161,6 @@ export class HTTPProber extends BaseProber {
     return result
   }
 
-  private handleFailedRequest(responses: ProbeRequestResponse[]) {
-    const hasFailedRequest = responses.find(
-      ({ result }) => result !== probeRequestResult.success
-    )
-    const requestIndex = responses.findIndex(
-      ({ result }) => result !== probeRequestResult.success
-    )
-
-    getEventEmitter().emit(events.probe.alert.triggered, {
-      probe: this.probeConfig,
-      requestIndex,
-      alertQuery: '',
-    })
-
-    startDowntimeCounter({
-      alert: failedRequestAssertion,
-      probeID: this.probeConfig.id,
-      url: this.probeConfig?.requests?.[requestIndex].url || '',
-    })
-
-    saveProbeRequestLog({
-      probe: this.probeConfig,
-      requestIndex,
-      probeRes: hasFailedRequest!,
-      alertQueries: [failedRequestAssertion.assertion],
-      error: hasFailedRequest!.errMessage,
-    })
-
-    this.sendNotification({
-      requestURL: this.probeConfig?.requests?.[requestIndex].url || '',
-      notificationType: NotificationType.Incident,
-      validation: {
-        alert: failedRequestAssertion,
-        isAlertTriggered: true,
-        response: hasFailedRequest!,
-      },
-    })
-
-    this.printLogMessage(
-      false,
-      getErrorMessage(hasFailedRequest!.errMessage || 'Unknown error.'),
-      getNotificationMessage({ isIncident: true })
-    )
-  }
-
-  private handleIncidentRecovery(responses: ProbeRequestResponse[]) {
-    const recoveredIncident = getContext().incidents.find(
-      (incident) => incident.probeID === this.probeConfig.id
-    )
-    const requestIndex =
-      this.probeConfig?.requests?.findIndex(
-        ({ url }) => url === recoveredIncident?.probeRequestURL
-      ) || 0
-    if (recoveredIncident) {
-      stopDowntimeCounter({
-        alert: recoveredIncident.alert,
-        probeID: this.probeConfig.id,
-        url: this.probeConfig?.requests?.[requestIndex].url || '',
-      })
-      this.sendNotification({
-        requestURL: this.probeConfig?.requests?.[requestIndex].url || '',
-        notificationType: NotificationType.Recover,
-        validation: {
-          alert: recoveredIncident.alert,
-          isAlertTriggered: false,
-          response: responses[requestIndex],
-        },
-      }).catch((error) => log.error(error.mesage))
-
-      this.printLogMessage(true, getNotificationMessage({ isIncident: false }))
-    }
-
-    saveProbeRequestLog({
-      probe: this.probeConfig,
-      requestIndex,
-      probeRes: responses[requestIndex],
-      alertQueries: [recoveredIncident?.alert.assertion || ''],
-    })
-  }
-
   private handleAssertionFailed(
     response: ProbeRequestResponse,
     requestIndex: number,
@@ -267,7 +188,7 @@ export class HTTPProber extends BaseProber {
       },
     })
 
-    this.printLogMessage(
+    this.logMessage(
       false,
       getAssertionMessage(triggeredAlert.assertion),
       getNotificationMessage({ isIncident: true })
@@ -291,21 +212,16 @@ export class HTTPProber extends BaseProber {
   }
 
   private generateAlertMessage(): string {
-    const hasAlert = this.probeConfig.alerts.length > 0
-    const defaultAlertsInString = JSON.stringify(getDefaultAlerts())
     const alertsInString = JSON.stringify(this.probeConfig.alerts)
 
-    return `    Alerts: ${hasAlert ? alertsInString : defaultAlertsInString}\n`
+    return `    Alerts: ${alertsInString}\n`
   }
 
   private validateResponse(
     response: ProbeRequestResponse,
-    additionalAssertions?: ProbeAlert[]
+    additionalAssertions: ProbeAlert[]
   ): ValidatedResponse[] {
-    const assertions: ProbeAlert[] = [
-      ...(this.probeConfig.alerts || getDefaultAlerts()),
-      ...(additionalAssertions || []),
-    ]
+    const assertions = [...this.probeConfig.alerts, ...additionalAssertions]
 
     return assertions.map((assertion) => ({
       alert: assertion,
@@ -313,23 +229,6 @@ export class HTTPProber extends BaseProber {
       response,
     }))
   }
-
-  private printLogMessage(isSuccess: boolean, ...message: string[]): void {
-    if (isSuccess) {
-      log.info(
-        `${this.getMessagePrefix()} ${message.filter(Boolean).join(', ')}`
-      )
-      return
-    }
-
-    log.warn(`${this.getMessagePrefix()} ${message.filter(Boolean).join(', ')}`)
-  }
-
-  private getMessagePrefix() {
-    return `${new Date().toISOString()} ${this.counter} id:${
-      this.probeConfig.id
-    }`
-  }
 }
 
 function getProbeResultMessage({
@@ -370,19 +269,3 @@ function getNotificationMessage({
 }): string {
   return `NOTIF: ${isIncident ? 'Service probably down' : 'Service is back up'}`
 }
-
-function getDefaultAlerts(): ProbeAlert[] {
-  return [
-    {
-      id: uuid(),
-      assertion: 'response.status < 200 or response.status > 299',
-      message: 'HTTP Status is {{ response.status }}, expecting 200',
-    },
-    {
-      id: uuid(),
-      assertion: 'response.time > 2000',
-      message:
-        'Response time is {{ response.time }}ms, expecting less than 2000ms',
-    },
-  ]
-}
diff --git a/src/components/probe/prober/index.ts b/src/components/probe/prober/index.ts
index 3e028fd2..e7951ae9 100644
--- a/src/components/probe/prober/index.ts
+++ b/src/components/probe/prober/index.ts
@@ -23,7 +23,6 @@
  **********************************************************************************/
 
 import type { Notification } from '@hyperjumptech/monika-notification'
-import { v4 as uuid } from 'uuid'
 import { type Incident, getContext } from '../../../context'
 import events from '../../../events'
 import type { Probe, ProbeAlert } from '../../../interfaces/probe'
@@ -42,6 +41,7 @@ import {
   startDowntimeCounter,
   stopDowntimeCounter,
 } from '../../downtime-counter'
+import { FAILED_REQUEST_ASSERTION } from '../../../looper'
 
 export type ProbeResult = {
   isAlertTriggered: boolean
@@ -76,17 +76,6 @@ enum ProbeState {
   Down = 'DOWN',
 }
 
-export enum ProbeMessage {
-  ProbeNotAccessible = 'Probe not accessible',
-  ProbeAccessibleAgain = 'Probe accessible again',
-}
-
-export const failedRequestAssertion: ProbeAlert = {
-  id: uuid(),
-  assertion: '',
-  message: ProbeMessage.ProbeNotAccessible,
-}
-
 export class BaseProber implements Prober {
   protected readonly counter: number
   protected readonly notifications: Notification[]
@@ -107,8 +96,8 @@ export class BaseProber implements Prober {
   }
 
   protected processProbeResults(probeResults: ProbeResult[]): void {
-    for (const probeResult of probeResults) {
-      logMessage(probeResult)
+    for (const { isAlertTriggered, logMessage } of probeResults) {
+      this.logMessage(isAlertTriggered, logMessage)
     }
 
     if (
@@ -118,11 +107,11 @@ export class BaseProber implements Prober {
       )
     ) {
       if (this.hasIncident()) {
-        throw new Error(ProbeMessage.ProbeNotAccessible)
+        throw new Error('There is an ongoing incident.')
       }
 
       this.handleFailedProbe(probeResults)
-      throw new Error(ProbeMessage.ProbeNotAccessible)
+      throw new Error('Probe request is failed.')
     }
 
     if (this.hasIncident()) {
@@ -151,6 +140,38 @@ export class BaseProber implements Prober {
     }
   }
 
+  protected getFailedRequestAssertion(
+    requestIndex?: number
+  ): ProbeAlert | undefined {
+    const getFailedRequestAssertionFromProbe = (): ProbeAlert | undefined =>
+      this.probeConfig.alerts.find(
+        ({ assertion, message }) =>
+          assertion === FAILED_REQUEST_ASSERTION.assertion &&
+          message === FAILED_REQUEST_ASSERTION.message
+      )
+    const getFailedRequestAssertionFromRequests = (
+      requestIndex?: number
+    ): ProbeAlert | undefined => {
+      if (
+        this.probeConfig.requests === undefined ||
+        requestIndex === undefined
+      ) {
+        return undefined
+      }
+
+      return (this.probeConfig.requests[requestIndex].alerts || []).find(
+        ({ assertion, message }) =>
+          assertion === FAILED_REQUEST_ASSERTION.assertion &&
+          message === FAILED_REQUEST_ASSERTION.message
+      )
+    }
+
+    return (
+      getFailedRequestAssertionFromProbe() ||
+      getFailedRequestAssertionFromRequests(requestIndex)
+    )
+  }
+
   protected hasIncident(): Incident | undefined {
     return getContext().incidents.find(
       (incident) => incident.probeID === this.probeConfig.id
@@ -197,7 +218,9 @@ export class BaseProber implements Prober {
     )
   }
 
-  private handleFailedProbe(probeResults: ProbeResult[]) {
+  protected handleFailedProbe(
+    probeResults: Pick<ProbeResult, 'requestResponse'>[]
+  ): void {
     const hasfailedProbe = probeResults.find(
       ({ requestResponse }) =>
         requestResponse.result !== probeRequestResult.success
@@ -207,6 +230,12 @@ export class BaseProber implements Prober {
       ({ requestResponse }) =>
         requestResponse.result !== probeRequestResult.success
     )
+    const failedRequestAssertion = this.getFailedRequestAssertion(requestIndex)
+
+    if (!failedRequestAssertion) {
+      log.error('Failed request assertion is not found')
+      return
+    }
 
     getEventEmitter().emit(events.probe.alert.triggered, {
       probe: this.probeConfig,
@@ -239,7 +268,9 @@ export class BaseProber implements Prober {
     }).catch((error) => log.error(error.mesage))
   }
 
-  private handleRecovery(probeResults: ProbeResult[]) {
+  protected handleRecovery(
+    probeResults: Pick<ProbeResult, 'requestResponse'>[]
+  ): void {
     const recoveredIncident = getContext().incidents.find(
       (incident) => incident.probeID === this.probeConfig.id
     )
@@ -259,7 +290,7 @@ export class BaseProber implements Prober {
         requestURL: this.probeConfig?.requests?.[requestIndex].url || '',
         notificationType: NotificationType.Recover,
         validation: {
-          alert: failedRequestAssertion,
+          alert: recoveredIncident.alert,
           isAlertTriggered: false,
           response: probeResults[requestIndex].requestResponse,
         },
@@ -270,20 +301,28 @@ export class BaseProber implements Prober {
       probe: this.probeConfig,
       requestIndex,
       probeRes: probeResults[requestIndex].requestResponse,
-      alertQueries: [failedRequestAssertion.assertion],
+      alertQueries: [recoveredIncident?.alert.assertion || ''],
     })
   }
 
+  protected logMessage(isSuccess: boolean, ...message: string[]): void {
+    if (isSuccess) {
+      log.info(
+        `${this.getMessagePrefix()} ${message.filter(Boolean).join(', ')}`
+      )
+      return
+    }
+
+    log.warn(`${this.getMessagePrefix()} ${message.filter(Boolean).join(', ')}`)
+  }
+
   private hasNotification() {
     return this.notifications.length > 0
   }
-}
 
-function logMessage({ isAlertTriggered, logMessage }: ProbeResult): void {
-  if (isAlertTriggered) {
-    log.warn(logMessage)
-    return
+  private getMessagePrefix() {
+    return `${new Date().toISOString()} ${this.counter} id:${
+      this.probeConfig.id
+    }`
   }
-
-  log.info(logMessage)
 }
diff --git a/src/jobs/tls-check.ts b/src/jobs/tls-check.ts
index ec573b6a..34bddf44 100644
--- a/src/jobs/tls-check.ts
+++ b/src/jobs/tls-check.ts
@@ -22,7 +22,6 @@
  * SOFTWARE.                                                                      *
  **********************************************************************************/
 
-import { v4 as uuid } from 'uuid'
 import { getConfig } from '../components/config'
 import { saveNotificationLog } from '../components/logger/history'
 import { sendAlerts } from '../components/notification'
@@ -94,7 +93,7 @@ function sendTLSErrorNotification({
     // validation is used because it is needed to send alert
     const validation: ValidatedResponse = {
       alert: {
-        id: uuid(),
+        id: '',
         assertion: '',
         message: errorMessage,
       },
diff --git a/src/looper/index.ts b/src/looper/index.ts
index df39b9f8..7f912309 100644
--- a/src/looper/index.ts
+++ b/src/looper/index.ts
@@ -91,34 +91,30 @@ function sanitizeAlerts({
   }
 
   if (alerts === undefined || alerts.length === 0) {
-    return getDefaultAlerts(isHTTPProbe)
+    return addFailedRequestAssertions(getDefaultAlerts(isHTTPProbe))
   }
 
-  return alerts.map((alert) => {
-    if (alert.query) {
-      return { ...alert, assertion: alert.query }
-    }
+  return addFailedRequestAssertions(
+    alerts.map((alert) => {
+      if (alert.query !== undefined) {
+        return { ...alert, assertion: alert.query }
+      }
 
-    return alert
-  })
+      return alert
+    })
+  )
 }
 
 function getDefaultAlerts(isHTTPProbe: boolean): ProbeAlert[] {
   if (!isHTTPProbe) {
-    return [
-      {
-        id: uuid(),
-        assertion: '',
-        message: 'Probe is not accesible',
-      },
-    ]
+    return []
   }
 
   return [
     {
       id: uuid(),
       assertion: 'response.status < 200 or response.status > 299',
-      message: 'HTTP Status is {{ response.status }}, expecting 200',
+      message: 'HTTP Status is {{ response.status }}, expecting 2xx',
     },
     {
       id: uuid(),
@@ -129,12 +125,27 @@ function getDefaultAlerts(isHTTPProbe: boolean): ProbeAlert[] {
   ]
 }
 
+export const FAILED_REQUEST_ASSERTION = {
+  assertion: '',
+  message: 'Probe not accessible',
+}
+
+function addFailedRequestAssertions(assertions: ProbeAlert[]) {
+  return [
+    ...assertions,
+    {
+      id: uuid(),
+      ...FAILED_REQUEST_ASSERTION,
+    },
+  ]
+}
+
 function sanitizeRequests(requests?: RequestConfig[]) {
   return requests?.map((request) => ({
     ...request,
     method: request.method || 'GET',
     alerts: request.alerts?.map((alert) => {
-      if (alert.query) {
+      if (alert.query !== undefined) {
         return { ...alert, assertion: alert.query }
       }
 
diff --git a/src/symon/bree/report.ts b/src/symon/bree/report.ts
index 279426fa..680e1b64 100644
--- a/src/symon/bree/report.ts
+++ b/src/symon/bree/report.ts
@@ -79,7 +79,6 @@ const main = async (data: Record<string, any>) => {
           },
         },
         headers: {
-          'Content-Encoding': 'gzip',
           'Content-Type': 'application/json',
           'x-api-key': apiKey,
         },


Test patch:
diff --git a/src/components/logger/startup-message.test.ts b/src/components/logger/startup-message.test.ts
index 848fa692..bc292c15 100644
--- a/src/components/logger/startup-message.test.ts
+++ b/src/components/logger/startup-message.test.ts
@@ -39,7 +39,13 @@ const defaultConfig: Config = {
       requests: [
         { url: 'https://example.com', headers: {}, body: '', timeout: 0 },
       ],
-      alerts: [],
+      alerts: [
+        {
+          assertion: 'response.status < 200 or response.status > 299',
+          id: '0BGKU',
+          message: 'HTTP Status is {{ response.status }}, expecting 2xx',
+        },
+      ],
     },
   ],
   notifications: [{ id: 'UVIsL', type: 'desktop', data: undefined }],
diff --git a/src/components/probe/index.test.ts b/src/components/probe/index.test.ts
index 0d1d0ce9..9bdb0728 100644
--- a/src/components/probe/index.test.ts
+++ b/src/components/probe/index.test.ts
@@ -39,6 +39,7 @@ import type { Probe } from '../../interfaces/probe'
 import { afterEach, beforeEach } from 'mocha'
 import { getContext, resetContext, setContext } from '../../context'
 import type { MonikaFlags } from '../../context/monika-flags'
+import { FAILED_REQUEST_ASSERTION } from '../../looper'
 
 let urlRequestTotal = 0
 let notificationAlert: Record<string, Record<string, any>> = {}
@@ -181,6 +182,10 @@ describe('Probe processing', () => {
           },
         ],
         alerts: [
+          {
+            id: 'Cqkjh',
+            ...FAILED_REQUEST_ASSERTION,
+          },
           {
             id: 'fKBzx',
             assertion: 'response.status == 200',
@@ -373,6 +378,12 @@ describe('Probe processing', () => {
             database: '',
           },
         ],
+        alerts: [
+          {
+            id: 'Cqkjh',
+            ...FAILED_REQUEST_ASSERTION,
+          },
+        ],
       } as Probe
       initializeProbeStates([probe])
       // wait until the interval passed
@@ -424,6 +435,12 @@ describe('Probe processing', () => {
             database: '',
           },
         ],
+        alerts: [
+          {
+            id: 'Cqkjh',
+            ...FAILED_REQUEST_ASSERTION,
+          },
+        ],
       } as Probe
       initializeProbeStates([probe])
       // wait until the interval passed
diff --git a/src/looper/index.test.ts b/src/looper/index.test.ts
index aac48374..d5f5614a 100644
--- a/src/looper/index.test.ts
+++ b/src/looper/index.test.ts
@@ -23,7 +23,7 @@
  **********************************************************************************/
 
 import { expect } from '@oclif/test'
-import { sanitizeProbe } from '.'
+import { FAILED_REQUEST_ASSERTION, sanitizeProbe } from '.'
 import type { Probe } from '../interfaces/probe'
 
 describe('Looper', () => {
@@ -111,7 +111,7 @@ describe('Looper', () => {
         'response.status < 200 or response.status > 299'
       )
       expect(result.alerts[0].message).eq(
-        'HTTP Status is {{ response.status }}, expecting 200'
+        'HTTP Status is {{ response.status }}, expecting 2xx'
       )
       expect(result.alerts[1].assertion).eq('response.time > 2000')
       expect(result.alerts[1].message).eq(
@@ -130,7 +130,7 @@ describe('Looper', () => {
 
       // assert
       expect(result.alerts[0].assertion).eq('')
-      expect(result.alerts[0].message).eq('Probe is not accesible')
+      expect(result.alerts[0].message).eq(FAILED_REQUEST_ASSERTION.message)
     })
 
     it('should remove alerts on Symon mode', () => {