Coverage for tests/store/test_package_has_sboms.py: 99%

106 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-18 22:11 +0000

1import unittest 

2from unittest.mock import patch, Mock 

3from webapp.store.views import package_has_sboms 

4 

5 

6class TestPackageHasSboms(unittest.TestCase): 

7 """Test cases for the package_has_sboms function.""" 

8 

9 def test_package_has_sboms_no_revisions(self): 

10 """Test that function returns False when revisions is empty or None.""" 

11 # Test with None 

12 result = package_has_sboms(None, "test-package-123") 

13 self.assertFalse(result) 

14 

15 # Test with empty list 

16 result = package_has_sboms([], "test-package-123") 

17 self.assertFalse(result) 

18 

19 @patch("webapp.store.views.requests.head") 

20 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

21 def test_package_has_sboms_success_200( 

22 self, mock_get_endpoint_url, mock_head 

23 ): 

24 """Test that function returns True when HEAD request returns 200.""" 

25 # Setup mocks 

26 mock_get_endpoint_url.return_value = "https://example.com/sbom/path" 

27 mock_response = Mock() 

28 mock_response.status_code = 200 

29 mock_head.return_value = mock_response 

30 

31 revisions = ["revision-123"] 

32 package_id = "test-package-456" 

33 

34 result = package_has_sboms(revisions, package_id) 

35 

36 # Assertions 

37 self.assertTrue(result) 

38 expected_sbom_path = ( 

39 f"download/sbom_charm_{package_id}_{revisions[0]}.spdx2.3.json" 

40 ) 

41 mock_get_endpoint_url.assert_called_once_with(expected_sbom_path) 

42 mock_head.assert_called_once_with("https://example.com/sbom/path") 

43 

44 @patch("webapp.store.views.requests.head") 

45 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

46 def test_package_has_sboms_success_302( 

47 self, mock_get_endpoint_url, mock_head 

48 ): 

49 """Test that function returns True when HEAD request returns 302.""" 

50 # Setup mocks 

51 mock_get_endpoint_url.return_value = "https://example.com/sbom/path" 

52 mock_response = Mock() 

53 mock_response.status_code = 302 

54 mock_head.return_value = mock_response 

55 

56 revisions = ["revision-789"] 

57 package_id = "test-package-abc" 

58 

59 result = package_has_sboms(revisions, package_id) 

60 

61 # Assertions 

62 self.assertTrue(result) 

63 expected_sbom_path = ( 

64 f"download/sbom_charm_{package_id}_{revisions[0]}.spdx2.3.json" 

65 ) 

66 mock_get_endpoint_url.assert_called_once_with(expected_sbom_path) 

67 mock_head.assert_called_once_with("https://example.com/sbom/path") 

68 

69 @patch("webapp.store.views.requests.head") 

70 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

71 def test_package_has_sboms_failure_404( 

72 self, mock_get_endpoint_url, mock_head 

73 ): 

74 """Test that function returns False when HEAD request returns 404.""" 

75 # Setup mocks 

76 mock_get_endpoint_url.return_value = "https://example.com/sbom/path" 

77 mock_response = Mock() 

78 mock_response.status_code = 404 

79 mock_head.return_value = mock_response 

80 

81 revisions = ["revision-456"] 

82 package_id = "test-package-def" 

83 

84 result = package_has_sboms(revisions, package_id) 

85 

86 # Assertions 

87 self.assertFalse(result) 

88 expected_sbom_path = ( 

89 f"download/sbom_charm_{package_id}_{revisions[0]}.spdx2.3.json" 

90 ) 

91 mock_get_endpoint_url.assert_called_once_with(expected_sbom_path) 

92 mock_head.assert_called_once_with("https://example.com/sbom/path") 

93 

94 @patch("webapp.store.views.requests.head") 

95 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

96 def test_package_has_sboms_failure_500( 

97 self, mock_get_endpoint_url, mock_head 

98 ): 

