Merge pull request #117 from PQClean/run-only-diffs

Be more selective in test runs
This commit is contained in:
Thom Wiggers 2019-04-19 17:09:29 +02:00 committed by GitHub
commit da10273e52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 195 additions and 106 deletions

View File

@ -4,22 +4,27 @@ version: 2
machine: true machine: true
steps: steps:
- checkout - checkout
- run: - run: &checkouttask
name: Pull submodules name: Pull submodules
command: | command: |
git submodule init git submodule init
git submodule update git submodule update
git checkout $CIRCLECI_BRANCH
git reset --hard $CIRCLECI_SHA1
- run: - run:
name: Install the emulation handlers name: Install the emulation handlers
command: docker run --rm --privileged multiarch/qemu-user-static:register --reset command: docker run --rm --privileged multiarch/qemu-user-static:register --reset
- run: - run:
name: Run the tests in a container name: Run the tests in a container
command: | command: |
docker run -e CI=true --rm -v `pwd`:`pwd` -w `pwd` "pqclean/ci-container:$ARCH" /bin/bash -c " docker run -e CI=true -e PQCLEAN_ONLY_DIFF=1 --rm -v `pwd`:`pwd` -w `pwd` "pqclean/ci-container:$ARCH" /bin/bash -c "
uname -a && uname -a &&
export CC=${CC} && export CC=${CC} &&
pip3 install -r requirements.txt && pip3 install -r requirements.txt &&
cd test && python3 -m nose --rednose --verbose" mkdir test-results &&
cd test && python3 -m nose --rednose --verbose --with-xunit --xunit-file=../test-results/nosetests.xml"
- store_test_results:
path: test-results
.native_job: &nativejob .native_job: &nativejob
docker: docker:
@ -27,17 +32,18 @@ version: 2
steps: steps:
- checkout - checkout
- run: - run:
name: Pull submodules <<: *checkouttask
command: |
git submodule init
git submodule update
- run: - run:
name: Run tests name: Run tests
command: | command: |
export CC=${CC} export CC=${CC}
pip3 install -r requirements.txt && export PQCLEAN_ONLY_DIFF=1
cd test && python3 -m nose --rednose --verbose pip3 install -r requirements.txt
mkdir test-results
cd test
python3 -m nose --rednose --verbose --with-xunit --xunit-file=../test-results/nosetests.xml
- store_test_results:
path: test-results
jobs: jobs:
arm64-gcc: arm64-gcc:

View File

@ -6,8 +6,15 @@ matrix:
compiler: clang compiler: clang
before_install: before_install:
- pip3 install -r requirements.txt - pip3 install -r requirements.txt
before_script:
- git config --replace-all remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
- git fetch --unshallow
- git checkout $TRAVIS_BRANCH
- git reset --hard $TRAVIS_COMMIT
script: script:
- "cd test && python3 -m nose --rednose --verbose" - "cd test && python3 -m nose --rednose --verbose"
env:
PQCLEAN_ONLY_DIFF: 1
addons: addons:
homebrew: homebrew:
packages: packages:
@ -21,7 +28,13 @@ matrix:
packages: packages:
- astyle - astyle
- gcc@8 - gcc@8
env:
PQCLEAN_ONLY_DIFF: 1
before_install: before_install:
- git config --replace-all remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
- git fetch --unshallow
- git checkout $TRAVIS_BRANCH
- git reset --hard $TRAVIS_COMMIT
- pip3 install -r requirements.txt - pip3 install -r requirements.txt
- brew link gcc - brew link gcc
- export PATH="/usr/local/bin:$PATH" - export PATH="/usr/local/bin:$PATH"

View File

@ -5,7 +5,10 @@ image: Visual Studio 2017
build: build:
verbosity: minimal verbosity: minimal
shallow_clone: false
environment: environment:
PQCLEAN_ONLY_DIFF: 1
matrix: matrix:
- BITS: 64 - BITS: 64
- BITS: 32 - BITS: 32
@ -19,6 +22,11 @@ init:
- set PATH="C:\\Python37";"C:\\Python37\Scripts";%PATH% - set PATH="C:\\Python37";"C:\\Python37\Scripts";%PATH%
build_script: build_script:
- git config --replace-all remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
- git fetch --all
- git checkout %APPVEYOR_REPO_BRANCH%
- git reset --hard %APPVEYOR_REPO_COMMIT%
- git diff --name-only origin/master
- python -m pip install -r requirements.txt - python -m pip install -r requirements.txt
- cd test - cd test
# Download Astyle to local folder because putting it in PATH doesn't work # Download Astyle to local folder because putting it in PATH doesn't work

