Coverage for tests/endpoints/publisher/tests_listing.py: 100%

112 statements  

« prev     ^ index     » next       coverage.py v7.10.5, created at 2025-08-26 22:06 +0000

1from unittest.mock import patch 

2from tests.endpoints.endpoint_testing import TestEndpoints 

3 

4 

5class TestGetListingData(TestEndpoints): 

6 @patch("webapp.endpoints.publisher.listing.helpers.get_yaml") 

7 @patch("webapp.endpoints.publisher.listing.helpers.get_licenses") 

8 @patch("webapp.endpoints.publisher.listing.logic.filter_categories") 

9 @patch( 

10 "webapp.endpoints.publisher.listing.logic." 

11 "replace_reserved_categories_key" 

12 ) 

13 @patch("webapp.endpoints.publisher.listing.logic.categorise_media") 

14 @patch("webapp.endpoints.publisher.listing.get_categories") 

15 @patch("webapp.endpoints.publisher.listing.device_gateway") 

16 @patch("webapp.endpoints.publisher.listing.dashboard") 

17 def test_get_listing_data_success( 

18 self, 

19 mock_dashboard, 

20 mock_device_gateway, 

21 mock_get_categories, 

22 mock_categorise_media, 

23 mock_replace_reserved_categories_key, 

24 mock_filter_categories, 

25 mock_get_licenses, 

26 mock_get_yaml, 

27 ): 

28 # Mock snap details from dashboard 

29 mock_snap_details = { 

30 "title": "Test Snap", 

31 "summary": "A test snap for testing", 

32 "description": ( 

33 "This is a test snap used for unit testing purposes" 

34 ), 

35 "snap_id": "test-snap-id-123", 

36 "public_metrics_enabled": True, 

37 "public_metrics_blacklist": ["install_size"], 

38 "media": [ 

39 {"type": "icon", "url": "https://example.com/icon.png"}, 

40 { 

41 "type": "screenshot", 

42 "url": "https://example.com/screenshot.png", 

43 }, 

44 ], 

45 "links": { 

46 "website": ["https://example.com", "https://secondary.com"], 

47 "contact": ["mailto:contact@example.com"], 

48 "source": ["https://github.com/example/repo"], 

49 }, 

50 "license": "MIT", 

51 "categories": [{"name": "productivity"}, {"name": "utilities"}], 

52 "video_urls": ["https://example.com/video.mp4"], 

53 "update_metadata_on_release": True, 

54 } 

55 mock_dashboard.get_snap_info.return_value = mock_snap_details 

56 

57 # Mock device gateway categories 

58 mock_device_gateway.get_categories.return_value = [ 

59 {"name": "productivity", "slug": "productivity"}, 

60 {"name": "utilities", "slug": "utilities"}, 

61 ] 

62 

63 # Mock get_categories function 

64 mock_get_categories.return_value = [ 

65 {"name": "productivity", "slug": "productivity"}, 

66 {"name": "utilities", "slug": "utilities"}, 

67 ] 

68 

69 # Mock media categorization 

70 mock_categorise_media.return_value = ( 

71 ["https://example.com/icon.png"], # icon_urls 

72 ["https://example.com/screenshot.png"], # screenshot_urls 

73 [], # banner_urls 

74 ) 

75 

76 # Mock category processing 

77 mock_replace_reserved_categories_key.return_value = { 

78 "categories": [{"name": "productivity"}, {"name": "utilities"}] 

79 } 

80 mock_filter_categories.return_value = { 

81 "categories": [{"name": "productivity"}, {"name": "utilities"}] 

82 } 

83 

84 # Mock licenses 

85 mock_get_licenses.return_value = [ 

86 {"licenseId": "MIT", "name": "MIT License"}, 

87 {"licenseId": "Apache-2.0", "name": "Apache License 2.0"}, 

88 ] 

89 

90 # Mock YAML tour steps 

91 mock_get_yaml.return_value = [ 

92 {"title": "Welcome", "content": "Welcome to the tour"} 

93 ] 

94 

95 # Make the request 

96 response = self.client.get("/api/test-snap/listing") 

97 data = response.json 

98 

99 # Assert response structure 

100 self.assertEqual(response.status_code, 200) 

101 self.assertTrue(data["success"]) 

