libcontainer: add test cases for Intel RDT/CAT

Signed-off-by: Xiaochen Shen <xiaochen.shen@intel.com>
This commit is contained in:
Xiaochen Shen 2017-08-30 19:35:09 +08:00
parent 692f6e1e27
commit 4d2756c116
4 changed files with 198 additions and 4 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/intelrdt"
"github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/system"
) )
@ -19,6 +20,11 @@ type mockCgroupManager struct {
paths map[string]string paths map[string]string
} }
type mockIntelRdtManager struct {
stats *intelrdt.Stats
path string
}
func (m *mockCgroupManager) GetPids() ([]int, error) { func (m *mockCgroupManager) GetPids() ([]int, error) {
return m.pids, nil return m.pids, nil
} }
@ -51,6 +57,26 @@ func (m *mockCgroupManager) Freeze(state configs.FreezerState) error {
return nil return nil
} }
func (m *mockIntelRdtManager) Apply(pid int) error {
return nil
}
func (m *mockIntelRdtManager) GetStats() (*intelrdt.Stats, error) {
return m.stats, nil
}
func (m *mockIntelRdtManager) Destroy() error {
return nil
}
func (m *mockIntelRdtManager) GetPath() string {
return m.path
}
func (m *mockIntelRdtManager) Set(container *configs.Config) error {
return nil
}
type mockProcess struct { type mockProcess struct {
_pid int _pid int
started uint64 started uint64
@ -118,6 +144,11 @@ func TestGetContainerStats(t *testing.T) {
}, },
}, },
}, },
intelRdtManager: &mockIntelRdtManager{
stats: &intelrdt.Stats{
L3CacheSchema: "L3:0=f;1=f0",
},
},
} }
stats, err := container.Stats() stats, err := container.Stats()
if err != nil { if err != nil {
@ -129,6 +160,14 @@ func TestGetContainerStats(t *testing.T) {
if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 { if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 {
t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage.Usage) t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage.Usage)
} }
if intelrdt.IsIntelRdtEnabled() {
if stats.IntelRdtStats == nil {
t.Fatal("intel rdt stats are nil")
}
if stats.IntelRdtStats.L3CacheSchema != "L3:0=f;1=f0" {
t.Fatalf("expected L3CacheSchema L3:0=f;1=f0 but recevied %s", stats.IntelRdtStats.L3CacheSchema)
}
}
} }
func TestGetContainerState(t *testing.T) { func TestGetContainerState(t *testing.T) {
@ -136,6 +175,7 @@ func TestGetContainerState(t *testing.T) {
pid = os.Getpid() pid = os.Getpid()
expectedMemoryPath = "/sys/fs/cgroup/memory/myid" expectedMemoryPath = "/sys/fs/cgroup/memory/myid"
expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid) expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid)
expectedIntelRdtPath = "/sys/fs/resctrl/myid"
) )
container := &linuxContainer{ container := &linuxContainer{
id: "myid", id: "myid",
@ -166,6 +206,12 @@ func TestGetContainerState(t *testing.T) {
"memory": expectedMemoryPath, "memory": expectedMemoryPath,
}, },
}, },
intelRdtManager: &mockIntelRdtManager{
stats: &intelrdt.Stats{
L3CacheSchema: "L3:0=f0;1=f",
},
path: expectedIntelRdtPath,
},
} }
container.state = &createdState{c: container} container.state = &createdState{c: container}
state, err := container.State() state, err := container.State()
@ -185,6 +231,15 @@ func TestGetContainerState(t *testing.T) {
if memPath := paths["memory"]; memPath != expectedMemoryPath { if memPath := paths["memory"]; memPath != expectedMemoryPath {
t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath) t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath)
} }
if intelrdt.IsIntelRdtEnabled() {
intelRdtPath := state.IntelRdtPath
if intelRdtPath == "" {
t.Fatal("intel rdt path should not be empty")
}
if intelRdtPath != expectedIntelRdtPath {
t.Fatalf("expected intel rdt path %q but received %q", expectedIntelRdtPath, intelRdtPath)
}
}
for _, ns := range container.config.Namespaces { for _, ns := range container.config.Namespaces {
path := state.NamespacePaths[ns.Type] path := state.NamespacePaths[ns.Type]
if path == "" { if path == "" {

View File

@ -50,6 +50,32 @@ func TestFactoryNew(t *testing.T) {
} }
} }
func TestFactoryNewIntelRdt(t *testing.T) {
root, rerr := newTestRoot()
if rerr != nil {
t.Fatal(rerr)
}
defer os.RemoveAll(root)
factory, err := New(root, Cgroupfs, IntelRdtFs)
if err != nil {
t.Fatal(err)
}
if factory == nil {
t.Fatal("factory should not be nil")
}
lfactory, ok := factory.(*LinuxFactory)
if !ok {
t.Fatal("expected linux factory returned on linux based systems")
}
if lfactory.Root != root {
t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root)
}
if factory.Type() != "libcontainer" {
t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer")
}
}
func TestFactoryNewTmpfs(t *testing.T) { func TestFactoryNewTmpfs(t *testing.T) {
root, rerr := newTestRoot() root, rerr := newTestRoot()
if rerr != nil { if rerr != nil {
@ -164,7 +190,7 @@ func TestFactoryLoadContainer(t *testing.T) {
if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil { if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil {
t.Fatal(err) t.Fatal(err)
} }
factory, err := New(root, Cgroupfs) factory, err := New(root, Cgroupfs, IntelRdtFs)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -0,0 +1,46 @@
// +build linux
package intelrdt
import (
"strings"
"testing"
)
func TestIntelRdtSetL3CacheSchema(t *testing.T) {
if !IsIntelRdtEnabled() {
return
}
helper := NewIntelRdtTestUtil(t)
defer helper.cleanup()
const (
l3CacheSchemaBefore = "L3:0=f;1=f0"
l3CacheSchemeAfter = "L3:0=f0;1=f"
)
helper.writeFileContents(map[string]string{
"schemata": l3CacheSchemaBefore + "\n",
})
helper.IntelRdtData.config.IntelRdt.L3CacheSchema = l3CacheSchemeAfter
intelrdt := &IntelRdtManager{
Config: helper.IntelRdtData.config,
Path: helper.IntelRdtPath,
}
if err := intelrdt.Set(helper.IntelRdtData.config); err != nil {
t.Fatal(err)
}
tmpStrings, err := getIntelRdtParamString(helper.IntelRdtPath, "schemata")
if err != nil {
t.Fatalf("Failed to parse file 'schemata' - %s", err)
}
values := strings.Split(tmpStrings, "\n")
value := values[0]
if value != l3CacheSchemeAfter {
t.Fatal("Got the wrong value, set 'schemata' failed.")
}
}

View File

@ -0,0 +1,67 @@
// +build linux
/*
* Utility for testing Intel RDT operations.
* Creates a mock of the Intel RDT "resource control" filesystem for the duration of the test.
*/
package intelrdt
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/opencontainers/runc/libcontainer/configs"
)
type intelRdtTestUtil struct {
// intelRdt data to use in tests
IntelRdtData *intelRdtData
// Path to the mock Intel RDT "resource control" filesystem directory
IntelRdtPath string
// Temporary directory to store mock Intel RDT "resource control" filesystem
tempDir string
t *testing.T
}
// Creates a new test util
func NewIntelRdtTestUtil(t *testing.T) *intelRdtTestUtil {
d := &intelRdtData{
config: &configs.Config{
IntelRdt: &configs.IntelRdt{},
},
}
tempDir, err := ioutil.TempDir("", "intelrdt_test")
if err != nil {
t.Fatal(err)
}
d.root = tempDir
testIntelRdtPath := filepath.Join(d.root, "resctrl")
if err != nil {
t.Fatal(err)
}
// Ensure the full mock Intel RDT "resource control" filesystem path exists
err = os.MkdirAll(testIntelRdtPath, 0755)
if err != nil {
t.Fatal(err)
}
return &intelRdtTestUtil{IntelRdtData: d, IntelRdtPath: testIntelRdtPath, tempDir: tempDir, t: t}
}
func (c *intelRdtTestUtil) cleanup() {
os.RemoveAll(c.tempDir)
}
// Write the specified contents on the mock of the specified Intel RDT "resource control" files
func (c *intelRdtTestUtil) writeFileContents(fileContents map[string]string) {
for file, contents := range fileContents {
err := writeFile(c.IntelRdtPath, file, contents)
if err != nil {
c.t.Fatal(err)
}
}
}