Add support for specifying architecture and feature limits (#224)
* Add support for specifying architecture and feature limits * cpuinfo not supported on ppc * Detect 32-bit python interpreter on 64-bit CPU * Fix bugs in isolated tests * Also support restricting operating system
This commit is contained in:
parent
aa46b5239d
commit
2eaf382689
@ -2,3 +2,4 @@ PyYAML
|
||||
pytest
|
||||
pytest-xdist
|
||||
pycparser
|
||||
py-cpuinfo
|
||||
|
@ -69,7 +69,7 @@ $(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)
|
||||
mkdir -p $(DEST_DIR)
|
||||
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/testvectors.c $(COMMON_FILES) $(TEST_COMMON_DIR)/notrandombytes.c -o $@ -L$(SCHEME_DIR) -l$(SCHEME)_$(IMPLEMENTATION)
|
||||
|
||||
$(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION): build-scheme crypto_$(TYPE)/printparams.c
|
||||
$(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION): crypto_$(TYPE)/printparams.c
|
||||
mkdir -p $(DEST_DIR)
|
||||
$(CC) $(CFLAGS) -DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE) -I$(SCHEME_DIR) crypto_$(TYPE)/printparams.c -o $@
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import glob
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
import yaml
|
||||
import platform
|
||||
|
||||
|
||||
class Scheme:
|
||||
@ -37,6 +39,11 @@ class Scheme:
|
||||
implementations.extend(scheme.implementations)
|
||||
return implementations
|
||||
|
||||
@staticmethod
|
||||
def all_supported_implementations():
|
||||
return [impl for impl in Scheme.all_implementations()
|
||||
if impl.supported_on_current_platform()]
|
||||
|
||||
@staticmethod
|
||||
def all_schemes_of_type(type: str) -> list:
|
||||
schemes = []
|
||||
@ -111,10 +118,57 @@ class Implementation:
|
||||
implementations.append(Implementation(scheme, d))
|
||||
return implementations
|
||||
|
||||
@staticmethod
|
||||
def all_supported_implementations(scheme: Scheme) -> list:
|
||||
return [impl for impl in Implementation.all_implementations(scheme)
|
||||
if impl.supported_on_current_platform()]
|
||||
|
||||
def namespace_prefix(self):
|
||||
return '{}{}_'.format(self.scheme.namespace_prefix(),
|
||||
self.name.upper()).replace('-', '')
|
||||
|
||||
def supported_on_os(self, os: Optional[str] = None) -> bool:
|
||||
"""Check if we support the OS
|
||||
|
||||
If no OS is specified, then we run on the current OS
|
||||
"""
|
||||
if os is None:
|
||||
os = platform.system()
|
||||
|
||||
for platform_ in self.metadata().get('supported_platforms', []):
|
||||
if 'operating_systems' in platform_:
|
||||
if os not in platform_['operating_systems']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def supported_on_current_platform(self) -> bool:
|
||||
if 'supported_platforms' not in self.metadata():
|
||||
return True
|
||||
|
||||
if platform.machine() == 'ppc':
|
||||
return False
|
||||
|
||||
if not self.supported_on_os():
|
||||
return False
|
||||
|
||||
if not hasattr(Implementation, 'CPUINFO'):
|
||||
import cpuinfo
|
||||
Implementation.CPUINFO = cpuinfo.get_cpu_info()
|
||||
|
||||
CPUINFO = Implementation.CPUINFO
|
||||
|
||||
for platform_ in self.metadata()['supported_platforms']:
|
||||
if platform_['architecture'] == CPUINFO['arch'].lower():
|
||||
# Detect actually running on emulated i386
|
||||
if (platform_['architecture'] == 'x86_64' and
|
||||
platform.architecture()[0] == '32bit'):
|
||||
continue
|
||||
if all([flag in CPUINFO['flags']
|
||||
for flag in platform_['required_flags']]):
|
||||
return True
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "{} implementation of {}".format(self.name, self.scheme.name)
|
||||
|
||||
|
@ -11,8 +11,8 @@ import pqclean
|
||||
@pytest.mark.parametrize(
|
||||
'implementation,test_dir,impl_dir, init, destr',
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_compile_lib(implementation, test_dir, impl_dir, init, destr):
|
||||
|
@ -11,8 +11,8 @@ import pqclean
|
||||
@pytest.mark.parametrize(
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.skip_windows()
|
||||
@helpers.filtered_test
|
||||
|
@ -16,8 +16,8 @@ import pqclean
|
||||
@pytest.mark.parametrize(
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_functest(implementation, impl_path, test_dir,
|
||||
@ -45,8 +45,8 @@ def test_functest(implementation, impl_path, test_dir,
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl,
|
||||
*helpers.isolate_test_files(impl.path(), 'test_functest_sanitizers_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.skip_windows()
|
||||
@helpers.filtered_test
|
||||
|
@ -13,7 +13,7 @@ additional_flags = [] #['-fix-errors']
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'implementation',
|
||||
pqclean.Scheme.all_implementations(),
|
||||
pqclean.Scheme.all_supported_implementations(),
|
||||
ids=str,
|
||||
)
|
||||
@helpers.skip_windows()
|
||||
|
@ -17,8 +17,8 @@ import pqclean
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl,
|
||||
*helpers.isolate_test_files(impl.path(), 'test_makefile_deps_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_makefile_dependencies(implementation, impl_path, test_dir,
|
||||
|
@ -17,10 +17,23 @@ import pqclean
|
||||
ids=str,
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_makefiles_present(implementation):
|
||||
def test_makefile_present(implementation):
|
||||
p1 = os.path.join(implementation.path(), 'Makefile')
|
||||
assert os.path.isfile(p1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'implementation',
|
||||
pqclean.Scheme.all_implementations(),
|
||||
ids=str,
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_microsoft_nmakefile_present(implementation):
|
||||
p2 = os.path.join(implementation.path(), 'Makefile.Microsoft_nmake')
|
||||
assert(os.path.isfile(p1) and os.path.isfile(p2))
|
||||
if implementation.supported_on_os(os='Windows'):
|
||||
assert os.path.isfile(p2)
|
||||
else:
|
||||
assert not os.path.isfile(p2), "Should not have an NMake file"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -61,6 +61,31 @@ EXPECTED_FIELDS = {
|
||||
'spec': {
|
||||
'name': {'type': str},
|
||||
'version': {'type': str},
|
||||
'supported_platforms': {
|
||||
'type': list,
|
||||
'optional': True,
|
||||
'elements': {
|
||||
'type': dict,
|
||||
'spec': {
|
||||
'architecture': {
|
||||
'type': str,
|
||||
'values': ['x86', 'x86_64', 'aarch64']},
|
||||
'required_flags': {
|
||||
'type': list,
|
||||
'optional': True,
|
||||
'elements': {'type': str},
|
||||
},
|
||||
'operating_systems': {
|
||||
'type': list,
|
||||
'optional': True,
|
||||
'elements': {
|
||||
'type': str,
|
||||
'values': ['Linux', 'Windows', 'Darwin'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ import pqclean
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_printparams_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
)
|
||||
|
@ -20,8 +20,8 @@ import pqclean
|
||||
@pytest.mark.parametrize(
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_nistkat(implementation, impl_path, test_dir, init, destr):
|
||||
|
@ -16,8 +16,8 @@ import pqclean
|
||||
'implementation,test_dir,impl_path,init,destr',
|
||||
[(impl,
|
||||
*helpers.isolate_test_files(impl.path(), 'test_symbol_ns_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_symbol_namespaces(implementation, impl_path, test_dir, init, destr):
|
||||
|
@ -5,6 +5,7 @@ the one provided in the META file for every scheme/implementation.
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
@ -22,6 +23,8 @@ import pqclean
|
||||
)
|
||||
@helpers.filtered_test
|
||||
def test_testvectors(implementation, impl_path, test_dir, init, destr):
|
||||
if not implementation.supported_on_current_platform():
|
||||
raise unittest.SkipTest("Not supported on current platform")
|
||||
init()
|
||||
dest_dir = os.path.join(test_dir, 'bin')
|
||||
helpers.make('testvectors',
|
||||
|
@ -27,8 +27,8 @@ def valgrind_supports_exit_early():
|
||||
@pytest.mark.parametrize(
|
||||
'implementation,test_dir,impl_path, init, destr',
|
||||
[(impl, *helpers.isolate_test_files(impl.path(), 'test_functest_'))
|
||||
for impl in pqclean.Scheme.all_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_implementations()],
|
||||
for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
ids=[str(impl) for impl in pqclean.Scheme.all_supported_implementations()],
|
||||
)
|
||||
@helpers.slow_test
|
||||
@helpers.filtered_test
|
||||
|
Loading…
Reference in New Issue
Block a user