Skip to content

Commit

Permalink
consolidate tests to be runable from build path (#42)
Browse files Browse the repository at this point in the history
* generate data sets required for unit and integration tests when building the project
* this requires significant refactoring to make the tests and data sets location agnostic
* add the unit and cli tests to meson: `meson test cli` now "just works"
* tests are now only built if configured: `meson setup -Dtests=enabled`
  • Loading branch information
bcumming authored Dec 19, 2024
1 parent 848f115 commit 2d149dd
Show file tree
Hide file tree
Showing 17 changed files with 255 additions and 168 deletions.
46 changes: 31 additions & 15 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,43 @@ jobs:
- name: Update apt repositories for ccache
run: sudo apt update
- name: Install dependencies
run: sudo apt-get install util-linux libmount-dev slurm-wlm libslurm-dev slurmd slurmctld slurm-client
- name: Set up ccache
uses: hendrikmuhs/[email protected]
with:
key: ccache-linux-${{ matrix.buildtype }}-${{ matrix.sanitizer }}
- name: Setup compiler and build tools
run: sudo apt install --no-install-recommends --yes g++-12 meson ninja-build
run: sudo apt-get install util-linux libmount-dev libslurm-dev
# run: sudo apt-get install util-linux libmount-dev slurm-wlm libslurm-dev slurmd slurmctld slurm-client
# disable for now, because the cache has never actually worked
# ironically, this means that it slows down the build
#- name: Set up ccache
# uses: hendrikmuhs/[email protected]
# with:
# key: ccache-linux-${{ matrix.buildtype }}-${{ matrix.sanitizer }}
- name: Install compiler and build tools
run: sudo apt install --no-install-recommends --yes g++-12 ninja-build
- name: install meson
run: |
wget https://github.com/mesonbuild/meson/releases/download/1.6.1/meson-1.6.1.tar.gz && \
tar -xzf meson-1.6.1.tar.gz && \
mv meson-1.6.1 meson && \
mv meson/meson.py meson/meson
- name: install squashfs-mount
run: |
wget https://github.com/eth-cscs/squashfs-mount/archive/refs/tags/v1.1.0.tar.gz
tar -xzf v1.1.0.tar.gz
./meson/meson setup build-sqfs squashfs-mount-1.1.0
./meson/meson compile -C build-sqfs
sudo ./meson/meson install -C build-sqfs
- name: Configure
run: |
CXX="ccache g++-12" meson setup \
CC="gcc-12" CXX="g++-12" ./meson/meson setup \
--buildtype ${{ matrix.buildtype }} \
-Db_sanitize=${{ matrix.sanitizer }} \
-Dtests=enabled \
--warnlevel 3 \
--werror \
build .
- name: Build
run: ninja -C build
- name: Setup Test
run: cd test/setup && ./setup
- name: Test
run: ./meson/meson compile -Cbuild
- name: test unit
run: ./meson/meson test -Cbuild --verbose unit
- name: test cli
run: |
export ASAN_OPTIONS=fast_unwind_on_malloc=0:strict_string_checks=1:detect_leaks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
export UBSAN_OPTIONS=print_stacktrace=1
cd build && ./unit
sudo mkdir /user-tools /user-environment
./meson/meson test -Cbuild --verbose cli
13 changes: 4 additions & 9 deletions install-alps-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,13 @@ install=$HOME/.local/$arch

rm -rf $build
rm -rf $pyenv

echo "== use python to install meson and ninja in venv: $pyenv"
python3 -m venv $pyenv
source $pyenv/bin/activate
pip install --upgrade pip
pip install meson ninja
echo "== configure in $build"
CC=gcc-12 CXX=g++-12 meson setup --prefix=$install $build $root

CC=gcc-12 CXX=g++-12 uenv run prgenv-gnu/24.11:v1 --view=default -- meson setup --prefix=$install $build $root
echo "== build"
meson compile -C$build
uenv run prgenv-gnu/24.11:v1 --view=default -- meson compile -C$build
echo "== install"
meson install -C$build --skip-subprojects
uenv run prgenv-gnu/24.11:v1 --view=default -- meson install -C$build --skip-subprojects

echo ""
echo "== succesfully installed"
Expand Down
32 changes: 9 additions & 23 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ project('uenv', ['cpp'],
'warning_level=3',
],
version: files('VERSION'),
meson_version: '>=0.57')
meson_version: '>=1.3')
version = meson.project_version()

