2015-02-11 00:49:32 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-02-11 00:49:32 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package record
import (
2015-11-03 16:38:52 +00:00
"reflect"
"strings"
2015-03-21 16:24:16 +00:00
"testing"
2015-11-03 16:38:52 +00:00
"time"
2015-03-21 16:24:16 +00:00
2015-09-17 22:21:55 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2016-11-18 21:35:28 +00:00
"k8s.io/kubernetes/pkg/api/v1"
2016-05-26 03:08:56 +00:00
"k8s.io/kubernetes/pkg/util/clock"
2016-03-11 02:43:55 +00:00
"k8s.io/kubernetes/pkg/util/diff"
2015-02-11 00:49:32 +00:00
)
2016-11-18 21:00:33 +00:00
func makeObjectReference ( kind , name , namespace string ) v1 . ObjectReference {
return v1 . ObjectReference {
2015-11-03 16:38:52 +00:00
Kind : kind ,
Name : name ,
Namespace : namespace ,
UID : "C934D34AFB20242" ,
APIVersion : "version" ,
}
}
2016-11-18 21:00:33 +00:00
func makeEvent ( reason , message string , involvedObject v1 . ObjectReference ) v1 . Event {
2015-09-17 22:21:55 +00:00
eventTime := unversioned . Now ( )
2016-11-18 21:00:33 +00:00
event := v1 . Event {
2015-11-03 16:38:52 +00:00
Reason : reason ,
Message : message ,
InvolvedObject : involvedObject ,
2016-11-18 21:00:33 +00:00
Source : v1 . EventSource {
2015-02-11 00:49:32 +00:00
Component : "kubelet" ,
Host : "kublet.node1" ,
} ,
Count : 1 ,
FirstTimestamp : eventTime ,
LastTimestamp : eventTime ,
2016-11-18 21:00:33 +00:00
Type : v1 . EventTypeNormal ,
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
return event
2015-02-11 00:49:32 +00:00
}
2016-11-18 21:00:33 +00:00
func makeEvents ( num int , template v1 . Event ) [ ] v1 . Event {
events := [ ] v1 . Event { }
2015-11-03 16:38:52 +00:00
for i := 0 ; i < num ; i ++ {
events = append ( events , template )
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
return events
}
2015-02-11 00:49:32 +00:00
2016-11-18 21:00:33 +00:00
func makeUniqueEvents ( num int ) [ ] v1 . Event {
events := [ ] v1 . Event { }
2015-11-03 16:38:52 +00:00
kind := "Pod"
for i := 0 ; i < num ; i ++ {
reason := strings . Join ( [ ] string { "reason" , string ( i ) } , "-" )
message := strings . Join ( [ ] string { "message" , string ( i ) } , "-" )
name := strings . Join ( [ ] string { "pod" , string ( i ) } , "-" )
namespace := strings . Join ( [ ] string { "ns" , string ( i ) } , "-" )
involvedObject := makeObjectReference ( kind , name , namespace )
events = append ( events , makeEvent ( reason , message , involvedObject ) )
}
return events
2015-02-11 00:49:32 +00:00
}
2016-11-18 21:00:33 +00:00
func makeSimilarEvents ( num int , template v1 . Event , messagePrefix string ) [ ] v1 . Event {
2015-11-03 16:38:52 +00:00
events := makeEvents ( num , template )
for i := range events {
events [ i ] . Message = strings . Join ( [ ] string { messagePrefix , string ( i ) , events [ i ] . Message } , "-" )
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
return events
}
2015-02-11 00:49:32 +00:00
2016-11-18 21:00:33 +00:00
func setCount ( event v1 . Event , count int ) v1 . Event {
2016-04-27 04:35:14 +00:00
event . Count = int32 ( count )
2015-11-03 16:38:52 +00:00
return event
}
2015-02-11 00:49:32 +00:00
2016-11-18 21:00:33 +00:00
func validateEvent ( messagePrefix string , actualEvent * v1 . Event , expectedEvent * v1 . Event , t * testing . T ) ( * v1 . Event , error ) {
2015-11-03 16:38:52 +00:00
recvEvent := * actualEvent
expectCompression := expectedEvent . Count > 1
t . Logf ( "%v - expectedEvent.Count is %d\n" , messagePrefix , expectedEvent . Count )
// Just check that the timestamp was set.
if recvEvent . FirstTimestamp . IsZero ( ) || recvEvent . LastTimestamp . IsZero ( ) {
t . Errorf ( "%v - timestamp wasn't set: %#v" , messagePrefix , recvEvent )
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
actualFirstTimestamp := recvEvent . FirstTimestamp
actualLastTimestamp := recvEvent . LastTimestamp
if actualFirstTimestamp . Equal ( actualLastTimestamp ) {
if expectCompression {
t . Errorf ( "%v - FirstTimestamp (%q) and LastTimestamp (%q) must be different to indicate event compression happened, but were the same. Actual Event: %#v" , messagePrefix , actualFirstTimestamp , actualLastTimestamp , recvEvent )
}
} else {
if expectedEvent . Count == 1 {
t . Errorf ( "%v - FirstTimestamp (%q) and LastTimestamp (%q) must be equal to indicate only one occurrence of the event, but were different. Actual Event: %#v" , messagePrefix , actualFirstTimestamp , actualLastTimestamp , recvEvent )
}
}
// Temp clear time stamps for comparison because actual values don't matter for comparison
recvEvent . FirstTimestamp = expectedEvent . FirstTimestamp
recvEvent . LastTimestamp = expectedEvent . LastTimestamp
// Check that name has the right prefix.
if n , en := recvEvent . Name , expectedEvent . Name ; ! strings . HasPrefix ( n , en ) {
t . Errorf ( "%v - Name '%v' does not contain prefix '%v'" , messagePrefix , n , en )
}
recvEvent . Name = expectedEvent . Name
if e , a := expectedEvent , & recvEvent ; ! reflect . DeepEqual ( e , a ) {
2016-03-11 02:43:55 +00:00
t . Errorf ( "%v - diff: %s" , messagePrefix , diff . ObjectGoPrintDiff ( e , a ) )
2015-11-03 16:38:52 +00:00
}
recvEvent . FirstTimestamp = actualFirstTimestamp
recvEvent . LastTimestamp = actualLastTimestamp
return actualEvent , nil
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
// TestDefaultEventFilterFunc ensures that no events are filtered
func TestDefaultEventFilterFunc ( t * testing . T ) {
event := makeEvent ( "end-of-world" , "it was fun" , makeObjectReference ( "Pod" , "pod1" , "other" ) )
if DefaultEventFilterFunc ( & event ) {
t . Fatalf ( "DefaultEventFilterFunc should always return false" )
2015-02-11 00:49:32 +00:00
}
}
2015-11-03 16:38:52 +00:00
// TestEventAggregatorByReasonFunc ensures that two events are aggregated if they vary only by event.message
func TestEventAggregatorByReasonFunc ( t * testing . T ) {
event1 := makeEvent ( "end-of-world" , "it was fun" , makeObjectReference ( "Pod" , "pod1" , "other" ) )
event2 := makeEvent ( "end-of-world" , "it was awful" , makeObjectReference ( "Pod" , "pod1" , "other" ) )
event3 := makeEvent ( "nevermind" , "it was a bug" , makeObjectReference ( "Pod" , "pod1" , "other" ) )
2015-02-11 00:49:32 +00:00
2015-11-03 16:38:52 +00:00
aggKey1 , localKey1 := EventAggregatorByReasonFunc ( & event1 )
aggKey2 , localKey2 := EventAggregatorByReasonFunc ( & event2 )
aggKey3 , _ := EventAggregatorByReasonFunc ( & event3 )
2015-02-11 00:49:32 +00:00
2015-11-03 16:38:52 +00:00
if aggKey1 != aggKey2 {
t . Errorf ( "Expected %v equal %v" , aggKey1 , aggKey2 )
}
if localKey1 == localKey2 {
t . Errorf ( "Expected %v to not equal %v" , aggKey1 , aggKey3 )
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
if aggKey1 == aggKey3 {
t . Errorf ( "Expected %v to not equal %v" , aggKey1 , aggKey3 )
}
}
2015-02-11 00:49:32 +00:00
2015-11-03 16:38:52 +00:00
// TestEventAggregatorByReasonMessageFunc validates the proper output for an aggregate message
func TestEventAggregatorByReasonMessageFunc ( t * testing . T ) {
expected := "(events with common reason combined)"
event1 := makeEvent ( "end-of-world" , "it was fun" , makeObjectReference ( "Pod" , "pod1" , "other" ) )
if actual := EventAggregatorByReasonMessageFunc ( & event1 ) ; expected != actual {
t . Errorf ( "Expected %v got %v" , expected , actual )
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
}
2015-02-11 00:49:32 +00:00
2015-11-03 16:38:52 +00:00
// TestEventCorrelator validates proper counting, aggregation of events
func TestEventCorrelator ( t * testing . T ) {
firstEvent := makeEvent ( "first" , "i am first" , makeObjectReference ( "Pod" , "my-pod" , "my-ns" ) )
duplicateEvent := makeEvent ( "duplicate" , "me again" , makeObjectReference ( "Pod" , "my-pod" , "my-ns" ) )
uniqueEvent := makeEvent ( "unique" , "snowflake" , makeObjectReference ( "Pod" , "my-pod" , "my-ns" ) )
similarEvent := makeEvent ( "similar" , "similar message" , makeObjectReference ( "Pod" , "my-pod" , "my-ns" ) )
aggregateEvent := makeEvent ( similarEvent . Reason , EventAggregatorByReasonMessageFunc ( & similarEvent ) , similarEvent . InvolvedObject )
scenario := map [ string ] struct {
2016-11-18 21:00:33 +00:00
previousEvents [ ] v1 . Event
newEvent v1 . Event
expectedEvent v1 . Event
2015-11-03 16:38:52 +00:00
intervalSeconds int
} {
"create-a-single-event" : {
2016-11-18 21:00:33 +00:00
previousEvents : [ ] v1 . Event { } ,
2015-11-03 16:38:52 +00:00
newEvent : firstEvent ,
expectedEvent : setCount ( firstEvent , 1 ) ,
intervalSeconds : 5 ,
} ,
"the-same-event-should-just-count" : {
previousEvents : makeEvents ( 1 , duplicateEvent ) ,
newEvent : duplicateEvent ,
expectedEvent : setCount ( duplicateEvent , 2 ) ,
intervalSeconds : 5 ,
} ,
"the-same-event-should-just-count-even-if-more-than-aggregate" : {
previousEvents : makeEvents ( defaultAggregateMaxEvents , duplicateEvent ) ,
newEvent : duplicateEvent ,
expectedEvent : setCount ( duplicateEvent , defaultAggregateMaxEvents + 1 ) ,
intervalSeconds : 5 ,
} ,
"create-many-unique-events" : {
previousEvents : makeUniqueEvents ( 30 ) ,
newEvent : uniqueEvent ,
expectedEvent : setCount ( uniqueEvent , 1 ) ,
intervalSeconds : 5 ,
} ,
"similar-events-should-aggregate-event" : {
previousEvents : makeSimilarEvents ( defaultAggregateMaxEvents - 1 , similarEvent , similarEvent . Message ) ,
newEvent : similarEvent ,
expectedEvent : setCount ( aggregateEvent , 1 ) ,
intervalSeconds : 5 ,
} ,
"similar-events-many-times-should-count-the-aggregate" : {
previousEvents : makeSimilarEvents ( defaultAggregateMaxEvents , similarEvent , similarEvent . Message ) ,
newEvent : similarEvent ,
expectedEvent : setCount ( aggregateEvent , 2 ) ,
intervalSeconds : 5 ,
} ,
"similar-events-whose-interval-is-greater-than-aggregate-interval-do-not-aggregate" : {
previousEvents : makeSimilarEvents ( defaultAggregateMaxEvents - 1 , similarEvent , similarEvent . Message ) ,
newEvent : similarEvent ,
expectedEvent : setCount ( similarEvent , 1 ) ,
intervalSeconds : defaultAggregateIntervalInSeconds ,
} ,
2015-02-11 00:49:32 +00:00
}
2015-11-03 16:38:52 +00:00
for testScenario , testInput := range scenario {
eventInterval := time . Duration ( testInput . intervalSeconds ) * time . Second
2016-05-26 03:08:56 +00:00
clock := clock . IntervalClock { Time : time . Now ( ) , Duration : eventInterval }
2015-11-03 16:38:52 +00:00
correlator := NewEventCorrelator ( & clock )
for i := range testInput . previousEvents {
event := testInput . previousEvents [ i ]
now := unversioned . NewTime ( clock . Now ( ) )
event . FirstTimestamp = now
event . LastTimestamp = now
result , err := correlator . EventCorrelate ( & event )
if err != nil {
t . Errorf ( "scenario %v: unexpected error playing back prevEvents %v" , testScenario , err )
}
correlator . UpdateState ( result . Event )
}
// update the input to current clock value
now := unversioned . NewTime ( clock . Now ( ) )
testInput . newEvent . FirstTimestamp = now
testInput . newEvent . LastTimestamp = now
result , err := correlator . EventCorrelate ( & testInput . newEvent )
if err != nil {
t . Errorf ( "scenario %v: unexpected error correlating input event %v" , testScenario , err )
}
_ , err = validateEvent ( testScenario , result . Event , & testInput . expectedEvent , t )
if err != nil {
t . Errorf ( "scenario %v: unexpected error validating result %v" , testScenario , err )
}
}
2015-02-11 00:49:32 +00:00
}