2022-12-08 13:05:19 -03:00

191 lines
4.0 KiB
Go

// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.
package cgroups
import (
"math"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
var cgroupPath = []string{"/kubepods", "burstable", "pods234sdf", "234as8df34"}
func createHierarchy(t *testing.T, cpuEnabled bool) (string, string) {
testRoot := t.TempDir()
if err := os.WriteFile(filepath.Join(testRoot, "cgroup.controllers"), []byte(""), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(testRoot, "cgroup.subtree_control"), []byte(""), 0755); err != nil {
t.Fatal(err)
}
testCgroup := ""
for i, level := range cgroupPath {
testCgroup = filepath.Join(testCgroup, level)
fullPath := filepath.Join(testRoot, testCgroup)
if err := os.Mkdir(fullPath, 0o755); err != nil {
t.Fatal(err)
}
ctrlFile, err := os.Create(filepath.Join(fullPath, "cgroup.controllers"))
if err != nil {
t.Fatal(err)
}
defer ctrlFile.Close()
if cpuEnabled {
if _, err := ctrlFile.WriteString("cpu"); err != nil {
t.Fatal(err)
}
}
subTreeFile, err := os.Create(filepath.Join(fullPath, "cgroup.subtree_control"))
if err != nil {
t.Fatal(err)
}
defer subTreeFile.Close()
if cpuEnabled && i < len(cgroupPath)-1 {
if _, err := subTreeFile.WriteString("cpu"); err != nil {
t.Fatal(err)
}
}
}
return testRoot, testCgroup
}
func TestEnableController(t *testing.T) {
root, cgroup := createHierarchy(t, false)
if err := EnsureCpuControllerEnabled(root, cgroup); err != nil {
t.Fatal(err)
}
levelPath := root
for _, level := range cgroupPath {
verifyCpuControllerToggled(t, levelPath, true)
levelPath = filepath.Join(levelPath, level)
}
verifyCpuControllerToggled(t, levelPath, false)
}
func verifyCpuControllerToggled(t *testing.T, path string, enabled bool) {
t.Helper()
content, err := os.ReadFile(filepath.Join(path, "cgroup.subtree_control"))
if err != nil {
t.Fatal(err)
}
if enabled && string(content) != "+cpu" {
t.Fatalf("%s should have enabled cpu controller", path)
} else if !enabled && string(content) == "+cpu" {
t.Fatalf("%s should not have enabled cpu controller", path)
}
}
func TestReadSingleValue(t *testing.T) {
scenarios := []struct {
name string
content string
expected uint64
}{
{
name: "cgroup2 max value",
content: "max",
expected: math.MaxUint64,
},
{
name: "cgroup1 max value",
content: "-1",
expected: math.MaxUint64,
},
{
name: "valid value",
content: "100000",
expected: 100_000,
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
f, err := os.CreateTemp("", "cgroup_test*")
if err != nil {
t.Fatal(err)
}
if _, err := f.Write([]byte(s.content)); err != nil {
t.Fatal(err)
}
v, err := ReadSingleValue(f.Name())
if err != nil {
t.Fatal(err)
}
assert.Equal(t, s.expected, v)
})
}
}
func TestReadPSI(t *testing.T) {
scenarios := []struct {
name string
content string
expected PSI
}{
{
name: "psi some",
content: "some avg10=61.00 avg60=64.28 avg300=29.94 total=149969752",
expected: PSI{
Some: 149969752,
Full: 0,
},
},
{
name: "psi full",
content: "full avg10=36.27 avg60=37.15 avg300=17.59 total=93027571",
expected: PSI{
Some: 0,
Full: 93027571,
},
},
{
name: "psi some and full",
content: "some avg10=61.00 avg60=64.28 avg300=29.94 total=149969752\nfull avg10=36.27 avg60=37.15 avg300=17.59 total=93027571",
expected: PSI{
Some: 149969752,
Full: 93027571,
},
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
f, err := os.CreateTemp("", "cgroup_test*")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
if _, err := f.Write([]byte(s.content)); err != nil {
t.Fatal(err)
}
v, err := ReadPSIValue(f.Name())
if err != nil {
t.Fatal(err)
}
assert.Equal(t, s.expected, v)
})
}
}