blob: ed8c14639a13f74fc99ad43e1e37262f0632d015 [file]
# Copyright 2026 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Tests for the FreshnessTriager class in pw_fortifier."""
# pylint: disable=protected-access
import asyncio
from datetime import date
import unittest
from unittest.mock import patch
from pyfakefs.fake_filesystem_unittest import TestCaseMixin
from pw_fortifier.async_path import AsyncPath
from pw_fortifier.code_snippet import CodeSnippet
from pw_fortifier.freshness_result import FreshnessResult, PackageVersion
from pw_fortifier.freshness_triager import FreshnessTriager
from pw_fortifier.pipeline_stage import PipelineSink
from pw_fortifier.scanner import configure_stage_for_test
class TestFreshnessTriager(unittest.IsolatedAsyncioTestCase, TestCaseMixin):
"""Unit tests for the FreshnessTriager class."""
def setUp(self) -> None:
self.setUpPyfakefs()
self.working_dir = AsyncPath('/working')
self.fs.create_dir(self.working_dir.path)
@patch(
'pw_fortifier.triager.CoreOwnerFinder.find',
return_value='assignee@google.com',
)
async def test_triage_freshness_result_success(self, _mock_find) -> None:
"""Tests that FreshnessTriager correctly modifies a FreshnessResult."""
triager = FreshnessTriager()
next_stage = PipelineSink()
triager.connect(next_stage)
await configure_stage_for_test(
triager,
working_dir=str(self.working_dir),
)
# Create input freshness result (tier 0)
result = FreshnessResult(
package='test-package',
location=CodeSnippet(file='MODULE.bazel'),
pkg_type='bazel_dep',
current=PackageVersion('1.0.0', date(2026, 1, 1)),
earliest=PackageVersion('2.0.0', date(2026, 6, 1)),
tier=0,
)
test_file = AsyncPath(self.working_dir, 'result-1.json')
await result.save(test_file)
# Run triager
run_task = asyncio.create_task(triager.run())
await triager.input_queue.put(test_file)
await triager.input_queue.put(None)
await run_task
# Verify output
self.assertEqual(next_stage.input_queue.qsize(), 2)
forwarded_path = await next_stage.input_queue.get()
assert forwarded_path is not None
triaged_result = await FreshnessResult.load(forwarded_path)
self.assertEqual(triaged_result.priority, 1) # tier 0 // 2 + 1 = 1
self.assertEqual(triaged_result.severity, 2) # tier 0 // 2 + 2 = 2
self.assertEqual(triaged_result.assignee, 'assignee@google.com')
async def test_triage_tier2_priority_and_severity(self) -> None:
"""Tests priority and severity computation for tier 2 dependencies."""
triager = FreshnessTriager()
result = FreshnessResult(
package='dev-package',
location=CodeSnippet(file='requirements.txt'),
pkg_type='pip',
current=PackageVersion('1.0', date(2026, 1, 1)),
earliest=PackageVersion('2.0', date(2026, 6, 1)),
tier=2,
)
await triager._triage(result)
self.assertEqual(result.priority, 2) # tier 2 // 2 + 1 = 2
self.assertEqual(result.severity, 3) # tier 2 // 2 + 2 = 3
if __name__ == '__main__':
unittest.main()