blob: 199f58576fafb9d570f7fca98febe0defc11149a [file]
#!/usr/bin/env python3
# Copyright (c) 2023 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
"""
Tests for scl.py functions
"""
import sys
import types
from contextlib import nullcontext
from importlib import reload
from unittest import mock
import pytest
import scl
from jsonschema.exceptions import ValidationError
from yaml.scanner import ScannerError
@pytest.mark.parametrize("has_cyaml", [True, False], ids=["C YAML", "non-C YAML"])
def test_yaml_imports(has_cyaml):
"""
scl.py does:
from yaml import CSafeLoader as SafeLoader
falling back to:
from yaml import SafeLoader
So we simulate a yaml module with/without CSafeLoader.
"""
fake_yaml = types.ModuleType("yaml")
fake_yaml.load = mock.Mock()
fake_yaml.SafeLoader = object()
if has_cyaml:
fake_yaml.CSafeLoader = object()
with mock.patch.dict(sys.modules, {"yaml": fake_yaml}):
reload(scl)
assert scl.SafeLoader is (fake_yaml.CSafeLoader if has_cyaml else fake_yaml.SafeLoader)
# cleanup
reload(scl)
TESTDATA_3 = [
(False),
(True),
]
@pytest.mark.parametrize(
'fail_parsing',
TESTDATA_3,
ids=['ok', 'parsing error']
)
def test_yaml_load(caplog, fail_parsing):
result_mock = mock.Mock()
def mock_load(*args, **kwargs):
if fail_parsing:
context_mark = mock.Mock()
problem_mark = mock.Mock()
type(context_mark).args = mock.PropertyMock(return_value=[])
type(context_mark).name = 'dummy context mark'
type(context_mark).line = 0
type(context_mark).column = 0
type(problem_mark).args = mock.PropertyMock(return_value=[])
type(problem_mark).name = 'dummy problem mark'
type(problem_mark).line = 0
type(problem_mark).column = 0
raise ScannerError(context='dummy context',
context_mark=context_mark, problem='dummy problem',
problem_mark=problem_mark, note='Dummy note')
return result_mock
filename = 'dummy/file.yaml'
with mock.patch('yaml.load', side_effect=mock_load), \
mock.patch('builtins.open', mock.mock_open()) as mock_file:
with pytest.raises(ScannerError) if fail_parsing else nullcontext():
result = scl.yaml_load(filename)
mock_file.assert_called_with('dummy/file.yaml', 'r', encoding='utf-8')
if not fail_parsing:
assert result == result_mock
else:
assert 'dummy problem mark:0:0: error: dummy problem' \
' (note Dummy note context @dummy context mark:0:0' \
' dummy context)' in caplog.text
TESTDATA_4 = [
(True, False, None),
(False, False, ValidationError),
(False, True, ScannerError),
]
@pytest.mark.parametrize(
'validate, fail_load, expected_error',
TESTDATA_4,
ids=['successful validation', 'failed validation', 'failed load']
)
def test_yaml_load_verify(validate, fail_load, expected_error):
filename = 'dummy/file.yaml'
schema_mock = mock.Mock()
data_mock = mock.Mock()
def mock_load(file_name):
assert file_name == filename
if fail_load:
raise ScannerError
return data_mock
def mock_validate(data, schema):
assert data == data_mock
assert schema == schema_mock
if validate:
return None
raise ValidationError("Schema validation failed")
with mock.patch('scl.yaml_load', side_effect=mock_load), \
mock.patch('scl._yaml_validate', side_effect=mock_validate), \
pytest.raises(expected_error) if expected_error else nullcontext():
res = scl.yaml_load_verify(filename, schema_mock)
if validate:
assert res == data_mock
def test_yaml_validate():
data = {"a": 1}
schema = {
"type": "object",
"properties": {
"a": {"type": "string"}
},
"required": ["a"],
"additionalProperties": False,
}
with pytest.raises(ValidationError):
scl._yaml_validate(data, schema)
def test_yaml_validate_no_schema():
data = {"a": 1}
assert scl._yaml_validate(data, None) is None
def test_yaml_load_empty_file(tmp_path):
quarantine_file = tmp_path / 'empty_quarantine.yml'
quarantine_file.write_text("# yaml file without data", encoding="utf-8")
with pytest.raises(scl.EmptyYamlFileException):
scl.yaml_load_verify(quarantine_file, None)