...

Source file src/k8s.io/kubernetes/pkg/kubelet/container/cache_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/container

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package container
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  	"k8s.io/apimachinery/pkg/types"
    27  )
    28  
    29  func newTestCache() *cache {
    30  	c := NewCache()
    31  	return c.(*cache)
    32  }
    33  
    34  func TestCacheNotInitialized(t *testing.T) {
    35  	cache := newTestCache()
    36  	// If the global timestamp is not set, always return nil.
    37  	d := cache.getIfNewerThan(types.UID("1234"), time.Time{})
    38  	assert.True(t, d == nil, "should return nil since cache is not initialized")
    39  }
    40  
    41  func getTestPodIDAndStatus(numContainers int) (types.UID, *PodStatus) {
    42  	id := types.UID(strconv.FormatInt(time.Now().UnixNano(), 10))
    43  	name := fmt.Sprintf("cache-foo-%s", string(id))
    44  	namespace := "ns"
    45  	var status *PodStatus
    46  	if numContainers > 0 {
    47  		status = &PodStatus{ID: id, Name: name, Namespace: namespace}
    48  	} else {
    49  		status = &PodStatus{ID: id}
    50  	}
    51  	for i := 0; i < numContainers; i++ {
    52  		status.ContainerStatuses = append(status.ContainerStatuses, &Status{Name: strconv.Itoa(i)})
    53  	}
    54  	return id, status
    55  }
    56  
    57  func TestGetIfNewerThanWhenPodExists(t *testing.T) {
    58  	cache := newTestCache()
    59  	timestamp := time.Now()
    60  
    61  	cases := []struct {
    62  		cacheTime time.Time
    63  		modified  time.Time
    64  		expected  bool
    65  	}{
    66  		{
    67  			// Both the global cache timestamp and the modified time are newer
    68  			// than the timestamp.
    69  			cacheTime: timestamp.Add(time.Second),
    70  			modified:  timestamp,
    71  			expected:  true,
    72  		},
    73  		{
    74  			// Global cache timestamp is newer, but the pod entry modified
    75  			// time is older than the given timestamp. This means that the
    76  			// entry is up-to-date even though it hasn't changed for a while.
    77  			cacheTime: timestamp.Add(time.Second),
    78  			modified:  timestamp.Add(-time.Second * 10),
    79  			expected:  true,
    80  		},
    81  		{
    82  			// Global cache timestamp is older, but the pod entry modified
    83  			// time is newer than the given timestamp. This means that the
    84  			// entry is up-to-date but the rest of the cache are still being
    85  			// updated.
    86  			cacheTime: timestamp.Add(-time.Second),
    87  			modified:  timestamp.Add(time.Second * 3),
    88  			expected:  true,
    89  		},
    90  		{
    91  			// Both the global cache timestamp and the modified time are older
    92  			// than the given timestamp.
    93  			cacheTime: timestamp.Add(-time.Second),
    94  			modified:  timestamp.Add(-time.Second),
    95  			expected:  false,
    96  		},
    97  	}
    98  	for i, c := range cases {
    99  		podID, status := getTestPodIDAndStatus(2)
   100  		cache.UpdateTime(c.cacheTime)
   101  		cache.Set(podID, status, nil, c.modified)
   102  		d := cache.getIfNewerThan(podID, timestamp)
   103  		assert.Equal(t, c.expected, d != nil, "test[%d]", i)
   104  	}
   105  }
   106  
   107  func TestGetPodNewerThanWhenPodDoesNotExist(t *testing.T) {
   108  	cache := newTestCache()
   109  	cacheTime := time.Now()
   110  	cache.UpdateTime(cacheTime)
   111  	podID := types.UID("1234")
   112  
   113  	cases := []struct {
   114  		timestamp time.Time
   115  		expected  bool
   116  	}{
   117  		{
   118  			timestamp: cacheTime.Add(-time.Second),
   119  			expected:  true,
   120  		},
   121  		{
   122  			timestamp: cacheTime.Add(time.Second),
   123  			expected:  false,
   124  		},
   125  	}
   126  	for i, c := range cases {
   127  		d := cache.getIfNewerThan(podID, c.timestamp)
   128  		assert.Equal(t, c.expected, d != nil, "test[%d]", i)
   129  	}
   130  }
   131  
   132  func TestCacheSetAndGet(t *testing.T) {
   133  	cache := NewCache()
   134  	cases := []struct {
   135  		numContainers int
   136  		error         error
   137  	}{
   138  		{numContainers: 3, error: nil},
   139  		{numContainers: 2, error: fmt.Errorf("unable to get status")},
   140  		{numContainers: 0, error: nil},
   141  	}
   142  	for i, c := range cases {
   143  		podID, status := getTestPodIDAndStatus(c.numContainers)
   144  		cache.Set(podID, status, c.error, time.Time{})
   145  		// Read back the status and error stored in cache and make sure they
   146  		// match the original ones.
   147  		actualStatus, actualErr := cache.Get(podID)
   148  		assert.Equal(t, status, actualStatus, "test[%d]", i)
   149  		assert.Equal(t, c.error, actualErr, "test[%d]", i)
   150  	}
   151  }
   152  
   153  func TestCacheGetPodDoesNotExist(t *testing.T) {
   154  	cache := NewCache()
   155  	podID, status := getTestPodIDAndStatus(0)
   156  	// If the pod does not exist in cache, cache should return an status
   157  	// object with id filled.
   158  	actualStatus, actualErr := cache.Get(podID)
   159  	assert.Equal(t, status, actualStatus)
   160  	assert.Equal(t, nil, actualErr)
   161  }
   162  
   163  func TestDelete(t *testing.T) {
   164  	cache := &cache{pods: map[types.UID]*data{}}
   165  	// Write a new pod status into the cache.
   166  	podID, status := getTestPodIDAndStatus(3)
   167  	cache.Set(podID, status, nil, time.Time{})
   168  	actualStatus, actualErr := cache.Get(podID)
   169  	assert.Equal(t, status, actualStatus)
   170  	assert.Equal(t, nil, actualErr)
   171  	// Delete the pod from cache, and verify that we get an empty status.
   172  	cache.Delete(podID)
   173  	expectedStatus := &PodStatus{ID: podID}
   174  	actualStatus, actualErr = cache.Get(podID)
   175  	assert.Equal(t, expectedStatus, actualStatus)
   176  	assert.Equal(t, nil, actualErr)
   177  }
   178  
   179  func verifyNotification(t *testing.T, ch chan *data, expectNotification bool) {
   180  	if expectNotification {
   181  		assert.True(t, len(ch) > 0, "Did not receive notification")
   182  	} else {
   183  		assert.True(t, len(ch) < 1, "Should not have triggered the notification")
   184  	}
   185  	// Drain the channel.
   186  	for i := 0; i < len(ch); i++ {
   187  		<-ch
   188  	}
   189  }
   190  
   191  func TestRegisterNotification(t *testing.T) {
   192  	cache := newTestCache()
   193  	cacheTime := time.Now()
   194  	cache.UpdateTime(cacheTime)
   195  
   196  	podID, status := getTestPodIDAndStatus(1)
   197  	ch := cache.subscribe(podID, cacheTime.Add(time.Second))
   198  	verifyNotification(t, ch, false)
   199  	cache.Set(podID, status, nil, cacheTime.Add(time.Second))
   200  	// The Set operation should've triggered the notification.
   201  	verifyNotification(t, ch, true)
   202  
   203  	podID, _ = getTestPodIDAndStatus(1)
   204  
   205  	ch = cache.subscribe(podID, cacheTime.Add(time.Second))
   206  	verifyNotification(t, ch, false)
   207  	cache.UpdateTime(cacheTime.Add(time.Second * 2))
   208  	// The advance of cache timestamp should've triggered the notification.
   209  	verifyNotification(t, ch, true)
   210  }
   211  

View as plain text