Skip to content

Commit 730ae43

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

File tree

3 files changed

+167
-1
lines changed

3 files changed

+167
-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: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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, *args, **kwargs):
75+
# this is for pylint check
76+
mode = "r"
77+
if len(args) > 0:
78+
mode = args[0]
79+
elif "mode" in kwargs:
80+
mode = kwargs["mode"]
81+
if path == expected_asc1 and "w" in mode:
82+
raise IOError("mock write error")
83+
return real_open(path, *args, **kwargs)
84+
mock_open.side_effect = side_effect
85+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
86+
87+
self.assertEqual(len(failed), 1)
88+
self.assertNotIn(expected_asc1, generated)
89+
self.assertIn(expected_asc2, generated)
90+
91+
def test_sign_files_generation_with_missing_result(self):
92+
self.__prepare_artifacts()
93+
# simulate missing pull result by removing the sign result file loc
94+
shutil.rmtree(self.__sign_result_loc)
95+
96+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
97+
self.assertEqual(failed, [])
98+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
99+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
100+
self.assertEqual(generated, [])
101+
self.assertFalse(os.path.exists(expected_asc1))
102+
self.assertFalse(os.path.exists(expected_asc2))
103+
104+
def test_sign_files_generation_with_not_single_results(self):
105+
self.__prepare_artifacts()
106+
another_result_file = os.path.join(self.__sign_result_loc, "result2.json")
107+
overwrite_file(another_result_file, "test_json")
108+
109+
failed, generated = generate_radas_sign(self.__repo_dir, self.__sign_result_loc)
110+
self.assertEqual(failed, [])
111+
expected_asc1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar.asc")
112+
expected_asc2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar.asc")
113+
self.assertEqual(generated, [])
114+
self.assertFalse(os.path.exists(expected_asc1))
115+
self.assertFalse(os.path.exists(expected_asc2))
116+
117+
def __prepare_sign_result_file(self):
118+
self.__sign_result_loc = tempfile.mkdtemp()
119+
self.__sign_result_file = os.path.join(self.__sign_result_loc, "result.json")
120+
self.__repo_dir = os.path.join(tempfile.mkdtemp(), "maven-repository")
121+
data = {
122+
"request-id": "request-id",
123+
"file-reference": "quay.io/org/maven-zip@hash",
124+
"result": [
125+
{
126+
"file": "maven-repository/foo/bar/1.0/foo-bar-1.0.jar",
127+
"signature": (
128+
"-----BEGIN PGP SIGNATURE-----"
129+
"signature1@hash"
130+
"-----END PGP SIGNATURE-----"
131+
),
132+
"checksum": "sha256:sha256-content",
133+
},
134+
{
135+
"file": "maven-repository/foo/bar/2.0/foo-bar-2.0.jar",
136+
"signature": (
137+
"-----BEGIN PGP SIGNATURE-----"
138+
"signature2@hash"
139+
"-----END PGP SIGNATURE-----"
140+
),
141+
"checksum": "sha256:sha256-content",
142+
},
143+
],
144+
}
145+
json_str = json.dumps(data, indent=2)
146+
overwrite_file(self.__sign_result_file, json_str)
147+
148+
def __prepare_artifacts(self):
149+
os.makedirs(os.path.join(self.__repo_dir, "foo/bar/1.0"), exist_ok=True)
150+
os.makedirs(os.path.join(self.__repo_dir, "foo/bar/2.0"), exist_ok=True)
151+
artifact1 = os.path.join(self.__repo_dir, "foo/bar/1.0/foo-bar-1.0.jar")
152+
artifact2 = os.path.join(self.__repo_dir, "foo/bar/2.0/foo-bar-2.0.jar")
153+
with open(artifact1, "w") as f:
154+
f.write("dummy1")
155+
with open(artifact2, "w") as f:
156+
f.write("dummy2")
157+
158+
def __clear_sign_result_file(self):
159+
if os.path.exists(self.__sign_result_loc):
160+
shutil.rmtree(self.__sign_result_loc)
161+
if os.path.exists(self.__repo_dir):
162+
shutil.rmtree(self.__repo_dir)

0 commit comments

Comments
 (0)