github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/utils/cgnetcls/cgnetcls_test.go (about)

     1  // +build linux
     2  
     3  package cgnetcls
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"math/rand"
     9  	"os"
    10  	"path/filepath"
    11  	"strconv"
    12  	"strings"
    13  	"syscall"
    14  	"testing"
    15  
    16  	markconstants "go.aporeto.io/enforcerd/trireme-lib/utils/constants"
    17  )
    18  
    19  // This package does not use interfaces/objects from other trireme component so we don't need to mock anything here
    20  // We will create actual system objects
    21  // This can be tested only on linux since the directory structure will not exist anywhere else
    22  // Tests here will be skipped if you don't run as root
    23  
    24  const (
    25  	testcgroupname       = "/test"
    26  	testcgroupnameformat = "test"
    27  	testmark             = 100
    28  	testRootUser         = "root"
    29  )
    30  
    31  func cleanupnetclsgroup() {
    32  	data, _ := ioutil.ReadFile(filepath.Join(cgroupNetClsPath, testcgroupname, procs))
    33  	fmt.Println(string(data))
    34  	_ = ioutil.WriteFile(filepath.Join(cgroupNetClsPath, procs), data, 0644)
    35  	_ = os.RemoveAll(filepath.Join(cgroupNetClsPath, testcgroupname))
    36  }
    37  
    38  func TestCreategroup(t *testing.T) {
    39  
    40  	if os.Getenv("USER") != testRootUser {
    41  		t.SkipNow()
    42  	}
    43  
    44  	cg := NewCgroupNetController("/tmp", "")
    45  	if err := cg.Creategroup(testcgroupnameformat); err != nil {
    46  		//Check if all the files required are created
    47  		t.Errorf("Failed to create group error returned %s", err.Error())
    48  	}
    49  
    50  	defer cleanupnetclsgroup()
    51  
    52  	if _, err := ioutil.ReadFile(filepath.Join(cgroupNetClsPath, releaseAgentConfFile)); err != nil {
    53  		if os.IsNotExist(err) {
    54  			t.Errorf("ReleaseAgentConf File does not exist.Cgroup mount failed")
    55  			t.SkipNow()
    56  		}
    57  	}
    58  
    59  	if val, err := ioutil.ReadFile(filepath.Join(cgroupNetClsPath, notifyOnReleaseFile)); err != nil {
    60  		if os.IsNotExist(err) {
    61  			t.Errorf("Notify on release file does not exist.Cgroup mount failed")
    62  			t.SkipNow()
    63  		}
    64  	} else {
    65  		if strings.TrimSpace(string(val)) != "1" {
    66  			t.Errorf("Notify release file in base net_cls not programmed")
    67  			t.SkipNow()
    68  		}
    69  	}
    70  
    71  	if val, err := ioutil.ReadFile(filepath.Join(cgroupNetClsPath, notifyOnReleaseFile)); err != nil {
    72  		if os.IsNotExist(err) {
    73  			t.Errorf("Notify on release file does not exist.Cgroup mount failed")
    74  			t.SkipNow()
    75  		}
    76  	} else {
    77  		if strings.TrimSpace(string(val)) != "1" {
    78  			t.Errorf("Notify release file in aporeto base dir /sys/fs/cgroup/aporeto not programmed")
    79  			t.SkipNow()
    80  		}
    81  	}
    82  
    83  	if val, err := ioutil.ReadFile(filepath.Join(cgroupNetClsPath, testcgroupname, notifyOnReleaseFile)); err != nil {
    84  		if os.IsNotExist(err) {
    85  			t.Errorf("Notify on release file does not exist.Cgroup mount failed")
    86  			t.SkipNow()
    87  		}
    88  	} else {
    89  		if strings.TrimSpace(string(val)) != "1" {
    90  			t.Errorf("Notify release file in cgroup not programmed")
    91  			t.SkipNow()
    92  		}
    93  	}
    94  }
    95  
    96  func TestAssignMark(t *testing.T) {
    97  	cg := NewCgroupNetController("/tmp", "")
    98  	if os.Getenv("USER") != testRootUser {
    99  		t.SkipNow()
   100  	}
   101  	//Assigning mark before creating group
   102  	if err := cg.AssignMark(testcgroupname, testmark); err == nil {
   103  		t.Errorf("Assign mark succeeded without a valid group being present ")
   104  		t.SkipNow()
   105  	}
   106  	if err := cg.Creategroup(testcgroupnameformat); err != nil {
   107  		t.Errorf("Error creating cgroup %s", err)
   108  		t.SkipNow()
   109  	}
   110  
   111  	defer cleanupnetclsgroup()
   112  
   113  	if err := cg.AssignMark(testcgroupnameformat, testmark); err != nil {
   114  		t.Errorf("Failed to assign mark error = %s", err.Error())
   115  		t.SkipNow()
   116  	} else {
   117  		data, _ := ioutil.ReadFile(filepath.Join(cgroupNetClsPath, testcgroupname, markFile))
   118  		u, err := strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
   119  		if err != nil {
   120  			t.Errorf("Non Integer mark value in classid file")
   121  			t.SkipNow()
   122  		}
   123  		if u != testmark {
   124  			t.Errorf("Unexpected mark val expected %d, read %d", testmark, u)
   125  			t.SkipNow()
   126  		}
   127  	}
   128  }
   129  
   130  func TestAddProcess(t *testing.T) {
   131  	//hopefully this pid does not exist
   132  	pid := 1<<31 - 1
   133  	r := rand.New(rand.NewSource(23))
   134  	if os.Getenv("USER") != testRootUser {
   135  		t.SkipNow()
   136  	}
   137  	cg := NewCgroupNetController("/tmp", "")
   138  	//AddProcess to a non-existent group
   139  	if err := cg.AddProcess(testcgroupname, os.Getpid()); err == nil {
   140  		t.Errorf("Process successfully added to a non existent group")
   141  		t.SkipNow()
   142  	}
   143  	if err := cg.Creategroup(testcgroupnameformat); err != nil {
   144  		t.Errorf("Error creating cgroup")
   145  		t.SkipNow()
   146  	}
   147  
   148  	defer cleanupnetclsgroup()
   149  
   150  	//Add a non-existent process
   151  	//loop to find non-existent pid
   152  	for {
   153  		if err := syscall.Kill(pid, 0); err != nil {
   154  			break
   155  		}
   156  		pid = r.Int()
   157  
   158  	}
   159  	if err := cg.AddProcess(testcgroupnameformat, pid); err != nil {
   160  		t.Errorf("Unexpected error not returned for non-existent process")
   161  		t.SkipNow()
   162  	}
   163  	pid = 1 //Guaranteed to be present
   164  	if err := cg.AddProcess(testcgroupname, pid); err != nil {
   165  		t.Errorf("Failed to add process %s", err.Error())
   166  		t.SkipNow()
   167  	} else {
   168  		//This directory structure should not be delete
   169  		if err := os.RemoveAll(filepath.Join(cgroupNetClsPath, testcgroupname)); err == nil {
   170  			t.Errorf("Process not added to cgroup")
   171  			t.SkipNow()
   172  		}
   173  	}
   174  }
   175  
   176  func TestRemoveProcess(t *testing.T) {
   177  	if os.Getenv("USER") != testRootUser {
   178  		t.SkipNow()
   179  	}
   180  	cg := NewCgroupNetController("/tmp", "")
   181  	//Removing process from non-existent group
   182  	if err := cg.RemoveProcess(testcgroupname, 1); err == nil {
   183  		t.Errorf("RemoveProcess succeeded without valid group being present ")
   184  		t.SkipNow()
   185  	}
   186  	if err := cg.Creategroup(testcgroupnameformat); err != nil {
   187  		t.Errorf("Error creating cgroup")
   188  		t.SkipNow()
   189  	}
   190  
   191  	defer cleanupnetclsgroup()
   192  
   193  	if err := cg.AddProcess(testcgroupname, 1); err != nil {
   194  		t.Errorf("Error adding process")
   195  		t.SkipNow()
   196  	}
   197  	if err := cg.RemoveProcess(testcgroupnameformat, 10); err == nil {
   198  		t.Errorf("Removed process which was not a part of this cgroup")
   199  		t.SkipNow()
   200  	}
   201  	if err := cg.RemoveProcess(testcgroupname, 1); err != nil {
   202  		t.Errorf("Failed to remove process %s", err.Error())
   203  		t.SkipNow()
   204  	}
   205  }
   206  
   207  func TestDeleteCgroup(t *testing.T) {
   208  	if os.Getenv("USER") != testRootUser {
   209  		t.SkipNow()
   210  	}
   211  	cg := NewCgroupNetController("/tmp", "")
   212  	//Removing process from non-existent group
   213  	if err := cg.DeleteCgroup(testcgroupnameformat); err != nil {
   214  		t.Errorf("Non-existent cgroup delelte returned an error")
   215  		t.SkipNow()
   216  	}
   217  	if err := cg.Creategroup(testcgroupname); err != nil {
   218  		t.Errorf("Failed to create cgroup %s", err.Error())
   219  		t.SkipNow()
   220  	}
   221  
   222  	defer cleanupnetclsgroup()
   223  
   224  	if err := cg.DeleteCgroup(testcgroupname); err != nil {
   225  		t.Errorf("Failed to delete cgroup %s", err.Error())
   226  		t.SkipNow()
   227  	}
   228  
   229  }
   230  
   231  func TestDeleteBasePath(t *testing.T) {
   232  	if os.Getenv("USER") != testRootUser {
   233  		t.SkipNow()
   234  	}
   235  	cg := NewCgroupNetController("/tmp", "")
   236  	//Removing process from non-existent group
   237  	if err := cg.DeleteCgroup(testcgroupname); err != nil {
   238  		t.Errorf("Delete of group failed %s", err.Error())
   239  	}
   240  
   241  	defer cleanupnetclsgroup()
   242  
   243  	cg.Deletebasepath(testcgroupnameformat)
   244  	_, err := os.Stat(filepath.Join(cgroupNetClsPath, testcgroupname))
   245  	if err == nil {
   246  		t.Errorf("Delete of cgroup from system failed")
   247  		t.SkipNow()
   248  	}
   249  }
   250  
   251  func TestListCgroupProcesses(t *testing.T) {
   252  	pid := 1<<31 - 1
   253  	r := rand.New(rand.NewSource(23))
   254  	if os.Getenv("USER") != testRootUser {
   255  		t.SkipNow()
   256  	}
   257  	cg := NewCgroupNetController("/tmp", "")
   258  
   259  	_, err := cg.ListCgroupProcesses(testcgroupname)
   260  	if err == nil {
   261  		t.Errorf("No process found but succeeded")
   262  	}
   263  	//AddProcess to a non-existent group
   264  	if err = cg.AddProcess(testcgroupname, os.Getpid()); err == nil {
   265  		t.Errorf("Process successfully added to a non existent group")
   266  		t.SkipNow()
   267  	}
   268  	if err = cg.Creategroup(testcgroupname); err != nil {
   269  		t.Errorf("Error creating cgroup")
   270  		t.SkipNow()
   271  	}
   272  
   273  	defer cleanupnetclsgroup()
   274  
   275  	//Add a non-existent process
   276  	//loop to find non-existent pid
   277  	for {
   278  		if err = syscall.Kill(pid, 0); err != nil {
   279  			break
   280  		}
   281  		pid = r.Int()
   282  
   283  	}
   284  
   285  	pid = 1 //Guaranteed to be present
   286  	if err = cg.AddProcess(testcgroupname, pid); err != nil {
   287  		t.Errorf("Failed to add process %s", err.Error())
   288  		t.SkipNow()
   289  	} else {
   290  		//This directory structure should not be delete
   291  		if err = os.RemoveAll(filepath.Join(cgroupNetClsPath, testcgroupname)); err == nil {
   292  			t.Errorf("Process not added to cgroup")
   293  			t.SkipNow()
   294  		}
   295  	}
   296  
   297  	procs, err := cg.ListCgroupProcesses(testcgroupname)
   298  	if procs[0] != "1" && err != nil {
   299  		t.Errorf("No process found %d", err)
   300  	}
   301  }
   302  
   303  func TestMarkVal(t *testing.T) {
   304  	type test struct {
   305  		name string
   306  		want uint64
   307  	}
   308  	// this is kind of silly, but as this is an atomic counter,
   309  	// there is no other way than to really count up and compare
   310  	generateTests := func() []test {
   311  		ret := []test{}
   312  		i := 1
   313  		for {
   314  			want := i + markconstants.Initialmarkval
   315  			// this is the exception, in this case we should get plus one
   316  			if want >= markconstants.EnforcerCgroupMark {
   317  				want++
   318  			}
   319  			ret = append(ret, test{
   320  				name: strconv.Itoa(i + markconstants.Initialmarkval),
   321  				want: uint64(want),
   322  			})
   323  			// abort a couple tests after that
   324  			if want == markconstants.EnforcerCgroupMark+2 {
   325  				break
   326  			}
   327  			i++
   328  		}
   329  		return ret
   330  	}
   331  	for _, tt := range generateTests() {
   332  		t.Run(tt.name, func(t *testing.T) {
   333  			got := MarkVal()
   334  			t.Logf("test %s, markVal %d", tt.name, got)
   335  			if got != tt.want {
   336  				t.Errorf("MarkVal() = %v, want %v", got, tt.want)
   337  			}
   338  		})
   339  	}
   340  }