Skip to content

Commit 2b2a177

Browse files
committed
Add Unit tests for RADAS signing results parse and generation
1 parent ae5ec19 commit 2b2a177

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

charon/pkgs/maven.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ def handle_maven_uploading(
423423
)
424424
if not _generated_signs:
425425
logger.error(
426-
"No sign result files were downloaded, "
426+
"No sign result files were generated, "
427427
"please make sure the sign process is already done and without timeout")
428428
return (tmp_root, False)
429429

charon/pkgs/radas_signature_handler.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ def generate_radas_sign(top_level: str, sign_result_loc: str) -> Tuple[List[str]
103103
"""
104104
Generate .asc files based on RADAS sign result json file
105105
"""
106+
if not os.path.isdir(sign_result_loc):
107+
logger.error("Sign result loc dir does not exist: %s", sign_result_loc)
108+
return [], []
109+
106110
files = [
107111
os.path.join(sign_result_loc, f)
108112
for f in os.listdir(sign_result_loc)

tests/test_radas_sign_handler.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"""
2+
Copyright (C) 2022 Red Hat, Inc. (https://github.com/Commonjava/charon)
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
"""
16+
17+
import logging
18+
import unittest
19+
import tempfile
20+
import os
21+
import json
22+
import shutil
23+
import builtins
24+
from unittest import mock
25+
from charon.utils.files import overwrite_file
26+
from charon.pkgs.radas_signature_handler import generate_radas_sign
27+
28+
logger = logging.getLogger(__name__)
29+
30+
31+
class RadasSignHandlerTest(unittest.TestCase):
32+
def setUp(self) -> None:
33+
super().setUp()
34+
self.__prepare_sign_result_file()
35+
36+
def tearDown(self) -> None:
37+
super().tearDown()
38+
self.__clear_sign_result_file()
39+
40+
def test_multi_sign_files_generation(self):
41+
self.__prepare_artifacts()
42+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
43+
self.assertEqual(failed, [])
44+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
45+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
46+
self.assertEqual(len(generated), 2)
47+
self.assertIn(expected_asc1, generated)
48+
self.assertIn(expected_asc2, generated)
49+
50+
with open(expected_asc1) as f:
51+
content1 = f.read()
52+
with open(expected_asc2) as f:
53+
content2 = f.read()
54+
self.assertIn("signature1@hash", content1)
55+
self.assertIn("signature2@hash", content2)
56+
57+
def test_sign_files_generation_with_missing_artifacts(self):
58+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
59+
self.assertEqual(failed, [])
60+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
61+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
62+
self.assertEqual(generated, [])
63+
self.assertFalse(os.path.exists(expected_asc1))
64+
self.assertFalse(os.path.exists(expected_asc2))
65+
66+
def test_sign_files_generation_with_failure(self):
67+
self.__prepare_artifacts()
68+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
69+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
70+
71+
# simulate expected_asc1 can not open to write properly
72+
real_open = builtins.open
73+
with mock.patch("builtins.open") as mock_open:
74+
def side_effect(path, mode="r", *args, **kwargs):
75+
if path == expected_asc1 and "w" in mode:
76+
raise IOError("mock write error")
77+
return real_open(path, mode, *args, **kwargs)
78+
mock_open.side_effect = side_effect
79+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
80+
81+
self.assertEqual(len(failed), 1)
82+
self.assertNotIn(expected_asc1, generated)
83+
self.assertIn(expected_asc2, generated)
84+
85+
def test_sign_files_generation_with_missing_result(self):
86+
self.__prepare_artifacts()
87+
# simulate missing pull result by removing the sign result file loc
88+
shutil.rmtree(self.__sign_result_loc)
89+
90+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
91+
self.assertEqual(failed, [])
92+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
93+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
94+
self.assertEqual(generated, [])
95+
self.assertFalse(os.path.exists(expected_asc1))
96+
self.assertFalse(os.path.exists(expected_asc2))
97+
98+
def test_sign_files_generation_with_not_single_results(self):
99+
self.__prepare_artifacts()
100+
another_result_file = os.path.join(self.__sign_result_loc, "result2.json")
101+
overwrite_file(another_result_file, "test_json")
102+
103+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
104+
self.assertEqual(failed, [])
105+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
106+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
107+
self.assertEqual(generated, [])
108+
self.assertFalse(os.path.exists(expected_asc1))
109+
self.assertFalse(os.path.exists(expected_asc2))
110+
111+
def __prepare_sign_result_file(self):
112+
self.__sign_result_loc = tempfile.mkdtemp()
113+
self.__sign_result_file = os.path.join(self.__sign_result_loc, "result.json")
114+
self.__repo_dir = os.path.join(tempfile.mkdtemp(), "maven-repository")
115+
data = {
116+
"request-id": "request-id",
117+
"file-reference": "quay.io/org/maven-zip@hash",
118+
"result": [
119+
{
120+
"file": "maven-repository/foo/bar/1.0/foo-bar-1.0.jar",
121+
"signature": (
122+
"-----BEGIN PGP SIGNATURE-----"
123+
"signature1@hash"
124+
"-----END PGP SIGNATURE-----"
125+
),
126+
"checksum": "sha256:sha256-content",
127+
},
128+
{
129+
"file": "maven-repository/foo/bar/2.0/foo-bar-2.0.jar",
130+
"signature": (
131+
"-----BEGIN PGP SIGNATURE-----"
132+
"signature2@hash"
133+
"-----END PGP SIGNATURE-----"
134+
),
135+
"checksum": "sha256:sha256-content",
136+
},
137+
],
138+
}
139+
json_str = json.dumps(data, indent=2)
140+
overwrite_file(self.__sign_result_file, json_str)
141+
142+
def __prepare_artifacts(self):
143+
os.makedirs(os.path.join(self.__repo_dir, "foo/bar/1.0"), exist_ok=True)
144+
os.makedirs(os.path.join(self.__repo_dir, "foo/bar/2.0"), exist_ok=True)
145+
artifact1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar")
146+
artifact2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar")
147+
with open(artifact1, "w") as f:
148+
f.write("dummy1")
149+
with open(artifact2, "w") as f:
150+
f.write("dummy2")
151+
152+
def __clear_sign_result_file(self):
153+
if os.path.exists(self.__sign_result_loc):
154+
shutil.rmtree(self.__sign_result_loc)
155+
if os.path.exists(self.__repo_dir):
156+
shutil.rmtree(self.__repo_dir)

0 commit comments

Comments
 (0)