2014-10-11 00:46:38 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2014-10-11 00:46:38 +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 .
* /
2015-01-09 18:02:48 +00:00
package record
2014-10-11 00:46:38 +00:00
import (
2015-10-07 16:58:35 +00:00
"encoding/json"
2014-10-11 00:46:38 +00:00
"fmt"
"reflect"
2015-01-10 00:58:07 +00:00
"strconv"
2014-10-30 00:27:11 +00:00
"strings"
2014-10-11 00:46:38 +00:00
"testing"
2015-10-07 16:58:35 +00:00
"time"
2014-10-11 00:46:38 +00:00
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
2015-08-12 18:18:22 +00:00
client "k8s.io/kubernetes/pkg/client/unversioned"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
2015-10-07 16:58:35 +00:00
"k8s.io/kubernetes/pkg/util/strategicpatch"
2014-10-11 00:46:38 +00:00
)
2015-01-09 18:02:48 +00:00
func init ( ) {
2015-01-10 00:58:07 +00:00
// Don't bother sleeping between retries.
2015-01-13 19:13:24 +00:00
sleepDuration = 0
2015-01-09 18:02:48 +00:00
}
2015-03-03 06:06:20 +00:00
type testEventSink struct {
2015-02-11 00:49:32 +00:00
OnCreate func ( e * api . Event ) ( * api . Event , error )
OnUpdate func ( e * api . Event ) ( * api . Event , error )
2015-10-07 16:58:35 +00:00
OnPatch func ( e * api . Event , p [ ] byte ) ( * api . Event , error )
2014-10-11 00:46:38 +00:00
}
// CreateEvent records the event for testing.
2015-03-03 06:06:20 +00:00
func ( t * testEventSink ) Create ( e * api . Event ) ( * api . Event , error ) {
2015-02-11 00:49:32 +00:00
if t . OnCreate != nil {
return t . OnCreate ( e )
2014-10-11 00:46:38 +00:00
}
return e , nil
}
2015-02-11 00:49:32 +00:00
// UpdateEvent records the event for testing.
2015-03-03 06:06:20 +00:00
func ( t * testEventSink ) Update ( e * api . Event ) ( * api . Event , error ) {
2015-02-11 00:49:32 +00:00
if t . OnUpdate != nil {
return t . OnUpdate ( e )
}
return e , nil
2014-10-11 00:46:38 +00:00
}
2015-10-07 16:58:35 +00:00
// PatchEvent records the event for testing.
func ( t * testEventSink ) Patch ( e * api . Event , p [ ] byte ) ( * api . Event , error ) {
if t . OnPatch != nil {
return t . OnPatch ( e , p )
}
return e , nil
}
type OnCreateFunc func ( * api . Event ) ( * api . Event , error )
func OnCreateFactory ( testCache map [ string ] * api . Event , createEvent chan <- * api . Event ) OnCreateFunc {
return func ( event * api . Event ) ( * api . Event , error ) {
testCache [ getEventKey ( event ) ] = event
createEvent <- event
return event , nil
}
}
type OnPatchFunc func ( * api . Event , [ ] byte ) ( * api . Event , error )
func OnPatchFactory ( testCache map [ string ] * api . Event , patchEvent chan <- * api . Event ) OnPatchFunc {
return func ( event * api . Event , patch [ ] byte ) ( * api . Event , error ) {
cachedEvent , found := testCache [ getEventKey ( event ) ]
if ! found {
return nil , fmt . Errorf ( "unexpected error: couldn't find Event in testCache. Try to find Event: %v" , event )
}
originalData , err := json . Marshal ( cachedEvent )
if err != nil {
return nil , fmt . Errorf ( "unexpected error: %v" , err )
}
patched , err := strategicpatch . StrategicMergePatch ( originalData , patch , event )
if err != nil {
return nil , fmt . Errorf ( "unexpected error: %v" , err )
}
patchedObj := & api . Event { }
err = json . Unmarshal ( patched , patchedObj )
if err != nil {
return nil , fmt . Errorf ( "unexpected error: %v" , err )
}
patchEvent <- patchedObj
return patchedObj , nil
}
}
2014-10-11 00:46:38 +00:00
func TestEventf ( t * testing . T ) {
2014-11-04 00:06:36 +00:00
testPod := & api . Pod {
ObjectMeta : api . ObjectMeta {
2015-04-08 23:28:28 +00:00
SelfLink : "/api/version/pods/foo" ,
2014-11-04 00:06:36 +00:00
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
} ,
}
2015-02-11 00:49:32 +00:00
testPod2 := & api . Pod {
ObjectMeta : api . ObjectMeta {
2015-04-08 23:28:28 +00:00
SelfLink : "/api/version/pods/foo" ,
2015-02-11 00:49:32 +00:00
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
} ,
}
2015-06-09 17:45:46 +00:00
testRef , err := api . GetPartialReference ( testPod , "spec.containers[2]" )
testRef2 , err := api . GetPartialReference ( testPod2 , "spec.containers[3]" )
2014-11-04 00:06:36 +00:00
if err != nil {
t . Fatal ( err )
}
2014-10-11 00:46:38 +00:00
table := [ ] struct {
2015-02-11 00:49:32 +00:00
obj runtime . Object
reason string
messageFmt string
elements [ ] interface { }
expect * api . Event
expectLog string
expectUpdate bool
2014-10-11 00:46:38 +00:00
} {
{
2014-11-04 00:06:36 +00:00
obj : testRef ,
2014-12-12 21:27:25 +00:00
reason : "Started" ,
2014-11-04 00:06:36 +00:00
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta {
2014-10-30 00:27:11 +00:00
Name : "foo" ,
Namespace : "baz" ,
2014-10-11 00:46:38 +00:00
} ,
2014-11-04 00:06:36 +00:00
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[2]" ,
2014-11-04 00:06:36 +00:00
} ,
2015-01-14 01:10:57 +00:00
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
2015-02-06 02:21:01 +00:00
Count : 1 ,
2014-10-11 00:46:38 +00:00
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : false ,
2014-11-04 00:06:36 +00:00
} ,
{
obj : testPod ,
2015-02-11 00:49:32 +00:00
reason : "Killed" ,
messageFmt : "some other verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-02-11 00:49:32 +00:00
} ,
Reason : "Killed" ,
Message : "some other verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
2015-04-08 23:28:28 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:""}): reason: 'Killed' some other verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : false ,
} ,
{
obj : testRef ,
2014-12-12 21:27:25 +00:00
reason : "Started" ,
2014-10-11 00:46:38 +00:00
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
2014-10-30 00:27:11 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
2014-10-11 00:46:38 +00:00
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
2014-10-30 00:27:11 +00:00
Namespace : "baz" ,
2014-10-23 02:59:15 +00:00
UID : "bar" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[2]" ,
2015-02-11 00:49:32 +00:00
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 2 ,
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : true ,
} ,
{
obj : testRef2 ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[3]" ,
2014-10-11 00:46:38 +00:00
} ,
2015-01-14 01:10:57 +00:00
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
2015-02-06 02:21:01 +00:00
Count : 1 ,
2014-10-11 00:46:38 +00:00
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): reason: 'Started' some verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : false ,
} ,
{
obj : testRef ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[2]" ,
2015-02-11 00:49:32 +00:00
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 3 ,
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : true ,
} ,
{
obj : testRef2 ,
reason : "Stopped" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[3]" ,
2015-02-11 00:49:32 +00:00
} ,
Reason : "Stopped" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): reason: 'Stopped' some verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : false ,
} ,
{
obj : testRef2 ,
reason : "Stopped" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[3]" ,
2015-02-11 00:49:32 +00:00
} ,
Reason : "Stopped" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 2 ,
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): reason: 'Stopped' some verbose message: 1 ` ,
2015-02-11 00:49:32 +00:00
expectUpdate : true ,
2014-10-11 00:46:38 +00:00
} ,
}
2015-10-07 16:58:35 +00:00
testCache := map [ string ] * api . Event { }
2015-09-06 16:04:29 +00:00
logCalled := make ( chan struct { } )
createEvent := make ( chan * api . Event )
updateEvent := make ( chan * api . Event )
2015-10-07 16:58:35 +00:00
patchEvent := make ( chan * api . Event )
2015-09-06 16:04:29 +00:00
testEvents := testEventSink {
2015-10-07 16:58:35 +00:00
OnCreate : OnCreateFactory ( testCache , createEvent ) ,
2015-09-06 16:04:29 +00:00
OnUpdate : func ( event * api . Event ) ( * api . Event , error ) {
updateEvent <- event
return event , nil
} ,
2015-10-07 16:58:35 +00:00
OnPatch : OnPatchFactory ( testCache , patchEvent ) ,
2015-09-06 16:04:29 +00:00
}
eventBroadcaster := NewBroadcaster ( )
sinkWatcher := eventBroadcaster . StartRecordingToSink ( & testEvents )
2015-10-07 16:58:35 +00:00
clock := & util . FakeClock { time . Now ( ) }
recorder := recorderWithFakeClock ( api . EventSource { Component : "eventTest" } , eventBroadcaster , clock )
2014-10-11 00:46:38 +00:00
for _ , item := range table {
2015-10-07 16:58:35 +00:00
clock . Step ( 1 * time . Second )
2015-03-17 04:03:07 +00:00
logWatcher1 := eventBroadcaster . StartLogging ( t . Logf ) // Prove that it is useful
logWatcher2 := eventBroadcaster . StartLogging ( func ( formatter string , args ... interface { } ) {
2014-10-11 00:46:38 +00:00
if e , a := item . expectLog , fmt . Sprintf ( formatter , args ... ) ; e != a {
t . Errorf ( "Expected '%v', got '%v'" , e , a )
}
2015-09-06 16:04:29 +00:00
logCalled <- struct { } { }
2014-10-11 00:46:38 +00:00
} )
2015-03-17 04:03:07 +00:00
recorder . Eventf ( item . obj , item . reason , item . messageFmt , item . elements ... )
2014-10-11 00:46:38 +00:00
2015-09-06 16:04:29 +00:00
<- logCalled
// validate event
if item . expectUpdate {
2015-10-07 16:58:35 +00:00
actualEvent := <- patchEvent
2015-09-06 16:04:29 +00:00
validateEvent ( actualEvent , item . expect , t )
} else {
actualEvent := <- createEvent
validateEvent ( actualEvent , item . expect , t )
}
2015-03-17 04:03:07 +00:00
logWatcher1 . Stop ( )
logWatcher2 . Stop ( )
2014-10-11 00:46:38 +00:00
}
2015-09-06 16:04:29 +00:00
sinkWatcher . Stop ( )
2014-10-11 00:46:38 +00:00
}
2014-11-21 00:01:42 +00:00
2015-02-11 00:49:32 +00:00
func validateEvent ( actualEvent * api . Event , expectedEvent * api . Event , t * testing . T ) ( * api . Event , error ) {
2015-09-06 16:04:29 +00:00
recvEvent := * actualEvent
2015-02-11 00:49:32 +00:00
expectCompression := expectedEvent . Count > 1
2015-09-06 16:04:29 +00:00
t . Logf ( "expectedEvent.Count is %d\n" , expectedEvent . Count )
2015-02-11 00:49:32 +00:00
// Just check that the timestamp was set.
2015-09-06 16:04:29 +00:00
if recvEvent . FirstTimestamp . IsZero ( ) || recvEvent . LastTimestamp . IsZero ( ) {
t . Errorf ( "timestamp wasn't set: %#v" , recvEvent )
2015-02-11 00:49:32 +00:00
}
2015-09-06 16:04:29 +00:00
actualFirstTimestamp := recvEvent . FirstTimestamp
actualLastTimestamp := recvEvent . LastTimestamp
2015-08-23 00:51:09 +00:00
if actualFirstTimestamp . Equal ( actualLastTimestamp ) {
2015-02-11 00:49:32 +00:00
if expectCompression {
2015-09-06 16:04:29 +00:00
t . Errorf ( "FirstTimestamp (%q) and LastTimestamp (%q) must be different to indicate event compression happened, but were the same. Actual Event: %#v" , actualFirstTimestamp , actualLastTimestamp , recvEvent )
2015-02-11 00:49:32 +00:00
}
} else {
2015-08-23 00:51:09 +00:00
if expectedEvent . Count == 1 {
2015-09-06 16:04:29 +00:00
t . Errorf ( "FirstTimestamp (%q) and LastTimestamp (%q) must be equal to indicate only one occurrence of the event, but were different. Actual Event: %#v" , actualFirstTimestamp , actualLastTimestamp , recvEvent )
2015-02-11 00:49:32 +00:00
}
}
// Temp clear time stamps for comparison because actual values don't matter for comparison
2015-09-06 16:04:29 +00:00
recvEvent . FirstTimestamp = expectedEvent . FirstTimestamp
recvEvent . LastTimestamp = expectedEvent . LastTimestamp
2015-02-11 00:49:32 +00:00
// Check that name has the right prefix.
2015-09-06 16:04:29 +00:00
if n , en := recvEvent . Name , expectedEvent . Name ; ! strings . HasPrefix ( n , en ) {
2015-02-11 00:49:32 +00:00
t . Errorf ( "Name '%v' does not contain prefix '%v'" , n , en )
}
2015-09-06 16:04:29 +00:00
recvEvent . Name = expectedEvent . Name
if e , a := expectedEvent , & recvEvent ; ! reflect . DeepEqual ( e , a ) {
2015-02-11 00:49:32 +00:00
t . Errorf ( "diff: %s" , util . ObjectGoPrintDiff ( e , a ) )
}
2015-09-06 16:04:29 +00:00
recvEvent . FirstTimestamp = actualFirstTimestamp
recvEvent . LastTimestamp = actualLastTimestamp
2015-02-11 00:49:32 +00:00
return actualEvent , nil
}
2015-10-07 16:58:35 +00:00
func recorderWithFakeClock ( eventSource api . EventSource , eventBroadcaster EventBroadcaster , clock util . Clock ) EventRecorder {
return & recorderImpl { eventSource , eventBroadcaster . ( * eventBroadcasterImpl ) . Broadcaster , clock }
}
2014-11-21 00:01:42 +00:00
func TestWriteEventError ( t * testing . T ) {
ref := & api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2014-11-21 00:01:42 +00:00
}
type entry struct {
timesToSendError int
attemptsMade int
attemptsWanted int
err error
}
table := map [ string ] * entry {
"giveUp1" : {
timesToSendError : 1000 ,
attemptsWanted : 1 ,
err : & client . RequestConstructionError { } ,
} ,
"giveUp2" : {
timesToSendError : 1000 ,
attemptsWanted : 1 ,
err : & errors . StatusError { } ,
} ,
"retry1" : {
timesToSendError : 1000 ,
2015-01-13 19:13:24 +00:00
attemptsWanted : 12 ,
2014-11-21 00:01:42 +00:00
err : & errors . UnexpectedObjectError { } ,
} ,
"retry2" : {
timesToSendError : 1000 ,
2015-01-13 19:13:24 +00:00
attemptsWanted : 12 ,
2014-11-21 00:01:42 +00:00
err : fmt . Errorf ( "A weird error" ) ,
} ,
"succeedEventually" : {
timesToSendError : 2 ,
attemptsWanted : 2 ,
err : fmt . Errorf ( "A weird error" ) ,
} ,
}
done := make ( chan struct { } )
2015-03-17 04:03:07 +00:00
eventBroadcaster := NewBroadcaster ( )
defer eventBroadcaster . StartRecordingToSink (
2015-03-03 06:06:20 +00:00
& testEventSink {
2015-02-11 00:49:32 +00:00
OnCreate : func ( event * api . Event ) ( * api . Event , error ) {
2014-11-21 00:01:42 +00:00
if event . Message == "finished" {
close ( done )
return event , nil
}
item , ok := table [ event . Message ]
if ! ok {
t . Errorf ( "Unexpected event: %#v" , event )
return event , nil
}
item . attemptsMade ++
if item . attemptsMade < item . timesToSendError {
return nil , item . err
}
return event , nil
} ,
} ,
) . Stop ( )
2015-10-07 16:58:35 +00:00
clock := & util . FakeClock { time . Now ( ) }
recorder := recorderWithFakeClock ( api . EventSource { Component : "eventTest" } , eventBroadcaster , clock )
2014-11-21 00:01:42 +00:00
for caseName := range table {
2015-10-07 16:58:35 +00:00
clock . Step ( 1 * time . Second )
2015-03-17 04:03:07 +00:00
recorder . Event ( ref , "Reason" , caseName )
2014-11-21 00:01:42 +00:00
}
2015-03-17 04:03:07 +00:00
recorder . Event ( ref , "Reason" , "finished" )
2014-11-21 00:01:42 +00:00
<- done
for caseName , item := range table {
if e , a := item . attemptsWanted , item . attemptsMade ; e != a {
t . Errorf ( "case %v: wanted %v, got %v attempts" , caseName , e , a )
}
}
}
2015-01-10 00:58:07 +00:00
func TestLotsOfEvents ( t * testing . T ) {
recorderCalled := make ( chan struct { } )
loggerCalled := make ( chan struct { } )
// Fail each event a few times to ensure there's some load on the tested code.
var counts [ 1000 ] int
2015-03-03 06:06:20 +00:00
testEvents := testEventSink {
2015-02-11 00:49:32 +00:00
OnCreate : func ( event * api . Event ) ( * api . Event , error ) {
2015-01-10 00:58:07 +00:00
num , err := strconv . Atoi ( event . Message )
if err != nil {
t . Error ( err )
return event , nil
}
counts [ num ] ++
if counts [ num ] < 5 {
return nil , fmt . Errorf ( "fake error" )
}
recorderCalled <- struct { } { }
return event , nil
} ,
}
2015-03-17 04:03:07 +00:00
eventBroadcaster := NewBroadcaster ( )
sinkWatcher := eventBroadcaster . StartRecordingToSink ( & testEvents )
logWatcher := eventBroadcaster . StartLogging ( func ( formatter string , args ... interface { } ) {
2015-01-10 00:58:07 +00:00
loggerCalled <- struct { } { }
} )
2015-03-17 04:03:07 +00:00
recorder := eventBroadcaster . NewRecorder ( api . EventSource { Component : "eventTest" } )
2015-01-10 00:58:07 +00:00
ref := & api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
2015-04-08 23:28:28 +00:00
APIVersion : "version" ,
2015-01-10 00:58:07 +00:00
}
for i := 0 ; i < maxQueuedEvents ; i ++ {
2015-03-17 04:03:07 +00:00
go recorder . Eventf ( ref , "Reason" , strconv . Itoa ( i ) )
2015-01-10 00:58:07 +00:00
}
// Make sure no events were dropped by either of the listeners.
for i := 0 ; i < maxQueuedEvents ; i ++ {
<- recorderCalled
<- loggerCalled
}
// Make sure that every event was attempted 5 times
for i := 0 ; i < maxQueuedEvents ; i ++ {
if counts [ i ] < 5 {
t . Errorf ( "Only attempted to record event '%d' %d times." , i , counts [ i ] )
}
}
2015-03-17 04:03:07 +00:00
sinkWatcher . Stop ( )
logWatcher . Stop ( )
2015-01-10 00:58:07 +00:00
}
2015-04-28 23:08:16 +00:00
func TestEventfNoNamespace ( t * testing . T ) {
testPod := & api . Pod {
ObjectMeta : api . ObjectMeta {
SelfLink : "/api/version/pods/foo" ,
Name : "foo" ,
UID : "bar" ,
} ,
}
2015-06-09 17:45:46 +00:00
testRef , err := api . GetPartialReference ( testPod , "spec.containers[2]" )
2015-04-28 23:08:16 +00:00
if err != nil {
t . Fatal ( err )
}
table := [ ] struct {
obj runtime . Object
reason string
messageFmt string
elements [ ] interface { }
expect * api . Event
expectLog string
expectUpdate bool
} {
{
obj : testRef ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "default" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "" ,
UID : "bar" ,
APIVersion : "version" ,
2015-06-09 17:45:46 +00:00
FieldPath : "spec.containers[2]" ,
2015-04-28 23:08:16 +00:00
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
2015-06-09 17:45:46 +00:00
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
2015-04-28 23:08:16 +00:00
expectUpdate : false ,
} ,
}
2015-10-07 16:58:35 +00:00
testCache := map [ string ] * api . Event { }
2015-09-06 16:04:29 +00:00
logCalled := make ( chan struct { } )
createEvent := make ( chan * api . Event )
updateEvent := make ( chan * api . Event )
2015-10-07 16:58:35 +00:00
patchEvent := make ( chan * api . Event )
2015-09-06 16:04:29 +00:00
testEvents := testEventSink {
2015-10-07 16:58:35 +00:00
OnCreate : OnCreateFactory ( testCache , createEvent ) ,
2015-09-06 16:04:29 +00:00
OnUpdate : func ( event * api . Event ) ( * api . Event , error ) {
updateEvent <- event
return event , nil
} ,
2015-10-07 16:58:35 +00:00
OnPatch : OnPatchFactory ( testCache , patchEvent ) ,
2015-09-06 16:04:29 +00:00
}
eventBroadcaster := NewBroadcaster ( )
sinkWatcher := eventBroadcaster . StartRecordingToSink ( & testEvents )
2015-10-07 16:58:35 +00:00
clock := & util . FakeClock { time . Now ( ) }
recorder := recorderWithFakeClock ( api . EventSource { Component : "eventTest" } , eventBroadcaster , clock )
2015-09-06 16:04:29 +00:00
2015-04-28 23:08:16 +00:00
for _ , item := range table {
2015-10-07 16:58:35 +00:00
clock . Step ( 1 * time . Second )
2015-04-28 23:08:16 +00:00
logWatcher1 := eventBroadcaster . StartLogging ( t . Logf ) // Prove that it is useful
logWatcher2 := eventBroadcaster . StartLogging ( func ( formatter string , args ... interface { } ) {
if e , a := item . expectLog , fmt . Sprintf ( formatter , args ... ) ; e != a {
t . Errorf ( "Expected '%v', got '%v'" , e , a )
}
2015-09-06 16:04:29 +00:00
logCalled <- struct { } { }
2015-04-28 23:08:16 +00:00
} )
recorder . Eventf ( item . obj , item . reason , item . messageFmt , item . elements ... )
2015-09-06 16:04:29 +00:00
<- logCalled
// validate event
if item . expectUpdate {
2015-10-07 16:58:35 +00:00
actualEvent := <- patchEvent
2015-09-06 16:04:29 +00:00
validateEvent ( actualEvent , item . expect , t )
} else {
actualEvent := <- createEvent
validateEvent ( actualEvent , item . expect , t )
}
2015-04-28 23:08:16 +00:00
logWatcher1 . Stop ( )
logWatcher2 . Stop ( )
}
2015-09-06 16:04:29 +00:00
sinkWatcher . Stop ( )
}
func TestMultiSinkCache ( t * testing . T ) {
testPod := & api . Pod {
ObjectMeta : api . ObjectMeta {
SelfLink : "/api/version/pods/foo" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
} ,
}
testPod2 := & api . Pod {
ObjectMeta : api . ObjectMeta {
SelfLink : "/api/version/pods/foo" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
} ,
}
testRef , err := api . GetPartialReference ( testPod , "spec.containers[2]" )
testRef2 , err := api . GetPartialReference ( testPod2 , "spec.containers[3]" )
if err != nil {
t . Fatal ( err )
}
table := [ ] struct {
obj runtime . Object
reason string
messageFmt string
elements [ ] interface { }
expect * api . Event
expectLog string
expectUpdate bool
} {
{
obj : testRef ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
APIVersion : "version" ,
FieldPath : "spec.containers[2]" ,
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
expectUpdate : false ,
} ,
{
obj : testPod ,
reason : "Killed" ,
messageFmt : "some other verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
APIVersion : "version" ,
} ,
Reason : "Killed" ,
Message : "some other verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:""}): reason: 'Killed' some other verbose message: 1 ` ,
expectUpdate : false ,
} ,
{
obj : testRef ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
APIVersion : "version" ,
FieldPath : "spec.containers[2]" ,
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 2 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
expectUpdate : true ,
} ,
{
obj : testRef2 ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
APIVersion : "version" ,
FieldPath : "spec.containers[3]" ,
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): reason: 'Started' some verbose message: 1 ` ,
expectUpdate : false ,
} ,
{
obj : testRef ,
reason : "Started" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "bar" ,
APIVersion : "version" ,
FieldPath : "spec.containers[2]" ,
} ,
Reason : "Started" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 3 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): reason: 'Started' some verbose message: 1 ` ,
expectUpdate : true ,
} ,
{
obj : testRef2 ,
reason : "Stopped" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
APIVersion : "version" ,
FieldPath : "spec.containers[3]" ,
} ,
Reason : "Stopped" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 1 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): reason: 'Stopped' some verbose message: 1 ` ,
expectUpdate : false ,
} ,
{
obj : testRef2 ,
reason : "Stopped" ,
messageFmt : "some verbose message: %v" ,
elements : [ ] interface { } { 1 } ,
expect : & api . Event {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "baz" ,
} ,
InvolvedObject : api . ObjectReference {
Kind : "Pod" ,
Name : "foo" ,
Namespace : "baz" ,
UID : "differentUid" ,
APIVersion : "version" ,
FieldPath : "spec.containers[3]" ,
} ,
Reason : "Stopped" ,
Message : "some verbose message: 1" ,
Source : api . EventSource { Component : "eventTest" } ,
Count : 2 ,
} ,
expectLog : ` Event(api.ObjectReference { Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): reason: 'Stopped' some verbose message: 1 ` ,
expectUpdate : true ,
} ,
}
2015-10-07 16:58:35 +00:00
testCache := map [ string ] * api . Event { }
2015-09-06 16:04:29 +00:00
createEvent := make ( chan * api . Event )
updateEvent := make ( chan * api . Event )
2015-10-07 16:58:35 +00:00
patchEvent := make ( chan * api . Event )
2015-09-06 16:04:29 +00:00
testEvents := testEventSink {
2015-10-07 16:58:35 +00:00
OnCreate : OnCreateFactory ( testCache , createEvent ) ,
2015-09-06 16:04:29 +00:00
OnUpdate : func ( event * api . Event ) ( * api . Event , error ) {
updateEvent <- event
return event , nil
} ,
2015-10-07 16:58:35 +00:00
OnPatch : OnPatchFactory ( testCache , patchEvent ) ,
2015-09-06 16:04:29 +00:00
}
2015-10-07 16:58:35 +00:00
testCache2 := map [ string ] * api . Event { }
2015-09-06 16:04:29 +00:00
createEvent2 := make ( chan * api . Event )
updateEvent2 := make ( chan * api . Event )
2015-10-07 16:58:35 +00:00
patchEvent2 := make ( chan * api . Event )
2015-09-06 16:04:29 +00:00
testEvents2 := testEventSink {
2015-10-07 16:58:35 +00:00
OnCreate : OnCreateFactory ( testCache2 , createEvent2 ) ,
2015-09-06 16:04:29 +00:00
OnUpdate : func ( event * api . Event ) ( * api . Event , error ) {
updateEvent2 <- event
return event , nil
} ,
2015-10-07 16:58:35 +00:00
OnPatch : OnPatchFactory ( testCache2 , patchEvent2 ) ,
2015-09-06 16:04:29 +00:00
}
eventBroadcaster := NewBroadcaster ( )
2015-10-07 16:58:35 +00:00
clock := & util . FakeClock { time . Now ( ) }
recorder := recorderWithFakeClock ( api . EventSource { Component : "eventTest" } , eventBroadcaster , clock )
2015-09-06 16:04:29 +00:00
sinkWatcher := eventBroadcaster . StartRecordingToSink ( & testEvents )
for _ , item := range table {
2015-10-07 16:58:35 +00:00
clock . Step ( 1 * time . Second )
2015-09-06 16:04:29 +00:00
recorder . Eventf ( item . obj , item . reason , item . messageFmt , item . elements ... )
// validate event
if item . expectUpdate {
2015-10-07 16:58:35 +00:00
actualEvent := <- patchEvent
2015-09-06 16:04:29 +00:00
validateEvent ( actualEvent , item . expect , t )
} else {
actualEvent := <- createEvent
validateEvent ( actualEvent , item . expect , t )
}
}
// Another StartRecordingToSink call should start to record events with new clean cache.
sinkWatcher2 := eventBroadcaster . StartRecordingToSink ( & testEvents2 )
for _ , item := range table {
2015-10-07 16:58:35 +00:00
clock . Step ( 1 * time . Second )
2015-09-06 16:04:29 +00:00
recorder . Eventf ( item . obj , item . reason , item . messageFmt , item . elements ... )
// validate event
if item . expectUpdate {
2015-10-07 16:58:35 +00:00
actualEvent := <- patchEvent2
2015-09-06 16:04:29 +00:00
validateEvent ( actualEvent , item . expect , t )
} else {
actualEvent := <- createEvent2
validateEvent ( actualEvent , item . expect , t )
}
}
sinkWatcher . Stop ( )
sinkWatcher2 . Stop ( )
2015-04-28 23:08:16 +00:00
}