View File

@ -20,6 +20,9 @@ CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -std=c99 \
-fstrict-aliasing -fno-common -pipe \ -fstrict-aliasing -fno-common -pipe \
-I$(COMMON_DIR) $(EXTRAFLAGS) -I$(COMMON_DIR) $(EXTRAFLAGS)
# Number of tests run for functests
NTESTS=1
all: $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION) \ all: $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION) \
$(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION) \ $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION) \
$(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION) $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION)
@ -50,7 +53,7 @@ $(DEST_DIR)/test_common_%: common/%.c $(COMMON_FILES)
$(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/functest.c $(COMMON_FILES) $(COMMON_DIR)/randombytes.c $(COMMON_HEADERS) $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/functest.c $(COMMON_FILES) $(COMMON_DIR)/randombytes.c $(COMMON_HEADERS)
mkdir -p $(DEST_DIR) mkdir -p $(DEST_DIR)
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/functest.c $(COMMON_FILES) $(COMMON_DIR)/notrandombytes.c -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION) $(CC) $(CFLAGS) -DNTESTS=$(NTESTS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/functest.c $(COMMON_FILES) $(COMMON_DIR)/notrandombytes.c -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION)
$(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/testvectors.c $(COMMON_FILES) $(COMMON_DIR)/notrandombytes.c $(COMMON_HEADERS) $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/testvectors.c $(COMMON_FILES) $(COMMON_DIR)/notrandombytes.c $(COMMON_HEADERS)
mkdir -p $(DEST_DIR) mkdir -p $(DEST_DIR)

View File

@ -5,7 +5,9 @@
#include "api.h" #include "api.h"
#include "randombytes.h" #include "randombytes.h"
#ifndef NTESTS
#define NTESTS 5 #define NTESTS 5
#endif
const uint8_t canary[8] = { const uint8_t canary[8] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF

View File

@ -6,7 +6,10 @@
#include "api.h" #include "api.h"
#include "randombytes.h" #include "randombytes.h"
#ifndef NTESTS
#define NTESTS 5 #define NTESTS 5
#endif
#define MLEN 32 #define MLEN 32
const uint8_t canary[8] = { const uint8_t canary[8] = {

View File

@ -7,6 +7,8 @@ import sys
import pqclean import pqclean
import logging
def run_subprocess(command, working_dir='.', env=None, expected_returncode=0): def run_subprocess(command, working_dir='.', env=None, expected_returncode=0):
""" """
@ -113,7 +115,7 @@ def ensure_available(executable):
raise AssertionError("{} not available on CI".format(executable)) raise AssertionError("{} not available on CI".format(executable))
def permit_test(testname, thing, **args): def permit_test(testname, thing, *args, **kwargs):
if 'PQCLEAN_ONLY_TESTS' in os.environ: if 'PQCLEAN_ONLY_TESTS' in os.environ:
if not(testname.lower() in os.environ['PQCLEAN_ONLY_TESTS'].lower().split(',')): if not(testname.lower() in os.environ['PQCLEAN_ONLY_TESTS'].lower().split(',')):
return False return False
@ -142,13 +144,14 @@ def permit_test(testname, thing, **args):
return False return False
if 'PQCLEAN_ONLY_DIFF' in os.environ: if 'PQCLEAN_ONLY_DIFF' in os.environ:
if shutil.which('git') != None: if shutil.which('git') is not None:
# if we're on a non-master branch, and the only changes are in schemes, # if we're on a non-master branch, and the only changes are in schemes,
# only run tests on those schemes # only run tests on those schemes
branch_result = subprocess.run( branch_result = subprocess.run(
['git', 'status', '--porcelain=2', '--branch'], ['git', 'status', '--porcelain=2', '--branch'],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT stderr=subprocess.STDOUT,
cwd="..",
) )
# ensure we're in a working directory # ensure we're in a working directory
if branch_result.returncode != 0: if branch_result.returncode != 0:
@ -161,14 +164,18 @@ def permit_test(testname, thing, **args):
return True return True
# where are there changes? # where are there changes?
diff_result = subprocess.run( diff_result = subprocess.run(
['git', 'diff', '--name-only', 'master'], ['git', 'diff', '--name-only', 'origin/master'],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT stderr=subprocess.STDOUT
) )
assert(diff_result.returncode == 0), "Got unexpected return code {}".format(diff_result.returncode) assert diff_result.returncode == 0, \
"Got unexpected return code {}".format(diff_result.returncode)
for diff_line in diff_result.stdout.decode('utf-8').splitlines(): for diff_line in diff_result.stdout.decode('utf-8').splitlines():
# don't skip test if there are any changes outside schemes # don't skip test if there are any changes outside schemes
if not(diff_line.startswith('crypto_kem')) and not (diff_line.startswith('crypto_sign')): if (not diff_line.startswith('crypto_kem') and
not diff_line.startswith('crypto_sign')):
logging.info("Running all tests as there are changes "
"outside of schemes")
return True return True
# do test if the scheme in question has been changed # do test if the scheme in question has been changed
if diff_line.startswith(thing.path(base='')): if diff_line.startswith(thing.path(base='')):
@ -177,3 +184,15 @@ def permit_test(testname, thing, **args):
return False return False
return True return True
def filtered_test(func):
funcname = func.__name__[len("check_"):]
@functools.wraps(func)
def wrapper(*args, **kwargs):
if permit_test(funcname, *args, **kwargs):
return func(*args, **kwargs)
else:
raise unittest.SkipTest("Test disabled by filter")
return wrapper

View File

@ -55,7 +55,7 @@ class Scheme:
metafile = os.path.join(self.path(), 'META.yml') metafile = os.path.join(self.path(), 'META.yml')
try: try:
with open(metafile, encoding='utf-8') as f: with open(metafile, encoding='utf-8') as f:
metadata = yaml.load(f.read()) metadata = yaml.safe_load(f.read())
return metadata return metadata
except Exception as e: except Exception as e:
print("Can't open {}: {}".format(metafile, e)) print("Can't open {}: {}".format(metafile, e))

View File

@ -5,14 +5,14 @@ import helpers
import pqclean import pqclean
def test_preprocessor(): def test_api_h():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('preprocessor', implementation): yield check_api_h, implementation
yield check_preprocessor, implementation
def check_preprocessor(implementation: pqclean.Implementation): @helpers.filtered_test
def check_api_h(implementation: pqclean.Implementation):
apipath = os.path.join(implementation.path(), 'api.h') apipath = os.path.join(implementation.path(), 'api.h')
errors = [] errors = []
p = re.compile(r'^\s*#include\s*"') p = re.compile(r'^\s*#include\s*"')
@ -25,6 +25,7 @@ def check_preprocessor(implementation: pqclean.Implementation):
"Prohibited external include in api.h" + "".join(errors) "Prohibited external include in api.h" + "".join(errors)
) )
if __name__ == "__main__": if __name__ == "__main__":
try: try:
import nose2 import nose2

View File

@ -17,8 +17,7 @@ def test_char():
) )
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('char', implementation): yield check_char, implementation
yield check_char, implementation
def walk_tree(ast): def walk_tree(ast):
@ -30,6 +29,7 @@ def walk_tree(ast):
yield from walk_tree(child) # recursively yield prohibited nodes yield from walk_tree(child) # recursively yield prohibited nodes
@helpers.filtered_test
@helpers.skip_windows() @helpers.skip_windows()
def check_char(implementation): def check_char(implementation):
errors = [] errors = []