99 """Test that function returns False when HEAD request returns 500.""" 

100 # Setup mocks 

101 mock_get_endpoint_url.return_value = "https://example.com/sbom/path" 

102 mock_response = Mock() 

103 mock_response.status_code = 500 

104 mock_head.return_value = mock_response 

105 

106 revisions = ["revision-999"] 

107 package_id = "test-package-xyz" 

108 

109 result = package_has_sboms(revisions, package_id) 

110 

111 # Assertions 

112 self.assertFalse(result) 

113 expected_sbom_path = ( 

114 f"download/sbom_charm_{package_id}_{revisions[0]}.spdx2.3.json" 

115 ) 

116 mock_get_endpoint_url.assert_called_once_with(expected_sbom_path) 

117 mock_head.assert_called_once_with("https://example.com/sbom/path") 

118 

119 @patch("webapp.store.views.requests.head") 

120 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

121 def test_package_has_sboms_multiple_revisions_uses_first( 

122 self, mock_get_endpoint_url, mock_head 

123 ): 

124 """Test that function uses only the first revision when multiple""" 

125 # Setup mocks 

126 mock_get_endpoint_url.return_value = "https://example.com/sbom/path" 

127 mock_response = Mock() 

128 mock_response.status_code = 200 

129 mock_head.return_value = mock_response 

130 

131 revisions = ["first-revision", "second-revision", "third-revision"] 

132 package_id = "multi-revision-package" 

133 

134 result = package_has_sboms(revisions, package_id) 

135 

136 # Assertions 

137 self.assertTrue(result) 

138 # Should use only the first revision 

139 expected_sbom_path = ( 

140 f"download/sbom_charm_{package_id}_first-revision.spdx2.3.json" 

141 ) 

142 mock_get_endpoint_url.assert_called_once_with(expected_sbom_path) 

143 mock_head.assert_called_once_with("https://example.com/sbom/path") 

144 

145 @patch("webapp.store.views.requests.head") 

146 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

147 def test_package_has_sboms_request_exception_returns_false( 

148 self, mock_get_endpoint_url, mock_head 

149 ): 

150 """Test function returns False when requests.head raises exception.""" 

151 # Setup mocks 

152 mock_get_endpoint_url.return_value = "https://example.com/sbom/path" 

153 mock_head.side_effect = Exception("Network error") 

154 

155 revisions = ["revision-error"] 

156 package_id = "error-package" 

157 

158 # Function should handle exceptions gracefully and return False 

159 with self.assertRaises(Exception): 

160 package_has_sboms(revisions, package_id) 

161 

162 @patch("webapp.store.views.requests.head") 

163 @patch("webapp.store.views.device_gateway_sbom.get_endpoint_url") 

164 def test_package_has_sboms_edge_cases( 

165 self, mock_get_endpoint_url, mock_head 

166 ): 

167 """Test edge cases with various status codes.""" 

168 test_cases = [ 

169 (100, False), # Continue 

170 (201, False), # Created 

171 (301, False), # Moved Permanently 

172 (400, False), # Bad Request 

173 (401, False), # Unauthorized 

174 (403, False), # Forbidden 

175 (418, False), # I'm a teapot 

176 ] 

177 

178 for status_code, expected_result in test_cases: 

179 with self.subTest(status_code=status_code): 

180 # Reset mocks 

181 mock_get_endpoint_url.reset_mock() 

182 mock_head.reset_mock() 

183 

184 # Setup mocks 

185 mock_get_endpoint_url.return_value = ( 

186 "https://example.com/sbom/path" 

187 ) 

188 mock_response = Mock() 

189 mock_response.status_code = status_code 

190 mock_head.return_value = mock_response 

191 

192 revisions = ["test-revision"] 

193 package_id = f"test-package-{status_code}" 

194 

195 result = package_has_sboms(revisions, package_id) 

196 self.assertEqual(result, expected_result) 

197 

198 

199if __name__ == "__main__": 

200 unittest.main()