...

Source file src/github.com/containerd/cgroups/cgroup_test.go

Documentation: github.com/containerd/cgroups

     1  /*
     2     Copyright The containerd 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 cgroups
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"testing"
    25  
    26  	specs "github.com/opencontainers/runtime-spec/specs-go"
    27  )
    28  
    29  // using t.Error in test were defers do cleanup on the filesystem
    30  
    31  func TestCreate(t *testing.T) {
    32  	mock, err := newMock(t)
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	defer mock.delete()
    37  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
    38  	if err != nil {
    39  		t.Error(err)
    40  		return
    41  	}
    42  	if control == nil {
    43  		t.Error("control is nil")
    44  		return
    45  	}
    46  	for _, s := range Subsystems() {
    47  		if _, err := os.Stat(filepath.Join(mock.root, string(s), "test")); err != nil {
    48  			if os.IsNotExist(err) {
    49  				t.Errorf("group %s was not created", s)
    50  				return
    51  			}
    52  			t.Errorf("group %s was not created correctly %s", s, err)
    53  			return
    54  		}
    55  	}
    56  }
    57  
    58  func TestStat(t *testing.T) {
    59  	mock, err := newMock(t)
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  	defer mock.delete()
    64  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
    65  	if err != nil {
    66  		t.Error(err)
    67  		return
    68  	}
    69  	s, err := control.Stat(IgnoreNotExist)
    70  	if err != nil {
    71  		t.Error(err)
    72  		return
    73  	}
    74  	if s == nil {
    75  		t.Error("stat result is nil")
    76  		return
    77  	}
    78  }
    79  
    80  func TestAdd(t *testing.T) {
    81  	mock, err := newMock(t)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	defer mock.delete()
    86  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
    87  	if err != nil {
    88  		t.Error(err)
    89  		return
    90  	}
    91  	if err := control.Add(Process{Pid: 1234}); err != nil {
    92  		t.Error(err)
    93  		return
    94  	}
    95  	for _, s := range Subsystems() {
    96  		if err := checkPid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
    97  			t.Error(err)
    98  			return
    99  		}
   100  	}
   101  }
   102  
   103  func TestAddFilteredSubsystems(t *testing.T) {
   104  	mock, err := newMock(t)
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	defer mock.delete()
   109  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   110  	if err != nil {
   111  		t.Error(err)
   112  		return
   113  	}
   114  
   115  	filteredSubsystems := []Name{"memory", "cpu"}
   116  	if err := control.Add(Process{Pid: 1234}, filteredSubsystems...); err != nil {
   117  		t.Error(err)
   118  		return
   119  	}
   120  
   121  	for _, s := range filteredSubsystems {
   122  		if err := checkPid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
   123  			t.Error(err)
   124  			return
   125  		}
   126  	}
   127  
   128  	if err := checkPid(mock, filepath.Join("devices", "test"), 1234); err == nil {
   129  		t.Error("Pid should not be added to the devices subsystem")
   130  		return
   131  	}
   132  
   133  	bogusSubsystems := append(filteredSubsystems, "bogus")
   134  	if err := control.Add(Process{Pid: 5678}, bogusSubsystems...); err != nil {
   135  		t.Error(err)
   136  		return
   137  	}
   138  
   139  	for _, s := range filteredSubsystems {
   140  		if err := checkPid(mock, filepath.Join(string(s), "test"), 5678); err != nil {
   141  			t.Error(err)
   142  			return
   143  		}
   144  	}
   145  
   146  	nilSubsystems := []Name{}
   147  	if err := control.Add(Process{Pid: 9012}, nilSubsystems...); err != nil {
   148  		t.Error(err)
   149  		return
   150  	}
   151  
   152  	for _, s := range Subsystems() {
   153  		if err := checkPid(mock, filepath.Join(string(s), "test"), 9012); err != nil {
   154  			t.Error(err)
   155  			return
   156  		}
   157  	}
   158  }
   159  
   160  func TestAddTask(t *testing.T) {
   161  	mock, err := newMock(t)
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	defer mock.delete()
   166  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   167  	if err != nil {
   168  		t.Error(err)
   169  		return
   170  	}
   171  	if err := control.AddTask(Process{Pid: 1234}); err != nil {
   172  		t.Error(err)
   173  		return
   174  	}
   175  	for _, s := range Subsystems() {
   176  		if err := checkTaskid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
   177  			t.Error(err)
   178  			return
   179  		}
   180  	}
   181  }
   182  
   183  func TestAddTaskFilteredSubsystems(t *testing.T) {
   184  	mock, err := newMock(t)
   185  	if err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	defer mock.delete()
   189  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   190  	if err != nil {
   191  		t.Error(err)
   192  		return
   193  	}
   194  	filteredSubsystems := []Name{"memory", "cpu"}
   195  	if err := control.AddTask(Process{Pid: 1234}, filteredSubsystems...); err != nil {
   196  		t.Error(err)
   197  		return
   198  	}
   199  	for _, s := range filteredSubsystems {
   200  		if err := checkTaskid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
   201  			t.Error(err)
   202  			return
   203  		}
   204  	}
   205  
   206  	if err := checkTaskid(mock, filepath.Join("devices", "test"), 1234); err == nil {
   207  		t.Error("Task should not be added to the devices subsystem")
   208  		return
   209  	}
   210  
   211  	bogusSubsystems := append(filteredSubsystems, "bogus")
   212  	if err := control.AddTask(Process{Pid: 5678}, bogusSubsystems...); err != nil {
   213  		t.Error(err)
   214  		return
   215  	}
   216  
   217  	for _, s := range filteredSubsystems {
   218  		if err := checkTaskid(mock, filepath.Join(string(s), "test"), 5678); err != nil {
   219  			t.Error(err)
   220  			return
   221  		}
   222  	}
   223  }
   224  
   225  func TestListPids(t *testing.T) {
   226  	mock, err := newMock(t)
   227  	if err != nil {
   228  		t.Fatal(err)
   229  	}
   230  	defer mock.delete()
   231  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   232  	if err != nil {
   233  		t.Error(err)
   234  		return
   235  	}
   236  	if err := control.Add(Process{Pid: 1234}); err != nil {
   237  		t.Error(err)
   238  		return
   239  	}
   240  	for _, s := range Subsystems() {
   241  		if err := checkPid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
   242  			t.Error(err)
   243  			return
   244  		}
   245  	}
   246  	procs, err := control.Processes(Freezer, false)
   247  	if err != nil {
   248  		t.Error(err)
   249  		return
   250  	}
   251  	if l := len(procs); l != 1 {
   252  		t.Errorf("should have one process but received %d", l)
   253  		return
   254  	}
   255  	if procs[0].Pid != 1234 {
   256  		t.Errorf("expected pid %d but received %d", 1234, procs[0].Pid)
   257  	}
   258  }
   259  
   260  func TestListTasksPids(t *testing.T) {
   261  	mock, err := newMock(t)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	defer mock.delete()
   266  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   267  	if err != nil {
   268  		t.Error(err)
   269  		return
   270  	}
   271  	if err := control.AddTask(Process{Pid: 1234}); err != nil {
   272  		t.Error(err)
   273  		return
   274  	}
   275  	for _, s := range Subsystems() {
   276  		if err := checkTaskid(mock, filepath.Join(string(s), "test"), 1234); err != nil {
   277  			t.Error(err)
   278  			return
   279  		}
   280  	}
   281  	tasks, err := control.Tasks(Freezer, false)
   282  	if err != nil {
   283  		t.Error(err)
   284  		return
   285  	}
   286  	if l := len(tasks); l != 1 {
   287  		t.Errorf("should have one task but received %d", l)
   288  		return
   289  	}
   290  	if tasks[0].Pid != 1234 {
   291  		t.Errorf("expected task pid %d but received %d", 1234, tasks[0].Pid)
   292  	}
   293  }
   294  
   295  func readValue(mock *mockCgroup, path string) (string, error) {
   296  	data, err := os.ReadFile(filepath.Join(mock.root, path))
   297  	if err != nil {
   298  		return "", err
   299  	}
   300  	return string(data), nil
   301  }
   302  
   303  func checkPid(mock *mockCgroup, path string, expected int) error {
   304  	data, err := readValue(mock, filepath.Join(path, cgroupProcs))
   305  	if err != nil {
   306  		return err
   307  	}
   308  	v, err := strconv.Atoi(data)
   309  	if err != nil {
   310  		return err
   311  	}
   312  	if v != expected {
   313  		return fmt.Errorf("expected pid %d but received %d", expected, v)
   314  	}
   315  	return nil
   316  }
   317  
   318  func checkTaskid(mock *mockCgroup, path string, expected int) error {
   319  	data, err := readValue(mock, filepath.Join(path, cgroupTasks))
   320  	if err != nil {
   321  		return err
   322  	}
   323  	v, err := strconv.Atoi(data)
   324  	if err != nil {
   325  		return err
   326  	}
   327  	if v != expected {
   328  		return fmt.Errorf("expected task id %d but received %d", expected, v)
   329  	}
   330  	return nil
   331  }
   332  
   333  func mockNewNotInRdma(subsystems []Subsystem, path Path, resources *specs.LinuxResources) (Cgroup, error) {
   334  	for _, s := range subsystems {
   335  		if s.Name() != Rdma {
   336  			if err := initializeSubsystem(s, path, resources); err != nil {
   337  				return nil, err
   338  			}
   339  		}
   340  	}
   341  	return &cgroup{
   342  		path:       path,
   343  		subsystems: subsystems,
   344  	}, nil
   345  }
   346  
   347  func TestLoad(t *testing.T) {
   348  	mock, err := newMock(t)
   349  	if err != nil {
   350  		t.Fatal(err)
   351  	}
   352  	defer mock.delete()
   353  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   354  	if err != nil {
   355  		t.Error(err)
   356  		return
   357  	}
   358  	if control, err = Load(mock.hierarchy, StaticPath("test")); err != nil {
   359  		t.Error(err)
   360  		return
   361  	}
   362  	if control == nil {
   363  		t.Error("control is nil")
   364  		return
   365  	}
   366  }
   367  
   368  func TestLoadWithMissingSubsystems(t *testing.T) {
   369  	mock, err := newMock(t)
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	defer mock.delete()
   374  	subsystems, err := mock.hierarchy()
   375  	if err != nil {
   376  		t.Error(err)
   377  		return
   378  	}
   379  	control, err := mockNewNotInRdma(subsystems, StaticPath("test"), &specs.LinuxResources{})
   380  	if err != nil {
   381  		t.Error(err)
   382  		return
   383  	}
   384  	if control == nil {
   385  		t.Error("control is nil")
   386  		return
   387  	}
   388  	if control, err = Load(mock.hierarchy, StaticPath("test")); err != nil {
   389  		t.Error(err)
   390  		return
   391  	}
   392  	if control == nil {
   393  		t.Error("control is nil")
   394  		return
   395  	}
   396  	if len(control.Subsystems()) != len(subsystems)-1 {
   397  		t.Error("wrong number of active subsystems")
   398  		return
   399  	}
   400  }
   401  
   402  func TestDelete(t *testing.T) {
   403  	mock, err := newMock(t)
   404  	if err != nil {
   405  		t.Fatal(err)
   406  	}
   407  	defer mock.delete()
   408  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   409  	if err != nil {
   410  		t.Error(err)
   411  		return
   412  	}
   413  	if err := control.Delete(); err != nil {
   414  		t.Error(err)
   415  	}
   416  }
   417  
   418  func TestCreateSubCgroup(t *testing.T) {
   419  	mock, err := newMock(t)
   420  	if err != nil {
   421  		t.Fatal(err)
   422  	}
   423  	defer mock.delete()
   424  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   425  	if err != nil {
   426  		t.Error(err)
   427  		return
   428  	}
   429  	sub, err := control.New("child", &specs.LinuxResources{})
   430  	if err != nil {
   431  		t.Error(err)
   432  		return
   433  	}
   434  	if err := sub.Add(Process{Pid: 1234}); err != nil {
   435  		t.Error(err)
   436  		return
   437  	}
   438  	for _, s := range Subsystems() {
   439  		if err := checkPid(mock, filepath.Join(string(s), "test", "child"), 1234); err != nil {
   440  			t.Error(err)
   441  			return
   442  		}
   443  	}
   444  	if err := sub.AddTask(Process{Pid: 5678}); err != nil {
   445  		t.Error(err)
   446  		return
   447  	}
   448  	for _, s := range Subsystems() {
   449  		if err := checkTaskid(mock, filepath.Join(string(s), "test", "child"), 5678); err != nil {
   450  			t.Error(err)
   451  			return
   452  		}
   453  	}
   454  }
   455  
   456  func TestFreezeThaw(t *testing.T) {
   457  	mock, err := newMock(t)
   458  	if err != nil {
   459  		t.Fatal(err)
   460  	}
   461  	defer mock.delete()
   462  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   463  	if err != nil {
   464  		t.Error(err)
   465  		return
   466  	}
   467  	if err := control.Freeze(); err != nil {
   468  		t.Error(err)
   469  		return
   470  	}
   471  	if state := control.State(); state != Frozen {
   472  		t.Errorf("expected %q but received %q", Frozen, state)
   473  		return
   474  	}
   475  	if err := control.Thaw(); err != nil {
   476  		t.Error(err)
   477  		return
   478  	}
   479  	if state := control.State(); state != Thawed {
   480  		t.Errorf("expected %q but received %q", Thawed, state)
   481  		return
   482  	}
   483  }
   484  
   485  func TestSubsystems(t *testing.T) {
   486  	mock, err := newMock(t)
   487  	if err != nil {
   488  		t.Fatal(err)
   489  	}
   490  	defer mock.delete()
   491  	control, err := New(mock.hierarchy, StaticPath("test"), &specs.LinuxResources{})
   492  	if err != nil {
   493  		t.Error(err)
   494  		return
   495  	}
   496  	cache := make(map[Name]struct{})
   497  	for _, s := range control.Subsystems() {
   498  		cache[s.Name()] = struct{}{}
   499  	}
   500  	for _, s := range Subsystems() {
   501  		if _, ok := cache[s]; !ok {
   502  			t.Errorf("expected subsystem %q but not found", s)
   503  		}
   504  	}
   505  }
   506  
   507  func TestCpusetParent(t *testing.T) {
   508  	const expected = "0-3"
   509  	mock, err := newMock(t)
   510  	if err != nil {
   511  		t.Fatal(err)
   512  	}
   513  	defer mock.delete()
   514  	control, err := New(mock.hierarchy, StaticPath("/parent/child"), &specs.LinuxResources{})
   515  	if err != nil {
   516  		t.Error(err)
   517  		return
   518  	}
   519  	defer control.Delete()
   520  	for _, file := range []string{
   521  		"parent/cpuset.cpus",
   522  		"parent/cpuset.mems",
   523  		"parent/child/cpuset.cpus",
   524  		"parent/child/cpuset.mems",
   525  	} {
   526  		v, err := readValue(mock, filepath.Join(string(Cpuset), file))
   527  		if err != nil {
   528  			t.Error(err)
   529  			return
   530  		}
   531  		if v != expected {
   532  			t.Errorf("expected %q for %s but received %q", expected, file, v)
   533  		}
   534  	}
   535  }
   536  

View as plain text