def help_send_alerts(self, to_list):
        try:
            self.setup(to_list)

            ########################################################################
            # TEST
            ########################################################################
            send_alerts(
                settings=struct.wrap({"param": {"debug": True}}),
                db=self.db
            )

            ########################################################################
            # VERIFY
            ########################################################################
            emails = self.get_new_emails() # id, to, body

            if len(to_list) == 0:
                assert len(emails) == 0
                return

            #VERIFY ONE MAIL SENT
            assert len(emails) == 1
            #VERIFY to MATCHES WHAT WAS PASSED TO THIS FUNCTION
            assert set(emails[0].to) == set(to_list), "mail.delivery not matching what's send"

            #VERIFY last_sent IS WRITTEN
            alert_state = self.db.query("""
                SELECT
                    id
                FROM
                    alerts
                WHERE
                    reason={{reason}} AND
                    last_sent>={{send_time}}
            """, {
                "reason": self.reason,
                "send_time": self.now
            })
            expected_marked = set([d.id for d in self.test_data if CNV.JSON2object(d.details).expect == 'pass'])
            actual_marked = set(Q.select(alert_state, "id"))
            assert expected_marked == actual_marked, expand_template(
                "Expecting only id in {{expected}}, but instead got {{actual}}", {
                    "expected": str(expected_marked),
                    "actual": str(actual_marked)
                })

            #VERIFY BODY HAS THE CORRECT ALERTS
            expecting_alerts = set([d.id for d in map(lambda d: CNV.JSON2object(d.details), self.test_data) if d.expect == 'pass'])
            actual_alerts_sent = set([
                CNV.value2int(between(b, ">>>>", "<<<<"))
                for b in emails[0].body.split(dzAlerts.daemons.alert.SEPARATOR)
                if CNV.value2int(between(b, ">>>>", "<<<<")) != None
            ])
            assert expecting_alerts == actual_alerts_sent
        except Exception, e:
            Log.error("Test failure", e)
示例#2
0
def send_alerts(settings, db):
    """
    BLINDLY SENDS ALERTS FROM THE ALERTS TABLE, ASSUMING ALL HAVE THE SAME STRUCTURE.
    """
    debug = settings.param.debug
    db.debug = debug

    #TODO: REMOVE, LEAVE IN DB
    if db.debug:
        db.execute("update reasons set email_subject={{subject}}, email_template={{template}} where code={{reason}}", {
            "template": CNV.object2JSON(TEMPLATE),
            "subject": CNV.object2JSON(SUBJECT),
            "reason": REASON
        })
        db.flush()

    try:
        new_alerts = db.query("""
            SELECT
                a.id alert_id,
                a.reason,
                r.description,
                a.details,
                a.severity,
                a.confidence,
                a.revision,
                r.email_template,
                r.email_subject
            FROM
                alerts a
            JOIN
                reasons r on r.code = a.reason
            WHERE
                a.last_sent IS NULL AND
                a.status <> 'obsolete' AND
                math.bayesian_add(a.severity, a.confidence) > {{alert_limit}} AND
                a.solution IS NULL AND
                a.reason in {{reasons}} AND
                a.create_time > {{min_time}}
            ORDER BY
                math.bayesian_add(a.severity, a.confidence) DESC,
                json.number(left(details, 65000), "diff_percent") DESC
            LIMIT
                10
        """, {
            "last_sent": datetime.utcnow() - RESEND_AFTER,
            "alert_limit": ALERT_LIMIT - EPSILON,
            "min_time": datetime.utcnow()-LOOK_BACK,
            "reasons": SQL("("+", ".join(db.quote_value(v) for v in SEND_REASONS)+")")
        })

        if not new_alerts:
            if debug:
                Log.note("Nothing important to email")
            return

        for alert in new_alerts:
            #poor souls that signed up for emails
            listeners = ";".join(db.query("SELECT email FROM listeners WHERE reason={{reason}}", {"reason": alert.reason}).email)

            body = [HEADER]
            if alert.confidence >= 1:
                alert.confidence = 0.999999

            alert.details = CNV.JSON2object(alert.details)
            try:
                alert.revision = CNV.JSON2object(alert.revision)
            except Exception, e:
                pass
            alert.score = str(-log(1.0-Math.bayesian_add(alert.severity, alert.confidence), 10))  #SHOW NUMBER OF NINES
            alert.details.url = alert.details.page_url
            example = alert.details.example
            for e in alert.details.tests.example + [example]:
                if e.push_date_min:
                    e.push_date_max = (2 * e.push_date) - e.push_date_min
                    e.date_range = (datetime.utcnow()-CNV.milli2datetime(e.push_date_min)).total_seconds()/(24*60*60)  #REQUIRED FOR DATAZILLA B2G CHART REFERENCE
                    e.date_range = nvl(nvl(*[v for v in (7, 30, 60) if v > e.date_range]), 90)  #PICK FIRST v > CURRENT VALUE

            subject = expand_template(CNV.JSON2object(alert.email_subject), alert)
            body.append(expand_template(CNV.JSON2object(alert.email_template), alert))
            body = "".join(body)+FOOTER

            if debug:
                Log.note("EMAIL: {{email}}", {"email": body})

            if len(body) > MAX_EMAIL_LENGTH:
                Log.note("Truncated the email body")
                suffix = "... (has been truncated)"
                body = body[0:MAX_EMAIL_LENGTH - len(suffix)] + suffix   #keep it reasonable

            db.call("mail.send", (
                listeners, #to
                subject,
                body, #body
                None
            ))

            #I HOPE I CAN SEND ARRAYS OF NUMBERS
            db.execute(
                "UPDATE alerts SET last_sent={{time}} WHERE {{where}}", {
                    "time": datetime.utcnow(),
                    "where": esfilter2sqlwhere(db, {"terms": {"id": Q.select(new_alerts, "alert_id")}})
                })

    except Exception, e:
        Log.error("Could not send alerts", e)