2020-02-12 12:41:29 +00:00
package main
import (
2020-06-20 23:07:59 +00:00
"testing"
2020-02-12 12:41:29 +00:00
"github.com/prometheus/client_golang/prometheus"
io_prometheus_client "github.com/prometheus/client_model/go"
"github.com/stretchr/testify/assert"
)
func TestPostfixExporter_CollectFromLogline ( t * testing . T ) {
type fields struct {
showqPath string
2020-06-20 23:07:59 +00:00
logSrc LogSource
2020-02-12 12:41:29 +00:00
cleanupProcesses prometheus . Counter
cleanupRejects prometheus . Counter
cleanupNotAccepted prometheus . Counter
lmtpDelays * prometheus . HistogramVec
pipeDelays * prometheus . HistogramVec
qmgrInsertsNrcpt prometheus . Histogram
qmgrInsertsSize prometheus . Histogram
qmgrRemoves prometheus . Counter
2021-04-14 08:52:11 +00:00
qmgrExpires prometheus . Counter
2020-02-12 12:41:29 +00:00
smtpDelays * prometheus . HistogramVec
smtpTLSConnects * prometheus . CounterVec
smtpDeferreds prometheus . Counter
2021-04-07 13:21:26 +00:00
smtpStatusDeferred prometheus . Counter
smtpProcesses * prometheus . CounterVec
2020-02-12 12:41:29 +00:00
smtpdConnects prometheus . Counter
smtpdDisconnects prometheus . Counter
smtpdFCrDNSErrors prometheus . Counter
smtpdLostConnections * prometheus . CounterVec
smtpdProcesses * prometheus . CounterVec
smtpdRejects * prometheus . CounterVec
smtpdSASLAuthenticationFailures prometheus . Counter
smtpdTLSConnects * prometheus . CounterVec
2021-04-07 13:31:44 +00:00
bounceNonDelivery prometheus . Counter
2021-04-07 13:41:26 +00:00
virtualDelivered prometheus . Counter
2020-02-12 12:41:29 +00:00
unsupportedLogEntries * prometheus . CounterVec
}
type args struct {
2020-02-23 19:41:35 +00:00
line [ ] string
removedCount int
2021-04-14 08:52:11 +00:00
expiredCount int
2020-02-23 19:41:35 +00:00
saslFailedCount int
outgoingTLS int
smtpdMessagesProcessed int
2021-04-07 13:21:26 +00:00
smtpMessagesProcessed int
2021-04-07 13:31:44 +00:00
bounceNonDelivery int
2021-04-07 13:41:26 +00:00
virtualDelivered int
2021-04-14 10:40:02 +00:00
unsupportedLogEntries [ ] string
2020-02-12 12:41:29 +00:00
}
tests := [ ] struct {
name string
fields fields
args args
} {
{
name : "Single line" ,
args : args {
line : [ ] string {
"Feb 11 16:49:24 letterman postfix/qmgr[8204]: AAB4D259B1: removed" ,
} ,
2020-02-22 16:06:44 +00:00
removedCount : 1 ,
saslFailedCount : 0 ,
} ,
fields : fields {
2020-02-23 19:41:35 +00:00
qmgrRemoves : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
2021-04-14 10:40:02 +00:00
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
2020-02-12 12:41:29 +00:00
} ,
} ,
{
name : "Multiple lines" ,
args : args {
line : [ ] string {
"Feb 11 16:49:24 letterman postfix/qmgr[8204]: AAB4D259B1: removed" ,
"Feb 11 16:49:24 letterman postfix/qmgr[8204]: C2032259E6: removed" ,
"Feb 11 16:49:24 letterman postfix/qmgr[8204]: B83C4257DC: removed" ,
"Feb 11 16:49:24 letterman postfix/qmgr[8204]: 721BE256EA: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: CA94A259EB: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: AC1E3259E1: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: D114D221E3: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: A55F82104D: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: D6DAA259BC: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: E3908259F0: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: 0CBB8259BF: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: EA3AD259F2: removed" ,
"Feb 11 16:49:25 letterman postfix/qmgr[8204]: DDEF824B48: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 289AF21DB9: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 6192B260E8: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: F2831259F4: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 09D60259F8: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 13A19259FA: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 2D42722065: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 746E325A0E: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 4D2F125A02: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: E30BC259EF: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: DC88924DA1: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 2164B259FD: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 8C30525A14: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: 8DCCE25A15: removed" ,
"Feb 11 16:49:26 letterman postfix/qmgr[8204]: C5217255D5: removed" ,
"Feb 11 16:49:27 letterman postfix/qmgr[8204]: D8EE625A28: removed" ,
"Feb 11 16:49:27 letterman postfix/qmgr[8204]: 9AD7C25A19: removed" ,
"Feb 11 16:49:27 letterman postfix/qmgr[8204]: D0EEE2596C: removed" ,
"Feb 11 16:49:27 letterman postfix/qmgr[8204]: DFE732172E: removed" ,
} ,
2020-02-22 16:06:44 +00:00
removedCount : 31 ,
saslFailedCount : 0 ,
} ,
fields : fields {
2020-02-23 19:41:35 +00:00
qmgrRemoves : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
2021-04-14 10:40:02 +00:00
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
2020-02-22 16:06:44 +00:00
} ,
} ,
2021-04-14 08:52:11 +00:00
{
name : "qmgr expired" ,
args : args {
line : [ ] string {
"Apr 10 14:50:16 mail postfix/qmgr[3663]: BACE842E72: from=<noreply@domain.com>, status=expired, returned to sender" ,
"Apr 10 14:50:16 mail postfix/qmgr[3663]: BACE842E73: from=<noreply@domain.com>, status=force-expired, returned to sender" ,
} ,
expiredCount : 2 ,
} ,
fields : fields {
qmgrExpires : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
} ,
} ,
2020-02-22 16:06:44 +00:00
{
name : "SASL Failed" ,
args : args {
line : [ ] string {
"Apr 26 10:55:19 tcc1 postfix/smtpd[21126]: warning: SASL authentication failure: cannot connect to saslauthd server: Permission denied" ,
"Apr 26 10:55:19 tcc1 postfix/smtpd[21126]: warning: SASL authentication failure: Password verification failed" ,
"Apr 26 10:55:19 tcc1 postfix/smtpd[21126]: warning: laptop.local[192.168.1.2]: SASL PLAIN authentication failed: generic failure" ,
} ,
saslFailedCount : 1 ,
removedCount : 0 ,
} ,
fields : fields {
2020-02-23 19:41:35 +00:00
smtpdSASLAuthenticationFailures : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
2021-04-14 10:40:02 +00:00
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
2021-04-07 13:21:26 +00:00
smtpProcesses : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "status" } ) ,
2020-02-12 12:41:29 +00:00
} ,
} ,
2020-02-23 19:41:35 +00:00
{
name : "SASL login" ,
args : args {
line : [ ] string {
"Oct 30 13:19:26 mailgw-out1 postfix/smtpd[27530]: EB4B2C19E2: client=xxx[1.2.3.4], sasl_method=PLAIN, sasl_username=user@domain" ,
2020-02-24 15:44:29 +00:00
"Feb 24 16:42:00 letterman postfix/smtpd[24906]: 1CF582025C: client=xxx[2.3.4.5]" ,
2020-02-23 19:41:35 +00:00
} ,
removedCount : 0 ,
saslFailedCount : 0 ,
outgoingTLS : 0 ,
2020-02-24 15:44:29 +00:00
smtpdMessagesProcessed : 2 ,
2020-02-23 19:41:35 +00:00
} ,
fields : fields {
2021-04-14 10:40:02 +00:00
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
2020-02-23 19:41:35 +00:00
smtpdProcesses : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "sasl_method" } ) ,
} ,
} ,
2020-02-22 21:43:26 +00:00
{
name : "Issue #35" ,
args : args {
line : [ ] string {
"Jul 24 04:38:17 mail postfix/smtp[30582]: Verified TLS connection established to gmail-smtp-in.l.google.com[108.177.14.26]:25: TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256" ,
"Jul 24 03:28:15 mail postfix/smtp[24052]: Verified TLS connection established to mx2.comcast.net[2001:558:fe21:2a::6]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)" ,
} ,
removedCount : 0 ,
saslFailedCount : 0 ,
outgoingTLS : 2 ,
2021-04-07 13:21:26 +00:00
smtpdMessagesProcessed : 0 ,
2020-02-22 21:43:26 +00:00
} ,
fields : fields {
2021-04-14 10:40:02 +00:00
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
2020-02-22 21:43:26 +00:00
smtpTLSConnects : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "Verified" , "TLSv1.2" , "ECDHE-RSA-AES256-GCM-SHA384" , "256" , "256" } ) ,
2021-04-07 13:21:26 +00:00
smtpProcesses : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "status" } ) ,
2020-02-22 21:43:26 +00:00
} ,
} ,
2020-02-24 15:26:35 +00:00
{
name : "Testing delays" ,
args : args {
line : [ ] string {
"Feb 24 16:18:40 letterman postfix/smtp[59649]: 5270320179: to=<hebj@telia.com>, relay=mail.telia.com[81.236.60.210]:25, delay=2017, delays=0.1/2017/0.03/0.05, dsn=2.0.0, status=sent (250 2.0.0 6FVIjIMwUJwU66FVIjAEB0 mail accepted for delivery)" ,
} ,
removedCount : 0 ,
saslFailedCount : 0 ,
outgoingTLS : 0 ,
smtpdMessagesProcessed : 0 ,
2021-04-07 13:21:26 +00:00
smtpMessagesProcessed : 1 ,
2020-02-24 15:26:35 +00:00
} ,
fields : fields {
smtpDelays : prometheus . NewHistogramVec ( prometheus . HistogramOpts { } , [ ] string { "stage" } ) ,
2021-04-07 13:21:26 +00:00
smtpProcesses : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "status" } ) ,
} ,
} ,
{
name : "Testing different smtp statuses" ,
args : args {
line : [ ] string {
"Dec 29 02:54:09 mail postfix/smtp[7648]: 732BB407C3: host mail.domain.com[1.1.1.1] said: 451 DT:SPM 163 mx13,P8CowECpNVM_oEVaenoEAQ--.23796S3 1514512449, please try again 15min later (in reply to end of DATA command)" ,
"Dec 29 02:54:12 mail postfix/smtp[7648]: 732BB407C3: to=<redacted@domain.com>, relay=mail.domain.com[1.1.1.1]:25, delay=6.2, delays=0.1/0/5.2/0.87, dsn=4.0.0, status=deferred (host mail.domain.com[1.1.1.1] said: 451 DT:SPM 163 mx40,WsCowAAnEhlCoEVa5GjcAA--.20089S3 1514512452, please try again 15min later (in reply to end of DATA command))" ,
"Dec 29 03:03:48 mail postfix/smtp[8492]: 732BB407C3: to=<redacted@domain.com>, relay=mail.domain.com[1.1.1.1]:25, delay=582, delays=563/16/1.7/0.81, dsn=5.0.0, status=bounced (host mail.domain.com[1.1.1.1] said: 554 DT:SPM 163 mx9,O8CowEDJVFKCokVaRhz+AA--.26016S3 1514513028,please see http://mail.domain.com/help/help_spam.htm?ip= (in reply to end of DATA command))" ,
"Dec 29 03:03:48 mail postfix/bounce[9321]: 732BB407C3: sender non-delivery notification: 5DE184083C" ,
} ,
smtpMessagesProcessed : 2 ,
2021-04-07 13:31:44 +00:00
bounceNonDelivery : 1 ,
2021-04-07 13:21:26 +00:00
} ,
fields : fields {
2021-04-14 10:40:02 +00:00
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
2021-04-07 13:21:26 +00:00
smtpDelays : prometheus . NewHistogramVec ( prometheus . HistogramOpts { } , [ ] string { "stage" } ) ,
smtpStatusDeferred : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
smtpProcesses : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "status" } ) ,
2021-04-07 13:31:44 +00:00
bounceNonDelivery : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
2020-02-24 15:26:35 +00:00
} ,
} ,
2021-04-07 13:41:26 +00:00
{
name : "Testing virtual delivered" ,
args : args {
line : [ ] string {
"Apr 7 15:35:20 123-mail postfix/virtual[20235]: 199041033BE: to=<me@domain.fr>, relay=virtual, delay=0.08, delays=0.08/0/0/0, dsn=2.0.0, status=sent (delivered to maildir)" ,
} ,
virtualDelivered : 1 ,
} ,
fields : fields {
virtualDelivered : prometheus . NewCounter ( prometheus . CounterOpts { } ) ,
} ,
} ,
2021-04-14 10:40:02 +00:00
{
name : "Testing levels of unsupported entries" ,
args : args {
line : [ ] string {
"Feb 14 19:05:25 123-mail postfix/smtpd[1517]: table hash:/etc/postfix/virtual_mailbox_maps(0,lock|fold_fix) has changed -- restarting" ,
"Mar 16 12:28:02 123-mail postfix/smtpd[16268]: fatal: file /etc/postfix/main.cf: parameter default_privs: unknown user name value: nobody" ,
"Mar 16 23:30:44 123-mail postfix/qmgr[29980]: warning: please avoid flushing the whole queue when you have" ,
"Mar 16 23:30:44 123-mail postfix/qmgr[29980]: warning: lots of deferred mail, that is bad for performance" ,
} ,
unsupportedLogEntries : [ ] string {
` label:<name:"level" value:"" > label:<name:"service" value:"smtpd" > counter:<value:1 > ` ,
` label:<name:"level" value:"fatal" > label:<name:"service" value:"smtpd" > counter:<value:1 > ` ,
` label:<name:"level" value:"warning" > label:<name:"service" value:"qmgr" > counter:<value:2 > ` ,
} ,
} ,
fields : fields {
unsupportedLogEntries : prometheus . NewCounterVec ( prometheus . CounterOpts { } , [ ] string { "service" , "level" } ) ,
} ,
} ,
2020-02-12 12:41:29 +00:00
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
e := & PostfixExporter {
showqPath : tt . fields . showqPath ,
2020-06-20 23:07:59 +00:00
logSrc : tt . fields . logSrc ,
2020-02-12 12:41:29 +00:00
cleanupProcesses : tt . fields . cleanupProcesses ,
cleanupRejects : tt . fields . cleanupRejects ,
cleanupNotAccepted : tt . fields . cleanupNotAccepted ,
lmtpDelays : tt . fields . lmtpDelays ,
pipeDelays : tt . fields . pipeDelays ,
qmgrInsertsNrcpt : tt . fields . qmgrInsertsNrcpt ,
qmgrInsertsSize : tt . fields . qmgrInsertsSize ,
qmgrRemoves : tt . fields . qmgrRemoves ,
2021-04-14 08:52:11 +00:00
qmgrExpires : tt . fields . qmgrExpires ,
2020-02-12 12:41:29 +00:00
smtpDelays : tt . fields . smtpDelays ,
smtpTLSConnects : tt . fields . smtpTLSConnects ,
smtpDeferreds : tt . fields . smtpDeferreds ,
2021-04-07 13:21:26 +00:00
smtpStatusDeferred : tt . fields . smtpStatusDeferred ,
smtpProcesses : tt . fields . smtpProcesses ,
2020-02-12 12:41:29 +00:00
smtpdConnects : tt . fields . smtpdConnects ,
smtpdDisconnects : tt . fields . smtpdDisconnects ,
smtpdFCrDNSErrors : tt . fields . smtpdFCrDNSErrors ,
smtpdLostConnections : tt . fields . smtpdLostConnections ,
smtpdProcesses : tt . fields . smtpdProcesses ,
smtpdRejects : tt . fields . smtpdRejects ,
smtpdSASLAuthenticationFailures : tt . fields . smtpdSASLAuthenticationFailures ,
smtpdTLSConnects : tt . fields . smtpdTLSConnects ,
2021-04-07 13:31:44 +00:00
bounceNonDelivery : tt . fields . bounceNonDelivery ,
2021-04-07 13:41:26 +00:00
virtualDelivered : tt . fields . virtualDelivered ,
2020-02-12 12:41:29 +00:00
unsupportedLogEntries : tt . fields . unsupportedLogEntries ,
2020-02-22 21:43:26 +00:00
logUnsupportedLines : true ,
2020-02-12 12:41:29 +00:00
}
for _ , line := range tt . args . line {
2020-02-18 15:17:13 +00:00
e . CollectFromLogLine ( line )
2020-02-12 12:41:29 +00:00
}
2020-02-22 16:06:44 +00:00
assertCounterEquals ( t , e . qmgrRemoves , tt . args . removedCount , "Wrong number of lines counted" )
2021-04-14 08:52:11 +00:00
assertCounterEquals ( t , e . qmgrExpires , tt . args . expiredCount , "Wrong number of qmgr expired lines counted" )
2020-02-22 16:06:44 +00:00
assertCounterEquals ( t , e . smtpdSASLAuthenticationFailures , tt . args . saslFailedCount , "Wrong number of Sasl counter counted" )
2020-02-23 19:41:35 +00:00
assertCounterEquals ( t , e . smtpTLSConnects , tt . args . outgoingTLS , "Wrong number of TLS connections counted" )
assertCounterEquals ( t , e . smtpdProcesses , tt . args . smtpdMessagesProcessed , "Wrong number of smtpd messages processed" )
2021-04-07 13:21:26 +00:00
assertCounterEquals ( t , e . smtpProcesses , tt . args . smtpMessagesProcessed , "Wrong number of smtp messages processed" )
2021-04-07 13:31:44 +00:00
assertCounterEquals ( t , e . bounceNonDelivery , tt . args . bounceNonDelivery , "Wrong number of non delivery notifications" )
2021-04-07 13:41:26 +00:00
assertCounterEquals ( t , e . virtualDelivered , tt . args . virtualDelivered , "Wrong number of delivered mails" )
2021-04-14 10:40:02 +00:00
assertVecMetricsEquals ( t , e . unsupportedLogEntries , tt . args . unsupportedLogEntries , "Wrong number of unsupportedLogEntries" )
2020-02-12 12:41:29 +00:00
} )
}
}
2020-02-23 19:41:35 +00:00
func assertCounterEquals ( t * testing . T , counter prometheus . Collector , expected int , message string ) {
2020-02-22 21:43:26 +00:00
if counter != nil && expected > 0 {
switch counter . ( type ) {
case * prometheus . CounterVec :
counter := counter . ( * prometheus . CounterVec )
metricsChan := make ( chan prometheus . Metric )
go func ( ) {
counter . Collect ( metricsChan )
close ( metricsChan )
} ( )
var count int = 0
for metric := range metricsChan {
metricDto := io_prometheus_client . Metric { }
metric . Write ( & metricDto )
count += int ( * metricDto . Counter . Value )
}
assert . Equal ( t , expected , count , message )
2020-02-23 19:41:35 +00:00
case prometheus . Counter :
metricsChan := make ( chan prometheus . Metric )
go func ( ) {
counter . Collect ( metricsChan )
close ( metricsChan )
} ( )
var count int = 0
for metric := range metricsChan {
metricDto := io_prometheus_client . Metric { }
metric . Write ( & metricDto )
count += int ( * metricDto . Counter . Value )
}
assert . Equal ( t , expected , count , message )
2020-02-22 21:43:26 +00:00
default :
t . Fatal ( "Type not implemented" )
}
}
}
2021-04-14 10:40:02 +00:00
func assertVecMetricsEquals ( t * testing . T , counter * prometheus . CounterVec , expected [ ] string , message string ) {
if expected != nil {
metricsChan := make ( chan prometheus . Metric )
go func ( ) {
counter . Collect ( metricsChan )
close ( metricsChan )
} ( )
var res [ ] string
for metric := range metricsChan {
metricDto := io_prometheus_client . Metric { }
metric . Write ( & metricDto )
res = append ( res , metricDto . String ( ) )
}
assert . Equal ( t , expected , res , message )
}
}