oras_version = get_option('oras_version')
Expand All @@ -22,13 +22,13 @@ add_global_arguments('-Wno-missing-field-initializers', language : 'cpp')

# use meson wrap to provide the dependencies, because the 'default_library=static' option
# will be propogated to each dependency, for a statically linked executable.
catch_dep = subproject('catch2', default_options: ['werror=false', 'warning_level=0']).get_variable('catch2_with_main_dep')
catch_dep = subproject('catch2', default_options: ['werror=false', 'warning_level=0', 'tests=false']).get_variable('catch2_with_main_dep')
cli11_dep = subproject('cli11', default_options: ['werror=false', 'warning_level=0']).get_variable('CLI11_dep')
fmt_dep = subproject('fmt', default_options: ['werror=false', 'warning_level=0']).get_variable('fmt_dep')
json_dep = subproject('nlohmann_json', default_options: ['werror=false', 'warning_level=0']).get_variable('nlohmann_json_dep')
spdlog_dep = subproject('spdlog', default_options: ['werror=false', 'warning_level=0','std_format=disabled','external_fmt=enabled']).get_variable('spdlog_dep')
sqlite3_dep = subproject('sqlite3', default_options: ['werror=false', 'warning_level=0']).get_variable('sqlite3_dep')
subproject('curl', default_options: ['werror=false', 'warning_level=0'])
subproject('curl', default_options: ['werror=false', 'warning_level=0', 'tests=disabled', 'unittests=disabled', 'tool=disabled'])

curl_dep = dependency('libcurl', required: true)
barkeep_dep = declare_dependency(
Expand Down Expand Up @@ -106,7 +106,7 @@ if uenv_cli
oras_download = custom_target(
'oras-download',
output: 'oras.tar.gz',
command: ['curl', '-L', oras_url, '-o', '@OUTPUT@'],
command: ['wget', '--quiet', oras_url, '-O', '@OUTPUT@'],
install: false,
)

Expand All @@ -120,25 +120,11 @@ if uenv_cli
)
endif

unit_src = [
'test/unit/dates.cpp',
'test/unit/env.cpp',
'test/unit/envvars.cpp',
'test/unit/fs.cpp',
'test/unit/lex.cpp',
'test/unit/main.cpp',
'test/unit/parse.cpp',
'test/unit/signal.cpp',
'test/unit/repository.cpp',
'test/unit/subprocess.cpp',
]

unit = executable('unit',
sources: unit_src,
dependencies: [catch_dep, lib_dep],
build_by_default: true,
install: false)

if uenv_slurm_plugin
subdir('src/slurm')
endif

if get_option('tests').enabled()
subdir('test')
endif

3 changes: 3 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
option('tests', type: 'feature', value: 'disabled')

option('slurm_plugin', type: 'boolean', value: true)
option('cli', type: 'boolean', value: true)

option('oras_version', type: 'string', value: '1.2.0')
60 changes: 43 additions & 17 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,35 +40,61 @@ cd uenv2
The software uses meson wrap to bring its own dependencies, all of which are built as static libraries.