View File

@ -12,7 +12,8 @@ import helpers
def test_common(): def test_common():
for d in os.listdir('common'): for d in os.listdir('common'):
primitive = re.sub(r"\.c$", "", d) primitive = re.sub(r"\.c$", "", d)
if helpers.permit_test('common', None): yield check_common, primitive if helpers.permit_test('common', None):
yield check_common, primitive
def check_common(primitive): def check_common(primitive):

View File

@ -10,10 +10,10 @@ import helpers
def test_compile_lib(): def test_compile_lib():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('compile_lib', implementation): yield check_compile_lib, implementation
yield check_compile_lib, implementation
@helpers.filtered_test
def check_compile_lib(implementation): def check_compile_lib(implementation):
helpers.make('clean', working_dir=implementation.path()) helpers.make('clean', working_dir=implementation.path())
helpers.make(working_dir=implementation.path()) helpers.make(working_dir=implementation.path())

View File

@ -8,33 +8,54 @@ import helpers
import unittest import unittest
import yaml import yaml
helpers.skip_windows()
def _skipped_test(*args, **kwargs):
raise unittest.SkipTest("Skipped consistency check")
def test_duplicate_consistency(): def test_duplicate_consistency():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('duplicate_consistency', implementation): if not helpers.permit_test('duplicate_consistency',
if os.path.isfile(os.path.join('duplicate_consistency', '{}_{}.yml'.format(scheme.name, implementation.name))): implementation):
metafile = os.path.join('duplicate_consistency', '{}_{}.yml'.format(implementation.scheme.name, implementation.name)) yield _skipped_test, implementation
with open(metafile, encoding='utf-8') as f: continue
metadata = yaml.load(f.read())
for group in metadata['consistency_checks']: if os.path.isfile(
source = pqclean.Implementation.by_name(group['source']['scheme'], group['source']['implementation']) os.path.join(
for file in group['files']: 'duplicate_consistency',
yield check_duplicate_consistency, implementation, source, file '{}_{}.yml'.format(scheme.name, implementation.name))):
metafile = os.path.join(
'duplicate_consistency',
'{}_{}.yml'.format(scheme.name, implementation.name))
with open(metafile, encoding='utf-8') as f:
metadata = yaml.safe_load(f.read())
for group in metadata['consistency_checks']:
source = pqclean.Implementation.by_name(
group['source']['scheme'],
group['source']['implementation'])
for file in group['files']:
yield (check_duplicate_consistency, implementation,
source, file)
def file_get_contents(filename): def file_get_contents(filename):
with open(filename) as f: with open(filename) as f:
return f.read() return f.read()
@helpers.skip_windows()
def check_duplicate_consistency(implementation, source, file): def check_duplicate_consistency(implementation, source, file):
transformed_src = helpers.run_subprocess( transformed_src = helpers.run_subprocess(
['sed', '-e', 's/{}/{}/g'.format(source.namespace_prefix(), implementation.namespace_prefix()), os.path.join(source.path(), file)] ['sed', '-e', 's/{}/{}/g'.format(source.namespace_prefix(),
implementation.namespace_prefix()), os.path.join(source.path(), file)]
) )
this_src = file_get_contents(os.path.join(implementation.path(), file)) this_src = file_get_contents(os.path.join(implementation.path(), file))
print(os.path.join(implementation.path(), file)) print(os.path.join(implementation.path(), file))
print(this_src) print(this_src)
assert(transformed_src == this_src) assert(transformed_src == this_src)
if __name__ == '__main__': if __name__ == '__main__':
try: try:
import nose2 import nose2

