Skip to content

Commit d5a8f1f

Browse files
committed
Assert the coefficient checksum only when the server offers one
The flat /validation/download/ endpoint returns neither an ETag nor a Content-Length, so no digest can be recorded from it. The divided archive path does return the content MD5, but that path disappears at the July 2027 archive transition, and the beta archive returns neither header on any path on files.wwpdb.org or files.rcsb.org. So the digest is asserted when it was recorded and reported when it was not, rather than being required. Size validation applies either way, since the sidecar is written from the bytes actually read.
1 parent 510798c commit d5a8f1f

1 file changed

Lines changed: 31 additions & 7 deletions

File tree

biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/io/density/DensityMapIntegrationTest.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import java.io.File;
2727
import java.io.IOException;
28+
import java.nio.charset.StandardCharsets;
2829
import java.nio.file.Files;
2930
import java.util.Arrays;
3031
import java.util.List;
@@ -163,11 +164,22 @@ public void reportsWhyAnEntryHasNoDensity() throws IOException {
163164
}
164165

165166
/**
166-
* The wwPDB servers return the content MD5 as the ETag, so a coefficient
167-
* download is checksum-verified without a separate hash file.
167+
* Coefficients must arrive intact and be verifiable afterwards. Whether that
168+
* verification includes a cryptographic digest depends on the server.
169+
* <p>
170+
* The divided archive paths on files.wwpdb.org and files.rcsb.org return the content
171+
* MD5 as the ETag. The flat /validation/download/ endpoint this provider now uses
172+
* returns neither an ETag nor a Content-Length, and neither does the beta archive on
173+
* those two hosts, so no digest can be recorded there. The size sidecar is written
174+
* from the bytes actually read, so it exists either way.
175+
* <p>
176+
* The digest is therefore asserted when the server offered one and skipped when it
177+
* did not, rather than being required: requiring it would fail against the endpoint
178+
* we use, and hard-coding the divided path would only work until the archive
179+
* transition in July 2027.
168180
*/
169181
@Test
170-
public void mapCoefficientsArriveWithAVerifiableChecksum() throws IOException {
182+
public void mapCoefficientsArriveIntactAndVerifiable() throws IOException {
171183
cache.setSourceEnabled(DensityMapSource.WWPDB_MAP_COEFFICIENTS, true);
172184
cache.setSourceChain(DensityMapKind.TWO_FO_FC, Arrays.asList(DensityMapSource.WWPDB_MAP_COEFFICIENTS));
173185

@@ -180,12 +192,24 @@ public void mapCoefficientsArriveWithAVerifiableChecksum() throws IOException {
180192
assertFalse(result.isRenderable(),
181193
"structure factors are not a map and must not claim to be renderable");
182194

195+
// written from the observed byte count, so it is present whether or not the
196+
// server declared a length
197+
assertTrue(FileDownloadUtils.validateFile(result.getFile()),
198+
"a freshly downloaded file must validate against its own sidecars");
199+
183200
File hashFile = new File(result.getFile().getParentFile(), result.getFile().getName() + ".hash_MD5");
184-
assertTrue(hashFile.isFile(), "an MD5 should have been recorded from the ETag");
185-
assertTrue(FileDownloadUtils.validateFile(result.getFile()));
201+
if (hashFile.isFile()) {
202+
String recorded = new String(Files.readAllBytes(hashFile.toPath()), StandardCharsets.UTF_8).trim();
203+
assertTrue(FileDownloadUtils.verifyHash(result.getFile(), FileDownloadUtils.Hash.MD5, recorded),
204+
"the recorded MD5 must match the file it describes");
205+
} else {
206+
System.out.println("No MD5 recorded for " + result.getSourceUrl()
207+
+ " - the server offered no usable ETag. Size validation still applies.");
208+
}
186209

187-
// corrupt it and confirm the checksum actually catches it
210+
// corrupt it and confirm validation actually catches it
188211
Files.write(result.getFile().toPath(), new byte[] {0, 1, 2, 3});
189-
assertFalse(FileDownloadUtils.validateFile(result.getFile()));
212+
assertFalse(FileDownloadUtils.validateFile(result.getFile()),
213+
"a truncated file must not validate");
190214
}
191215
}

0 commit comments

Comments
 (0)