Cleanup
publish / publish (push) Successful in 10m36s

This commit is contained in:
khodowany
2026-09-24 19:40:03 -05:00
parent 097cb61d2d
commit 0c9ba1bff4
15 changed files with 628 additions and 53 deletions
+20
View File
@@ -5,6 +5,7 @@
#include <filesystem>
#include <fstream>
#include <iostream>
#include <limits>
#include <set>
#include <sstream>
#include <string>
@@ -270,3 +271,22 @@ BOOST_AUTO_TEST_CASE(modulus_load_config_handles_files) {
auto invalid = modulus::load_config(invalid_path.string());
BOOST_REQUIRE(!invalid.has_value());
}
BOOST_AUTO_TEST_CASE(modulus_json_float_fields_validate_numeric_types_and_bounds) {
auto object = boost::json::object{};
auto options = modulus::json_config::options{.category = "domain", .invalid_argument_code = 42};
auto read = [&] { return modulus::json_config::optional_float64_field(object, "gain", 0.5, 0.0, 1.0, options); };
BOOST_REQUIRE(read());
BOOST_TEST(static_cast<double>(*read()) == 0.5);
for (auto const &value : {boost::json::value{0}, boost::json::value{std::uint64_t{1}}, boost::json::value{0.25}}) {
object["gain"] = value;
BOOST_REQUIRE(read());
}
for (auto const &value : {boost::json::value{-1}, boost::json::value{2U}, boost::json::value{true}, boost::json::value{"0.5"}, boost::json::value{nullptr}, boost::json::value{std::numeric_limits<double>::infinity()}, boost::json::value{std::numeric_limits<double>::quiet_NaN()}}) {
object["gain"] = value;
auto result = read();
BOOST_REQUIRE(!result);
BOOST_TEST(std::string{result.error().category()} == "domain");
BOOST_TEST(result.error().code() == 42);
}
}
+125
View File
@@ -0,0 +1,125 @@
import ast
import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from unittest.mock import patch
import modulus.bootstrap
import modulus.cli
import modulus.config
import modulus.export
class BootstrapTests(unittest.TestCase):
def test_recipe_exports_prune_generated_trees(self):
workspace = Path(modulus.bootstrap.__file__).parents[2]
for name in ('modulus', 'ligo', 'noto', 'luma', 'sonus', 'product-vamp'):
recipe = workspace / name / 'conanfile.py'
if not recipe.exists():
continue
fields = {target.id: ast.literal_eval(node.value) for node in ast.walk(ast.parse(recipe.read_text())) if isinstance(node, ast.Assign) for target in node.targets if isinstance(target, ast.Name) and target.id in {'exports', 'exports_sources'}}
for field in ('exports', 'exports_sources'):
self.assertTrue({'!build', '!.git', '!test_package/build'}.issubset(fields[field]), f'{name}: {field}')
def test_consumers_use_canonical_bootstrap(self):
canonical = Path(modulus.bootstrap.__file__)
for name in ('ligo', 'noto', 'luma', 'sonus', 'product-vamp'):
consumer = canonical.parents[2] / name / 'modulus.py'
if consumer.exists():
self.assertEqual(canonical.read_bytes(), consumer.read_bytes(), name)
def test_read_environments_strip_all_credential_forms(self):
credentials = dict.fromkeys(('CONAN_USER', 'CONAN_TOKEN', 'CONAN_LOGIN_USERNAME', 'CONAN_PASSWORD', 'CONAN_LOGIN_USERNAME_KHODO', 'CONAN_PASSWORD_KHODO'), 'secret')
root = Path('/tmp/project')
context = modulus.cli.build_context(root, modulus.config.normalize({'package': {'name': 'sample'}}))
with patch.dict(os.environ, credentials):
for env in (modulus.bootstrap.fetch_env(root), modulus.cli.subprocess_environment(context, ['conan', 'install'])):
self.assertFalse(set(credentials) & env.keys())
self.assertEqual(env['CONAN_NON_INTERACTIVE'], '1')
self.assertEqual(env['CONAN_HOME'], str(root / 'build/build_common/conan_cache'))
def test_update_refreshes_runtime_and_offline_stays_offline(self):
root = Path('/tmp/project')
with patch.object(modulus.bootstrap, 'runtime_ready', return_value=True), patch.object(modulus.bootstrap, 'materialize_runtime') as refresh:
modulus.bootstrap.ensure_runtime(root)
refresh.assert_not_called()
modulus.bootstrap.ensure_runtime(root, update=True, no_remote=True)
refresh.assert_called_once_with(root, no_remote=True)
with patch.object(modulus.bootstrap, 'run_fetch', return_value=subprocess.CompletedProcess([], 0, '{}')) as fetch:
with self.assertRaisesRegex(SystemExit, 'local Conan cache'):
modulus.bootstrap.find_modulus(root)
self.assertNotIn('-r', fetch.call_args.args[1])
def test_fetch_failure_preserves_runtime(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
runtime = root / modulus.bootstrap.RUNTIME_DIR / 'modulus/cli.py'
runtime.parent.mkdir(parents=True)
runtime.write_text('old runtime')
with patch.object(modulus.bootstrap, 'remote_config', return_value=('khodo', 'https://example.test')), patch.object(modulus.bootstrap, 'configure_remote'), patch.object(modulus.bootstrap, 'find_modulus', side_effect=SystemExit(1)):
with self.assertRaises(SystemExit):
modulus.bootstrap.materialize_runtime(root)
self.assertEqual(runtime.read_text(), 'old runtime')
def test_offline_bootstrap_never_builds_a_fetch_image(self):
with patch.object(modulus.bootstrap.subprocess, 'run', return_value=subprocess.CompletedProcess([], 1)), patch.object(modulus.bootstrap, 'run') as build:
with self.assertRaisesRegex(SystemExit, 'offline bootstrap requires'):
modulus.bootstrap.ensure_fetch_image(offline=True)
build.assert_not_called()
def test_export_rolls_back_when_editor_refresh_fails(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / 'modulus.json').write_text(json.dumps({'package': {'name': 'sample'}}))
runtime = root / modulus.export.runtime_dir / 'modulus/cli.py'
runtime.parent.mkdir(parents=True)
runtime.write_text('old runtime')
package = root / 'package'
(package / 'modulus').mkdir(parents=True)
(package / 'modulus/cli.py').write_text('new runtime')
(package / 'tools').mkdir()
with patch.object(modulus.export, 'sync_editor_files', side_effect=OSError('editor is read-only')):
with self.assertRaisesRegex(OSError, 'read-only'):
modulus.export.sync_project(root, package)
self.assertEqual(runtime.read_text(), 'old runtime')
self.assertFalse((root / modulus.export.tools_dir).exists())
def test_public_remote_error_is_noninteractive_and_does_not_delete_packages(self):
completed = subprocess.CompletedProcess([], 1, '', '401 Unauthorized')
with patch.object(modulus.bootstrap, 'direct_mode', return_value=True), patch.object(modulus.bootstrap.subprocess, 'run', return_value=completed) as run:
with self.assertRaises(SystemExit):
modulus.bootstrap.find_modulus(Path('/tmp/project'), 'khodo')
self.assertEqual(run.call_args.args[0][:2], ['conan', 'list'])
self.assertEqual(run.call_args.kwargs['env']['CONAN_NON_INTERACTIVE'], '1')
def test_export_stages_all_payloads_before_replacing_runtime(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / 'modulus.json').write_text(json.dumps({'package': {'name': 'sample'}}))
runtime = root / modulus.export.runtime_dir / 'modulus/cli.py'
runtime.parent.mkdir(parents=True)
runtime.write_text('old runtime')
package = root / 'package'
(package / 'modulus').mkdir(parents=True)
(package / 'modulus/cli.py').write_text('new runtime')
with self.assertRaisesRegex(RuntimeError, 'missing tools'):
modulus.export.sync_project(root, package)
self.assertEqual(runtime.read_text(), 'old runtime')
def test_upload_exception_still_logs_out(self):
context = modulus.cli.build_context(Path('/tmp/project'), modulus.config.normalize({'package': {'name': 'sample'}}))
with patch.object(modulus.cli, 'configure_conan_remote', return_value=0), patch.object(modulus.cli, 'upload_all_packages', side_effect=RuntimeError('upload failed')), patch.object(modulus.cli, 'run', return_value=0) as run:
with self.assertRaisesRegex(RuntimeError, 'upload failed'):
modulus.cli.upload_packages(context)
run.assert_called_once_with(context, ['conan', 'remote', 'logout', 'khodo'])
def test_socket_is_scoped_and_docker_inputs_change_fingerprint(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
config = modulus.config.normalize({'package': {'name': 'sample'}, 'tooling': {'docker': {'dockerfile': 'package/build/Dockerfile', 'inputs': ['requirements.txt'], 'socket_commands': ['build', 'package']}}})
context = modulus.cli.build_context(root, config)
context.dockerfile.parent.mkdir(parents=True)
context.dockerfile.write_text('FROM scratch')
context.docker_inputs[0].parent.mkdir(parents=True)
for path in context.docker_inputs:
path.write_text('old')
before = modulus.clangd.recipe_digest(context)
context.docker_inputs[-1].write_text('new')
self.assertNotEqual(before, modulus.clangd.recipe_digest(context))
with patch.object(Path, 'is_socket', return_value=True), patch.object(Path, 'stat') as stat:
stat.return_value.st_gid = 123
for command in ('configure', 'test', 'lsp', 'clangd', 'format'):
self.assertEqual(modulus.cli.docker_socket_args(context, command), [])
self.assertIn('/var/run/docker.sock:/var/run/docker.sock', modulus.cli.docker_socket_args(context, 'package'))
+1
View File
@@ -23,6 +23,7 @@ class clangd_test(unittest.TestCase):
self.context.docker_marker = self.root / "not-in-container"
self.context.dockerfile.parent.mkdir(parents=True)
self.context.dockerfile.write_text("FROM sample\n")
self.context.docker_inputs[0].write_text("autopep8==2.3.2\n")
self.image = "sha256:" + "1" * 64
def test_defaults_and_custom_settings(self):
self.assertEqual(modulus.clangd.settings(self.context)["executable"], "/usr/bin/clangd-19")
+17 -12
View File
@@ -110,13 +110,15 @@ class upload_packages_test(unittest.TestCase):
self.assertEqual(cache.read_text(encoding="utf-8"), "keep")
@unittest.mock.patch.object(modulus.cli, "upload_all_packages", return_value=37)
@unittest.mock.patch.object(modulus.cli, "configure_conan_remote", return_value=0)
def test_failed_upload_does_not_force_by_default(self, configure, upload):
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)
def test_failed_upload_does_not_force_by_default(self, run, configure, upload):
context = self.context()
with unittest.mock.patch.dict(os.environ, {}, clear=True):
status = modulus.cli.upload_packages(context)
self.assertEqual(status, 37)
configure.assert_called_once_with(context, authenticate=True)
upload.assert_called_once_with(context, "origin", force=False)
run.assert_called_once_with(context, ["conan", "remote", "logout", "origin"])
@unittest.mock.patch.object(modulus.cli, "upload_all_packages")
@unittest.mock.patch.object(modulus.cli, "configure_conan_remote")
def test_replace_requires_guard_env(self, configure, upload):
@@ -127,7 +129,8 @@ class upload_packages_test(unittest.TestCase):
upload.assert_not_called()
@unittest.mock.patch.object(modulus.cli, "upload_all_packages", return_value=0)
@unittest.mock.patch.object(modulus.cli, "configure_conan_remote", return_value=0)
def test_replace_forces_upload_when_guarded(self, configure, upload):
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)
def test_replace_forces_upload_when_guarded(self, run, configure, upload):
context = self.context()
with unittest.mock.patch.dict(
os.environ,
@@ -186,8 +189,9 @@ class upload_packages_test(unittest.TestCase):
def test_docker_passthrough_includes_replace_env(self):
passthrough = modulus.cli.docker_passthrough_env(self.context())
self.assertIn("MODULUS_ALLOW_PACKAGE_REPLACE", passthrough)
self.assertIn("PACKAGE_REGISTRY_USER", passthrough)
self.assertIn("PACKAGE_REGISTRY_TOKEN", passthrough)
for name in ("CONAN_USER", "CONAN_TOKEN", "PACKAGE_REGISTRY_USER", "PACKAGE_REGISTRY_TOKEN"):
self.assertNotIn(name, passthrough)
self.assertIn(name, modulus.cli.docker_passthrough_env(self.context(), publishing=True))
self.assertIn("SAMPLE_PACKAGE_UPLOAD", passthrough)
self.assertNotIn("CONAN_PACKAGE_VERSION", passthrough)
self.assertNotIn("MODULUS_EXPORT_RUNTIME", passthrough)
@@ -368,7 +372,8 @@ class upload_packages_test(unittest.TestCase):
with unittest.mock.patch.dict(os.environ, {}, clear=True):
status = modulus.cli.configure_conan_remote(self.context())
self.assertEqual(status, 0)
self.assertEqual(len(run.call_args_list), 1)
self.assertEqual(len(run.call_args_list), 2)
self.assertEqual(run.call_args_list[-1].args[1], ["conan", "remote", "logout", "origin"])
self.assertEqual(
run.call_args_list[0].args[1],
[
@@ -381,11 +386,11 @@ class upload_packages_test(unittest.TestCase):
],
)
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)
def test_configure_remote_rejects_partial_conan_credentials(self, run):
def test_configure_remote_ignores_partial_conan_credentials(self, run):
with unittest.mock.patch.dict(os.environ, {"CONAN_USER": "dev"}, clear=True):
status = modulus.cli.configure_conan_remote(self.context())
self.assertEqual(status, 1)
run.assert_not_called()
self.assertEqual(status, 0)
self.assertEqual(run.call_args_list[-1].args[1], ["conan", "remote", "logout", "origin"])
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)
def test_configure_remote_skips_login_until_authentication_is_requested(self, run):
context = self.context()
@@ -399,7 +404,7 @@ class upload_packages_test(unittest.TestCase):
):
status = modulus.cli.configure_conan_remote(context)
self.assertEqual(status, 0)
self.assertEqual(len(run.call_args_list), 1)
self.assertEqual(len(run.call_args_list), 2)
self.assertEqual(
run.call_args_list[0].args[1],
[
@@ -744,7 +749,7 @@ class upload_packages_test(unittest.TestCase):
@unittest.mock.patch.object(modulus.cli, "create_package", return_value=0)
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)
@unittest.mock.patch.object(modulus.cli, "in_docker", return_value=True)
def test_package_rejects_partial_conan_credentials_before_create(self, docker, run, create_package):
def test_package_checks_credentials_only_at_upload(self, docker, run, create_package):
context = self.context()
with unittest.mock.patch.dict(
os.environ,
@@ -762,8 +767,8 @@ class upload_packages_test(unittest.TestCase):
],
)
self.assertEqual(status, 1)
create_package.assert_not_called()
run.assert_not_called()
create_package.assert_called_once()
self.assertEqual(run.call_args_list[-1].args[1], ["conan", "remote", "logout", "origin"])
docker.assert_called_once()
@unittest.mock.patch.object(modulus.cli, "clear_conan_deps")
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)