View File

@ -4,19 +4,17 @@ Checks that no dynamic memory functions are used
import pqclean import pqclean
import helpers import helpers
import sys
import unittest
def test_dynamic_memory(): def test_dynamic_memory():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('dynamic_memory', implementation): # Keep this loop outside, to allow multiple assertions
# Keep this loop outside, to allow multiple assertions for function in ['malloc', 'free', 'realloc', 'calloc']:
for function in ['malloc', 'free', 'realloc', 'calloc']: yield (check_dynamic_memory, implementation, function)
yield (check_dynamic_memory, implementation, function)
@helpers.filtered_test
@helpers.skip_windows() @helpers.skip_windows()
def check_dynamic_memory(implementation, function): def check_dynamic_memory(implementation, function):
# 'make' will take care of not rebuilding existing library files # 'make' will take care of not rebuilding existing library files

View File

@ -5,19 +5,20 @@ import pqclean
def test_formatting(): def test_formatting():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('format', implementation): yield check_format, implementation
yield check_format, implementation
@helpers.filtered_test
def check_format(implementation: pqclean.Implementation): def check_format(implementation: pqclean.Implementation):
helpers.ensure_available('astyle') helpers.ensure_available('astyle')
cfiles = implementation.cfiles() cfiles = implementation.cfiles()
hfiles = implementation.hfiles() hfiles = implementation.hfiles()
result = helpers.run_subprocess(['astyle', result = helpers.run_subprocess(
'--dry-run', ['astyle',
'--options=../.astylerc', '--dry-run',
*cfiles, '--options=../.astylerc',
*hfiles]) *cfiles,
*hfiles])
assert(not('Formatted' in result)) assert(not('Formatted' in result))

View File

@ -14,17 +14,16 @@ import helpers
def test_functest(): def test_functest():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('functest', implementation): yield check_functest, implementation
yield check_functest, implementation
def test_functest_sanitizers(): def test_functest_sanitizers():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('functest_sanitizers', implementation): yield check_functest_sanitizers, implementation
yield check_functest_sanitizers, implementation
@helpers.filtered_test
def check_functest(implementation): def check_functest(implementation):
helpers.make('functest', helpers.make('functest',
TYPE=implementation.scheme.type, TYPE=implementation.scheme.type,
@ -41,6 +40,7 @@ def check_functest(implementation):
) )
@helpers.filtered_test
@helpers.skip_windows() @helpers.skip_windows()
@helpers.slow_test @helpers.slow_test
def check_functest_sanitizers(implementation): def check_functest_sanitizers(implementation):

