...

Source file src/github.com/prometheus/alertmanager/test/with_api_v1/collector.go

Documentation: github.com/prometheus/alertmanager/test/with_api_v1

     1  // Copyright 2015 Prometheus Team
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package test
    15  
    16  import (
    17  	"fmt"
    18  	"sync"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/prometheus/common/model"
    23  )
    24  
    25  // Collector gathers alerts received by a notification receiver
    26  // and verifies whether all arrived and within the correct time boundaries.
    27  type Collector struct {
    28  	t    *testing.T
    29  	name string
    30  	opts *AcceptanceOpts
    31  
    32  	collected map[float64][]model.Alerts
    33  	expected  map[Interval][]model.Alerts
    34  
    35  	mtx sync.RWMutex
    36  }
    37  
    38  func (c *Collector) String() string {
    39  	return c.name
    40  }
    41  
    42  func batchesEqual(as, bs model.Alerts, opts *AcceptanceOpts) bool {
    43  	if len(as) != len(bs) {
    44  		return false
    45  	}
    46  
    47  	for _, a := range as {
    48  		found := false
    49  		for _, b := range bs {
    50  			if equalAlerts(a, b, opts) {
    51  				found = true
    52  				break
    53  			}
    54  		}
    55  		if !found {
    56  			return false
    57  		}
    58  	}
    59  	return true
    60  }
    61  
    62  // latest returns the latest relative point in time where a notification is
    63  // expected.
    64  func (c *Collector) latest() float64 {
    65  	c.mtx.RLock()
    66  	defer c.mtx.RUnlock()
    67  	var latest float64
    68  	for iv := range c.expected {
    69  		if iv.end > latest {
    70  			latest = iv.end
    71  		}
    72  	}
    73  	return latest
    74  }
    75  
    76  // Want declares that the Collector expects to receive the given alerts
    77  // within the given time boundaries.
    78  func (c *Collector) Want(iv Interval, alerts ...*TestAlert) {
    79  	c.mtx.Lock()
    80  	defer c.mtx.Unlock()
    81  	var nas model.Alerts
    82  	for _, a := range alerts {
    83  		nas = append(nas, a.nativeAlert(c.opts))
    84  	}
    85  
    86  	c.expected[iv] = append(c.expected[iv], nas)
    87  }
    88  
    89  // add the given alerts to the collected alerts.
    90  func (c *Collector) add(alerts ...*model.Alert) {
    91  	c.mtx.Lock()
    92  	defer c.mtx.Unlock()
    93  	arrival := c.opts.relativeTime(time.Now())
    94  
    95  	c.collected[arrival] = append(c.collected[arrival], model.Alerts(alerts))
    96  }
    97  
    98  func (c *Collector) check() string {
    99  	report := fmt.Sprintf("\ncollector %q:\n\n", c)
   100  
   101  	c.mtx.RLock()
   102  	defer c.mtx.RUnlock()
   103  	for iv, expected := range c.expected {
   104  		report += fmt.Sprintf("interval %v\n", iv)
   105  
   106  		var alerts []model.Alerts
   107  		for at, got := range c.collected {
   108  			if iv.contains(at) {
   109  				alerts = append(alerts, got...)
   110  			}
   111  		}
   112  
   113  		for _, exp := range expected {
   114  			found := len(exp) == 0 && len(alerts) == 0
   115  
   116  			report += "---\n"
   117  
   118  			for _, e := range exp {
   119  				report += fmt.Sprintf("- %v\n", c.opts.alertString(e))
   120  			}
   121  
   122  			for _, a := range alerts {
   123  				if batchesEqual(exp, a, c.opts) {
   124  					found = true
   125  					break
   126  				}
   127  			}
   128  
   129  			if found {
   130  				report += "  [ ✓ ]\n"
   131  			} else {
   132  				c.t.Fail()
   133  				report += "  [ ✗ ]\n"
   134  			}
   135  		}
   136  	}
   137  
   138  	// Detect unexpected notifications.
   139  	var totalExp, totalAct int
   140  	for _, exp := range c.expected {
   141  		for _, e := range exp {
   142  			totalExp += len(e)
   143  		}
   144  	}
   145  	for _, act := range c.collected {
   146  		for _, a := range act {
   147  			if len(a) == 0 {
   148  				c.t.Error("received empty notifications")
   149  			}
   150  			totalAct += len(a)
   151  		}
   152  	}
   153  	if totalExp != totalAct {
   154  		c.t.Fail()
   155  		report += fmt.Sprintf("\nExpected total of %d alerts, got %d", totalExp, totalAct)
   156  	}
   157  
   158  	if c.t.Failed() {
   159  		report += "\nreceived:\n"
   160  
   161  		for at, col := range c.collected {
   162  			for _, alerts := range col {
   163  				report += fmt.Sprintf("@ %v\n", at)
   164  				for _, a := range alerts {
   165  					report += fmt.Sprintf("- %v\n", c.opts.alertString(a))
   166  				}
   167  			}
   168  		}
   169  	}
   170  
   171  	return report
   172  }
   173  

View as plain text