blob: 14d7adfa631db89fdf31f35b089e920202a79427 [file] [log] [blame]
# test_doins.py -- Portage Unit Testing Functionality
# Copyright 2007-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
import grp
import os
import pwd
import stat
from portage.tests.bin import setup_env
from portage import tests
doins = setup_env.doins
exists_in_D = setup_env.exists_in_D
class DoIns(setup_env.BinTestCase):
def testDoIns(self):
"""Tests the most basic senario."""
self.init()
try:
env = setup_env.env
# Create a file to be installed.
test_path = os.path.join(env['S'], 'test')
with open(test_path, 'w'):
pass
doins('test')
exists_in_D('/test')
st = os.lstat(env['D'] + '/test')
# By default, `install`'s permission is 755.
if stat.S_IMODE(st.st_mode) != 0o755:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsOption(self):
"""Tests with INSOPTIONS doins.py understands."""
self.init()
try:
env = setup_env.env
env['INSOPTIONS'] = '-m0644'
with open(os.path.join(env['S'], 'test'), 'w'):
pass
doins('test')
st = os.lstat(env['D'] + '/test')
if stat.S_IMODE(st.st_mode) != 0o644:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsOptionUnsupportedMode(self):
"""Tests with INSOPTIONS in the format doins.py doesn't know."""
self.init()
try:
env = setup_env.env
# Parse test for -m with unsupported format.
# It should fall back to `install` command.
env['INSOPTIONS'] = '-m u+r'
with open(os.path.join(env['S'], 'test'), 'w'):
pass
doins('test')
st = os.lstat(env['D'] + '/test')
if stat.S_IMODE(st.st_mode) != 0o400:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsOptionUid(self):
"""Tests setting owner by uid works."""
self.init()
try:
env = setup_env.env
with open(os.path.join(env['S'], 'test'), 'w'):
pass
uid = os.lstat(os.path.join(env['S'], 'test')).st_uid
# Set owner option with uid. No guarantee that this
# runs with capability, we set the current UID so that
# chown should success, although it is difficult to
# check if chown actually runs or not.
env['INSOPTIONS'] = '-o %d' % uid
doins('test')
st = os.lstat(env['D'] + '/test')
if st.st_uid != uid:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsOptionUserName(self):
"""Tests setting owner by name works."""
self.init()
try:
env = setup_env.env
with open(os.path.join(env['S'], 'test'), 'w'):
pass
uid = os.lstat(os.path.join(env['S'], 'test')).st_uid
pw = pwd.getpwuid(uid)
# Similary to testDoInsOptionUid, use user name.
env['INSOPTIONS'] = '-o %s' % pw.pw_name
doins('test')
st = os.lstat(env['D'] + '/test')
if st.st_uid != uid:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsOptionGid(self):
"""Tests setting group by gid works."""
self.init()
try:
env = setup_env.env
with open(os.path.join(env['S'], 'test'), 'w'):
pass
gid = os.lstat(os.path.join(env['S'], 'test')).st_gid
# Similary to testDoInsOptionUid, use gid.
env['INSOPTIONS'] = '-g %d' % gid
doins('test')
st = os.lstat(env['D'] + '/test')
if st.st_gid != gid:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsOptionGroupName(self):
"""Tests setting group by name works."""
self.init()
try:
env = setup_env.env
with open(os.path.join(env['S'], 'test'), 'w'):
pass
gid = os.lstat(os.path.join(env['S'], 'test')).st_gid
gr = grp.getgrgid(gid)
# Similary to testDoInsOptionUid, use group name.
env['INSOPTIONS'] = '-g %s' % gr.gr_name
doins('test')
st = os.lstat(env['D'] + '/test')
if st.st_gid != gid:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoInsFallback(self):
"""Tests if falling back to the `install` command works."""
self.init()
try:
env = setup_env.env
# Use an option which doins.py does not know.
# Then, fallback to `install` command is expected.
env['INSOPTIONS'] = '-p'
with open(os.path.join(env['S'], 'test'), 'w'):
pass
doins('test')
# So `install` should still work.
exists_in_D('/test')
finally:
self.cleanup()
def testDoInsRecursive(self):
"""Tests installing a directory recursively."""
self.init()
try:
env = setup_env.env
os.mkdir(os.path.join(env['S'], 'testdir'))
with open(os.path.join(env['S'], 'testdir/test'), 'w'):
pass
doins('-r testdir')
exists_in_D('/testdir/test')
finally:
self.cleanup()
def testDoDirOption(self):
"""Tests with DIROPTIONS."""
self.init()
try:
env = setup_env.env
# Use an option which doins.py knows.
env['DIROPTIONS'] = '-m0755'
os.mkdir(os.path.join(env['S'], 'testdir'))
with open(os.path.join(env['S'], 'testdir/test'), 'w'):
pass
doins('-r testdir')
st = os.lstat(env['D'] + '/testdir')
if stat.S_IMODE(st.st_mode) != 0o755:
raise tests.TestCase.failureException
finally:
self.cleanup()
def testDoDirFallback(self):
"""Tests with DIROPTIONS which doins.py doesn't understand."""
self.init()
try:
env = setup_env.env
# Use an option which doins.py does not know.
# Then, fallback to `install` command is expected.
env['DIROPTIONS'] = '-p'
os.mkdir(os.path.join(env['S'], 'testdir'))
with open(os.path.join(env['S'], 'testdir/test'), 'w'):
pass
doins('-r testdir')
# So, `install` should still work.
exists_in_D('/testdir/test')
finally:
self.cleanup()
def testSymlinkFile(self):
"""Tests if installing a symlink works.
In EAPI=4 and later, installing a symlink should creates a
symlink at destination.
"""
self.init()
try:
env = setup_env.env
env['EAPI'] = '4' # Enable symlink.
env['ED'] = env['D']
env['PORTAGE_ACTUAL_DISTDIR'] = '/foo'
# Create a file to be installed.
test_path = os.path.join(env['S'], 'test')
with open(test_path, 'w'):
pass
symlink_path = os.path.join(env['S'], 'symlink')
os.symlink('test', symlink_path)
doins('test symlink')
exists_in_D('/symlink')
# Make sure installed symlink is actually a symbolic
# link pointing to test.
if not os.path.islink(env['D'] + '/symlink'):
raise tests.TestCase.failureException
if os.readlink(env['D'] + '/symlink') != 'test':
raise tests.TestCase.failureException
finally:
self.cleanup()
def testSymlinkFileRecursive(self):
"""Tests if installing a symlink in a directory works."""
self.init()
try:
env = setup_env.env
env['EAPI'] = '4' # Enable symlink.
env['ED'] = env['D']
env['PORTAGE_ACTUAL_DISTDIR'] = '/foo'
# Create a file to be installed.
parent_path = os.path.join(env['S'], 'test')
os.mkdir(parent_path)
with open(os.path.join(parent_path, 'test'), 'w'):
pass
symlink_path = os.path.join(
env['S'], 'test', 'symlink')
os.symlink('test', symlink_path)
doins('-r test')
exists_in_D('/test/symlink')
# Make sure installed symlink is actually a symbolic
# link pointing to test.
if not os.path.islink(env['D'] + '/test/symlink'):
raise tests.TestCase.failureException
if os.readlink(env['D'] + '/test/symlink') != 'test':
raise tests.TestCase.failureException
finally:
self.cleanup()
def testSymlinkDir(self):
"""Tests installing a symlink to a directory."""
self.init()
try:
env = setup_env.env
env['EAPI'] = '4' # Enable symlink.
env['ED'] = env['D']
env['PORTAGE_ACTUAL_DISTDIR'] = '/foo'
# Create a dir to be installed.
os.mkdir(os.path.join(env['S'], 'test'))
symlink_path = os.path.join(env['S'], 'symlink')
os.symlink('test', symlink_path)
doins('test symlink')
# Make sure installed symlink is actually a symbolic
# link pointing to test.
if not os.path.islink(env['D'] + '/symlink'):
raise tests.TestCase.failureException
if os.readlink(env['D'] + '/symlink') != 'test':
raise tests.TestCase.failureException
finally:
self.cleanup()
def testSymlinkDirRecursive(self):
"""Tests installing a symlink to a directory under a directory.
"""
self.init()
try:
env = setup_env.env
env['EAPI'] = '4' # Enable symlink.
env['ED'] = env['D']
env['PORTAGE_ACTUAL_DISTDIR'] = '/foo'
# Create a file to be installed.
parent_path = os.path.join(env['S'], 'test')
os.mkdir(parent_path)
os.mkdir(os.path.join(parent_path, 'test'))
symlink_path = os.path.join(
env['S'], 'test', 'symlink')
os.symlink('test', symlink_path)
doins('-r test')
# Make sure installed symlink is actually a symbolic
# link pointing to test.
if not os.path.islink(env['D'] + '/test/symlink'):
raise tests.TestCase.failureException
if not os.path.isdir(env['D'] + '/test/symlink'):
raise tests.TestCase.failureException
if os.readlink(env['D'] + '/test/symlink') != 'test':
raise tests.TestCase.failureException
finally:
self.cleanup()
def testSymlinkOverwrite(self):
"""Tests installing a file to overwrite the existing file.
Specifically, if the existing file is a symlink, it should be
removed once, and the file content should be copied.
"""
self.init()
try:
env = setup_env.env
test_path = os.path.join(env['S'], 'test')
with open(test_path, 'w'):
pass
# Create a dangling symlink. If removal does not work,
# this would easily cause ENOENT error.
os.symlink('foo/bar', env['D'] + '/test')
doins('test')
# Actual file should be installed.
if os.path.islink(env['D'] + '/test'):
raise tests.TestCase.failureException
finally:
self.cleanup()
def testHardlinkOverwrite(self):
"""Tests installing a file to overwrite the hardlink.
If the existing file is a hardlink, it should be removed once,
and the file content should be copied.
"""
self.init()
try:
env = setup_env.env
test_path = os.path.join(env['S'], 'test')
with open(test_path, 'w'):
pass
# Create hardlink at the dest.
os.link(test_path, env['D'] + '/test')
doins('test')
# The hardlink should be unlinked, and then a copy
# should be created.
if os.path.samefile(test_path, env['D'] + '/test'):
raise tests.TestCase.failureException
finally:
self.cleanup()