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)
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)