diff --git a/.travis.yml b/.travis.yml
index 3eb7b32..e43ddc3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,16 +2,23 @@ language: bash
sudo: required
+env:
+ - TRAVIS_BASH_VERSION="4.0"
+
+before_install:
+ - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION"
+
install:
- - PATH=$PWD/bin:$PATH
- - junest -- echo "Installing JuNest (\$(uname -m))"
- - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))"
- # TODO: Remember to enable x86 tests when fixed
- #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))"
+ - PATH=$PWD/bin:$PATH
+ - junest -- echo "Installing JuNest (\$(uname -m))"
+ - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))"
+ # TODO: Remember to enable x86 tests when fixed
+ #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))"
script:
- - ./tests/unit-tests.sh
- - junest --check ./bin/junest
- - yes | junest --delete
- - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests
- - yes | JUNEST_HOME=~/.junest-arm junest --delete
+ - bash --version
+ - ./tests/unit-tests/unit-tests.sh
+ - junest --check ./bin/junest
+ - yes | junest --delete
+ - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests
+ - yes | JUNEST_HOME=~/.junest-arm junest --delete
diff --git a/LICENSE b/LICENSE
index 6b156fe..610ce97 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,6 @@
-GNU GENERAL PUBLIC LICENSE
+
+
+ GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
@@ -631,8 +633,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- {one line to give the program's name and a brief idea of what it does.}
- Copyright (C) {year} {name of author}
+ JuNest: The Arch Linux based distro that runs upon any Linux distros without root access
+ Copyright (C) 2014 Filippo Squillace
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -652,7 +654,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
- {project} Copyright (C) {year} {fullname}
+ JuNest Copyright (C) 2014 Filippo Squillace
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -673,3 +675,4 @@ the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
+
diff --git a/README.md b/README.md
index 8f7a22e..ef21b49 100644
--- a/README.md
+++ b/README.md
@@ -58,14 +58,22 @@ visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rose
Installation
============
-JuNest can works on GNU/Linux OS with kernel version greater or equal
-2.6.0 (JuNest was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures.
+
+## Dependencies ##
+JuNest comes with a very short list of dependencies in order to be installed in most
+of GNU/Linux distributions.
+Before installing JuNest be sure that all dependencies are properly installed in your system:
+
+- [bash (>=4.0)](https://www.gnu.org/software/bash/)
+- [GNU coreutils](https://www.gnu.org/software/coreutils/)
+
+The minimum recommended Linux kernel is 2.6.0+ on x86 32 and 64 bit and ARM architectures.
## Method one (Recommended) ##
-Just clone the JuNest repo somewhere (for example in ~/junest):
+Just clone the JuNest repo somewhere (for example in ~/.local/share/junest):
- git clone git://github.com/fsquillace/junest ~/junest
- export PATH=~/junest/bin:$PATH
+ git clone git://github.com/fsquillace/junest ~/.local/share/junest
+ export PATH=~/.local/share/junest/bin:$PATH
### Installation using AUR (Arch Linux only) ###
If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/):
@@ -81,22 +89,6 @@ Alternatively, another installation method would be to directly download the JuN
curl https://dl.dropboxusercontent.com/u/42449030/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest
export PATH=~/.junest/opt/junest/bin:$PATH
-Dependencies
-============
-JuNest comes with a very short list of dependencies in order to be installed in most
-of GNU/Linux distributions. The needed executables in the host OS are:
-
-- bash
-- chown (for root access only)
-- ln
-- mkdir
-- rm
-- tar
-- uname
-- wget or curl
-
-The minimum recommended linux kernel is 2.6.0+
-
Advanced usage
==============
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..b3ae5c7
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+5.6.7
diff --git a/bin/jchroot b/bin/jchroot
index 98f8680..8eaa8d4 100755
--- a/bin/jchroot
+++ b/bin/jchroot
@@ -1,30 +1,14 @@
#!/bin/bash
#
-# This file is part of JuNest (https://github.com/fsquillace/junest)
-#
-# Copyright (c) 2015
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
# This script is the simplified and portable version of arch-chroot
# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot)
+#
set -e
-################################ IMPORTS ##################################
-source "$(dirname $0)/../lib/util.sh"
+JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)"
+
+source "${JUNEST_BASE}/lib/utils.sh"
################################ MAIN FUNCTIONS ###########################
diff --git a/bin/junest b/bin/junest
index 9ac3736..530a759 100755
--- a/bin/junest
+++ b/bin/junest
@@ -2,24 +2,10 @@
#
# This file is part of JuNest (https://github.com/fsquillace/junest).
#
-# Copyright (c) 2015
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-JUNEST_BASE="$(dirname $0)/.."
+JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)"
+source "${JUNEST_BASE}/lib/utils.sh"
source "${JUNEST_BASE}/lib/core.sh"
###################################
@@ -27,9 +13,10 @@ source "${JUNEST_BASE}/lib/core.sh"
###################################
usage() {
- echo -e "$NAME: $DESCRIPTION"
+ echo -e "$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION"
+ echo
echo -e "Usage: $CMD [options] [--] [command]"
- echo
+ echo
echo -e "Setup options:"
echo -e "-i, --setup-from-file Setup the $NAME image in ${JUNEST_HOME}"
echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)."
@@ -54,9 +41,7 @@ usage() {
}
version() {
- echo -e "$NAME $VERSION ($CODE_NAME): $DESCRIPTION"
- echo -e "Copyright (c) $COPYRIGHT $AUTHOR"
- echo -e "Homepage: $HOMEPAGE"
+ echo -e "$NAME $(cat $JUNEST_BASE/VERSION)"
}
check_cli(){
@@ -142,90 +127,94 @@ check_cli(){
function parse_arguments(){
- OPT_SETUP_FROM_FILE=false
- IMAGE_FILE=""
- OPT_FAKEROOT=false
- OPT_ROOT=false
- OPT_PROOT_ARGS=false
- PROOT_ARGS=""
- OPT_ARCH=false
- ARCH_ARG=""
- OPT_BUILD_IMAGE=false
- OPT_DISABLE_VALIDATION=false
- OPT_CHECK=false
- CHECK_ARG=""
- OPT_SKIP_ROOT_TEST=false
- OPT_DELETE=false
- OPT_HELP=false
- OPT_VERSION=false
- for opt in "$@"
- do
- case "$1" in
- -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;;
- -f|--fakeroot) OPT_FAKEROOT=true ; shift ;;
- -r|--root) OPT_ROOT=true ; shift ;;
- -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;;
- -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;;
- -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;;
- -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;;
- -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;;
- -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;;
- -d|--delete) OPT_DELETE=true ; shift ;;
- -h|--help) OPT_HELP=true ; shift ;;
- -v|--version) OPT_VERSION=true ; shift ;;
- --) shift ; break ;;
- -*) die "Invalid option $1" ;;
- *) break ;;
- esac
- done
+ OPT_SETUP_FROM_FILE=false
+ IMAGE_FILE=""
+ OPT_FAKEROOT=false
+ OPT_ROOT=false
+ OPT_PROOT_ARGS=false
+ PROOT_ARGS=""
+ OPT_ARCH=false
+ ARCH_ARG=""
+ OPT_BUILD_IMAGE=false
+ OPT_DISABLE_VALIDATION=false
+ OPT_CHECK=false
+ CHECK_ARG=""
+ OPT_SKIP_ROOT_TEST=false
+ OPT_DELETE=false
+ OPT_HELP=false
+ OPT_VERSION=false
+ for opt in "$@"
+ do
+ case "$1" in
+ -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;;
+ -f|--fakeroot) OPT_FAKEROOT=true ; shift ;;
+ -r|--root) OPT_ROOT=true ; shift ;;
+ -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;;
+ -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;;
+ -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;;
+ -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;;
+ -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;;
+ -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;;
+ -d|--delete) OPT_DELETE=true ; shift ;;
+ -h|--help) OPT_HELP=true ; shift ;;
+ -v|--version) OPT_VERSION=true ; shift ;;
+ --) shift ; break ;;
+ -*) die "Invalid option $1" ;;
+ *) break ;;
+ esac
+ done
- ARGS=()
- for arg in "$@"
- do
- ARGS+=("$arg")
- done
+ ARGS=()
+ for arg in "$@"
+ do
+ ARGS+=("$arg")
+ done
}
function execute_operation(){
- $OPT_HELP && usage && return
- $OPT_VERSION && version && return
+ $OPT_HELP && usage && return
+ $OPT_VERSION && version && return
- if $OPT_BUILD_IMAGE; then
- build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST
- return
- elif $OPT_DELETE; then
- delete_env
- return
- elif $OPT_CHECK; then
- check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST
- return
- fi
+ if $OPT_BUILD_IMAGE; then
+ build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST
+ return
+ elif $OPT_DELETE; then
+ delete_env
+ return
+ elif $OPT_CHECK; then
+ check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST
+ return
+ fi
- if ! is_env_installed
- then
- if $OPT_SETUP_FROM_FILE; then
- setup_env_from_file $IMAGE_FILE
- else
- setup_env $ARCH_ARG
- unset ARCH_ARG
- fi
- elif $OPT_SETUP_FROM_FILE; then
- die "Error: The image cannot be installed since $JUNEST_HOME is not empty."
- fi
+ if ! is_env_installed
+ then
+ if $OPT_SETUP_FROM_FILE; then
+ setup_env_from_file $IMAGE_FILE
+ else
+ setup_env $ARCH_ARG
+ unset ARCH_ARG
+ fi
+ elif $OPT_SETUP_FROM_FILE; then
+ die "Error: The image cannot be installed since $JUNEST_HOME is not empty."
+ fi
- [ -z "${ARCH_ARG}" ] || \
- die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME"
+ [ -z "${ARCH_ARG}" ] || \
+ die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME"
- if $OPT_FAKEROOT; then
- run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}"
- elif $OPT_ROOT; then
- run_env_as_root "${ARGS[@]}"
- else
- run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}"
- fi
+ if $OPT_FAKEROOT; then
+ run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}"
+ elif $OPT_ROOT; then
+ run_env_as_root "${ARGS[@]}"
+ else
+ run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}"
+ fi
}
-parse_arguments "$@"
-check_cli
-execute_operation
+function cli() {
+ parse_arguments "$@"
+ check_cli
+ execute_operation
+}
+
+cli "$@"
# vim: set ts=4 sw=4 noet:
diff --git a/lib/core.sh b/lib/core.sh
index 4cd08f0..7012391 100644
--- a/lib/core.sh
+++ b/lib/core.sh
@@ -1,48 +1,31 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2015
+# This module contains all core functionalities for JuNest.
#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
+# Dependencies:
+# - lib/utils.sh
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-# References:
-# https://wiki.archlinux.org/index.php/PKGBUILD
-# https://wiki.archlinux.org/index.php/Creating_Packages
+# vim: ft=sh
set -e
-################################ IMPORTS #################################
-source "$(dirname ${BASH_ARGV[0]})/util.sh"
-
-################################# VARIABLES ##############################
-
NAME='JuNest'
CMD='junest'
-VERSION='5.6.7'
-CODE_NAME='Nitida'
DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access'
-AUTHOR='Filippo Squillace '
-HOMEPAGE="https://github.com/fsquillace/${CMD}"
-COPYRIGHT='2012-2016'
+NOT_AVAILABLE_ARCH=102
+NOT_EXISTING_FILE=103
+ARCHITECTURE_MISMATCH=104
+ROOT_ACCESS_ERROR=105
+NESTED_ENVIRONMENT=106
+VARIABLE_NOT_SET=107
if [ "$JUNEST_ENV" == "1" ]
then
- die "Error: Nested ${NAME} environments are not allowed"
+ die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed"
elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ]
then
- die "The variable JUNEST_ENV is not properly set"
+ die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set"
fi
[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD}
@@ -101,6 +84,9 @@ WGET="wget --no-check-certificate"
CURL="curl -L -J -O -k"
TAR=tar
CHOWN="chown"
+LN=ln
+RM=rm
+MKDIR=mkdir
LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib"
@@ -109,19 +95,19 @@ LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib"
# image.
function ln_cmd(){
- ln $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/ln $@
+ $LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@
}
function rm_cmd(){
- rm $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/rm $@
+ $RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@
}
function chown_cmd(){
- $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chown $@
+ $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@
}
function mkdir_cmd(){
- mkdir $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/mkdir $@
+ $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@
}
function proot_cmd(){
@@ -148,6 +134,19 @@ function chroot_cmd(){
################################# MAIN FUNCTIONS ##############################
+#######################################
+# Check if the JuNest system is installed in JUNEST_HOME.
+#
+# Globals:
+# JUNEST_HOME (RO) : Contains the JuNest home directory.
+# Arguments:
+# None
+# Returns:
+# 0 : If JuNest is installed
+# 1 : If JuNest is not installed
+# Output:
+# None
+#######################################
function is_env_installed(){
[ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0
return 1
@@ -155,8 +154,8 @@ function is_env_installed(){
function _cleanup_build_directory(){
-# $1: maindir (optional) - str: build directory to get rid
local maindir=$1
+ check_not_null "$maindir"
builtin cd $ORIGIN_WD
trap - QUIT EXIT ABRT KILL TERM INT
rm_cmd -fr "$maindir"
@@ -164,17 +163,21 @@ function _cleanup_build_directory(){
function _prepare_build_directory(){
+ local maindir=$1
+ check_not_null "$maindir"
trap - QUIT EXIT ABRT KILL TERM INT
trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
}
function _setup_env(){
+ local imagepath=$1
+ check_not_null "$imagepath"
+
is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME"
+
mkdir_cmd -p "${JUNEST_HOME}"
- imagepath=$1
$TAR -zxpf ${imagepath} -C ${JUNEST_HOME}
- mkdir_cmd -p ${JUNEST_HOME}/run/lock
info "The default mirror URL is ${DEFAULT_MIRROR}."
info "Remember to refresh the package databases from the server:"
info " pacman -Syy"
@@ -182,14 +185,33 @@ function _setup_env(){
}
+#######################################
+# Setup JuNest.
+#
+# Globals:
+# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
+# to be installed.
+# ARCH (RO) : The host architecture.
+# JUNEST_TEMPDIR (RO) : The JuNest temporary directory for building
+# the JuNest system from the image.
+# ENV_REPO (RO) : URL of the site containing JuNest images.
+# NAME (RO) : The JuNest name.
+# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
+# Arguments:
+# arch ($1?) : The JuNest architecture image to download.
+# Defaults to the host architecture
+# Returns:
+# $NOT_AVAILABLE_ARCH : If the architecture is not one of the available ones.
+# Output:
+# None
+#######################################
function setup_env(){
- local arch=$ARCH
- [ -z $1 ] || arch="$1"
+ local arch=${1:-$ARCH}
contains_element $arch "${ARCH_LIST[@]}" || \
- die "The architecture is not one of: ${ARCH_LIST[@]}"
+ die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}"
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
- _prepare_build_directory
+ _prepare_build_directory $maindir
info "Downloading ${NAME}..."
builtin cd ${maindir}
@@ -202,21 +224,51 @@ function setup_env(){
_cleanup_build_directory ${maindir}
}
-
+#######################################
+# Setup JuNest from file.
+#
+# Globals:
+# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
+# to be installed.
+# NAME (RO) : The JuNest name.
+# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
+# Arguments:
+# imagefile ($1) : The JuNest image file.
+# Returns:
+# $NOT_EXISTING_FILE : If the image file does not exist.
+# Output:
+# None
+#######################################
function setup_env_from_file(){
local imagefile=$1
- [ ! -e ${imagefile} ] && die "Error: The ${NAME} image file ${imagefile} does not exist"
+ check_not_null "$imagefile"
+ [ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist"
info "Installing ${NAME} from ${imagefile}..."
_setup_env ${imagefile}
-
- builtin cd $ORIGIN_WD
}
+#######################################
+# Run JuNest as real root.
+#
+# Globals:
+# JUNEST_HOME (RO) : The JuNest home directory.
+# UID (RO) : The user ID.
+# SUDO_USER (RO) : The sudo user ID.
+# SUDO_GID (RO) : The sudo group ID.
+# SH (RO) : Contains the default command to run in JuNest.
+# Arguments:
+# cmd ($@?) : The command to run inside JuNest environment.
+# Default command is defined by SH variable.
+# Returns:
+# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
+# Output:
+# - : The command output.
+#######################################
function run_env_as_root(){
source ${JUNEST_HOME}/etc/junest/info
[ "$JUNEST_ARCH" != "$ARCH" ] && \
- die "The host system architecture is not correct: $ARCH != $JUNEST_ARCH"
+ die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH"
local uid=$UID
# SUDO_USER is more reliable compared to SUDO_UID
@@ -227,11 +279,7 @@ function run_env_as_root(){
# With chown the ownership of the files is assigned to the real user
trap - QUIT EXIT ABRT KILL TERM INT
- trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -f ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT
-
- # The mtab file should already be available in the image.
- # This following instruction will be deleted
- [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab
+ trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT
JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}"
}
@@ -268,36 +316,89 @@ function _run_env_with_qemu(){
_run_env_with_proot "$proot_args" "${@}"
}
+#######################################
+# Run JuNest as fakeroot.
+#
+# Globals:
+# JUNEST_HOME (RO) : The JuNest home directory.
+# EUID (RO) : The user ID.
+# SH (RO) : Contains the default command to run in JuNest.
+# Arguments:
+# cmd ($@?) : The command to run inside JuNest environment.
+# Default command is defined by SH variable.
+# Returns:
+# $ROOT_ACCESS_ERROR : If the user is the real root.
+# Output:
+# - : The command output.
+#######################################
function run_env_as_fakeroot(){
(( EUID == 0 )) && \
- die "You cannot access with root privileges. Use --root option instead."
- # The mtab file should already be available in the image.
- # This following instruction will be deleted
- [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab
+ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead."
+
_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}"
}
+#######################################
+# Run JuNest as normal user.
+#
+# Globals:
+# JUNEST_HOME (RO) : The JuNest home directory.
+# EUID (RO) : The user ID.
+# SH (RO) : Contains the default command to run in JuNest.
+# Arguments:
+# cmd ($@?) : The command to run inside JuNest environment.
+# Default command is defined by SH variable.
+# Returns:
+# $ROOT_ACCESS_ERROR : If the user is the real root.
+# Output:
+# - : The command output.
+#######################################
function run_env_as_user(){
(( EUID == 0 )) && \
- die "You cannot access with root privileges. Use --root option instead."
- # The mtab file should already be available in the image.
- # This following instruction will be deleted
- [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab
- _run_env_with_qemu "$(_provide_bindings_as_user) -r ${JUNEST_HOME} $1" "${@:2}"
+ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead."
+
+ _provide_bindings_as_user
+ local bindings="$RESULT"
+ unset RESULT
+ _run_env_with_qemu "$bindings -r ${JUNEST_HOME} $1" "${@:2}"
}
+#######################################
+# Provide the proot binding options for the normal user.
+#
+# Globals:
+# HOME (RO) : The home directory.
+# RESULT (WO) : Contains the binding options.
+# Arguments:
+# None
+# Returns:
+# None
+# Output:
+# None
+#######################################
function _provide_bindings_as_user(){
# The list of bindings can be found in `proot --help`. This function excludes
# /etc/mtab file so that it will not give conflicts with the related
# symlink in the image.
- local existing_bindings=""
+ RESULT=""
for bind in "/etc/host.conf" "/etc/hosts" "/etc/hosts.equiv" "/etc/netgroup" "/etc/networks" "/etc/passwd" "/etc/group" "/etc/nsswitch.conf" "/etc/resolv.conf" "/etc/localtime" "/dev" "/sys" "/proc" "/tmp" "$HOME"
do
- [ -e "$bind" ] && existing_bindings="-b $bind $existing_bindings"
+ [ -e "$bind" ] && RESULT="-b $bind $RESULT"
done
- echo $existing_bindings
}
+#######################################
+# Remove an existing JuNest system.
+#
+# Globals:
+# JUNEST_HOME (RO) : The JuNest home directory to remove.
+# Arguments:
+# None
+# Returns:
+# None
+# Output:
+# None
+#######################################
function delete_env(){
! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return
if mountpoint -q ${JUNEST_HOME}
@@ -364,6 +465,7 @@ function build_image_env(){
# yaourt requires sed
sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed
sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist"
+ mkdir -p ${maindir}/root/run/lock
info "Install ${NAME} script..."
sudo pacman --noconfirm --root ${maindir}/root -S git
diff --git a/lib/util.sh b/lib/util.sh
deleted file mode 100644
index 6865c16..0000000
--- a/lib/util.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env bash
-#
-# This file is part of JuNest (https://github.com/fsquillace/junest)
-#
-# Copyright (c) 2015
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-function echoerr(){
- echo "$@" 1>&2
-}
-function die(){
-# $@: msg (mandatory) - str: Message to print
- error $@
- exit 1
-}
-function error(){
-# $@: msg (mandatory) - str: Message to print
- echoerr -e "\033[1;31m$@\033[0m"
-}
-function warn(){
-# $@: msg (mandatory) - str: Message to print
- echoerr -e "\033[1;33m$@\033[0m"
-}
-function info(){
-# $@: msg (mandatory) - str: Message to print
- echo -e "\033[1;37m$@\033[0m"
-}
-
-function ask(){
- # $1: question string
- # $2: default value - can be either Y, y, N, n (by default Y)
-
- local default="Y"
- [ -z $2 ] || default=$(echo "$2" | tr '[:lower:]' '[:upper:]')
-
- local other="n"
- [ "$default" == "N" ] && other="y"
-
- local prompt="$1 (${default}/${other})> "
-
- local res="none"
- while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ];
- do
- read -p "$prompt" res
- res=$(echo "$res" | tr '[:lower:]' '[:upper:]')
- done
-
- [ "$res" == "" ] && res="$default"
-
- if [ "$res" == "Y" ]
- then
- return 0
- else
- return 1
- fi
-
-}
-
-function insert_quotes_on_spaces(){
-# It inserts quotes between arguments.
-# Useful to preserve quotes on command
-# to be used inside sh -c/bash -c
- C=''
- whitespace="[[:space:]]"
- for i in "$@"
- do
- if [[ $i =~ $whitespace ]]
- then
- C="$C \"$i\""
- else
- C="$C $i"
- fi
- done
- echo $C
-}
-
-contains_element () {
- local e
- for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
- return 1
-}
diff --git a/lib/utils.sh b/lib/utils.sh
new file mode 100644
index 0000000..840fbe9
--- /dev/null
+++ b/lib/utils.sh
@@ -0,0 +1,195 @@
+#!/usr/bin/env bash
+
+NULL_EXCEPTION=11
+WRONG_ANSWER=33
+
+#######################################
+# Check if the argument is null.
+#
+# Globals:
+# None
+# Arguments:
+# argument ($1) : Argument to check.
+# Returns:
+# 0 : If argument is not null.
+# NULL_EXCEPTION : If argument is null.
+# Output:
+# None
+#######################################
+function check_not_null() {
+ [ -z "$1" ] && { error "Error: null argument $1"; return $NULL_EXCEPTION; }
+ return 0
+}
+
+#######################################
+# Redirect message to stderr.
+#
+# Globals:
+# None
+# Arguments:
+# msg ($@): Message to print.
+# Returns:
+# None
+# Output:
+# Message printed to stderr.
+#######################################
+function echoerr() {
+ echo "$@" 1>&2;
+}
+
+#######################################
+# Print an error message to stderr and exit program.
+#
+# Globals:
+# None
+# Arguments:
+# msg ($@) : Message to print.
+# Returns:
+# 1 : The unique exit status printed.
+# Output:
+# Message printed to stderr.
+#######################################
+function die() {
+ error $@
+ exit 1
+}
+
+#######################################
+# Print an error message to stderr and exit program with a given status.
+#
+# Globals:
+# None
+# Arguments:
+# status ($1) : The exit status to use.
+# msg ($2-) : Message to print.
+# Returns:
+# $? : The $status exit status.
+# Output:
+# Message printed to stderr.
+#######################################
+function die_on_status() {
+ status=$1
+ shift
+ error $@
+ exit $status
+}
+
+#######################################
+# Print an error message to stderr.
+#
+# Globals:
+# None
+# Arguments:
+# msg ($@): Message to print.
+# Returns:
+# None
+# Output:
+# Message printed to stderr.
+#######################################
+function error() {
+ echoerr -e "\033[1;31m$@\033[0m"
+}
+
+#######################################
+# Print a warn message to stderr.
+#
+# Globals:
+# None
+# Arguments:
+# msg ($@): Message to print.
+# Returns:
+# None
+# Output:
+# Message printed to stderr.
+#######################################
+function warn() {
+ # $@: msg (mandatory) - str: Message to print
+ echoerr -e "\033[1;33m$@\033[0m"
+}
+
+#######################################
+# Print an info message to stdout.
+#
+# Globals:
+# None
+# Arguments:
+# msg ($@): Message to print.
+# Returns:
+# None
+# Output:
+# Message printed to stdout.
+#######################################
+function info(){
+ echo -e "\033[1;36m$@\033[0m"
+}
+
+#######################################
+# Ask a question and wait to receive an answer from stdin.
+# It returns $default_answer if no answer has be received from stdin.
+#
+# Globals:
+# None
+# Arguments:
+# question ($1) : The question to ask.
+# default_answer ($2) : Possible values: 'Y', 'y', 'N', 'n' (default: 'Y')
+# Returns:
+# 0 : If user replied with either 'Y' or 'y'.
+# 1 : If user replied with either 'N' or 'n'.
+# WRONG_ANSWER : If `default_answer` is not one of the possible values.
+# Output:
+# Print the question to ask.
+#######################################
+function ask(){
+ local question=$1
+ local default_answer=$2
+ check_not_null $question
+
+ if [ ! -z "$default_answer" ]
+ then
+ local answers="Y y N n"
+ [[ "$answers" =~ "$default_answer" ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; }
+ fi
+
+ local default="Y"
+ [ -z "$default_answer" ] || default=$(echo "$default_answer" | tr '[:lower:]' '[:upper:]')
+
+ local other="n"
+ [ "$default" == "N" ] && other="y"
+
+ local prompt=$(info "$question (${default}/${other})> ")
+
+ local res="none"
+ while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ];
+ do
+ read -p "$prompt" res
+ res=$(echo "$res" | tr '[:lower:]' '[:upper:]')
+ done
+
+ [ "$res" == "" ] && res="$default"
+
+ [ "$res" == "Y" ]
+}
+
+function insert_quotes_on_spaces(){
+# It inserts quotes between arguments.
+# Useful to preserve quotes on command
+# to be used inside sh -c/bash -c
+ C=''
+ whitespace="[[:space:]]"
+ for i in "$@"
+ do
+ if [[ $i =~ $whitespace ]]
+ then
+ C="$C \"$i\""
+ else
+ C="$C $i"
+ fi
+ done
+ echo $C
+}
+
+contains_element () {
+ local e
+ for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
+ return 1
+}
diff --git a/tests/integ-tests/install-bash.sh b/tests/integ-tests/install-bash.sh
new file mode 100755
index 0000000..575c9c5
--- /dev/null
+++ b/tests/integ-tests/install-bash.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -ex
+
+VERSION=$1
+
+cd /tmp
+wget http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz
+
+tar -zxf bash-$VERSION.tar.gz
+cd /tmp/bash-$VERSION*
+./configure
+make
+sudo make install
diff --git a/tests/test-cli.sh b/tests/test-cli.sh
deleted file mode 100755
index 46d38d1..0000000
--- a/tests/test-cli.sh
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/bin/bash
-source $(dirname $0)/../bin/junest -h &> /dev/null
-
-# Disable the exiterr
-set +e
-
-function setUp(){
- function is_env_installed(){
- return 0
- }
-}
-
-## Mock functions ##
-function usage(){
- echo "usage"
-}
-function version(){
- echo "version"
-}
-function build_image_env(){
- local disable_validation=$1
- local skip_root_tests=$2
- echo "build_image_env($disable_validation,$skip_root_tests)"
-}
-function check_env(){
- local env_home=$1
- local cmd_script=$2
- local skip_root_tests=$3
- echo "check_env($env_home,$cmd_script,$skip_root_tests)"
-}
-function delete_env(){
- echo "delete_env"
-}
-function setup_env_from_file(){
- echo "setup_env_from_file($1)"
-}
-function setup_env(){
- echo "setup_env($1)"
-}
-function run_env_as_fakeroot(){
- local proot_args="$1"
- shift
- echo "run_env_as_fakeroot($proot_args,$@)"
-}
-function run_env_as_root(){
- echo "run_env_as_root $@"
-}
-function run_env_as_user(){
- local proot_args="$1"
- shift
- echo "run_env_as_user($proot_args,$@)"
-}
-
-function wrap_env(){
- parse_arguments "$@"
- check_cli
- execute_operation
-}
-
-function test_help(){
- local output=$(wrap_env -h)
- assertEquals $output "usage"
- local output=$(wrap_env --help)
- assertEquals $output "usage"
-}
-function test_version(){
- local output=$(wrap_env -v)
- assertEquals $output "version"
- local output=$(wrap_env --version)
- assertEquals $output "version"
-}
-function test_build_image_env(){
- local output=$(wrap_env -b)
- assertEquals $output "build_image_env(false,false)"
- local output=$(wrap_env --build-image)
- assertEquals $output "build_image_env(false,false)"
- local output=$(wrap_env -b -s)
- assertEquals $output "build_image_env(false,true)"
- local output=$(wrap_env -b -n)
- assertEquals $output "build_image_env(true,false)"
- local output=$(wrap_env -b -n -s)
- assertEquals $output "build_image_env(true,true)"
- local output=$(wrap_env --build-image --disable-validation --skip-root-tests)
- assertEquals $output "build_image_env(true,true)"
-}
-function test_check_env(){
- local output=$(wrap_env -c myscript)
- assertEquals $output "check_env(${JUNEST_HOME},myscript,false)"
- local output=$(wrap_env --check myscript)
- assertEquals $output "check_env(${JUNEST_HOME},myscript,false)"
- local output=$(wrap_env -c myscript -s)
- assertEquals $output "check_env(${JUNEST_HOME},myscript,true)"
- local output=$(wrap_env --check myscript --skip-root-tests)
- assertEquals $output "check_env(${JUNEST_HOME},myscript,true)"
-}
-function test_delete_env(){
- local output=$(wrap_env -d)
- assertEquals $output "delete_env"
- local output=$(wrap_env --delete)
- assertEquals $output "delete_env"
-}
-#function test_setup_env_from_file(){
- #local output=$(wrap_env -i myimage)
- #assertEquals $output "setup_env_from_file(myimage)"
- #local output=$(wrap_env --setup-from-file myimage)
- #assertEquals $output "setup_env_from_file(myimage)"
-#}
-function test_setup_env_from_file(){
- is_env_installed(){
- return 1
- }
- local output=$(wrap_env -i myimage)
- assertEquals "$output" "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")"
- local output=$(wrap_env --setup-from-file myimage)
- assertEquals "$output" "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")"
-
- is_env_installed(){
- return 0
- }
- $(wrap_env -i myimage 2> /dev/null)
- assertEquals 1 $?
-}
-
-function test_setup_env(){
- is_env_installed(){
- return 1
- }
- local output=$(wrap_env -a arm)
- assertEquals "$output" "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")"
- local output=$(wrap_env --arch arm)
- assertEquals "$output" "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")"
- local output=$(wrap_env)
- assertEquals "$output" "$(echo -e "setup_env()\nrun_env_as_user(,)")"
-
- is_env_installed(){
- return 0
- }
- $(wrap_env -a arm 2> /dev/null)
- assertEquals 1 $?
-}
-function test_run_env_as_fakeroot(){
- local output=$(wrap_env -f)
- assertEquals $output "run_env_as_fakeroot(,)"
- local output=$(wrap_env --fakeroot)
- assertEquals $output "run_env_as_fakeroot(,)"
-
- local output=$(wrap_env -f -p "-b arg")
- assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,)"
- local output=$(wrap_env -f -p "-b arg" -- command -kv)
- assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,command -kv)"
- local output=$(wrap_env -f command --as)
- assertEquals "${output[@]}" "run_env_as_fakeroot(,command --as)"
- $(wrap_env -a "myarch" -f command --as 2> /dev/null)
- assertEquals 1 $?
-}
-function test_run_env_as_user(){
- local output=$(wrap_env)
- assertEquals $output "run_env_as_user(,)"
-
- local output=$(wrap_env -p "-b arg")
- assertEquals "$output" "run_env_as_user(-b arg,)"
- local output=$(wrap_env -p "-b arg" -- command -ll)
- assertEquals "$output" "run_env_as_user(-b arg,command -ll)"
- local output=$(wrap_env command -ls)
- assertEquals "$output" "run_env_as_user(,command -ls)"
- $(wrap_env -a "myarch" -- command -ls 2> /dev/null)
- assertEquals 1 $?
-}
-function test_run_env_as_root(){
- local output=$(wrap_env -r)
- assertEquals $output "run_env_as_root"
-
- local output=$(wrap_env -r command)
- assertEquals "${output[@]}" "run_env_as_root command"
-}
-
-function test_check_cli(){
- $(wrap_env -b -h 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -b -c 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -d -s 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -n -v 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -d -r 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -h -f 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -v -i fsd 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -f -r 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -p args -v 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -a arch -v 2> /dev/null)
- assertEquals $? 1
- $(wrap_env -d args 2> /dev/null)
- assertEquals $? 1
-}
-
-source $(dirname $0)/shunit2
diff --git a/tests/test-core.sh b/tests/test-core.sh
deleted file mode 100755
index bd57032..0000000
--- a/tests/test-core.sh
+++ /dev/null
@@ -1,362 +0,0 @@
-#!/bin/bash
-
-function oneTimeSetUp(){
- [ -z "$SKIP_ROOT_TESTS" ] && SKIP_ROOT_TESTS=0
-
- CURRPWD=$PWD
- ENV_MAIN_HOME=/tmp/envtesthome
- [ -e $ENV_MAIN_HOME ] || JUNEST_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env"
- JUNEST_HOME=""
-}
-
-function install_mini_env(){
- cp -rfa $ENV_MAIN_HOME/* $JUNEST_HOME
-}
-
-function setUp(){
- cd $CURRPWD
- JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX)
- JUNEST_BASE="$CURRPWD/$(dirname $0)/.."
- source "${JUNEST_BASE}/lib/core.sh"
- ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX)
- cd $ORIGIN_WD
- JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX)
-
- set +e
-
- trap - QUIT EXIT ABRT KILL TERM INT
- trap "rm -rf ${JUNEST_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT
-}
-
-
-function tearDown(){
- # the CA directories are read only and can be deleted only by changing the mod
- [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
- rm -rf $JUNEST_HOME
- rm -rf $ORIGIN_WD
- rm -rf $JUNEST_TEMPDIR
- trap - QUIT EXIT ABRT KILL TERM INT
-}
-
-
-function test_is_env_installed(){
- is_env_installed
- assertEquals $? 1
- touch $JUNEST_HOME/just_file
- is_env_installed
- assertEquals $? 0
-}
-
-
-function test_download(){
- WGET=/bin/true
- CURL=/bin/false
- download_cmd
- assertEquals $? 0
-
- WGET=/bin/false
- CURL=/bin/true
- download_cmd
- assertEquals $? 0
-
- $(WGET=/bin/false CURL=/bin/false download_cmd something 2> /dev/null)
- assertEquals $? 1
-}
-
-function test_ln(){
- install_mini_env
-
- touch ln_file
- ln_cmd -s ln_file new_file
- assertEquals $? 0
- assertTrue "[ -e new_file ]"
- rm new_file
-
- touch ln_file
- OLDPATH="$PATH"
- PATH=""
- ln_cmd -s ln_file new_file 2> /dev/null
- local ret=$?
- PATH="$OLDPATH"
- assertEquals $ret 0
- assertTrue "[ -e new_file ]"
-}
-
-function test_rm(){
- install_mini_env
-
- touch rm_file
- rm_cmd rm_file
- assertEquals $? 0
- assertTrue "[ ! -e rm_file ]"
-
- touch rm_file
- OLDPATH="$PATH"
- PATH=""
- rm_cmd rm_file 2> /dev/null
- local ret=$?
- PATH="$OLDPATH"
- assertEquals $ret 0
- assertTrue "[ ! -e rm_file ]"
-}
-
-function test_chown(){
- install_mini_env
-
- local id=$(id -u)
-
- touch chown_file
- chown_cmd $id chown_file
- assertEquals $? 0
-
- touch chown_file
- OLDPATH="$PATH"
- PATH=""
- chown_cmd $id chown_file 2> /dev/null
- local ret=$?
- PATH="$OLDPATH"
- assertEquals $ret 0
-}
-
-function test_mkdir(){
- install_mini_env
-
- mkdir_cmd -p new_dir/new_dir
- assertEquals $? 0
- assertTrue "[ -d new_dir/new_dir ]"
- rm -rf new_dir
-
- OLDPATH="$PATH"
- PATH=""
- mkdir_cmd -p new_dir/new_dir 2> /dev/null
- local ret=$?
- PATH="$OLDPATH"
- assertEquals $ret 0
- assertTrue "[ -d new_dir/new_dir ]"
-}
-
-function test_setup_env(){
- wget_mock(){
- # Proof that the setup is happening
- # inside $JUNEST_TEMPDIR
- local cwd=${PWD#${JUNEST_TEMPDIR}}
- local parent_dir=${PWD%${cwd}}
- assertEquals "$JUNEST_TEMPDIR" "${parent_dir}"
- touch file
- tar -czvf ${CMD}-${ARCH}.tar.gz file
- }
- WGET=wget_mock
- setup_env 1> /dev/null
- assertTrue "[ -e $JUNEST_HOME/file ]"
- assertTrue "[ -e $JUNEST_HOME/run/lock ]"
-
- $(setup_env "noarch" 2> /dev/null)
- assertEquals 1 $?
-}
-
-
-function test_setup_env_from_file(){
- touch file
- tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
- setup_env_from_file ${CMD}-${ARCH}.tar.gz &> /dev/null
- assertTrue "[ -e $JUNEST_HOME/file ]"
- assertTrue "[ -e $JUNEST_HOME/run/lock ]"
-
- $(setup_env_from_file noexist.tar.gz 2> /dev/null)
- assertEquals $? 1
-}
-
-function test_setup_env_from_file_with_absolute_path(){
- touch file
- tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
- setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz &> /dev/null
- assertTrue "[ -e $JUNEST_HOME/file ]"
- assertTrue "[ -e $JUNEST_HOME/run/lock ]"
-}
-
-function test_run_env_as_root(){
- [ $SKIP_ROOT_TESTS -eq 1 ] && return
-
- install_mini_env
- CHROOT="sudo $CHROOT"
- CLASSIC_CHROOT="sudo $CLASSIC_CHROOT"
- CHOWN="sudo $CHOWN"
-
- local output=$(run_env_as_root pwd)
- assertEquals "/" "$output"
- run_env_as_root [ -e /run/lock ]
- assertEquals 0 $?
- run_env_as_root [ -e $HOME ]
- assertEquals 0 $?
-
- # test that normal user has ownership of the files created by root
- run_env_as_root touch /a_root_file
- # This ensure that the trap will be executed
- kill -TERM $$
- local output=$(run_env_as_root stat -c '%u' /a_root_file)
- assertEquals "$UID" "$output"
-
- SH=("sh" "--login" "-c" "type -t type")
- local output=$(run_env_as_root)
- assertEquals "builtin" "$output"
- SH=("sh" "--login" "-c" "[ -e /run/lock ]")
- run_env_as_root
- assertEquals 0 $?
- SH=("sh" "--login" "-c" "[ -e $HOME ]")
- run_env_as_root
- assertEquals 0 $?
-}
-
-function test_run_env_as_root_different_arch(){
- [ $SKIP_ROOT_TESTS -eq 1 ] && return
-
- install_mini_env
- echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info
- $(run_env_as_root pwd 2> /dev/null)
- assertEquals 1 $?
-}
-
-function test_run_env_as_classic_root(){
- [ $SKIP_ROOT_TESTS -eq 1 ] && return
-
- install_mini_env
- CHROOT="sudo unknowncommand"
- CLASSIC_CHROOT="sudo $CLASSIC_CHROOT"
- CHOWN="sudo $CHOWN"
-
- local output=$(run_env_as_root pwd 2> /dev/null)
- assertEquals "/" "$output"
- run_env_as_root [ -e /run/lock ] 2> /dev/null
- assertEquals 0 $?
-}
-
-function test_run_env_as_junest_root(){
- [ $SKIP_ROOT_TESTS -eq 1 ] && return
-
- install_mini_env
- CHROOT="sudo unknowncommand"
- CLASSIC_CHROOT="sudo unknowncommand"
- LD_EXEC="sudo $LD_EXEC"
- CHOWN="sudo $CHOWN"
-
- local output=$(run_env_as_root pwd 2> /dev/null)
- assertEquals "/" "$output"
- run_env_as_root [ -e /run/lock ] 2> /dev/null
- assertEquals 0 $?
- run_env_as_root [ -e $HOME ] 2> /dev/null
- assertEquals 1 $?
-}
-
-function test_run_env_as_user(){
- install_mini_env
- local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}')
- assertEquals "$output" "/usr/bin/mkdir"
- assertTrue "[ -e $JUNEST_HOME/newdir2 ]"
-
- SH=("/usr/bin/echo")
- local output=$(run_env_as_user "-k 3.10")
- assertEquals "-c :" "$output"
-}
-
-function test_run_env_as_proot_mtab(){
- install_mini_env
- $(run_env_as_fakeroot "-k 3.10" "echo")
- assertTrue "[ -e $JUNEST_HOME/etc/mtab ]"
- $(run_env_as_user "-k 3.10" "echo")
- assertTrue "[ -e $JUNEST_HOME/etc/mtab ]"
-}
-
-function test_run_env_as_root_mtab(){
- [ $SKIP_ROOT_TESTS -eq 1 ] && return
-
- install_mini_env
- CHROOT="sudo $CHROOT"
- CLASSIC_CHROOT="sudo $CLASSIC_CHROOT"
- CHOWN="sudo $CHOWN"
- $(run_env_as_root "echo")
- assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]"
-}
-
-function test_run_env_with_quotes(){
- install_mini_env
- local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}')
- assertEquals "/usr/bin/mkdir" "$output"
- assertTrue "[ -e $JUNEST_HOME/newdir2 ]"
-}
-
-function test_run_env_as_user_proot_args(){
- install_mini_env
- run_env_as_user "--help" "" &> /dev/null
- assertEquals 0 $?
-
- mkdir $JUNEST_TEMPDIR/newdir
- touch $JUNEST_TEMPDIR/newdir/newfile
- run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null
- assertEquals 0 $?
-
- $(_run_env_with_proot --helps 2> /dev/null)
- assertEquals 1 $?
-}
-
-function test_run_env_with_proot_compat(){
- PROOT="/bin/true"
- _run_env_with_proot "" "" &> /dev/null
- assertEquals 0 $?
-
- $(PROOT="/bin/false" _run_env_with_proot --helps 2> /dev/null)
- assertEquals 1 $?
-}
-
-function test_run_env_with_proot_as_root(){
- [ $SKIP_ROOT_TESTS -eq 1 ] && return
-
- install_mini_env
-
- $(sudo run_env_as_user 2> /dev/null)
- assertEquals 1 $?
- $(sudo run_env_as_fakeroot 2> /dev/null)
- assertEquals 1 $?
-}
-
-function test_run_proot_seccomp(){
- envv(){
- env
- }
- PROOT=envv
- local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP")
- assertEquals "" "$output"
-
- envv(){
- env | grep "^PROOT_NO_SECCOMP"
- }
- PROOT=envv
- local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP")
- # The variable PROOT_NO_SECCOMP will be produced
- # twice due to the fallback mechanism
- assertEquals "PROOT_NO_SECCOMP=1
-PROOT_NO_SECCOMP=1" "$output"
-}
-
-function test_run_env_as_fakeroot(){
- install_mini_env
- local output=$(run_env_as_fakeroot "-k 3.10" "id" | awk '{print $1}')
- assertEquals "uid=0(root)" "$output"
-}
-
-function test_delete_env(){
- install_mini_env
- echo "N" | delete_env 1> /dev/null
- is_env_installed
- assertEquals 0 $?
- echo "Y" | delete_env 1> /dev/null
- is_env_installed
- assertEquals 1 $?
-}
-
-function test_nested_env(){
- install_mini_env
- JUNEST_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null
- assertEquals 1 $?
-}
-
-source $(dirname $0)/shunit2
diff --git a/tests/test-util.sh b/tests/test-util.sh
deleted file mode 100755
index 80fd660..0000000
--- a/tests/test-util.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/bash
-source "$(dirname $0)/../lib/util.sh"
-
-# Disable the exiterr
-set +e
-
-function test_echoerr(){
- local actual=$(echoerr "Test" 2>&1)
- assertEquals "$actual" "Test"
-}
-
-function test_error(){
- local actual=$(error "Test" 2>&1)
- local expected=$(echo -e "\033[1;31mTest\033[0m")
- assertEquals "$actual" "$expected"
-}
-
-function test_warn(){
- local actual=$(warn "Test" 2>&1)
- local expected=$(echo -e "\033[1;33mTest\033[0m")
- assertEquals "$actual" "$expected"
-}
-
-function test_info(){
- local actual=$(info "Test")
- local expected=$(echo -e "\033[1;37mTest\033[0m")
- assertEquals "$actual" "$expected"
-}
-
-function test_die(){
- local actual=$(die "Test" 2>&1)
- local expected=$(echo -e "\033[1;31mTest\033[0m")
- assertEquals "$actual" "$expected"
- $(die Dying 2> /dev/null)
- assertEquals $? 1
-}
-
-function test_ask(){
- echo "Y" | ask "Test" &> /dev/null
- assertEquals $? 0
- echo "y" | ask "Test" &> /dev/null
- assertEquals $? 0
- echo "N" | ask "Test" &> /dev/null
- assertEquals $? 1
- echo "n" | ask "Test" &> /dev/null
- assertEquals $? 1
- echo -e "\n" | ask "Test" &> /dev/null
- assertEquals $? 0
- echo -e "\n" | ask "Test" "N" &> /dev/null
- assertEquals $? 1
- echo -e "asdf\n\n" | ask "Test" "N" &> /dev/null
- assertEquals $? 1
-}
-
-function test_insert_quotes_on_spaces(){
- local actual=$(insert_quotes_on_spaces this is "a test")
- assertEquals "this is \"a test\"" "$actual"
-
- local actual=$(insert_quotes_on_spaces this is 'a test')
- assertEquals "this is \"a test\"" "$actual"
-}
-
-function test_contains_element(){
- array=("something to search for" "a string" "test2000")
- contains_element "a string" "${array[@]}"
- assertEquals "$?" "0"
-
- contains_element "blabla" "${array[@]}"
- assertEquals "$?" "1"
-}
-
-source $(dirname $0)/shunit2
diff --git a/tests/shunit2 b/tests/unit-tests/shunit2
similarity index 100%
rename from tests/shunit2
rename to tests/unit-tests/shunit2
diff --git a/tests/unit-tests/test-cli.sh b/tests/unit-tests/test-cli.sh
new file mode 100755
index 0000000..5dd2513
--- /dev/null
+++ b/tests/unit-tests/test-cli.sh
@@ -0,0 +1,181 @@
+#!/bin/bash
+source "$(dirname $0)/utils.sh"
+
+source $(dirname $0)/../../bin/junest -h &> /dev/null
+
+# Disable the exiterr
+set +e
+
+function oneTimeSetUp(){
+ setUpUnitTests
+}
+
+function setUp(){
+ function is_env_installed(){
+ return 0
+ }
+}
+
+## Mock functions ##
+function usage(){
+ echo "usage"
+}
+function version(){
+ echo "version"
+}
+function build_image_env(){
+ local disable_validation=$1
+ local skip_root_tests=$2
+ echo "build_image_env($disable_validation,$skip_root_tests)"
+}
+function check_env(){
+ local env_home=$1
+ local cmd_script=$2
+ local skip_root_tests=$3
+ echo "check_env($env_home,$cmd_script,$skip_root_tests)"
+}
+function delete_env(){
+ echo "delete_env"
+}
+function setup_env_from_file(){
+ echo "setup_env_from_file($1)"
+}
+function setup_env(){
+ echo "setup_env($1)"
+}
+function run_env_as_fakeroot(){
+ local proot_args="$1"
+ shift
+ echo "run_env_as_fakeroot($proot_args,$@)"
+}
+function run_env_as_root(){
+ echo "run_env_as_root $@"
+}
+function run_env_as_user(){
+ local proot_args="$1"
+ shift
+ echo "run_env_as_user($proot_args,$@)"
+}
+
+function test_help(){
+ assertCommandSuccess cli -h
+ assertEquals "usage" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --help
+ assertEquals "usage" "$(cat $STDOUTF)"
+}
+function test_version(){
+ assertCommandSuccess cli -v
+ assertEquals "version" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --version
+ assertEquals "version" "$(cat $STDOUTF)"
+}
+function test_build_image_env(){
+ assertCommandSuccess cli -b
+ assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --build-image
+ assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -b -s
+ assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -b -n
+ assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -b -n -s
+ assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --build-image --disable-validation --skip-root-tests
+ assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)"
+}
+function test_check_env(){
+ assertCommandSuccess cli -c myscript
+ assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --check myscript
+ assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -c myscript -s
+ assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --check myscript --skip-root-tests
+ assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)"
+}
+function test_delete_env(){
+ assertCommandSuccess cli -d
+ assertEquals "delete_env" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --delete
+ assertEquals "delete_env" "$(cat $STDOUTF)"
+}
+function test_setup_env_from_file(){
+ is_env_installed(){
+ return 1
+ }
+ assertCommandSuccess cli -i myimage
+ assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --setup-from-file myimage
+ assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
+
+ is_env_installed(){
+ return 0
+ }
+ assertCommandFail cli -i myimage
+}
+
+function test_setup_env(){
+ is_env_installed(){
+ return 1
+ }
+ assertCommandSuccess cli -a arm
+ assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --arch arm
+ assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
+ assertCommandSuccess cli
+ assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)"
+
+ is_env_installed(){
+ return 0
+ }
+ assertCommandFail cli -a arm
+}
+function test_run_env_as_fakeroot(){
+ assertCommandSuccess cli -f
+ assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli --fakeroot
+ assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)"
+
+ assertCommandSuccess cli -f -p "-b arg"
+ assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -f -p "-b arg" -- command -kv
+ assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -f command --as
+ assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)"
+ assertCommandFail cli -a "myarch" -f command --as
+}
+function test_run_env_as_user(){
+ assertCommandSuccess cli
+ assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)"
+
+ assertCommandSuccess cli -p "-b arg"
+ assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli -p "-b arg" -- command -ll
+ assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)"
+ assertCommandSuccess cli command -ls
+ assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)"
+
+ assertCommandFail cli -a "myarch" -- command -ls
+}
+function test_run_env_as_root(){
+ assertCommandSuccess cli -r
+ assertEquals "run_env_as_root " "$(cat $STDOUTF)"
+ assertCommandSuccess cli -r command
+ assertEquals "run_env_as_root command" "$(cat $STDOUTF)"
+}
+
+function test_check_cli(){
+ assertCommandFail cli -b -h
+ assertCommandFail cli -b -c
+ assertCommandFail cli -d -s
+ assertCommandFail cli -n -v
+ assertCommandFail cli -d -r
+ assertCommandFail cli -h -f
+ assertCommandFail cli -v -i fsd
+ assertCommandFail cli -f -r
+ assertCommandFail cli -p args -v
+ assertCommandFail cli -a arch -v
+ assertCommandFail cli -d args
+}
+
+source $(dirname $0)/shunit2
diff --git a/tests/unit-tests/test-core.sh b/tests/unit-tests/test-core.sh
new file mode 100755
index 0000000..46072e1
--- /dev/null
+++ b/tests/unit-tests/test-core.sh
@@ -0,0 +1,292 @@
+#!/bin/bash
+
+JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
+
+source "$JUNEST_ROOT/tests/unit-tests/utils.sh"
+
+# Disable the exiterr
+set +e
+
+function oneTimeSetUp(){
+ SKIP_ROOT_TESTS=${SKIP_ROOT_TESTS:-0}
+ setUpUnitTests
+}
+
+function setUp(){
+ ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX)
+ cd $ORIGIN_CWD
+ JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX)
+ mkdir -p ${JUNEST_HOME}/etc/junest
+ echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info
+ mkdir -p ${JUNEST_HOME}/etc/ca-certificates
+ JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t junest-temp.XXXXXXXXXX)
+ source "$JUNEST_ROOT/lib/utils.sh"
+ source "$JUNEST_ROOT/lib/core.sh"
+
+ set +e
+
+ trap - QUIT EXIT ABRT KILL TERM INT
+ trap "rm -rf ${JUNEST_HOME}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT
+
+ ld_exec() {
+ echo "ld_exec $@"
+ }
+ LD_EXEC=ld_exec
+}
+
+
+function tearDown(){
+ # the CA directories are read only and can be deleted only by changing the mod
+ [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
+ rm -rf $JUNEST_HOME
+ rm -rf $JUNEST_TEMPDIR
+ rm -rf $ORIGIN_CWD
+ trap - QUIT EXIT ABRT KILL TERM INT
+}
+
+
+function test_ln(){
+ LN=echo assertCommandSuccess ln_cmd -s ln_file new_file
+ assertEquals "-s ln_file new_file" "$(cat $STDOUTF)"
+
+ LN=false assertCommandSuccess ln_cmd -s ln_file new_file
+ assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)"
+
+ LN=false LD_EXEC=false assertCommandFail ln_cmd
+}
+
+function test_download(){
+ WGET=/bin/true
+ CURL=/bin/false
+ assertCommandSuccess download_cmd
+
+ WGET=/bin/false
+ CURL=/bin/true
+ assertCommandSuccess download_cmd
+
+ WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd
+}
+
+function test_rm(){
+ RM=echo assertCommandSuccess rm_cmd rm_file
+ assertEquals "rm_file" "$(cat $STDOUTF)"
+
+ RM=false assertCommandSuccess rm_cmd rm_file
+ assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)"
+
+ RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file
+}
+
+function test_chown(){
+ local id=$(id -u)
+
+ CHOWN=echo assertCommandSuccess chown_cmd $id chown_file
+ assertEquals "$id chown_file" "$(cat $STDOUTF)"
+
+ CHOWN=false assertCommandSuccess chown_cmd $id chown_file
+ assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)"
+
+ CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file
+}
+
+function test_mkdir(){
+ MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir
+ assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)"
+
+ MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir
+ assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)"
+
+ MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir
+}
+
+function test_chroot(){
+ CHROOT=echo assertCommandSuccess chroot_cmd root
+ assertEquals "root" "$(cat $STDOUTF)"
+
+ CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root
+ assertEquals "root" "$(cat $STDOUTF)"
+
+ CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root
+ assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)"
+
+ CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root
+}
+
+function test_proot_cmd_compat(){
+ PROOT="/bin/true" assertCommandSuccess proot_cmd "" ""
+
+ PROOT="/bin/false" assertCommandFail proot_cmd --helps
+}
+
+function test_proot_cmd_seccomp(){
+ envv(){
+ env
+ }
+ PROOT=envv
+ assertCommandSuccess proot_cmd cmd
+ assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
+
+ envv(){
+ env | grep "^PROOT_NO_SECCOMP"
+ }
+ PROOT=envv
+ local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP")
+ assertCommandSuccess proot_cmd cmd
+ # The variable PROOT_NO_SECCOMP will be produced
+ # twice due to the fallback mechanism
+ assertEquals "PROOT_NO_SECCOMP=1
+PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
+}
+
+function test_is_env_installed(){
+ rm -rf $JUNEST_HOME/*
+ assertCommandFail is_env_installed
+ touch $JUNEST_HOME/just_file
+ assertCommandSuccess is_env_installed
+}
+
+function test_setup_env(){
+ rm -rf $JUNEST_HOME/*
+ wget_mock(){
+ # Proof that the setup is happening
+ # inside $JUNEST_TEMPDIR
+ local cwd=${PWD#${JUNEST_TEMPDIR}}
+ local parent_dir=${PWD%${cwd}}
+ assertEquals "$JUNEST_TEMPDIR" "${parent_dir}"
+ touch file
+ tar -czvf ${CMD}-${ARCH}.tar.gz file
+ }
+ WGET=wget_mock
+ setup_env 1> /dev/null
+ assertTrue "[ -e $JUNEST_HOME/file ]"
+
+ assertCommandFailOnStatus 102 setup_env "noarch"
+}
+
+
+function test_setup_env_from_file(){
+ rm -rf $JUNEST_HOME/*
+ touch file
+ tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
+ assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz
+ assertTrue "[ -e $JUNEST_HOME/file ]"
+}
+
+function test_setup_env_from_file_not_existing_file(){
+ assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz
+}
+
+function test_setup_env_from_file_with_absolute_path(){
+ rm -rf $JUNEST_HOME/*
+ touch file
+ tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
+ assertCommandSuccess setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz
+ assertTrue "[ -e $JUNEST_HOME/file ]"
+}
+
+function test_run_env_as_root_different_arch(){
+ echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info
+ assertCommandFailOnStatus 104 run_env_as_root pwd
+}
+
+function _test_run_env_as_root() {
+ chroot_cmd() {
+ [ "$JUNEST_ENV" != "1" ] && return 1
+ echo $@
+ }
+
+ assertCommandSuccess run_env_as_root $@
+}
+
+function test_run_env_as_root_cmd(){
+ _test_run_env_as_root pwd
+ assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
+}
+
+function test_run_env_as_classic_root_no_cmd(){
+ _test_run_env_as_root
+ assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)"
+}
+
+function test_run_env_as_user(){
+ _run_env_with_qemu() {
+ echo $@
+ }
+ assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
+ _provide_bindings_as_user
+ assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
+
+ SH=("/usr/bin/echo")
+ assertCommandSuccess run_env_as_user "-k 3.10"
+ _provide_bindings_as_user
+ assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
+}
+
+function test_run_env_as_fakeroot(){
+ _run_env_with_qemu() {
+ echo $@
+ }
+ assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
+ assertEquals "-S ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
+
+ SH=("/usr/bin/echo")
+ assertCommandSuccess run_env_as_fakeroot "-k 3.10"
+ assertEquals "-S ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
+}
+
+function test_run_env_with_quotes(){
+ _run_env_with_qemu() {
+ echo $@
+ }
+ assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2"
+ _provide_bindings_as_user
+ assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
+}
+
+function test_run_env_with_proot_args(){
+ proot_cmd() {
+ [ "$JUNEST_ENV" != "1" ] && return 1
+ echo $@
+ }
+
+ assertCommandSuccess _run_env_with_proot --help
+ assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)"
+
+ assertCommandSuccess _run_env_with_proot --help mycommand
+ assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)"
+
+ assertCommandFail _run_env_with_proot
+}
+
+function test_delete_env(){
+ echo "N" | delete_env 1> /dev/null
+ assertCommandSuccess is_env_installed
+ echo "Y" | delete_env 1> /dev/null
+ assertCommandFail is_env_installed
+}
+
+function test_nested_env(){
+ JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -ic "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh"
+}
+
+function test_nested_env_not_set_variable(){
+ JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -ic "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh"
+}
+
+function test_qemu() {
+ echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info
+ rm_cmd() {
+ echo $@
+ }
+ ln_cmd() {
+ echo $@
+ }
+ _run_env_with_proot() {
+ echo $@
+ }
+
+ RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu ""
+ assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)"
+}
+
+source $JUNEST_ROOT/tests/unit-tests/shunit2
diff --git a/tests/unit-tests/test-utils.sh b/tests/unit-tests/test-utils.sh
new file mode 100755
index 0000000..5816d11
--- /dev/null
+++ b/tests/unit-tests/test-utils.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+source "$(dirname $0)/utils.sh"
+
+unset HOME
+export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX)
+
+source "$(dirname $0)/../../lib/utils.sh"
+
+# Disable the exiterr
+set +e
+
+function oneTimeSetUp(){
+ setUpUnitTests
+}
+
+function test_check_not_null(){
+ assertCommandFailOnStatus 11 check_not_null "" ""
+ assertCommandSuccess check_not_null "bla" ""
+}
+
+function test_echoerr(){
+ assertCommandSuccess echoerr "Test"
+ assertEquals "Test" "$(cat $STDERRF)"
+}
+
+function test_error(){
+ assertCommandSuccess error "Test"
+ local expected=$(echo -e "\033[1;31mTest\033[0m")
+ assertEquals "$expected" "$(cat $STDERRF)"
+}
+
+function test_warn(){
+ assertCommandSuccess warn "Test"
+ local expected=$(echo -e "\033[1;33mTest\033[0m")
+ assertEquals "$expected" "$(cat $STDERRF)"
+}
+
+function test_info(){
+ assertCommandSuccess info "Test"
+ local expected=$(echo -e "\033[1;36mTest\033[0m")
+ assertEquals "$expected" "$(cat $STDOUTF)"
+}
+
+function test_die(){
+ assertCommandFail die "Test"
+ local expected=$(echo -e "\033[1;31mTest\033[0m")
+ assertEquals "$expected" "$(cat $STDERRF)"
+}
+
+function test_die_on_status(){
+ assertCommandFailOnStatus 222 die_on_status 222 "Test"
+ local expected=$(echo -e "\033[1;31mTest\033[0m")
+ assertEquals "$expected" "$(cat $STDERRF)"
+}
+
+function test_ask_null_question(){
+ assertCommandFailOnStatus 11 ask "" "Y"
+}
+
+function test_ask(){
+ echo "Y" | ask "Test" &> /dev/null
+ assertEquals 0 $?
+ echo "y" | ask "Test" &> /dev/null
+ assertEquals 0 $?
+ echo "N" | ask "Test" &> /dev/null
+ assertEquals 1 $?
+ echo "n" | ask "Test" &> /dev/null
+ assertEquals 1 $?
+ echo -e "\n" | ask "Test" &> /dev/null
+ assertEquals 0 $?
+ echo -e "\n" | ask "Test" "N" &> /dev/null
+ assertEquals 1 $?
+ echo -e "asdf\n\n" | ask "Test" "N" &> /dev/null
+ assertEquals 1 $?
+}
+
+function test_ask_wrong_default_answer() {
+ echo "Y" | ask "Test" G &> /dev/null
+ assertEquals 33 $?
+}
+
+function test_insert_quotes_on_spaces(){
+ assertCommandSuccess insert_quotes_on_spaces this is "a test"
+ assertEquals "this is \"a test\"" "$(cat $STDOUTF)"
+
+ assertCommandSuccess insert_quotes_on_spaces this is 'a test'
+ assertEquals "this is \"a test\"" "$(cat $STDOUTF)"
+}
+
+function test_contains_element(){
+ array=("something to search for" "a string" "test2000")
+ assertCommandSuccess contains_element "a string" "${array[@]}"
+
+ assertCommandFailOnStatus 1 contains_element "blabla" "${array[@]}"
+}
+
+source $(dirname $0)/shunit2
diff --git a/tests/unit-tests.sh b/tests/unit-tests/unit-tests.sh
similarity index 100%
rename from tests/unit-tests.sh
rename to tests/unit-tests/unit-tests.sh
diff --git a/tests/unit-tests/utils.sh b/tests/unit-tests/utils.sh
new file mode 100644
index 0000000..b12420e
--- /dev/null
+++ b/tests/unit-tests/utils.sh
@@ -0,0 +1,32 @@
+
+function setUpUnitTests(){
+ OUTPUT_DIR="${SHUNIT_TMPDIR}/output"
+ mkdir "${OUTPUT_DIR}"
+ STDOUTF="${OUTPUT_DIR}/stdout"
+ STDERRF="${OUTPUT_DIR}/stderr"
+}
+
+function assertCommandSuccess(){
+ $(set -e
+ "$@" > $STDOUTF 2> $STDERRF
+ )
+ assertTrue "The command $1 did not return 0 exit status" $?
+}
+
+function assertCommandFail(){
+ $(set -e
+ "$@" > $STDOUTF 2> $STDERRF
+ )
+ assertFalse "The command $1 returned 0 exit status" $?
+}
+
+# $1: expected exit status
+# $2-: The command under test
+function assertCommandFailOnStatus(){
+ local status=$1
+ shift
+ $(set -e
+ "$@" > $STDOUTF 2> $STDERRF
+ )
+ assertEquals $status $?
+}