102 self.assertEqual(data["message"], "") 

103 self.assertIn("data", data) 

104 

105 # Assert specific data fields 

106 context = data["data"] 

107 self.assertEqual(context["title"], "Test Snap") 

108 self.assertEqual(context["summary"], "A test snap for testing") 

109 self.assertEqual(context["snap_id"], "test-snap-id-123") 

110 self.assertTrue(context["public_metrics_enabled"]) 

111 self.assertEqual(context["public_metrics_blacklist"], ["install_size"]) 

112 self.assertEqual(context["license"], "MIT") 

113 self.assertEqual(context["license_type"], "simple") 

114 self.assertEqual(context["primary_website"], "https://example.com") 

115 self.assertEqual(context["primary_category"], "productivity") 

116 self.assertEqual(context["secondary_category"], "utilities") 

117 self.assertEqual(context["icon_url"], "https://example.com/icon.png") 

118 self.assertEqual( 

119 context["video_urls"], "https://example.com/video.mp4" 

120 ) 

121 self.assertTrue(context["update_metadata_on_release"]) 

122 

123 # Verify mocks were called correctly 

124 mock_dashboard.get_snap_info.assert_called_once() 

125 mock_device_gateway.get_categories.assert_called_once() 

126 mock_categorise_media.assert_called_once() 

127 

128 @patch("webapp.endpoints.publisher.listing.helpers.get_yaml") 

129 @patch("webapp.endpoints.publisher.listing.helpers.get_licenses") 

130 @patch("webapp.endpoints.publisher.listing.logic.filter_categories") 

131 @patch( 

132 "webapp.endpoints.publisher.listing.logic." 

133 "replace_reserved_categories_key" 

134 ) 

135 @patch("webapp.endpoints.publisher.listing.logic.categorise_media") 

136 @patch("webapp.endpoints.publisher.listing.get_categories") 

137 @patch("webapp.endpoints.publisher.listing.device_gateway") 

138 @patch("webapp.endpoints.publisher.listing.dashboard") 

139 def test_get_listing_data_minimal_snap_details( 

140 self, 

141 mock_dashboard, 

142 mock_device_gateway, 

143 mock_get_categories, 

144 mock_categorise_media, 

145 mock_replace_reserved_categories_key, 

146 mock_filter_categories, 

147 mock_get_licenses, 

148 mock_get_yaml, 

149 ): 

150 # Mock minimal snap details 

151 mock_snap_details = { 

152 "title": "Minimal Snap", 

153 "summary": "Minimal test snap", 

154 "description": "A minimal snap for testing edge cases", 

155 "snap_id": "minimal-snap-id", 

156 "public_metrics_enabled": False, 

157 "public_metrics_blacklist": [], 

158 "media": [], 

159 "links": {}, 

160 "license": "Proprietary", 

161 "categories": [], 

162 "video_urls": [], 

163 "update_metadata_on_release": False, 

164 } 

165 mock_dashboard.get_snap_info.return_value = mock_snap_details 

166 

167 # Mock other dependencies with minimal data 

168 mock_device_gateway.get_categories.return_value = [] 

169 mock_get_categories.return_value = [] 

170 mock_categorise_media.return_value = ([], [], []) 

171 mock_replace_reserved_categories_key.return_value = {"categories": []} 

172 mock_filter_categories.return_value = {"categories": []} 

173 mock_get_licenses.return_value = [] 

174 mock_get_yaml.return_value = [] 

175 

176 # Make the request 

177 response = self.client.get("/api/minimal-snap/listing") 

178 data = response.json 

179 

180 # Assert response structure 

181 self.assertEqual(response.status_code, 200) 

182 self.assertTrue(data["success"]) 

183 

184 # Assert minimal data handling 

185 context = data["data"] 

186 self.assertEqual(context["title"], "Minimal Snap") 

187 self.assertEqual(context["primary_website"], "") 

188 self.assertEqual(context["websites"], []) 

189 self.assertEqual(context["primary_category"], "") 

190 self.assertEqual(context["secondary_category"], "") 

191 self.assertIsNone(context["icon_url"]) 

192 self.assertEqual(context["screenshot_urls"], []) 

193 self.assertIsNone(context["video_urls"]) 

194 

195 

