Compare commits
8 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d38f68b1eb | ||
|
|
1fdc27c3ae | ||
|
|
165722aa03 | ||
|
|
1ac41ff742 | ||
|
|
52b9647fd7 | ||
|
|
aac03b7daa |
||
|
|
e2ae10693b | ||
|
|
b53844bfb9 |
20 changed files with 2835 additions and 1 deletions
0
.gitignore
vendored
Normal file
0
.gitignore
vendored
Normal file
1499
base-runtime.yaml
Normal file
1499
base-runtime.yaml
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1 +0,0 @@
|
||||||
Unsupported
|
|
||||||
4
jargon.txt
Normal file
4
jargon.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
Autogenerated
|
||||||
|
enablement
|
||||||
|
Modularity
|
||||||
|
Runtime
|
||||||
0
sources
Normal file
0
sources
Normal file
7
tests/Makefile
Normal file
7
tests/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
MODULE_LINT=/usr/share/moduleframework/tools/modulelint/*.py
|
||||||
|
CMD=MODULE=nspawn python -m avocado run smoke.py $(MODULE_LINT)
|
||||||
|
|
||||||
|
check:
|
||||||
|
$(CMD)
|
||||||
|
|
||||||
|
all: check
|
||||||
102
tests/brtconfig.py
Normal file
102
tests/brtconfig.py
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
"""
|
||||||
|
get configuration parameters for base runtime smoke testing
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from moduleframework import module_framework
|
||||||
|
|
||||||
|
|
||||||
|
def get_mockcfg(self):
|
||||||
|
"""
|
||||||
|
Get the path to the base runtime mock configuration file
|
||||||
|
|
||||||
|
This is provided by the avocado 'mockcfg' parameter if supplied,
|
||||||
|
otherwise it is set to "resources/base-runtime-mock.cfg" relative to
|
||||||
|
the test script directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
script_dir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
self.log.info("running script from directory: %s" % script_dir)
|
||||||
|
|
||||||
|
mockcfg = self.params.get('mockcfg', default=os.path.join(
|
||||||
|
script_dir, "resources", "base-runtime-mock.cfg"))
|
||||||
|
mockcfg = str(mockcfg)
|
||||||
|
|
||||||
|
if not mockcfg.endswith(".cfg"):
|
||||||
|
self.error("mock configuration file %s must have the extension '.cfg'" %
|
||||||
|
mockcfg)
|
||||||
|
|
||||||
|
if not os.path.isfile(mockcfg):
|
||||||
|
self.error("mock configuration file %s does not exist" %
|
||||||
|
mockcfg)
|
||||||
|
|
||||||
|
self.log.info("mock configuration file: %s" % mockcfg)
|
||||||
|
|
||||||
|
return mockcfg
|
||||||
|
|
||||||
|
|
||||||
|
def get_compiler_test_dir(self):
|
||||||
|
"""
|
||||||
|
Get the path to the base runtime compiler test resource directory
|
||||||
|
|
||||||
|
This is provided by the avocado 'compiler-test-dir' parameter if supplied,
|
||||||
|
otherwise it is set to "resources/hello-world" relative to
|
||||||
|
the test script directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
script_dir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
self.log.info("running script from directory: %s" % script_dir)
|
||||||
|
|
||||||
|
compdir = self.params.get(
|
||||||
|
'compiler-test-dir', default=os.path.join(script_dir, "resources", "hello-world"))
|
||||||
|
compdir = str(compdir)
|
||||||
|
|
||||||
|
if not os.path.isdir(compdir):
|
||||||
|
self.error("Compiler test resource directory %s does not exist" % compdir)
|
||||||
|
|
||||||
|
self.log.info("Compiler test resource directory: %s" % compdir)
|
||||||
|
|
||||||
|
return compdir
|
||||||
|
|
||||||
|
|
||||||
|
def get_docker_image_name(self):
|
||||||
|
"""
|
||||||
|
Get the name to use for the base runtime docker image
|
||||||
|
"""
|
||||||
|
|
||||||
|
container_helper = module_framework.ContainerHelper()
|
||||||
|
#It tries to get the name from URL env variable
|
||||||
|
#If URL is not defined it tries to get the name from config.yaml
|
||||||
|
image_name = container_helper.getDockerInstanceName()
|
||||||
|
if not image_name:
|
||||||
|
self.error("Could not find docker image name to use")
|
||||||
|
|
||||||
|
self.log.info("base runtime image name: %s" % image_name)
|
||||||
|
|
||||||
|
return image_name
|
||||||
|
|
||||||
|
def get_docker_labels(self):
|
||||||
|
"""
|
||||||
|
From config file get the labels that should be added to the image
|
||||||
|
"""
|
||||||
|
|
||||||
|
config = module_framework.get_config()
|
||||||
|
if not config:
|
||||||
|
self.error("Could not get config file")
|
||||||
|
if 'module' not in config.keys():
|
||||||
|
self.error("Config file does not have module section")
|
||||||
|
if 'docker' not in config['module'].keys():
|
||||||
|
self.error("Config file does not have docker module section")
|
||||||
|
|
||||||
|
docker_cfg = config['module']['docker']
|
||||||
|
if 'labels' not in docker_cfg.keys():
|
||||||
|
return None
|
||||||
|
return docker_cfg['labels']
|
||||||
|
|
||||||
|
def get_test_profile(self):
|
||||||
|
"""
|
||||||
|
From config file get the labels that should be added to the image
|
||||||
|
"""
|
||||||
|
|
||||||
|
return "container"
|
||||||
75
tests/cleanup.py
Normal file
75
tests/cleanup.py
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
"""
|
||||||
|
cleanup docker container/images and mock root for smoke testing
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger('avocado.test')
|
||||||
|
|
||||||
|
def cleanup_docker_and_mock(mockcfg, img_name):
|
||||||
|
|
||||||
|
# Clean-up old test artifacts (docker containers, image, mock root)
|
||||||
|
|
||||||
|
docker_containerlist_cmdline = 'docker ps --filter=ancestor=%s -a -q' % img_name
|
||||||
|
try:
|
||||||
|
containerlist = subprocess.check_output(docker_containerlist_cmdline,
|
||||||
|
stderr = subprocess.STDOUT, shell = True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log.error("command '%s' returned exit status %d; output:\n%s" %
|
||||||
|
(e.cmd, e.returncode, e.output))
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
log.info("docker container list with '%s' succeeded with output:\n%s" %
|
||||||
|
(docker_containerlist_cmdline, containerlist))
|
||||||
|
|
||||||
|
if containerlist:
|
||||||
|
containers = re.sub('[\r\n]+', ' ', containerlist)
|
||||||
|
log.info("docker containers using image %s need to be removed: %s\n" %
|
||||||
|
(img_name, containers));
|
||||||
|
docker_teardown_cmdline = 'docker rm -f %s' % containers
|
||||||
|
try:
|
||||||
|
docker_teardown_output = subprocess.check_output(docker_teardown_cmdline,
|
||||||
|
stderr = subprocess.STDOUT, shell = True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log.error("command '%s' returned exit status %d; output:\n%s" %
|
||||||
|
(e.cmd, e.returncode, e.output))
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
log.info("docker container teardown with '%s' succeeded with output:\n%s" %
|
||||||
|
(docker_teardown_cmdline, docker_teardown_output))
|
||||||
|
else:
|
||||||
|
log.info("no docker containers are using image %s\n" % img_name)
|
||||||
|
|
||||||
|
docker_teardown_cmdline = 'docker rmi %s' % img_name
|
||||||
|
try:
|
||||||
|
docker_teardown_output = subprocess.check_output(docker_teardown_cmdline,
|
||||||
|
stderr = subprocess.STDOUT, shell = True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
if "No such image" not in e.output:
|
||||||
|
log.error("command '%s' returned exit status %d; output:\n%s" %
|
||||||
|
(e.cmd, e.returncode, e.output))
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
log.info("No existing docker image named %s" % img_name)
|
||||||
|
else:
|
||||||
|
log.info("docker teardown with '%s' succeeded with output:\n%s" %
|
||||||
|
(docker_teardown_cmdline, docker_teardown_output))
|
||||||
|
|
||||||
|
mock_teardown_cmdline = ['mock', '-r', mockcfg, '--scrub=all']
|
||||||
|
try:
|
||||||
|
mock_teardown_output = subprocess.check_output(mock_teardown_cmdline,
|
||||||
|
stderr = subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log.error("command '%s' returned exit status %d; output:\n%s" %
|
||||||
|
(e.cmd, e.returncode, e.output))
|
||||||
|
raise
|
||||||
|
log.info("mock teardown with '%s' succeeded with output:\n%s" %
|
||||||
|
(mock_teardown_cmdline, mock_teardown_output))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
37
tests/config.yaml
Normal file
37
tests/config.yaml
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
document: modularity-testing
|
||||||
|
version: 1
|
||||||
|
name: baseruntime
|
||||||
|
modulemd-url: http://pkgs.fedoraproject.org/cgit/modules/base-runtime.git/plain/base-runtime.yaml
|
||||||
|
service:
|
||||||
|
port:
|
||||||
|
packages:
|
||||||
|
profiles:
|
||||||
|
- container
|
||||||
|
rpms:
|
||||||
|
default_module: docker
|
||||||
|
module:
|
||||||
|
docker:
|
||||||
|
setup: docker inspect base-runtime-smoke || python ./setup.py
|
||||||
|
start:
|
||||||
|
labels:
|
||||||
|
#Short-term solution as there is no bugzilla component yet
|
||||||
|
com.redhat.component: "https://github.com/fedora-modularity/base-runtime"
|
||||||
|
name: "base-runtime"
|
||||||
|
version: "0"
|
||||||
|
release: "1"
|
||||||
|
architecture: "x86_64"
|
||||||
|
usage: "docker run --rm -it base-runtime/base-runtime bash"
|
||||||
|
summary: "Minimal application runtime environment other modules can build upon."
|
||||||
|
url: "https://github.com/fedora-modularity/base-runtime"
|
||||||
|
FGC: "f26-boltron"
|
||||||
|
source: http://pkgs.fedoraproject.org/cgit/modules/base-runtime.git
|
||||||
|
container: docker=base-runtime-smoke
|
||||||
|
rpm:
|
||||||
|
setup: echo LANG=C.utf8 > {ROOT}/etc/locale.conf
|
||||||
|
start:
|
||||||
|
stop:
|
||||||
|
status:
|
||||||
|
repo: https://kojipkgs.fedoraproject.org/compose/latest-Fedora-Modular-26/compose/Server/x86_64/os/
|
||||||
|
test:
|
||||||
|
processrunnig:
|
||||||
|
- 'ls / | grep bin'
|
||||||
36
tests/resources/base-runtime-mock.cfg
Normal file
36
tests/resources/base-runtime-mock.cfg
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
config_opts['root'] = 'base-runtime-docker'
|
||||||
|
config_opts['target_arch'] = 'x86_64'
|
||||||
|
config_opts['legal_host_arches'] = ('x86_64',)
|
||||||
|
config_opts['chroot_setup_cmd'] = 'install --setopt=tsflags=nodocs bash coreutils-single filesystem glibc-minimal-langpack libcrypt microdnf rpm shadow-utils sssd-client util-linux'
|
||||||
|
config_opts['dist'] = ''
|
||||||
|
config_opts['extra_chroot_dirs'] = [ '/run/lock', ]
|
||||||
|
config_opts['releasever'] = ''
|
||||||
|
config_opts['package_manager'] = 'dnf'
|
||||||
|
config_opts['use_bootstrap_container'] = False
|
||||||
|
|
||||||
|
config_opts['yum.conf'] = """
|
||||||
|
[main]
|
||||||
|
keepcache=1
|
||||||
|
debuglevel=2
|
||||||
|
reposdir=/dev/null
|
||||||
|
logfile=/var/log/yum.log
|
||||||
|
retries=20
|
||||||
|
obsoletes=1
|
||||||
|
gpgcheck=0
|
||||||
|
assumeyes=1
|
||||||
|
syslog_ident=mock
|
||||||
|
syslog_device=
|
||||||
|
install_weak_deps=0
|
||||||
|
metadata_expire=3600
|
||||||
|
mdpolicy=group:primary
|
||||||
|
|
||||||
|
# repos
|
||||||
|
|
||||||
|
[buildrepo]
|
||||||
|
name=base-runtime
|
||||||
|
baseurl=https://kojipkgs.fedoraproject.org/compose/latest-Fedora-Modular-26/compose/Server/x86_64/os/
|
||||||
|
enabled=1
|
||||||
|
gpgcheck=0
|
||||||
|
|
||||||
|
"""
|
||||||
4
tests/resources/hello-world/Makefile
Normal file
4
tests/resources/hello-world/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
default: hello
|
||||||
|
|
||||||
|
hello: hello.c
|
||||||
|
gcc -Wall hello.c -o hello
|
||||||
15
tests/resources/hello-world/README.md
Normal file
15
tests/resources/hello-world/README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# compiler sanity smoke test for the Base Runtime docker image
|
||||||
|
|
||||||
|
The internal workings of this test are as follows:
|
||||||
|
|
||||||
|
1. Create a temporary directory.
|
||||||
|
2. Copy the `hello.sh` script from this resource directory into the temporary directory and make sure it is executable.
|
||||||
|
3. Place a gzipped tarball of `hello.c` and `Makefile` from this resource directory into the temporary directory with the name `hello.tgz`.
|
||||||
|
e.g.,
|
||||||
|
`$ tar czf /tmp/random/hello.tgz hello.c Makefile`
|
||||||
|
4. Run the docker container binding the temporary directory as `/mnt` and run `/mnt/hello.sh`.
|
||||||
|
e.g.,
|
||||||
|
`$ docker run -v /tmp/random:/mnt:z --rm base-runtime /bin/bash -c /mnt/hello.sh`
|
||||||
|
5. Clean up the temporary directory upon completion.
|
||||||
|
|
||||||
|
|
||||||
8
tests/resources/hello-world/hello.c
Normal file
8
tests/resources/hello-world/hello.c
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
printf ("Hello, world!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
tests/resources/hello-world/hello.sh
Executable file
7
tests/resources/hello-world/hello.sh
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e # exit immediately on any failure
|
||||||
|
microdnf install tar make gcc 1>&2
|
||||||
|
cd /mnt
|
||||||
|
tar xzvf hello.tgz 1>&2
|
||||||
|
make 1>&2
|
||||||
|
./hello
|
||||||
115
tests/resources/installed_packages/all_installed_pkgs_docker.txt
Normal file
115
tests/resources/installed_packages/all_installed_pkgs_docker.txt
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
audit-libs
|
||||||
|
basesystem
|
||||||
|
bash
|
||||||
|
bzip2-libs
|
||||||
|
ca-certificates
|
||||||
|
chkconfig
|
||||||
|
coreutils-single
|
||||||
|
cracklib
|
||||||
|
crypto-policies
|
||||||
|
curl
|
||||||
|
cyrus-sasl-lib
|
||||||
|
elfutils-libelf
|
||||||
|
expat
|
||||||
|
fedora-modular-release
|
||||||
|
fedora-modular-repos
|
||||||
|
filesystem
|
||||||
|
gawk
|
||||||
|
glib2
|
||||||
|
glibc
|
||||||
|
glibc-common
|
||||||
|
glibc-minimal-langpack
|
||||||
|
gmp
|
||||||
|
gnupg2
|
||||||
|
gnutls
|
||||||
|
gobject-introspection
|
||||||
|
gpgme
|
||||||
|
grep
|
||||||
|
gzip
|
||||||
|
info
|
||||||
|
keyutils-libs
|
||||||
|
krb5-libs
|
||||||
|
libacl
|
||||||
|
libarchive
|
||||||
|
libassuan
|
||||||
|
libattr
|
||||||
|
libblkid
|
||||||
|
libcap
|
||||||
|
libcap-ng
|
||||||
|
libcom_err
|
||||||
|
libcrypt
|
||||||
|
libcurl
|
||||||
|
libdb
|
||||||
|
libdb-utils
|
||||||
|
libdnf
|
||||||
|
libfdisk
|
||||||
|
libffi
|
||||||
|
libgcc
|
||||||
|
libgcrypt
|
||||||
|
libgpg-error
|
||||||
|
libidn2
|
||||||
|
libksba
|
||||||
|
libmetalink
|
||||||
|
libmount
|
||||||
|
libnghttp2
|
||||||
|
libpeas
|
||||||
|
libpsl
|
||||||
|
libpwquality
|
||||||
|
librepo
|
||||||
|
libselinux
|
||||||
|
libsemanage
|
||||||
|
libsepol
|
||||||
|
libsigsegv
|
||||||
|
libsmartcols
|
||||||
|
libsolv
|
||||||
|
libssh2
|
||||||
|
libsss_idmap
|
||||||
|
libsss_nss_idmap
|
||||||
|
libtasn1
|
||||||
|
libunistring
|
||||||
|
libutempter
|
||||||
|
libuuid
|
||||||
|
libverto
|
||||||
|
libxml2
|
||||||
|
lua-libs
|
||||||
|
lz4
|
||||||
|
lz4-libs
|
||||||
|
lzo
|
||||||
|
microdnf
|
||||||
|
mpfr
|
||||||
|
ncurses
|
||||||
|
ncurses-base
|
||||||
|
ncurses-libs
|
||||||
|
nettle
|
||||||
|
npth
|
||||||
|
nspr
|
||||||
|
nss
|
||||||
|
nss-pem
|
||||||
|
nss-softokn
|
||||||
|
nss-softokn-freebl
|
||||||
|
nss-sysinit
|
||||||
|
nss-tools
|
||||||
|
nss-util
|
||||||
|
openldap
|
||||||
|
openssl-libs
|
||||||
|
p11-kit
|
||||||
|
p11-kit-trust
|
||||||
|
pam
|
||||||
|
pcre
|
||||||
|
popt
|
||||||
|
publicsuffix-list-dafsa
|
||||||
|
readline
|
||||||
|
rpm
|
||||||
|
rpm-libs
|
||||||
|
rpm-plugin-selinux
|
||||||
|
sed
|
||||||
|
setup
|
||||||
|
shadow-utils
|
||||||
|
sqlite-libs
|
||||||
|
sssd-client
|
||||||
|
systemd-libs
|
||||||
|
tzdata
|
||||||
|
ustr
|
||||||
|
util-linux
|
||||||
|
xz-libs
|
||||||
|
zlib
|
||||||
150
tests/resources/installed_packages/all_installed_pkgs_nspawn.txt
Normal file
150
tests/resources/installed_packages/all_installed_pkgs_nspawn.txt
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
acl
|
||||||
|
audit-libs
|
||||||
|
basesystem
|
||||||
|
bash
|
||||||
|
binutils
|
||||||
|
bzip2-libs
|
||||||
|
ca-certificates
|
||||||
|
chkconfig
|
||||||
|
coreutils-single
|
||||||
|
cpp
|
||||||
|
cracklib
|
||||||
|
cracklib-dicts
|
||||||
|
crypto-policies
|
||||||
|
cryptsetup-libs
|
||||||
|
curl
|
||||||
|
cyrus-sasl-lib
|
||||||
|
dbus
|
||||||
|
dbus-libs
|
||||||
|
device-mapper
|
||||||
|
device-mapper-libs
|
||||||
|
diffutils
|
||||||
|
elfutils-default-yama-scope
|
||||||
|
elfutils-libelf
|
||||||
|
elfutils-libs
|
||||||
|
emacs-filesystem
|
||||||
|
expat
|
||||||
|
fedora-modular-release
|
||||||
|
fedora-modular-repos
|
||||||
|
filesystem
|
||||||
|
gawk
|
||||||
|
gc
|
||||||
|
gcc
|
||||||
|
glib2
|
||||||
|
glibc
|
||||||
|
glibc-common
|
||||||
|
glibc-devel
|
||||||
|
glibc-headers
|
||||||
|
glibc-minimal-langpack
|
||||||
|
gmp
|
||||||
|
gnupg2
|
||||||
|
gnutls
|
||||||
|
gobject-introspection
|
||||||
|
gpgme
|
||||||
|
grep
|
||||||
|
guile
|
||||||
|
gzip
|
||||||
|
info
|
||||||
|
iptables-libs
|
||||||
|
isl
|
||||||
|
kernel-headers
|
||||||
|
keyutils-libs
|
||||||
|
kmod-libs
|
||||||
|
krb5-libs
|
||||||
|
libacl
|
||||||
|
libarchive
|
||||||
|
libassuan
|
||||||
|
libatomic_ops
|
||||||
|
libattr
|
||||||
|
libblkid
|
||||||
|
libcap
|
||||||
|
libcap-ng
|
||||||
|
libcom_err
|
||||||
|
libcrypt
|
||||||
|
libcurl
|
||||||
|
libdb
|
||||||
|
libdb-utils
|
||||||
|
libdnf
|
||||||
|
libfdisk
|
||||||
|
libffi
|
||||||
|
libgcc
|
||||||
|
libgcrypt
|
||||||
|
libgomp
|
||||||
|
libgpg-error
|
||||||
|
libidn
|
||||||
|
libidn2
|
||||||
|
libksba
|
||||||
|
libmetalink
|
||||||
|
libmount
|
||||||
|
libmpc
|
||||||
|
libnghttp2
|
||||||
|
libsss_idmap
|
||||||
|
libsss_nss_idmap
|
||||||
|
libpcap
|
||||||
|
libpeas
|
||||||
|
libpsl
|
||||||
|
libpwquality
|
||||||
|
librepo
|
||||||
|
libseccomp
|
||||||
|
libselinux
|
||||||
|
libsemanage
|
||||||
|
libsepol
|
||||||
|
libsigsegv
|
||||||
|
libsmartcols
|
||||||
|
libsolv
|
||||||
|
libssh2
|
||||||
|
libstdc++
|
||||||
|
libtasn1
|
||||||
|
libtool-ltdl
|
||||||
|
libunistring
|
||||||
|
libutempter
|
||||||
|
libuuid
|
||||||
|
libverto
|
||||||
|
libxml2
|
||||||
|
lua-libs
|
||||||
|
lz4
|
||||||
|
lz4-libs
|
||||||
|
lzo
|
||||||
|
make
|
||||||
|
microdnf
|
||||||
|
mpfr
|
||||||
|
ncurses
|
||||||
|
ncurses-base
|
||||||
|
ncurses-libs
|
||||||
|
nettle
|
||||||
|
npth
|
||||||
|
nspr
|
||||||
|
nss
|
||||||
|
nss-pem
|
||||||
|
nss-softokn
|
||||||
|
nss-softokn-freebl
|
||||||
|
nss-sysinit
|
||||||
|
nss-tools
|
||||||
|
nss-util
|
||||||
|
openldap
|
||||||
|
openssl-libs
|
||||||
|
p11-kit
|
||||||
|
p11-kit-trust
|
||||||
|
pam
|
||||||
|
pcre
|
||||||
|
popt
|
||||||
|
publicsuffix-list-dafsa
|
||||||
|
qrencode-libs
|
||||||
|
readline
|
||||||
|
rpm
|
||||||
|
rpm-libs
|
||||||
|
rpm-plugin-selinux
|
||||||
|
sed
|
||||||
|
setup
|
||||||
|
shadow-utils
|
||||||
|
sqlite-libs
|
||||||
|
sssd-client
|
||||||
|
systemd
|
||||||
|
systemd-libs
|
||||||
|
systemd-pam
|
||||||
|
tar
|
||||||
|
tzdata
|
||||||
|
ustr
|
||||||
|
util-linux
|
||||||
|
xz-libs
|
||||||
|
zlib
|
||||||
96
tests/resources/os_release/os_release.sh
Executable file
96
tests/resources/os_release/os_release.sh
Executable file
|
|
@ -0,0 +1,96 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e # exit immediately on any failure
|
||||||
|
|
||||||
|
. /etc/os-release
|
||||||
|
|
||||||
|
EXP_NAME="Fedora Modular"
|
||||||
|
EXP_VERSION="26 (Twenty Six)"
|
||||||
|
EXP_ID="fedora-modular"
|
||||||
|
EXP_ID_LIKE="fedora"
|
||||||
|
EXP_VERSION_ID="26"
|
||||||
|
EXP_PRETTY_NAME="Fedora Modular 26 (Twenty Six)"
|
||||||
|
EXP_ANSI_COLOR="0;34"
|
||||||
|
EXP_CPE_NAME="cpe:/o:fedoraproject:fedora-modular:26"
|
||||||
|
EXP_HOME_URL="https://fedoraproject.org/"
|
||||||
|
EXP_BUG_REPORT_URL="https://bugzilla.redhat.com/"
|
||||||
|
EXP_REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||||
|
EXP_REDHAT_BUGZILLA_PRODUCT_VERSION="26"
|
||||||
|
EXP_REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||||
|
EXP_REDHAT_SUPPORT_PRODUCT_VERSION="26"
|
||||||
|
EXP_PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"
|
||||||
|
|
||||||
|
if [[ $NAME != $EXP_NAME ]]; then
|
||||||
|
echo "FAIL: Expected NAME to be '$EXP_NAME', but it is '$NAME'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $VERSION != $EXP_VERSION ]]; then
|
||||||
|
echo "FAIL: Expected VERSION to be '$EXP_VERSION', but it is '$VERSION'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $ID != $EXP_ID ]]; then
|
||||||
|
echo "FAIL: Expected ID to be '$EXP_ID', but it is '$ID'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $ID_LIKE != $EXP_ID_LIKE ]]; then
|
||||||
|
echo "FAIL: Expected ID_LIKE to be '$EXP_ID_LIKE', but it is '$ID_LIKE'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $VERSION_ID != $EXP_VERSION_ID ]]; then
|
||||||
|
echo "FAIL: Expected VERSION_ID to be '$EXP_VERSION_ID', but it is '$VERSION_ID'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $PRETTY_NAME != $EXP_PRETTY_NAME ]]; then
|
||||||
|
echo "FAIL: Expected PRETTY_NAME to be '$EXP_PRETTY_NAME', but it is '$PRETTY_NAME'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $ANSI_COLOR != $EXP_ANSI_COLOR ]]; then
|
||||||
|
echo "FAIL: Expected ANSI_COLOR to be '$EXP_ANSI_COLOR', but it is '$ANSI_COLOR'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $CPE_NAME != $EXP_CPE_NAME ]]; then
|
||||||
|
echo "FAIL: Expected CPE_NAME to be '$EXP_CPE_NAME', but it is '$CPE_NAME'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $HOME_URL != $EXP_HOME_URL ]]; then
|
||||||
|
echo "FAIL: Expected HOME_URL to be '$EXP_HOME_URL', but it is '$HOME_URL'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $BUG_REPORT_URL != $EXP_BUG_REPORT_URL ]]; then
|
||||||
|
echo "FAIL: Expected BUG_REPORT_URL to be '$EXP_BUG_REPORT_URL', but it is '$BUG_REPORT_URL'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $REDHAT_BUGZILLA_PRODUCT != $EXP_REDHAT_BUGZILLA_PRODUCT ]]; then
|
||||||
|
echo "FAIL: Expected REDHAT_BUGZILLA_PRODUCT to be '$EXP_REDHAT_BUGZILLA_PRODUCT', but it is '$REDHAT_BUGZILLA_PRODUCT'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $REDHAT_BUGZILLA_PRODUCT_VERSION != $EXP_REDHAT_BUGZILLA_PRODUCT_VERSION ]]; then
|
||||||
|
echo "FAIL: Expected REDHAT_BUGZILLA_PRODUCT_VERSION to be '$EXP_REDHAT_BUGZILLA_PRODUCT_VERSION', but it is '$REDHAT_BUGZILLA_PRODUCT_VERSION'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $REDHAT_SUPPORT_PRODUCT != $EXP_REDHAT_SUPPORT_PRODUCT ]]; then
|
||||||
|
echo "FAIL: Expected REDHAT_SUPPORT_PRODUCT to be '$EXP_REDHAT_SUPPORT_PRODUCT', but it is '$REDHAT_SUPPORT_PRODUCT'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $REDHAT_SUPPORT_PRODUCT_VERSION != $EXP_REDHAT_SUPPORT_PRODUCT_VERSION ]]; then
|
||||||
|
echo "FAIL: Expected REDHAT_SUPPORT_PRODUCT_VERSION to be '$EXP_REDHAT_SUPPORT_PRODUCT_VERSION', but it is '$REDHAT_SUPPORT_PRODUCT_VERSION'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $PRIVACY_POLICY_URL != $EXP_PRIVACY_POLICY_URL ]]; then
|
||||||
|
echo "FAIL: Expected PRIVACY_POLICY_URL to be '$EXP_PRIVACY_POLICY_URL', but it is '$PRIVACY_POLICY_URL'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
180
tests/setup.py
Executable file
180
tests/setup.py
Executable file
|
|
@ -0,0 +1,180 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import configparser
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from avocado import main
|
||||||
|
from avocado import Test
|
||||||
|
from moduleframework import module_framework
|
||||||
|
|
||||||
|
import cleanup
|
||||||
|
import brtconfig
|
||||||
|
|
||||||
|
|
||||||
|
class BaseRuntimeSetupDocker(Test, module_framework.CommonFunctions):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
|
||||||
|
self.mockcfg = brtconfig.get_mockcfg(self)
|
||||||
|
self.br_image_name = brtconfig.get_docker_image_name(self)
|
||||||
|
|
||||||
|
def _process_mockcfg(self):
|
||||||
|
|
||||||
|
profile_name = brtconfig.get_test_profile(self)
|
||||||
|
mockcfg = self.mockcfg
|
||||||
|
|
||||||
|
mock_root = ''
|
||||||
|
mockcfg_lines = []
|
||||||
|
#Regex to get packages that are configured on mockcfg to be installed
|
||||||
|
chroot_setup_pkg_regex = re.compile("config_opts\s*\[\s*'chroot_setup_cmd'\s*\]\s*="
|
||||||
|
"\s*'install --setopt=tsflags=nodocs\s*(.*)\s*'")
|
||||||
|
chroot_setup_pkgs = None
|
||||||
|
with open(mockcfg, 'r') as mock_cfgfile:
|
||||||
|
found_setup_cmd = False
|
||||||
|
for line in mock_cfgfile:
|
||||||
|
mockcfg_lines.append(line)
|
||||||
|
if re.match("config_opts\s*\[\s*'root'\s*\]", line) is not None:
|
||||||
|
mock_root = line.split('=')[1].split("'")[1]
|
||||||
|
if re.match("config_opts\s*\[\s*'chroot_setup_cmd'\s*\]", line) is not None:
|
||||||
|
found_setup_cmd = True
|
||||||
|
#Check if there are packages defined on chroot_setup_cmd
|
||||||
|
m = chroot_setup_pkg_regex.match(line)
|
||||||
|
if m:
|
||||||
|
chroot_setup_pkgs = sorted(m.group(1).split())
|
||||||
|
if len(mock_root) == 0:
|
||||||
|
self.error("mock configuration file %s does not specify mock root" %
|
||||||
|
mockcfg)
|
||||||
|
self.log.info("mock root: %s" % mock_root)
|
||||||
|
self.mock_root = mock_root
|
||||||
|
|
||||||
|
if not found_setup_cmd:
|
||||||
|
self.error("mock configuration file %s does not define chroot_setup_cmd" % mockcfg)
|
||||||
|
|
||||||
|
#Need to get all packages that need to be installed
|
||||||
|
mod_yaml = self.getModulemdYamlconfig()
|
||||||
|
if not mod_yaml:
|
||||||
|
self.error("Could not read modulemd Yaml file")
|
||||||
|
|
||||||
|
if "data" not in mod_yaml.keys():
|
||||||
|
self.error("'data' key was not found in modulemd Yaml file")
|
||||||
|
|
||||||
|
if "profiles" not in mod_yaml["data"].keys():
|
||||||
|
self.error("'profiles' key was not found in 'data' section")
|
||||||
|
|
||||||
|
if profile_name not in mod_yaml["data"]["profiles"].keys():
|
||||||
|
self.error("'%s' key was not found in 'profiles' section" % profile_name)
|
||||||
|
|
||||||
|
base_profile = mod_yaml["data"]["profiles"][profile_name]
|
||||||
|
if "rpms" not in base_profile.keys():
|
||||||
|
self.error("'rpms' key was not found in '%s' profile" % profile_name)
|
||||||
|
|
||||||
|
req_pkgs = base_profile["rpms"]
|
||||||
|
if not req_pkgs:
|
||||||
|
self.error("Could not find any package to be installed in the image")
|
||||||
|
|
||||||
|
#Only update mockcfg if the list of packages changed
|
||||||
|
if cmp(chroot_setup_pkgs, sorted(req_pkgs)):
|
||||||
|
#Need to change chroot_setup_cmd line on mockcfg file
|
||||||
|
setup_cmd = "install --setopt=tsflags=nodocs "
|
||||||
|
setup_cmd += " ".join(req_pkgs)
|
||||||
|
with open(mockcfg, 'w') as mock_cfgfile:
|
||||||
|
for line in mockcfg_lines:
|
||||||
|
if re.match("config_opts\s*\[\s*'chroot_setup_cmd'\s*\]", line) is not None:
|
||||||
|
line = "config_opts['chroot_setup_cmd'] = '%s'\n" % setup_cmd
|
||||||
|
mock_cfgfile.write(line)
|
||||||
|
|
||||||
|
#Test will exit with WARN to inform the config file has changed
|
||||||
|
self.log.warning("List of packages to be installed by mock changed")
|
||||||
|
|
||||||
|
def _run_command(self, cmd):
|
||||||
|
try:
|
||||||
|
cmd_output = subprocess.check_output(
|
||||||
|
cmd, stderr=subprocess.STDOUT, shell=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
self.error("command '%s' returned exit status %d; output:\n%s" %
|
||||||
|
(e.cmd, e.returncode, e.output))
|
||||||
|
else:
|
||||||
|
self.log.info("command '%s' succeeded with output:\n%s" %
|
||||||
|
(cmd, cmd_output))
|
||||||
|
|
||||||
|
def _set_dnf_conf(self):
|
||||||
|
filename = "/etc/dnf/dnf.conf"
|
||||||
|
path = "/var/lib/mock/" + self.mock_root + "/root" + filename
|
||||||
|
|
||||||
|
conf = "EOF\n"
|
||||||
|
conf += "[main]\n"
|
||||||
|
conf += "gpgcheck=1\n"
|
||||||
|
conf += "installonly_limit=3\n"
|
||||||
|
conf += "clean_requirements_on_remove=True\n"
|
||||||
|
conf += "EOF\n"
|
||||||
|
|
||||||
|
cmd = "sudo tee %s << %s" % (path, conf)
|
||||||
|
self._run_command(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def testCreateDockerImage(self):
|
||||||
|
|
||||||
|
self._process_mockcfg()
|
||||||
|
|
||||||
|
# Clean-up any old test artifacts (docker containers, image, mock root)
|
||||||
|
# first:
|
||||||
|
try:
|
||||||
|
cleanup.cleanup_docker_and_mock(self.mockcfg, self.br_image_name)
|
||||||
|
except:
|
||||||
|
self.error("artifact cleanup failed")
|
||||||
|
else:
|
||||||
|
self.log.info("artifact cleanup successful")
|
||||||
|
|
||||||
|
# Initialize chroot with mock
|
||||||
|
self._run_command('mock -r %s --init' % self.mockcfg)
|
||||||
|
|
||||||
|
self._set_dnf_conf()
|
||||||
|
|
||||||
|
# check if "sudo" allows us to tar up the chroot without a password
|
||||||
|
# Note: this must be configured in "sudoers" to work!
|
||||||
|
tar_cmd = "tar -C /var/lib/mock/%s/root -c ." % self.mock_root
|
||||||
|
try:
|
||||||
|
cmd_output = subprocess.check_output(
|
||||||
|
"sudo -n %s >/dev/null" % tar_cmd,
|
||||||
|
stderr=subprocess.STDOUT, shell=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
# no luck using "sudo", warn and proceed as ordinary user without
|
||||||
|
# it
|
||||||
|
self.log.info("command '%s' returned exit status %d; output:\n%s" %
|
||||||
|
(e.cmd, e.returncode, e.output))
|
||||||
|
self.log.warning("NO SUDO RIGHTS TO RUN COMMAND '%s' AS ROOT" %
|
||||||
|
tar_cmd)
|
||||||
|
self.log.warning("GENERATED DOCKER IMAGE '%s' MAY BE INCOMPLETE!" %
|
||||||
|
self.br_image_name)
|
||||||
|
else:
|
||||||
|
# "sudo" works, so use it
|
||||||
|
tar_cmd = "sudo -n " + tar_cmd
|
||||||
|
|
||||||
|
img_scratch = "%s-scratch" % self.br_image_name
|
||||||
|
# Import mock chroot as a docker image
|
||||||
|
self._run_command("%s | docker import - %s" %
|
||||||
|
(tar_cmd, img_scratch))
|
||||||
|
|
||||||
|
docker_labels = brtconfig.get_docker_labels(self)
|
||||||
|
#Dockerfile to use when building final image
|
||||||
|
dockerfile = 'EOF\n'
|
||||||
|
dockerfile += 'FROM %s\n' % img_scratch
|
||||||
|
#Set default locale to C.utf8
|
||||||
|
dockerfile += 'ENV LANG C.utf8\n'
|
||||||
|
if docker_labels:
|
||||||
|
for key in docker_labels.keys():
|
||||||
|
dockerfile += 'LABEL %s="%s"\n' % (key, docker_labels[key])
|
||||||
|
dockerfile += 'EOF\n'
|
||||||
|
|
||||||
|
# Build final image with extra information from dockerfile
|
||||||
|
self._run_command("docker build -t %s - << %s" %
|
||||||
|
(self.br_image_name, dockerfile))
|
||||||
|
#Remove temporary image
|
||||||
|
self._run_command("docker rmi %s" % img_scratch)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
468
tests/smoke.py
Normal file
468
tests/smoke.py
Normal file
|
|
@ -0,0 +1,468 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import stat
|
||||||
|
import tarfile
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from avocado import main
|
||||||
|
from moduleframework import module_framework
|
||||||
|
|
||||||
|
import brtconfig
|
||||||
|
|
||||||
|
|
||||||
|
class BaseRuntimeSmokeTest(module_framework.AvocadoTest):
|
||||||
|
"""
|
||||||
|
:avocado: enable
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
self.compiler_resource_dir = brtconfig.get_compiler_test_dir(self)
|
||||||
|
self.compiler_test_dir = None
|
||||||
|
|
||||||
|
def _check_cmd_result(self, cmd, return_code, cmd_output, expect_pass=True):
|
||||||
|
"""
|
||||||
|
Check based on return code if command passed or failed as expected
|
||||||
|
"""
|
||||||
|
if return_code == 0 and expect_pass:
|
||||||
|
self.log.info("command '%s' succeeded with output:\n%s" %
|
||||||
|
(cmd, cmd_output))
|
||||||
|
return True
|
||||||
|
elif return_code != 0 and not expect_pass:
|
||||||
|
self.log.info("command '%s' failed as expected with output:\n%s" %
|
||||||
|
(cmd, cmd_output))
|
||||||
|
return True
|
||||||
|
self.error("command '%s' returned unexpected exit status %d; output:\n%s" %
|
||||||
|
(cmd, return_code, cmd_output))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def testSmoke(self):
|
||||||
|
"""
|
||||||
|
Run several smoke tests
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO: fill this "placeholder" with actual, complete, smoke tests:
|
||||||
|
|
||||||
|
smoke_pass = [
|
||||||
|
"echo 'Hello, World!'",
|
||||||
|
"cat /etc/redhat-release",
|
||||||
|
"rpm -q glibc"]
|
||||||
|
|
||||||
|
smoke_fail = [
|
||||||
|
"exit 1"]
|
||||||
|
|
||||||
|
for cmd in smoke_pass:
|
||||||
|
cmd_result = self.run("%s" % cmd, ignore_status=True)
|
||||||
|
cmd_output = cmd_result.stdout + cmd_result.stderr
|
||||||
|
self._check_cmd_result(cmd, cmd_result.exit_status, cmd_output)
|
||||||
|
|
||||||
|
for cmd in smoke_fail:
|
||||||
|
cmd_result = self.run("%s" % cmd, ignore_status=True)
|
||||||
|
cmd_output = cmd_result.stdout + cmd_result.stderr
|
||||||
|
self._check_cmd_result(cmd, cmd_result.exit_status, cmd_output, expect_pass=False)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_all_installed_pkgs(self):
|
||||||
|
try:
|
||||||
|
cmd_result = self.run("rpm -qa --qf='%{{name}}\n'")
|
||||||
|
except BaseException as details:
|
||||||
|
self.error("Could not get all installed packages (%s)" % details)
|
||||||
|
except:
|
||||||
|
self.error("Could not get all installed packages")
|
||||||
|
output_list = cmd_result.stdout.split("\n")
|
||||||
|
#remove empty string from the list
|
||||||
|
return [item for item in output_list if item]
|
||||||
|
|
||||||
|
def testRequiredPackages(self):
|
||||||
|
"""
|
||||||
|
Check if all required packages defined on yaml file are installed
|
||||||
|
"""
|
||||||
|
|
||||||
|
profile_name = brtconfig.get_test_profile(self)
|
||||||
|
mod_yaml = self.getModulemdYamlconfig()
|
||||||
|
if not mod_yaml:
|
||||||
|
self.error("Could not read modulemd Yaml file")
|
||||||
|
|
||||||
|
if "data" not in mod_yaml.keys():
|
||||||
|
self.error("'data' key was not found in modulemd Yaml file")
|
||||||
|
|
||||||
|
if "profiles" not in mod_yaml["data"].keys():
|
||||||
|
self.error("'profiles' key was not found in 'data' section")
|
||||||
|
|
||||||
|
if profile_name not in mod_yaml["data"]["profiles"].keys():
|
||||||
|
self.error("'%s' key was not found in 'profiles' section" % profile_name)
|
||||||
|
|
||||||
|
base_profile = mod_yaml["data"]["profiles"][profile_name]
|
||||||
|
if "rpms" not in base_profile.keys():
|
||||||
|
self.error("'rpms' key was not found in '%s' profile" % profile_name)
|
||||||
|
|
||||||
|
req_pkgs = base_profile["rpms"]
|
||||||
|
if not req_pkgs:
|
||||||
|
self.error("No rpm is defined for container")
|
||||||
|
|
||||||
|
installed_pkgs = self._get_all_installed_pkgs()
|
||||||
|
|
||||||
|
for req_pkg in req_pkgs:
|
||||||
|
if req_pkg not in installed_pkgs:
|
||||||
|
self.error("Required package '%s' is not installed" % req_pkg)
|
||||||
|
|
||||||
|
def testInstalledPackages(self):
|
||||||
|
"""
|
||||||
|
Check if only the expected packages are installed on module
|
||||||
|
"""
|
||||||
|
|
||||||
|
expected_pkgs = None
|
||||||
|
|
||||||
|
if not self.moduleType:
|
||||||
|
self.error("moduleType is not defined")
|
||||||
|
|
||||||
|
all_installed_pkgs_path = ("resources/installed_packages/all_installed_pkgs_%s.txt"
|
||||||
|
% self.moduleType)
|
||||||
|
try:
|
||||||
|
with open(all_installed_pkgs_path) as f:
|
||||||
|
expected_pkgs = f.read().splitlines()
|
||||||
|
except:
|
||||||
|
self.error("Could not read the expected installed packages list")
|
||||||
|
|
||||||
|
if not expected_pkgs:
|
||||||
|
self.error("List of expected installed packages is empty")
|
||||||
|
|
||||||
|
installed_pkgs = self._get_all_installed_pkgs()
|
||||||
|
if not installed_pkgs:
|
||||||
|
self.error("It seems there is no package installed in the module")
|
||||||
|
|
||||||
|
for pkg in installed_pkgs:
|
||||||
|
if pkg not in expected_pkgs:
|
||||||
|
self.error("Did not expect to have package '%s' installed" % pkg)
|
||||||
|
|
||||||
|
def testInstallAllPackages(self):
|
||||||
|
"""
|
||||||
|
Check if all packages that we ship are able to be installed on module
|
||||||
|
"""
|
||||||
|
|
||||||
|
profile_name = brtconfig.get_test_profile(self)
|
||||||
|
mod_yaml = self.getModulemdYamlconfig()
|
||||||
|
if not mod_yaml:
|
||||||
|
self.error("Could not read modulemd Yaml file")
|
||||||
|
|
||||||
|
if "data" not in mod_yaml.keys():
|
||||||
|
self.error("'data' key was not found in modulemd Yaml file")
|
||||||
|
|
||||||
|
if "api" not in mod_yaml["data"].keys():
|
||||||
|
self.error("'api' key was not found in 'data' section")
|
||||||
|
|
||||||
|
if "rpms" not in mod_yaml["data"]["api"].keys():
|
||||||
|
self.error("'rpms' key was not found in 'api'")
|
||||||
|
|
||||||
|
all_api_pkgs = mod_yaml["data"]["api"]["rpms"]
|
||||||
|
|
||||||
|
repo_path = None
|
||||||
|
mod_dep = self.getModuleDependencies()
|
||||||
|
mod_name = "baseruntime"
|
||||||
|
if mod_dep and mod_name in mod_dep.keys():
|
||||||
|
if "urls" in mod_dep[mod_name].keys():
|
||||||
|
if len(mod_dep[mod_name]["urls"]) != 1:
|
||||||
|
self.error("Expected exactly 1 repo url for %s" % mod_name)
|
||||||
|
repo_path = mod_dep[mod_name]["urls"][0]
|
||||||
|
|
||||||
|
|
||||||
|
# docker uses the repo defined on mock cfg
|
||||||
|
if self.moduleType == "docker":
|
||||||
|
mockcfg = ""
|
||||||
|
with open(brtconfig.get_mockcfg(self)) as f:
|
||||||
|
mockcfg = f.read()
|
||||||
|
for line in mockcfg.split("\n"):
|
||||||
|
m = re.match("baseurl=(\S+)", line)
|
||||||
|
if m:
|
||||||
|
repo_path = m.group(1)
|
||||||
|
|
||||||
|
if not repo_path:
|
||||||
|
self.error("Could not find repo to query the packages")
|
||||||
|
|
||||||
|
#Query all available packages in our repo
|
||||||
|
query_repo_cmd = "repoquery -a --qf '%%{{name}}' --repofrompath=0,%s --repoid=0" % repo_path
|
||||||
|
all_repo_pkgs = self.runHost(query_repo_cmd).stdout.split("\n")
|
||||||
|
|
||||||
|
all_avail_pkgs = []
|
||||||
|
#Available packages are the ones from API that are available on repo
|
||||||
|
for pkg in all_api_pkgs:
|
||||||
|
if pkg in all_repo_pkgs:
|
||||||
|
all_avail_pkgs.append(pkg)
|
||||||
|
|
||||||
|
skip_pkg_image = {}
|
||||||
|
skip_pkg_image["docker"] = ["kernel", "dracut"]
|
||||||
|
skip_pkg_image["nspawn"] = ["kernel", "dracut"]
|
||||||
|
conflict_pkgs = {
|
||||||
|
"coreutils" : "coreutils-single",
|
||||||
|
"libcrypt-nss" : "libcrypt"
|
||||||
|
}
|
||||||
|
|
||||||
|
#Try to install packages that have conflicting packages installed
|
||||||
|
for pkg in conflict_pkgs.keys():
|
||||||
|
self.run("microdnf remove %s" % conflict_pkgs[pkg])
|
||||||
|
self.run("rpm -q %s" % pkg)
|
||||||
|
self.run("microdnf remove %s" % pkg)
|
||||||
|
self.run("rpm -q %s" % conflict_pkgs[pkg])
|
||||||
|
|
||||||
|
pkgs_2_install = []
|
||||||
|
for pkg in all_avail_pkgs:
|
||||||
|
if pkg in conflict_pkgs.keys():
|
||||||
|
continue
|
||||||
|
#Do not install packages such as dracut* on docker.
|
||||||
|
skip = False
|
||||||
|
for skip_pkg in skip_pkg_image[self.moduleType]:
|
||||||
|
if pkg.startswith(skip_pkg):
|
||||||
|
skip = True
|
||||||
|
if not skip:
|
||||||
|
pkgs_2_install.append(pkg)
|
||||||
|
self.run("microdnf install %s > /dev/null" % " ".join(pkgs_2_install))
|
||||||
|
|
||||||
|
|
||||||
|
def testUserManipulation(self):
|
||||||
|
"""
|
||||||
|
Check if can add, remove and modify user
|
||||||
|
"""
|
||||||
|
|
||||||
|
#We want to run multiple commands using same docker container
|
||||||
|
new_user = "usertest"
|
||||||
|
pass_cmds = []
|
||||||
|
#Create new user
|
||||||
|
pass_cmds.append("adduser %s" % new_user)
|
||||||
|
#Make sure user is created
|
||||||
|
pass_cmds.append("cat /etc/passwd | grep %s" % new_user)
|
||||||
|
pass_cmds.append("ls /home/%s" % new_user)
|
||||||
|
#set user password
|
||||||
|
pass_cmds.append("usermod --password testpassword %s" % new_user)
|
||||||
|
#Test new user functionality
|
||||||
|
pass_cmds.append('su - %s -c "touch ~/testfile.txt"' % new_user)
|
||||||
|
#Make sure the file was created by the correct user
|
||||||
|
pass_cmds.append("ls -allh /home/%s/testfile.txt | grep '%s %s'" %
|
||||||
|
(new_user, new_user, new_user))
|
||||||
|
#Remove user
|
||||||
|
pass_cmds.append("userdel -r %s" % new_user)
|
||||||
|
for cmd in pass_cmds:
|
||||||
|
cmd_result = self.run("%s" % cmd, ignore_status=True)
|
||||||
|
cmd_output = cmd_result.stdout + cmd_result.stderr
|
||||||
|
self._check_cmd_result(cmd, cmd_result.exit_status, cmd_output)
|
||||||
|
|
||||||
|
fail_cmds = []
|
||||||
|
#Make sure user is removed
|
||||||
|
fail_cmds.append("ls /home/%s" % new_user)
|
||||||
|
fail_cmds.append("cat /etc/passwd | grep usertest")
|
||||||
|
#relying on __del__ from BaseRuntimeRunCmd to remove container
|
||||||
|
for cmd in fail_cmds:
|
||||||
|
cmd_result = self.run("%s" % cmd, ignore_status=True)
|
||||||
|
cmd_output = cmd_result.stdout + cmd_result.stderr
|
||||||
|
self._check_cmd_result(cmd, cmd_result.exit_status, cmd_output, expect_pass=False)
|
||||||
|
|
||||||
|
def testOsRelease(self):
|
||||||
|
"""
|
||||||
|
Check if OS release information is correct
|
||||||
|
"""
|
||||||
|
|
||||||
|
test_path = "resources/os_release/os_release.sh"
|
||||||
|
dest_path = "/tmp/os_release.sh"
|
||||||
|
try:
|
||||||
|
self.copyTo(test_path, dest_path)
|
||||||
|
except:
|
||||||
|
self.error("Could not copy test file from %s to module %s" %
|
||||||
|
(test_path, dest_path))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.run(dest_path)
|
||||||
|
except:
|
||||||
|
self.error("%s failed" % dest_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.run("rm -f %s" % dest_path)
|
||||||
|
except:
|
||||||
|
self.error("Could not delete %s" % dest_path)
|
||||||
|
|
||||||
|
def test_glibc_i18n(self):
|
||||||
|
"""
|
||||||
|
Test glibc support to internationalization
|
||||||
|
"""
|
||||||
|
|
||||||
|
lang_default = {
|
||||||
|
#cmd : cmd_output
|
||||||
|
"ls /invalid_path" : "ls: cannot access '/invalid_path': No such file or directory",
|
||||||
|
"cp invalid_file tmp" : "cp: cannot stat 'invalid_file': No such file or directory",
|
||||||
|
"date -u -d \"2017-03-31\"" : "Fri Mar 31 00:00:00 UTC 2017",
|
||||||
|
"touch file; yes | rm -i file" : "rm: remove regular empty file 'file'?",
|
||||||
|
"numfmt --grouping 1234567890.98" : "1234567890.98"
|
||||||
|
}
|
||||||
|
|
||||||
|
lang_english = {
|
||||||
|
"LC_ALL=en_US ls /invalid_path" : "ls: cannot access '/invalid_path': No such file or directory",
|
||||||
|
"LC_ALL=en_US cp invalid_file tmp" : "cp: cannot stat 'invalid_file': No such file or directory",
|
||||||
|
"LC_ALL=en_US date -u -d \"2017-03-31\"" : "Fri Mar 31 00:00:00 UTC 2017",
|
||||||
|
"touch file; yes | LC_ALL=en_US rm -i file" : "rm: remove regular empty file 'file'?",
|
||||||
|
"LC_ALL=en_US numfmt --grouping 1234567890.98" : "1,234,567,890.98"
|
||||||
|
}
|
||||||
|
|
||||||
|
lang_spanish = {
|
||||||
|
"LC_ALL=es_ES ls /invalid_path" : "No existe el fichero o el directorio",
|
||||||
|
"LC_ALL=es_ES cp invalid_file tmp" : "No existe el fichero o el directorio",
|
||||||
|
"LC_ALL=es_ES date -u -d \"2017-03-31\"" : "vie mar 31 00:00:00 UTC 2017",
|
||||||
|
"LC_ALL=es_ES numfmt --grouping 1234567890,98" : "1.234.567.890,98"
|
||||||
|
}
|
||||||
|
|
||||||
|
langs = {}
|
||||||
|
langs["default"] = {
|
||||||
|
"pkg" : "glibc-minimal-langpack",
|
||||||
|
"cmds" : lang_default
|
||||||
|
}
|
||||||
|
|
||||||
|
langs["english"] = {
|
||||||
|
"pkg" : "glibc-langpack-en",
|
||||||
|
"cmds" : lang_english
|
||||||
|
}
|
||||||
|
|
||||||
|
langs["spanish"] = {
|
||||||
|
"pkg" : "glibc-langpack-es",
|
||||||
|
"cmds" : lang_spanish
|
||||||
|
}
|
||||||
|
|
||||||
|
#Check if C.utf8 is the default locale
|
||||||
|
self.run("echo $LANG | grep 'C.utf8'")
|
||||||
|
|
||||||
|
for i18n in langs.keys():
|
||||||
|
lang = langs[i18n]
|
||||||
|
self.log.info("Testing %s" % lang["pkg"])
|
||||||
|
|
||||||
|
install_package = True
|
||||||
|
# glibc-minimal-langpack is installed by default
|
||||||
|
if lang["pkg"] == "glibc-minimal-langpack":
|
||||||
|
install_package = False
|
||||||
|
|
||||||
|
if install_package:
|
||||||
|
try:
|
||||||
|
self.run("microdnf install %s" % lang["pkg"])
|
||||||
|
except:
|
||||||
|
self.error("Could not install %s" % lang["pkg"])
|
||||||
|
|
||||||
|
for cmd in lang["cmds"].keys():
|
||||||
|
cmd_result = self.run("%s" % cmd, ignore_status=True)
|
||||||
|
output = cmd_result.stdout
|
||||||
|
output += cmd_result.stderr
|
||||||
|
output = output.strip()
|
||||||
|
#search for pattern as Spanish might have special characters
|
||||||
|
if not re.search(lang["cmds"][cmd], output):
|
||||||
|
self.error("'%s'expected output '%s', but got '%s'" %
|
||||||
|
(cmd, lang["cmds"][cmd], output))
|
||||||
|
|
||||||
|
if install_package:
|
||||||
|
try:
|
||||||
|
self.run("microdnf remove %s" % lang["pkg"])
|
||||||
|
except:
|
||||||
|
self.error("Could not remove %s" % lang["pkg"])
|
||||||
|
|
||||||
|
def test_dnf(self):
|
||||||
|
"""
|
||||||
|
Check if DNF is able to install a package
|
||||||
|
"""
|
||||||
|
package = "tar"
|
||||||
|
self.run("microdnf install dnf")
|
||||||
|
self.run("dnf install -y %s" % package)
|
||||||
|
self.run("dnf remove -y %s" % package)
|
||||||
|
self.run("microdnf remove dnf")
|
||||||
|
|
||||||
|
def _prepare_compiler_test_directory(self):
|
||||||
|
|
||||||
|
# create a temporary directory
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
self.log.info("Compiler test temporary directory is %s" % tmpdir)
|
||||||
|
|
||||||
|
# Copy the `hello.sh` script from this resource directory into the
|
||||||
|
# temporary directory
|
||||||
|
src = os.path.join(self.compiler_resource_dir, "hello.sh")
|
||||||
|
dest = os.path.join(tmpdir, "hello.sh")
|
||||||
|
try:
|
||||||
|
shutil.copy(src, dest)
|
||||||
|
except shutil.Error as e:
|
||||||
|
self.log.info('Error: %s' % e)
|
||||||
|
except IOError as e:
|
||||||
|
self.log.info('Error: %s' % e.strerror)
|
||||||
|
|
||||||
|
# make sure destination script is executable
|
||||||
|
st = os.stat(dest)
|
||||||
|
os.chmod(dest, st.st_mode | stat.S_IEXEC)
|
||||||
|
|
||||||
|
# Place a gzipped tarball of `hello.c` and `Makefile` from the
|
||||||
|
# resource directory into the temporary directory with the name
|
||||||
|
# `hello.tgz`.
|
||||||
|
dest = os.path.join(tmpdir, "hello.tgz")
|
||||||
|
tar = tarfile.open(dest, "w:gz")
|
||||||
|
for f in ["hello.c", "Makefile"]:
|
||||||
|
src = os.path.join(self.compiler_resource_dir, f)
|
||||||
|
tar.add(src, arcname=f)
|
||||||
|
tar.close()
|
||||||
|
|
||||||
|
self.compiler_test_dir = tmpdir
|
||||||
|
|
||||||
|
def _cleanup_compiler_test_directory(self):
|
||||||
|
|
||||||
|
# clean up the temporary directory
|
||||||
|
if self.compiler_test_dir:
|
||||||
|
self.log.info("cleaning up compiler test directory")
|
||||||
|
shutil.rmtree(self.compiler_test_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
def testCompiler(self):
|
||||||
|
"""
|
||||||
|
Run a basic C compiler test on our docker image.
|
||||||
|
|
||||||
|
This actually tests the integration of several things, including the
|
||||||
|
ability to install packages, extract a gzipped tarball, run make to
|
||||||
|
compile a very simple C program, and run the compiled executable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._prepare_compiler_test_directory()
|
||||||
|
|
||||||
|
#The test dir should be the same one used on hello.sh
|
||||||
|
mod_compiler_test_dir = "/mnt"
|
||||||
|
|
||||||
|
#Make sure there is a container running
|
||||||
|
#TODO: Remove start() once https://pagure.io/modularity-testing-framework/issue/8 is fixed
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.copyTo("%s/." % self.compiler_test_dir, mod_compiler_test_dir)
|
||||||
|
except:
|
||||||
|
self.error("Could not copy test files from %s to module %s" %
|
||||||
|
(self.compiler_test_dir, mod_compiler_test_dir))
|
||||||
|
|
||||||
|
cmdline = "%s/hello.sh" % mod_compiler_test_dir
|
||||||
|
cmd_result = self.run("%s" % cmdline, ignore_status=True)
|
||||||
|
test_stdout = cmd_result.stdout
|
||||||
|
test_stderr = cmd_result.stderr
|
||||||
|
if cmd_result.exit_status:
|
||||||
|
self.error("command '%s' returned exit status %d; output:\n%s\nstderr:\n%s" %
|
||||||
|
(cmdline, cmd_result.exit_status, test_stdout, test_stderr))
|
||||||
|
|
||||||
|
self.log.info("command '%s' succeeded with output:\n%s\nstderr:\n%s" %
|
||||||
|
(cmdline, test_stdout, test_stderr))
|
||||||
|
|
||||||
|
# make sure we get exactly what we expect on stdout
|
||||||
|
# (all other output from commands in the script were sent to stderr)
|
||||||
|
expected_stdout = 'Hello, world!\n'
|
||||||
|
self.log.info("checking that compiler test returned expected output: %s" %
|
||||||
|
repr(expected_stdout))
|
||||||
|
if test_stdout != expected_stdout:
|
||||||
|
self.error("compiler test did not return unexpected output: %s" %
|
||||||
|
repr(test_stdout))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Tear-down
|
||||||
|
"""
|
||||||
|
super(self.__class__, self).tearDown()
|
||||||
|
|
||||||
|
self._cleanup_compiler_test_directory()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
32
tests/teardown.py
Executable file
32
tests/teardown.py
Executable file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
|
from avocado import main
|
||||||
|
from avocado import Test
|
||||||
|
|
||||||
|
import cleanup
|
||||||
|
import brtconfig
|
||||||
|
|
||||||
|
|
||||||
|
class BaseRuntimeTeardownDocker(Test):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
|
||||||
|
self.mockcfg = brtconfig.get_mockcfg(self)
|
||||||
|
self.br_image_name = brtconfig.get_docker_image_name(self)
|
||||||
|
|
||||||
|
def testRemoveDockerImage(self):
|
||||||
|
|
||||||
|
# Clean-up old test artifacts (docker containers, image, mock root)
|
||||||
|
try:
|
||||||
|
cleanup.cleanup_docker_and_mock(self.mockcfg, self.br_image_name)
|
||||||
|
except:
|
||||||
|
self.error("artifact cleanup failed")
|
||||||
|
else:
|
||||||
|
self.log.info("artifact cleanup successful")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue