github.com/google/cadvisor@v0.49.1/container/libcontainer/handler_test.go (about)

     1  // Copyright 2018 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package libcontainer
    16  
    17  import (
    18  	"os"
    19  	"reflect"
    20  	"testing"
    21  
    22  	"github.com/opencontainers/runc/libcontainer/cgroups"
    23  	"github.com/stretchr/testify/assert"
    24  
    25  	info "github.com/google/cadvisor/info/v1"
    26  )
    27  
    28  func TestScanInterfaceStats(t *testing.T) {
    29  	stats, err := scanInterfaceStats("testdata/procnetdev")
    30  	if err != nil {
    31  		t.Error(err)
    32  	}
    33  
    34  	netdevstats := []info.InterfaceStats{
    35  		{
    36  			Name:      "wlp4s0",
    37  			RxBytes:   1,
    38  			RxPackets: 2,
    39  			RxErrors:  3,
    40  			RxDropped: 4,
    41  			TxBytes:   9,
    42  			TxPackets: 10,
    43  			TxErrors:  11,
    44  			TxDropped: 12,
    45  		},
    46  		{
    47  			Name:      "em1",
    48  			RxBytes:   315849,
    49  			RxPackets: 1172,
    50  			RxErrors:  0,
    51  			RxDropped: 0,
    52  			TxBytes:   315850,
    53  			TxPackets: 1173,
    54  			TxErrors:  0,
    55  			TxDropped: 0,
    56  		},
    57  	}
    58  
    59  	if len(stats) != len(netdevstats) {
    60  		t.Errorf("Expected 2 net stats, got %d", len(stats))
    61  	}
    62  
    63  	for i, v := range netdevstats {
    64  		if v != stats[i] {
    65  			t.Errorf("Expected %#v, got %#v", v, stats[i])
    66  		}
    67  	}
    68  }
    69  
    70  func TestScanUDPStats(t *testing.T) {
    71  	udpStatsFile := "testdata/procnetudp"
    72  	r, err := os.Open(udpStatsFile)
    73  	if err != nil {
    74  		t.Errorf("failure opening %s: %v", udpStatsFile, err)
    75  	}
    76  
    77  	stats, err := scanUDPStats(r)
    78  	if err != nil {
    79  		t.Error(err)
    80  	}
    81  
    82  	udpstats := info.UdpStat{
    83  		Listen:   2,
    84  		Dropped:  4,
    85  		RxQueued: 10,
    86  		TxQueued: 11,
    87  	}
    88  
    89  	if stats != udpstats {
    90  		t.Errorf("Expected %#v, got %#v", udpstats, stats)
    91  	}
    92  }
    93  
    94  // https://github.com/docker/libcontainer/blob/v2.2.1/cgroups/fs/cpuacct.go#L19
    95  const nanosecondsInSeconds = 1000000000
    96  
    97  // https://github.com/containerd/cgroups/pull/12
    98  const clockTicks = 100
    99  
   100  func TestSetCPUStats(t *testing.T) {
   101  	perCPUUsage := make([]uint64, 31)
   102  	for i := uint32(0); i < 31; i++ {
   103  		perCPUUsage[i] = 8562955455524
   104  	}
   105  	s := &cgroups.Stats{
   106  		CpuStats: cgroups.CpuStats{
   107  			CpuUsage: cgroups.CpuUsage{
   108  				PercpuUsage:       perCPUUsage,
   109  				TotalUsage:        33802947350272,
   110  				UsageInKernelmode: 734746 * nanosecondsInSeconds / clockTicks,
   111  				UsageInUsermode:   2767637 * nanosecondsInSeconds / clockTicks,
   112  			},
   113  		},
   114  	}
   115  	var ret info.ContainerStats
   116  	setCPUStats(s, &ret, true)
   117  
   118  	expected := info.ContainerStats{
   119  		Cpu: info.CpuStats{
   120  			Usage: info.CpuUsage{
   121  				PerCpu: perCPUUsage,
   122  				User:   s.CpuStats.CpuUsage.UsageInUsermode,
   123  				System: s.CpuStats.CpuUsage.UsageInKernelmode,
   124  				Total:  33802947350272,
   125  			},
   126  		},
   127  	}
   128  
   129  	if !ret.Eq(&expected) {
   130  		t.Fatalf("expected %+v == %+v", ret, expected)
   131  	}
   132  }
   133  
   134  func TestSetProcessesStats(t *testing.T) {
   135  	ret := info.ContainerStats{
   136  		Processes: info.ProcessStats{
   137  			ProcessCount: 1,
   138  			FdCount:      2,
   139  		},
   140  	}
   141  	s := &cgroups.Stats{
   142  		PidsStats: cgroups.PidsStats{
   143  			Current: 5,
   144  			Limit:   100,
   145  		},
   146  	}
   147  	setThreadsStats(s, &ret)
   148  
   149  	expected := info.ContainerStats{
   150  
   151  		Processes: info.ProcessStats{
   152  			ProcessCount:   1,
   153  			FdCount:        2,
   154  			ThreadsCurrent: s.PidsStats.Current,
   155  			ThreadsMax:     s.PidsStats.Limit,
   156  		},
   157  	}
   158  
   159  	if expected.Processes.ProcessCount != ret.Processes.ProcessCount {
   160  		t.Fatalf("expected ProcessCount: %d == %d", ret.Processes.ProcessCount, expected.Processes.ProcessCount)
   161  	}
   162  	if expected.Processes.FdCount != ret.Processes.FdCount {
   163  		t.Fatalf("expected FdCount: %d == %d", ret.Processes.FdCount, expected.Processes.FdCount)
   164  	}
   165  
   166  	if expected.Processes.ThreadsCurrent != ret.Processes.ThreadsCurrent {
   167  		t.Fatalf("expected current threads: %d == %d", ret.Processes.ThreadsCurrent, expected.Processes.ThreadsCurrent)
   168  	}
   169  	if expected.Processes.ThreadsMax != ret.Processes.ThreadsMax {
   170  		t.Fatalf("expected max threads: %d == %d", ret.Processes.ThreadsMax, expected.Processes.ThreadsMax)
   171  	}
   172  }
   173  
   174  func TestParseLimitsFile(t *testing.T) {
   175  	testData := []struct {
   176  		limitLine string
   177  		expected  []info.UlimitSpec
   178  	}{
   179  		{
   180  			"Limit                     Soft Limit           Hard Limit           Units   \n",
   181  			[]info.UlimitSpec{},
   182  		},
   183  		{
   184  			"Max open files            8192                 8192                 files   \n",
   185  			[]info.UlimitSpec{{Name: "max_open_files", SoftLimit: 8192, HardLimit: 8192}},
   186  		},
   187  		{
   188  			"Max open files            85899345920          85899345920          files   \n",
   189  			[]info.UlimitSpec{{Name: "max_open_files", SoftLimit: 85899345920, HardLimit: 85899345920}},
   190  		},
   191  		{
   192  			"Max open files            gibberish1           8192                 files   \n",
   193  			[]info.UlimitSpec{},
   194  		},
   195  		{
   196  			"Max open files            8192                 0xbaddata            files   \n",
   197  			[]info.UlimitSpec{},
   198  		},
   199  		{
   200  			"Max stack size            8192                 8192                 files   \n",
   201  			[]info.UlimitSpec{},
   202  		},
   203  	}
   204  
   205  	for _, testItem := range testData {
   206  		actual := processLimitsFile(testItem.limitLine)
   207  		if reflect.DeepEqual(actual, testItem.expected) == false {
   208  			t.Fatalf("Parsed ulimit doesn't match expected values for line: %s", testItem.limitLine)
   209  		}
   210  	}
   211  }
   212  
   213  func TestReferencedBytesStat(t *testing.T) {
   214  	// overwrite package variables
   215  	smapsFilePathPattern = "testdata/smaps%d"
   216  	clearRefsFilePathPattern = "testdata/clear_refs%d"
   217  
   218  	pids := []int{4, 6, 8}
   219  	stat, err := referencedBytesStat(pids, 1, 3)
   220  	assert.Nil(t, err)
   221  	assert.Equal(t, uint64(416*1024), stat)
   222  
   223  	clearRefsFiles := []string{
   224  		"testdata/clear_refs4",
   225  		"testdata/clear_refs6",
   226  		"testdata/clear_refs8",
   227  	}
   228  
   229  	// check if clear_refs files have proper values
   230  	assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[0]))
   231  	assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[1]))
   232  	assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[2]))
   233  }
   234  
   235  func TestReferencedBytesStatWhenNeverCleared(t *testing.T) {
   236  	// overwrite package variables
   237  	smapsFilePathPattern = "testdata/smaps%d"
   238  	clearRefsFilePathPattern = "testdata/clear_refs%d"
   239  
   240  	pids := []int{4, 6, 8}
   241  	stat, err := referencedBytesStat(pids, 1, 0)
   242  	assert.Nil(t, err)
   243  	assert.Equal(t, uint64(416*1024), stat)
   244  
   245  	clearRefsFiles := []string{
   246  		"testdata/clear_refs4",
   247  		"testdata/clear_refs6",
   248  		"testdata/clear_refs8",
   249  	}
   250  
   251  	// check if clear_refs files have proper values
   252  	assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[0]))
   253  	assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[1]))
   254  	assert.Equal(t, "0\n", getFileContent(t, clearRefsFiles[2]))
   255  }
   256  
   257  func TestReferencedBytesStatWhenResetIsNeeded(t *testing.T) {
   258  	// overwrite package variables
   259  	smapsFilePathPattern = "testdata/smaps%d"
   260  	clearRefsFilePathPattern = "testdata/clear_refs%d"
   261  
   262  	pids := []int{4, 6, 8}
   263  	stat, err := referencedBytesStat(pids, 1, 1)
   264  	assert.Nil(t, err)
   265  	assert.Equal(t, uint64(416*1024), stat)
   266  
   267  	clearRefsFiles := []string{
   268  		"testdata/clear_refs4",
   269  		"testdata/clear_refs6",
   270  		"testdata/clear_refs8",
   271  	}
   272  
   273  	// check if clear_refs files have proper values
   274  	assert.Equal(t, "1\n", getFileContent(t, clearRefsFiles[0]))
   275  	assert.Equal(t, "1\n", getFileContent(t, clearRefsFiles[1]))
   276  	assert.Equal(t, "1\n", getFileContent(t, clearRefsFiles[2]))
   277  
   278  	clearTestData(t, clearRefsFiles)
   279  }
   280  
   281  func TestGetReferencedKBytesWhenSmapsMissing(t *testing.T) {
   282  	// overwrite package variable
   283  	smapsFilePathPattern = "testdata/smaps%d"
   284  
   285  	pids := []int{10}
   286  	referenced, err := getReferencedKBytes(pids)
   287  	assert.Nil(t, err)
   288  	assert.Equal(t, uint64(0), referenced)
   289  }
   290  
   291  func TestClearReferencedBytesWhenClearRefsMissing(t *testing.T) {
   292  	// overwrite package variable
   293  	clearRefsFilePathPattern = "testdata/clear_refs%d"
   294  
   295  	pids := []int{10}
   296  	err := clearReferencedBytes(pids, 0, 1)
   297  	assert.Nil(t, err)
   298  }
   299  
   300  var ulimits []info.UlimitSpec
   301  
   302  func BenchmarkProcessLimitsFile(b *testing.B) {
   303  	content, err := os.ReadFile("testdata/limits")
   304  	assert.Nil(b, err)
   305  
   306  	b.ResetTimer()
   307  	for i := 0; i < b.N; i++ {
   308  		ulimits = processLimitsFile(string(content))
   309  	}
   310  
   311  	// Ensure the compiler doesn't optimize away the benchmark
   312  	_ = ulimits
   313  }
   314  
   315  func TestProcessMaxOpenFileLimitLine(t *testing.T) {
   316  	line := "            1073741816           1073741816           files     "
   317  
   318  	ulimit, err := processMaxOpenFileLimitLine("max_open_files", line)
   319  	assert.Nil(t, err)
   320  	assert.Equal(t, "max_open_files", ulimit.Name)
   321  	assert.Equal(t, int64(1073741816), ulimit.SoftLimit)
   322  	assert.Equal(t, int64(1073741816), ulimit.HardLimit)
   323  }