196class TestPostListingData(TestEndpoints): 

197 @patch("webapp.endpoints.publisher.listing.dashboard") 

198 @patch("webapp.endpoints.publisher.listing.logic.filter_changes_data") 

199 def test_post_listing_data_success_no_changes( 

200 self, 

201 mock_filter_changes_data, 

202 mock_dashboard, 

203 ): 

204 """Test POST with no changes returns success""" 

205 # Make the request with no changes 

206 response = self.client.post("/api/test-snap/listing") 

207 data = response.json 

208 

209 # Assert response 

210 self.assertEqual(response.status_code, 200) 

211 self.assertTrue(data["success"]) 

212 

213 # Verify no API calls were made since there were no changes 

214 mock_dashboard.snap_screenshots.assert_not_called() 

215 mock_dashboard.snap_metadata.assert_not_called() 

216 

217 @patch("webapp.endpoints.publisher.listing.dashboard") 

218 @patch("webapp.endpoints.publisher.listing.logic.filter_changes_data") 

219 @patch( 

220 "webapp.endpoints.publisher.listing.logic.remove_invalid_characters" 

221 ) 

222 def test_post_listing_data_success_with_metadata_changes( 

223 self, 

224 mock_remove_invalid_characters, 

225 mock_filter_changes_data, 

226 mock_dashboard, 

227 ): 

228 """Test POST with metadata changes (title, description, etc.)""" 

229 # Mock the filter_changes_data to return some changes 

230 mock_filter_changes_data.return_value = { 

231 "title": "Updated Title", 

232 "description": "Updated description with some content", 

233 "summary": "Updated summary", 

234 } 

235 

236 # Mock character removal 

237 mock_remove_invalid_characters.return_value = ( 

238 "Updated description with some content" 

239 ) 

240 

241 # Prepare form data 

242 form_data = { 

243 "changes": ( 

244 '{"title": "Updated Title", ' 

245 '"description": "Updated description"}' 

246 ), 

247 "snap_id": "test-snap-id-123", 

248 } 

249 

250 # Make the request 

251 response = self.client.post("/api/test-snap/listing", data=form_data) 

252 data = response.json 

253 

254 # Assert response 

255 self.assertEqual(response.status_code, 200) 

256 self.assertTrue(data["success"]) 

257 

258 # Verify snap_metadata was called with the filtered data 

259 mock_dashboard.snap_metadata.assert_called_once() 

260 call_args = mock_dashboard.snap_metadata.call_args 

261 self.assertEqual(call_args[0][1], "test-snap-id-123") # snap_id 

262 

263 # Verify description was processed for invalid characters 

264 mock_remove_invalid_characters.assert_called_once_with( 

265 "Updated description with some content" 

266 ) 

267 

268 @patch("webapp.endpoints.publisher.listing.dashboard") 

269 @patch("webapp.endpoints.publisher.listing.logic.build_changed_images") 

270 def test_post_listing_data_success_with_image_changes( 

271 self, 

272 mock_build_changed_images, 

273 mock_dashboard, 

274 ): 

275 """Test POST with image changes (icon, screenshots, banner)""" 

276 # Mock existing screenshots 

277 mock_dashboard.snap_screenshots.side_effect = [ 

278 # First call for current screenshots 

279 [{"type": "screenshot", "url": "existing.png"}], 

280 None, # Second call for updating screenshots 

281 ] 

282 

283 # Mock build_changed_images 

284 mock_build_changed_images.return_value = ( 

285 [{"type": "icon", "url": "new-icon.png"}], # images_json 

286 [], # images_files 

287 ) 

288 

289 # Prepare form data with image changes 

290 form_data = { 

291 "changes": '{"images": {"icon": "new-icon.png"}}', 

292 "snap_id": "test-snap-id-456", 

293 } 

294 

295 # Make the request 

296 response = self.client.post("/api/test-snap/listing", data=form_data) 

297 data = response.json 

298 

299 # Assert response 

300 self.assertEqual(response.status_code, 200) 

301 self.assertTrue(data["success"]) 

302 

303 # Verify screenshots were fetched and updated 

304 self.assertEqual(mock_dashboard.snap_screenshots.call_count, 2) 

305 

306 # Verify build_changed_images was called 

307 mock_build_changed_images.assert_called_once()