@@ -217,9 +217,19 @@ void testValidationFiles() throws IOException{
217217 @ Nested
218218 class HttpStatus {
219219
220- @ Test
221- void notFoundThrowsAndLeavesNothingBehind () throws IOException {
222- // A path that is guaranteed absent from the wwPDB archive.
220+ /**
221+ * Which status an absent file comes back with is the server's business, and it
222+ * changes: files.wwpdb.org moved behind Amazon S3 in September 2026, and S3
223+ * answers a missing key with 403 rather than 404 when the caller cannot list
224+ * the bucket. Pinning the code made this test fail on an upstream hosting
225+ * change that broke nothing.
226+ * <p>
227+ * What must hold is the contract: an error status throws, and nothing is left
228+ * on disk for it. {@link HttpStatusException#isNotFound()} is pinned separately
229+ * below, without a network.
230+ */
231+ @ Test
232+ void anAbsentFileThrowsAndLeavesNothingBehind () throws IOException {
223233 URL missing = new URL ("https://files.wwpdb.org/pub/pdb/data/structures/divided/mmCIF/zz/zzzz.cif.gz" );
224234 File dest = new File (System .getProperty ("java.io.tmpdir" ), "bj-missing.cif.gz" );
225235 File sizeFile = new File (dest .getParentFile (), dest .getName () + ".size" );
@@ -228,14 +238,24 @@ void notFoundThrowsAndLeavesNothingBehind() throws IOException {
228238
229239 HttpStatusException e = assertThrows (HttpStatusException .class ,
230240 () -> FileDownloadUtils .downloadFile (missing , dest ));
231- assertEquals ( 404 , e .getStatusCode ());
232- assertTrue ( e . isNotFound ());
233- assertFalse (dest .exists (), "a 404 body must never be written to the destination" );
241+ assertTrue ( e .getStatusCode () >= 400 ,
242+ "an absent file must report an error status, got " + e . getStatusCode ());
243+ assertFalse (dest .exists (), "an error body must never be written to the destination" );
234244
235245 // ... and no validation metadata may be recorded for it either, or the
236246 // cached error page would later pass validation.
237247 FileDownloadUtils .createValidationFiles (missing , dest , null , FileDownloadUtils .Hash .UNKNOWN );
238- assertFalse (sizeFile .exists (), "no size file should be written for a 404 response" );
248+ assertFalse (sizeFile .exists (), "no size file should be written for an error response" );
249+ }
250+
251+ @ Test
252+ void isNotFoundCoversTheAbsentStatusesOnly () {
253+ assertTrue (new HttpStatusException (404 , "http://example.org/x" , "Not Found" ).isNotFound ());
254+ assertTrue (new HttpStatusException (410 , "http://example.org/x" , "Gone" ).isNotFound ());
255+ // 403 is what an S3-backed archive returns for a missing key, but it is not a
256+ // statement that the file does not exist, so it must not claim to be one
257+ assertFalse (new HttpStatusException (403 , "http://example.org/x" , "Forbidden" ).isNotFound ());
258+ assertFalse (new HttpStatusException (500 , "http://example.org/x" , "Server Error" ).isNotFound ());
239259 }
240260 }
241261
0 commit comments