blob: 4feffe72fcf733a221f43f816e9b98bd591a2562 [file] [log] [blame] [edit]
# Copyright 2014 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittests for the namespaces.py module."""
import errno
import os
import unittest
from chromite.lib import commandline
from chromite.lib import cros_test_lib
from chromite.lib import namespaces
class SetNSTests(cros_test_lib.TestCase):
"""Tests for SetNS()"""
def testBasic(self):
"""Simple functionality test."""
NS_PATH = "/proc/self/ns/mnt"
if not os.path.exists(NS_PATH):
raise unittest.SkipTest("kernel too old (missing %s)" % NS_PATH)
with open(NS_PATH, encoding="utf-8") as f:
try:
namespaces.SetNS(f.fileno(), 0)
except OSError as e:
if e.errno != errno.EPERM:
# Running as non-root will fail, so ignore it. We ran most
# of the code in the process which is all we really wanted.
raise
class UnshareTests(cros_test_lib.TestCase):
"""Tests for Unshare()"""
def testBasic(self):
"""Simple functionality test."""
try:
namespaces.Unshare(namespaces.CLONE_NEWNS)
except OSError as e:
if e.errno != errno.EPERM:
# Running as non-root will fail, so ignore it. We ran most
# of the code in the process which is all we really wanted.
raise
class UnshareCGroupsTests(cros_test_lib.TestCase):
"""Tests for Unshare() of CGroups"""
def testBasic(self):
"""Simple functionality test."""
try:
namespaces.Unshare(namespaces.CLONE_NEWCGROUP)
# After we have unshared cgroups, every cgroups entry in
# /proc/self/cgroups should have a path that's root (ie "/").
with open("/proc/self/cgroup", encoding="utf-8") as cgroups:
for cgroup in cgroups:
self.assertRegex(cgroup, ":/\n$")
except OSError as e:
if e.errno != errno.EPERM:
# Running as non-root will fail, so ignore it. We ran most
# of the code in the process which is all we really wanted.
raise
class SimpleUnshareCgroupsTests(cros_test_lib.MockTestCase):
"""Tests for SimpleUnshare with cgroups."""
def testSimpleUnshare(self):
"""Simple functionality test."""
unshare_mock = self.PatchObject(namespaces, "Unshare")
namespaces.SimpleUnshare(
mount=False,
uts=False,
ipc=False,
net=False,
pid=False,
cgroup=True,
)
unshare_mock.assert_called_once_with(namespaces.CLONE_NEWCGROUP)
class ReExecuteWithNamespaceTests(cros_test_lib.MockTestCase):
"""Tests for ReExecuteWithNamespace()."""
def testReExecuteWithNamespace(self):
"""Verify SimpleUnshare is called and the non-root user is restored."""
self.PatchDict(
os.environ,
{
"SUDO_GID": "123",
"SUDO_UID": "456",
"SUDO_USER": "testuser",
},
)
run_as_root_user_mock = self.PatchObject(commandline, "RunAsRootUser")
simple_unshare_mock = self.PatchObject(namespaces, "SimpleUnshare")
os_initgroups_mock = self.PatchObject(os, "initgroups")
os_setresgid_mock = self.PatchObject(os, "setresgid")
os_setresuid_mock = self.PatchObject(os, "setresuid")
namespaces.ReExecuteWithNamespace([], preserve_env=True)
run_as_root_user_mock.assert_called_once_with([], preserve_env=True)
simple_unshare_mock.assert_called_once_with(net=True, pid=True)
os_initgroups_mock.assert_called_once_with("testuser", 123)
os_setresgid_mock.assert_called_once_with(123, 123, 123)
os_setresuid_mock.assert_called_once_with(456, 456, 456)
self.assertEqual("testuser", os.environ["USER"])