To build you only need
* meson
* meson >= 1.5
* ninja
* g++ that supports C++17 (including the `std::filesystem` library implementation
* g++ that supports C++20 (we test g++12 regularly)

On your laptop these requirements can be met using your package manager of choice.

On an Alps vCluster, we want to use the system compiler "as is" without using a uenv or modules. The `g++` requirement is met by the `g++-12` compiler, that is installed on the vClusters as part of the boot image. The easiest way to set up meson and ninja is to pip install them to create an isolated build environment.

On Alps the version of Python3 is ancient, so it can't support the required meson version.
The `prgenv-gnu/24.11` uenv provides all of the tools required.

```
alias e="uenv run prgenv-gnu/24.11:v1 --view=default --"
CXX=g++-12 e meson setup -Dtests=enabled build
e meson compile -Cbuild
```
python3 -m venv ./.env
source .env/bin/activate
pip install ninja meson

mkdir build
cd build
CC=gcc-12 CXX=g++-12 meson setup ..
* use the system version of gcc-12 in order to create a statically linked binary that can run outside the uenv
* the integraton tests can't be run through the alias (or in the uenv), because it isn't possible to use `uenv run` or `uenv start` inside a uenv.

## testing

There are three sets of tests:

* `unit`: unit tests for the C++ library components (Catch2)
* `cli`: tests for the CLI interface (bats)
* `slurm`: tests for the Slurm plugin (bats)

ninja
To build tests, use the `-Dtests=enabled` flag to meson

```
meson setup -Dtests=enabled
```

## testing
The tests are installed in the `test` sub-directory of the build path:
```
cd build/test
**NOTE**: the tests require setup stages that are not straightforward to set up on Alps. A PR that fixes these issues is coming soon.
# run the unit tests
./unit
The C++ library has unit tests, that are built by default as the `unit` executable in the build path:
# run the cli tests
./bats cli.bats
```

```bash
> ./unit
Randomness seeded to: 478418581
===============================================================================
All tests passed (137 assertions in 16 test cases)
The tests can also be run using meson:
```
# run all the tests
meson test
# or run test suites separately
meson test cli
meson test unit
```

**NOTE**: the slurm integration tests require configuring Slurm to use the plugin, which requires root permissions.
For this reason, they can't be tested on Alps vClusters.

10 changes: 0 additions & 10 deletions src/slurm/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,13 @@ configure_file(input : 'config.hpp.in',

libmount_dep = dependency('mount')

#lib_src = ['./lib/parse_args.cpp',
#'./lib/database.cpp',
#'./lib/filesystem.cpp',
#'./lib/mount.cpp',
#'./lib/sqlite.cpp',
#'./lib/strings.cpp']

module_src = ['plugin.cpp', 'mount.cpp']

#module_inc = include_directories('src')

module_dep = [libmount_dep, sqlite3_dep, lib_dep]

shared_module('slurm-uenv-mount',
sources: module_src,
dependencies: module_dep,
#include_directories: module_inc,
cpp_args: ['-Wall', '-Wpedantic', '-Wextra'],
install: true)

44 changes: 20 additions & 24 deletions src/uenv/meson.build
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
version_path = meson.current_build_dir()+'config.h'
fs = import('fs')
if not fs.is_file(version_path)
uenv_version = meson.project_version()
uenv_version_array = uenv_version.split('-')
if uenv_version_array.length()==2
uenv_version_prerelease = uenv_version_array[1]
else
uenv_version_prerelease = ''
endif
uenv_version_array = uenv_version_array[0].split('.')
uenv_version_major = uenv_version_array[0].to_int()
uenv_version_minor = uenv_version_array[1].to_int()
uenv_version_patch = uenv_version_array[2].to_int()
uenv_version = meson.project_version()
uenv_version_array = uenv_version.split('-')
if uenv_version_array.length()==2
uenv_version_prerelease = uenv_version_array[1]
else
uenv_version_prerelease = ''
endif
uenv_version_array = uenv_version_array[0].split('.')
uenv_version_major = uenv_version_array[0].to_int()
uenv_version_minor = uenv_version_array[1].to_int()
uenv_version_patch = uenv_version_array[2].to_int()

conf = configuration_data()
conf = configuration_data()

conf.set('version', uenv_version)
conf.set('version_major', uenv_version_major)
conf.set('version_minor', uenv_version_minor)
conf.set('version_patch', uenv_version_patch)
conf.set('version_prerelease', uenv_version_prerelease)
conf.set('version', uenv_version)
conf.set('version_major', uenv_version_major)
conf.set('version_minor', uenv_version_minor)
conf.set('version_patch', uenv_version_patch)
conf.set('version_prerelease', uenv_version_prerelease)

configure_file(input : 'config.h.in',
output : 'config.h',
configuration : conf)
endif
configure_file(input : 'config.h.in',
output : 'config.h',
configuration : conf)

Loading

0 comments on commit 2d149dd

Please sign in to comment.