View File

@ -11,10 +11,10 @@ import helpers
def test_license(): def test_license():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('license', implementation): yield check_license, implementation
yield check_license, implementation
@helpers.filtered_test
def check_license(implementation): def check_license(implementation):
p1 = os.path.join(implementation.path(), 'LICENSE') p1 = os.path.join(implementation.path(), 'LICENSE')
p2 = os.path.join(implementation.path(), 'LICENSE.txt') p2 = os.path.join(implementation.path(), 'LICENSE.txt')

View File

@ -12,10 +12,10 @@ additional_flags = []
def test_clang_tidy(): def test_clang_tidy():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('linter', implementation): yield check_tidy, implementation
yield check_tidy, implementation
@helpers.filtered_test
@helpers.skip_windows() @helpers.skip_windows()
def check_tidy(implementation: pqclean.Implementation): def check_tidy(implementation: pqclean.Implementation):
helpers.ensure_available('clang-tidy') helpers.ensure_available('clang-tidy')

View File

@ -8,20 +8,30 @@ import pqclean
import helpers import helpers
import glob import glob
import datetime import datetime
import unittest
def _skipped_test(*args, **kwargs):
"""Used to indicate skipped tests"""
raise unittest.SkipTest("Skipped makefile dependencies test")
def test_makefile_dependencies(): def test_makefile_dependencies():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('makefile_dependencies', implementation): if not helpers.permit_test(
# initial build - want to have *all* files in place at beginning 'makefile_dependencies', implementation):
helpers.make('clean', working_dir=implementation.path()) yield _skipped_test, implementation
helpers.make(working_dir=implementation.path()) continue
# test case for each candidate file
cfiles = glob.glob(os.path.join(implementation.path(), '*.c')) # initial build - want to have *all* files in place at beginning
hfiles = glob.glob(os.path.join(implementation.path(), '*.h')) helpers.make('clean', working_dir=implementation.path())
for file in (cfiles + hfiles): helpers.make(working_dir=implementation.path())
yield (check_makefile_dependencies, implementation, file) # test case for each candidate file
cfiles = glob.glob(os.path.join(implementation.path(), '*.c'))
hfiles = glob.glob(os.path.join(implementation.path(), '*.h'))
for file in (cfiles + hfiles):
yield (check_makefile_dependencies, implementation, file)
def touch(time, *files): def touch(time, *files):

View File

@ -10,10 +10,10 @@ import pqclean
def test_metadata(): def test_metadata():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
if helpers.permit_test('metadata', scheme): yield check_metadata, scheme
yield check_metadata, scheme
@helpers.filtered_test
def check_metadata(scheme): def check_metadata(scheme):
metadata = scheme.metadata() metadata = scheme.metadata()

View File

@ -8,10 +8,10 @@ import helpers
def test_metadata_sizes(): def test_metadata_sizes():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('metadata_sizes', implementation): yield check_metadata_sizes, implementation
yield check_metadata_sizes, implementation
@helpers.filtered_test
def check_metadata_sizes(implementation): def check_metadata_sizes(implementation):
metadata = implementation.scheme.metadata() metadata = implementation.scheme.metadata()
impl_meta = next((impl for impl in metadata['implementations'] impl_meta = next((impl for impl in metadata['implementations']

View File

@ -2,7 +2,7 @@
Checks that (hash of the) KATs (in NIST format) produced on this platform matches Checks that (hash of the) KATs (in NIST format) produced on this platform matches
the one provided in the META file for every scheme/implementation. the one provided in the META file for every scheme/implementation.
Note that this only uses the first test case from the NIST-format KAT files. Note that this only uses the first test case from the NIST-format KAT files.
The appropriate hash can be generated from the original submission's KAT file The appropriate hash can be generated from the original submission's KAT file
using the command: using the command:
cat PQCkemKAT_whatever.rsp | head -n 8 | tail -n 6 | sha256sum cat PQCkemKAT_whatever.rsp | head -n 8 | tail -n 6 | sha256sum
@ -14,17 +14,21 @@ import pqclean
import helpers import helpers
import unittest import unittest
def test_nistkat(): def test_nistkat():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
if scheme.type != 'kem': continue if scheme.type != 'kem':
continue
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('nistkat', implementation): yield check_nistkat, implementation
yield check_nistkat, implementation
@helpers.filtered_test
def check_nistkat(implementation): def check_nistkat(implementation):
if implementation.scheme.name == "kyber768": if implementation.scheme.name == "kyber768":
raise unittest.SkipTest("Temporarily skip NIST KAT check for kyber768 since it's an outdated implementation") raise unittest.SkipTest(
"Temporarily skip NIST KAT check for kyber768 since it's "
"an outdated implementation")
helpers.make('nistkat', helpers.make('nistkat',
TYPE=implementation.scheme.type, TYPE=implementation.scheme.type,
SCHEME=implementation.scheme.name, SCHEME=implementation.scheme.name,

View File

@ -10,10 +10,10 @@ import helpers
def test_no_symlinks(): def test_no_symlinks():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('no_symlinks', implementation): yield check_no_symlinks, implementation
yield check_no_symlinks, implementation
@helpers.filtered_test
def check_no_symlinks(implementation): def check_no_symlinks(implementation):
for file in os.listdir(implementation.path()): for file in os.listdir(implementation.path()):
fpath = os.path.join(implementation.path(), file) fpath = os.path.join(implementation.path(), file)

View File

@ -5,10 +5,10 @@ import helpers
def test_preprocessor(): def test_preprocessor():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('preprocessor', implementation): yield check_preprocessor, implementation
yield check_preprocessor, implementation
@helpers.filtered_test
def check_preprocessor(implementation: pqclean.Implementation): def check_preprocessor(implementation: pqclean.Implementation):
cfiles = implementation.cfiles() cfiles = implementation.cfiles()
hfiles = implementation.hfiles() hfiles = implementation.hfiles()

View File

@ -12,10 +12,10 @@ import unittest
def test_symbol_namespace(): def test_symbol_namespace():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('symbol_namespace', implementation): yield check_symbol_namespace, implementation
yield check_symbol_namespace, implementation
@helpers.filtered_test
def check_symbol_namespace(implementation): def check_symbol_namespace(implementation):
if sys.platform not in ['linux', 'darwin']: if sys.platform not in ['linux', 'darwin']:
raise unittest.SkipTest("Unsupported platform") raise unittest.SkipTest("Unsupported platform")

View File

@ -10,28 +10,27 @@ import helpers
def test_testvectors(): def test_testvectors():
@helpers.filtered_test
def check_testvectors(implementation):
helpers.make('testvectors',
TYPE=implementation.scheme.type,
SCHEME=implementation.scheme.name,
IMPLEMENTATION=implementation.name,
working_dir=os.path.join('..', 'test'))
out = helpers.run_subprocess(
[os.path.join('..', 'bin', 'testvectors_{}_{}{}'.format(
implementation.scheme.name,
implementation.name,
'.exe' if os.name == 'nt' else ''
))],
os.path.join('..', 'bin'),
).replace('\r', '')
assert(implementation.scheme.metadata()['testvectors-sha256'].lower()
== hashlib.sha256(out.encode('utf-8')).hexdigest().lower())
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('testvectors', implementation): yield check_testvectors, implementation
yield check_vectors, implementation
def check_vectors(implementation):
helpers.make('testvectors',
TYPE=implementation.scheme.type,
SCHEME=implementation.scheme.name,
IMPLEMENTATION=implementation.name,
working_dir=os.path.join('..', 'test'))
out = helpers.run_subprocess(
[os.path.join('..', 'bin', 'testvectors_{}_{}{}'.format(
implementation.scheme.name,
implementation.name,
'.exe' if os.name == 'nt' else ''
))],
os.path.join('..', 'bin'),
).replace('\r', '')
assert(implementation.scheme.metadata()['testvectors-sha256'].lower()
== hashlib.sha256(out.encode('utf-8')).hexdigest().lower())
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -13,11 +13,11 @@ import helpers
def test_functest(): def test_functest():
for scheme in pqclean.Scheme.all_schemes(): for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations: for implementation in scheme.implementations:
if helpers.permit_test('valgrind', implementation): yield check_valgrind, implementation
yield check_valgrind, implementation
@helpers.slow_test @helpers.slow_test
@helpers.filtered_test
def check_valgrind(implementation: pqclean.Implementation): def check_valgrind(implementation: pqclean.Implementation):
if (platform.machine() not in ('i386', 'x86_64') or if (platform.machine() not in ('i386', 'x86_64') or
platform.system() != 'Linux'): platform.system() != 'Linux'):