001package org.fcrepo.migration.handlers.ocfl; 002 003import com.fasterxml.jackson.annotation.JsonInclude; 004import com.fasterxml.jackson.databind.ObjectMapper; 005import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 006import edu.wisc.library.ocfl.api.MutableOcflRepository; 007import edu.wisc.library.ocfl.api.model.FileDetails; 008import edu.wisc.library.ocfl.api.model.ObjectVersionId; 009import edu.wisc.library.ocfl.core.OcflRepositoryBuilder; 010import edu.wisc.library.ocfl.core.extension.storage.layout.config.HashedNTupleLayoutConfig; 011import edu.wisc.library.ocfl.core.path.mapper.LogicalPathMappers; 012import edu.wisc.library.ocfl.core.storage.OcflStorageBuilder; 013import org.apache.commons.codec.digest.DigestUtils; 014import org.apache.commons.io.IOUtils; 015import org.apache.commons.lang3.SystemUtils; 016import org.fcrepo.migration.ContentDigest; 017import org.fcrepo.migration.DatastreamInfo; 018import org.fcrepo.migration.DatastreamVersion; 019import org.fcrepo.migration.DefaultObjectInfo; 020import org.fcrepo.migration.MigrationType; 021import org.fcrepo.migration.ObjectProperties; 022import org.fcrepo.migration.ObjectProperty; 023import org.fcrepo.migration.ObjectVersionReference; 024import org.fcrepo.migration.ResourceMigrationType; 025import org.fcrepo.storage.ocfl.CommitType; 026import org.fcrepo.storage.ocfl.DefaultOcflObjectSessionFactory; 027import org.fcrepo.storage.ocfl.InteractionModel; 028import org.fcrepo.storage.ocfl.OcflObjectSession; 029import org.fcrepo.storage.ocfl.OcflObjectSessionFactory; 030import org.fcrepo.storage.ocfl.PersistencePaths; 031import org.fcrepo.storage.ocfl.ResourceHeadersVersion; 032import org.fcrepo.storage.ocfl.cache.NoOpCache; 033import org.junit.Before; 034import org.junit.Rule; 035import org.junit.Test; 036import org.junit.rules.TemporaryFolder; 037import org.mockito.Mockito; 038import org.mockito.stubbing.Answer; 039 040import java.io.ByteArrayInputStream; 041import java.io.IOException; 042import java.io.InputStream; 043import java.io.UncheckedIOException; 044import java.nio.charset.StandardCharsets; 045import java.nio.file.Files; 046import java.nio.file.Path; 047import java.time.Instant; 048import java.util.List; 049import java.util.Objects; 050 051import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS; 052import static org.hamcrest.MatcherAssert.assertThat; 053import static org.hamcrest.Matchers.allOf; 054import static org.hamcrest.Matchers.containsString; 055import static org.hamcrest.Matchers.not; 056import static org.junit.Assert.assertEquals; 057import static org.junit.Assert.assertFalse; 058import static org.junit.Assert.assertNotEquals; 059import static org.junit.Assert.assertNull; 060import static org.junit.Assert.assertTrue; 061import static org.mockito.Mockito.doReturn; 062import static org.mockito.Mockito.when; 063 064/** 065 * @author pwinckles 066 */ 067public class ArchiveGroupHandlerTest { 068 069 private static final String FCREPO_ROOT = "info:fedora/"; 070 private static final String USER = "fedoraAdmin"; 071 private static final String INLINE = "X"; 072 private static final String PROXY = "E"; 073 private static final String REDIRECT = "R"; 074 private static final String MANAGED = "M"; 075 private static final String DS_ACTIVE = "A"; 076 private static final String DS_INACTIVE = "I"; 077 private static final String DS_DELETED = "D"; 078 private static final String OBJ_ACTIVE = "Active"; 079 private static final String OBJ_INACTIVE = "Inactive"; 080 private static final String OBJ_DELETED = "Deleted"; 081 private static final String RELS_INT = "RELS-INT"; 082 private static final String RELS_EXT = "RELS-EXT"; 083 084 @Rule 085 public TemporaryFolder tempDir = new TemporaryFolder(); 086 087 private Path ocflRoot; 088 private Path staging; 089 090 private MutableOcflRepository ocflRepo; 091 private OcflObjectSessionFactory sessionFactory; 092 private OcflObjectSessionFactory plainSessionFactory; 093 094 private ObjectMapper objectMapper; 095 private String date; 096 private ResourceMigrationType resourceMigrationType; 097 098 @Before 099 public void setup() throws IOException { 100 ocflRoot = tempDir.newFolder("ocfl").toPath(); 101 staging = tempDir.newFolder("staging").toPath(); 102 103 final var logicalPathMapper = SystemUtils.IS_OS_WINDOWS ? 104 LogicalPathMappers.percentEncodingWindowsMapper() : LogicalPathMappers.percentEncodingLinuxMapper(); 105 106 ocflRepo = new OcflRepositoryBuilder() 107 .defaultLayoutConfig(new HashedNTupleLayoutConfig()) 108 .logicalPathMapper(logicalPathMapper) 109 .storage(OcflStorageBuilder.builder().fileSystem(ocflRoot).build()) 110 .workDir(staging) 111 .buildMutable(); 112 113 objectMapper = new ObjectMapper() 114 .configure(WRITE_DATES_AS_TIMESTAMPS, false) 115 .registerModule(new JavaTimeModule()) 116 .setSerializationInclusion(JsonInclude.Include.NON_NULL); 117 118 sessionFactory = new DefaultOcflObjectSessionFactory(ocflRepo, staging, objectMapper, 119 new NoOpCache<>(), new NoOpCache<>(), CommitType.NEW_VERSION, 120 "testing", USER, "info:fedora/fedoraAdmin"); 121 122 plainSessionFactory = new PlainOcflObjectSessionFactory(ocflRepo, staging, 123 "testing", USER, "info:fedora/fedoraAdmin", false); 124 125 date = Instant.now().toString().substring(0, 10); 126 resourceMigrationType = ResourceMigrationType.ARCHIVAL; 127 } 128 129 @Test 130 public void processObjectSingleVersionF6Format() throws IOException { 131 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 132 133 final var pid = "obj1"; 134 final var dsId1 = "ds1"; 135 final var dsId2 = "ds2"; 136 137 final var ds1 = datastreamVersion(dsId1, true, MANAGED, "text/plain", "hello", null); 138 final var ds2 = datastreamVersion(dsId2, true, INLINE, "application/xml", "<xml>goodbye</xml>", null); 139 when(ds2.getSize()).thenReturn(100L); 140 141 handler.processObjectVersions(List.of( 142 objectVersionReference(pid, true, List.of(ds1, ds2)) 143 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 144 145 final var ocflObjectId = addPrefix(pid); 146 final var session = sessionFactory.newSession(ocflObjectId); 147 148 verifyObjectRdf(contentToString(session, ocflObjectId)); 149 verifyObjectHeaders(session, ocflObjectId); 150 151 verifyBinary(contentToString(session, ocflObjectId, dsId1), ds1); 152 verifyHeaders(session, ocflObjectId, dsId1, ds1); 153 verifyDescRdf(session, ocflObjectId, dsId1, ds1); 154 verifyDescHeaders(session, ocflObjectId, dsId1); 155 156 verifyBinary(contentToString(session, ocflObjectId, dsId2), ds2); 157 verifyHeaders(session, ocflObjectId, dsId2, ds2); 158 verifyDescRdf(session, ocflObjectId, dsId2, ds2); 159 verifyDescHeaders(session, ocflObjectId, dsId2); 160 } 161 162 @Test 163 public void processObjectMultipleVersionsF6Format() throws IOException { 164 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 165 166 final var pid = "obj2"; 167 final var dsId1 = "ds3"; 168 final var dsId2 = "ds4"; 169 170 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 171 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 172 173 final var ds2V2 = datastreamVersion(dsId2, false, MANAGED, "text/plain", "fedora", null); 174 175 handler.processObjectVersions(List.of( 176 objectVersionReference(pid, true, List.of(ds1V1, ds2V1)), 177 objectVersionReference(pid, false, List.of(ds2V2)) 178 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 179 180 final var ocflObjectId = addPrefix(pid); 181 final var session = sessionFactory.newSession(ocflObjectId); 182 183 verifyObjectRdf(contentToString(session, ocflObjectId)); 184 verifyObjectHeaders(session, ocflObjectId); 185 186 verifyBinary(contentToString(session, ocflObjectId, dsId1), ds1V1); 187 verifyHeaders(session, ocflObjectId, dsId1, ds1V1); 188 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1); 189 verifyDescHeaders(session, ocflObjectId, dsId1); 190 191 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v1"), ds2V1); 192 verifyHeaders(session, ocflObjectId, dsId2, ds2V1, "v1"); 193 verifyDescRdf(session, ocflObjectId, dsId2, ds2V1, "v1"); 194 verifyDescHeaders(session, ocflObjectId, dsId2, "v1"); 195 196 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v2"), ds2V2); 197 verifyHeaders(session, ocflObjectId, dsId2, ds2V2, "v2"); 198 verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v2"); 199 verifyDescHeaders(session, ocflObjectId, dsId2, "v2"); 200 } 201 202 @Test 203 public void processObjectMultipleVersionsAtomic() throws IOException { 204 resourceMigrationType = ResourceMigrationType.ATOMIC; 205 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, true, false); 206 207 final var pid = "obj2"; 208 final var dsId1 = "ds3"; 209 final var dsId2 = "ds4"; 210 211 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 212 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 213 214 final var ds2V2 = datastreamVersion(dsId2, false, MANAGED, "text/plain", "fedora", null); 215 216 handler.processObjectVersions(List.of( 217 objectVersionReference(pid, true, List.of(ds1V1, ds2V1)), 218 objectVersionReference(pid, false, List.of(ds2V2)) 219 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 220 221 final var ocflObjectId = addPrefix(pid); 222 final var objectSession = sessionFactory.newSession(ocflObjectId); 223 final var ds1Session = sessionFactory.newSession(resourceId(ocflObjectId, dsId1)); 224 final var ds2Session = sessionFactory.newSession(resourceId(ocflObjectId, dsId2)); 225 226 verifyObjectRdf(contentToString(objectSession, ocflObjectId)); 227 verifyObjectHeaders(objectSession, ocflObjectId); 228 229 verifyBinary(contentToString(ds1Session, ocflObjectId, dsId1), ds1V1); 230 verifyHeaders(ds1Session, ocflObjectId, dsId1, ds1V1); 231 verifyDescRdf(ds1Session, ocflObjectId, dsId1, ds1V1); 232 verifyDescHeaders(ds1Session, ocflObjectId, dsId1); 233 234 verifyBinary(contentVersionToString(ds2Session, ocflObjectId, dsId2, "v1"), ds2V1); 235 verifyHeaders(ds2Session, ocflObjectId, dsId2, ds2V1, "v1"); 236 verifyDescRdf(ds2Session, ocflObjectId, dsId2, ds2V1, "v1"); 237 verifyDescHeaders(ds2Session, ocflObjectId, dsId2, "v1"); 238 239 verifyBinary(contentVersionToString(ds2Session, ocflObjectId, dsId2, "v2"), ds2V2); 240 verifyHeaders(ds2Session, ocflObjectId, dsId2, ds2V2, "v2"); 241 verifyDescRdf(ds2Session, ocflObjectId, dsId2, ds2V2, "v2"); 242 verifyDescHeaders(ds2Session, ocflObjectId, dsId2, "v2"); 243 } 244 245 @Test 246 public void updateFilenameFromRelsInt() throws IOException { 247 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 248 249 final var pid = "obj2"; 250 final var dsId1 = "ds3"; 251 252 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 253 final var relsIntV1 = datastreamVersion(RELS_INT, true, MANAGED, "application/rdf+xml", 254 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 255 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 256 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds3\">\n" + 257 "\t\t<fedora-model:downloadFilename>example.xml</fedora-model:downloadFilename>\n" + 258 "\t</rdf:Description>\n" + 259 "</rdf:RDF>", null); 260 261 handler.processObjectVersions(List.of( 262 objectVersionReference(pid, true, List.of(ds1V1)), 263 objectVersionReference(pid, false, List.of(relsIntV1)) 264 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 265 266 final var ocflObjectId = addPrefix(pid); 267 final var session = sessionFactory.newSession(ocflObjectId); 268 269 verifyObjectRdf(contentToString(session, ocflObjectId)); 270 verifyObjectHeaders(session, ocflObjectId); 271 272 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v1"), ds1V1); 273 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v1"); 274 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v1"); 275 verifyDescHeaders(session, ocflObjectId, dsId1, "v1"); 276 277 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v2"), ds1V1); 278 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v2", "example.xml"); 279 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v2"); 280 verifyDescHeaders(session, ocflObjectId, dsId1, "v2"); 281 } 282 283 @Test 284 public void filenameRemovedFromRelsInt() throws IOException { 285 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 286 287 final var pid = "obj2"; 288 final var dsId1 = "ds3"; 289 290 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 291 final var relsIntV1 = datastreamVersion(RELS_INT, true, MANAGED, "application/rdf+xml", 292 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 293 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 294 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds3\">\n" + 295 "\t\t<fedora-model:downloadFilename>example.xml</fedora-model:downloadFilename>\n" + 296 "\t</rdf:Description>\n" + 297 "</rdf:RDF>", null); 298 final var relsIntV2 = datastreamVersion(RELS_INT, false, MANAGED, "application/rdf+xml", 299 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 300 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 301 "</rdf:RDF>", null); 302 303 handler.processObjectVersions(List.of( 304 objectVersionReference(pid, true, List.of(ds1V1)), 305 objectVersionReference(pid, false, List.of(relsIntV1)), 306 objectVersionReference(pid, false, List.of(relsIntV2)) 307 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 308 309 final var ocflObjectId = addPrefix(pid); 310 final var session = sessionFactory.newSession(ocflObjectId); 311 312 verifyObjectRdf(contentToString(session, ocflObjectId)); 313 verifyObjectHeaders(session, ocflObjectId); 314 315 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v1"), ds1V1); 316 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v1"); 317 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v1"); 318 verifyDescHeaders(session, ocflObjectId, dsId1, "v1"); 319 320 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v2"), ds1V1); 321 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v2", "example.xml"); 322 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v2"); 323 verifyDescHeaders(session, ocflObjectId, dsId1, "v2"); 324 325 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v3"), ds1V1); 326 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v3", "ds3-label"); 327 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v3"); 328 verifyDescHeaders(session, ocflObjectId, dsId1, "v3"); 329 } 330 331 @Test 332 public void filenameRemovedFromRelsIntAndLabelChanged() throws IOException { 333 final var handler = createHandler(MigrationType.FEDORA_OCFL, true, false, false); 334 335 final var pid = "obj2"; 336 final var dsId1 = "ds3"; 337 338 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 339 final var relsIntV1 = datastreamVersion(RELS_INT, true, MANAGED, "application/rdf+xml", 340 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 341 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 342 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds3\">\n" + 343 "\t\t<fedora-model:downloadFilename>example.xml</fedora-model:downloadFilename>\n" + 344 "\t</rdf:Description>\n" + 345 "</rdf:RDF>", null); 346 347 final var ds1V2 = datastreamVersion(dsId1, false, false, MANAGED, "application/xml", "<h1>hello</h1>", 348 DS_ACTIVE, null, "test"); 349 final var relsIntV2 = datastreamVersion(RELS_INT, false, MANAGED, "application/rdf+xml", 350 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 351 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 352 "</rdf:RDF>", null); 353 354 handler.processObjectVersions(List.of( 355 objectVersionReference(pid, true, List.of(ds1V1)), 356 objectVersionReference(pid, false, List.of(relsIntV1)), 357 objectVersionReference(pid, false, List.of(relsIntV2, ds1V2)) 358 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 359 360 final var ocflObjectId = addPrefix(pid); 361 final var session = sessionFactory.newSession(ocflObjectId); 362 363 verifyObjectRdf(contentToString(session, ocflObjectId)); 364 verifyObjectHeaders(session, ocflObjectId); 365 366 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v1"), ds1V1); 367 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v1", "ds3-label.xml"); 368 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v1"); 369 verifyDescHeaders(session, ocflObjectId, dsId1, "v1"); 370 371 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v2"), ds1V1); 372 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v2", "example.xml"); 373 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v2"); 374 verifyDescHeaders(session, ocflObjectId, dsId1, "v2"); 375 376 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v3"), ds1V1); 377 verifyHeaders(session, ocflObjectId, dsId1, ds1V2, "v3", "test.xml"); 378 verifyDescRdf(session, ocflObjectId, dsId1, ds1V2, "v3"); 379 verifyDescHeaders(session, ocflObjectId, dsId1, "v3"); 380 } 381 382 @Test 383 public void addRelsTriples() throws IOException { 384 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 385 386 final var pid = "obj2"; 387 final var dsId1 = "ds3"; 388 final var dsId2 = "ds4"; 389 390 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 391 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 392 final var relsExtV1 = datastreamVersion(RELS_EXT, true, MANAGED, "application/rdf+xml", 393 "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 394 "\t<rdf:Description rdf:about=\"info:fedora/obj2\">\n" + 395 "\t\t<hasModel xmlns=\"info:fedora/fedora-system:def/model#\"" + 396 " rdf:resource=\"info:fedora/TestObject\"></hasModel>\n" + 397 "\t\t<isMemberOf xmlns=\"info:fedora/fedora-system:def/relations-external#\"" + 398 " rdf:resource=\"info:fedora/obj1\"></isMemberOf>\n" + 399 "\t</rdf:Description>\n" + 400 "</rdf:RDF>", null); 401 final var relsIntV1 = datastreamVersion(RELS_INT, true, MANAGED, "application/rdf+xml", 402 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 403 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" + 404 " xmlns:example=\"http://example.com/#\">\n" + 405 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds3\">\n" + 406 "\t\t<example:animal>cat</example:animal>\n" + 407 "\t</rdf:Description>\n" + 408 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds4\">\n" + 409 "\t\t<example:animal>dog</example:animal>\n" + 410 "\t</rdf:Description>\n" + 411 "</rdf:RDF>", null); 412 413 final var ds2V2 = datastreamVersion(dsId2, false, MANAGED, "text/plain", "fedora", null); 414 final var relsExtV2 = datastreamVersion(RELS_EXT, false, MANAGED, "application/rdf+xml", 415 "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" + 416 "\t<rdf:Description rdf:about=\"info:fedora/obj2\">\n" + 417 "\t\t<hasModel xmlns=\"info:fedora/fedora-system:def/model#\"" + 418 " rdf:resource=\"info:fedora/ExampleObject\"></hasModel>\n" + 419 "\t\t<isMemberOf xmlns=\"info:fedora/fedora-system:def/relations-external#\"" + 420 " rdf:resource=\"info:fedora/obj1\"></isMemberOf>\n" + 421 "\t</rdf:Description>\n" + 422 "</rdf:RDF>", null); 423 final var relsIntV2 = datastreamVersion(RELS_INT, false, MANAGED, "application/rdf+xml", 424 "<rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\"" + 425 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" + 426 " xmlns:example=\"http://example.com/#\">\n" + 427 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds3\">\n" + 428 "\t\t<example:animal>cat</example:animal>\n" + 429 "\t</rdf:Description>\n" + 430 "\t<rdf:Description rdf:about=\"info:fedora/obj2/ds4\">\n" + 431 "\t\t<example:animal>frog</example:animal>\n" + 432 "\t</rdf:Description>\n" + 433 "</rdf:RDF>", null); 434 435 handler.processObjectVersions(List.of( 436 objectVersionReference(pid, true, List.of(ds1V1, ds2V1, relsExtV1, relsIntV1)), 437 objectVersionReference(pid, false, List.of(ds2V2, relsExtV2)), 438 objectVersionReference(pid, false, List.of(relsIntV2)) 439 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 440 441 final var ocflObjectId = addPrefix(pid); 442 final var session = sessionFactory.newSession(ocflObjectId); 443 444 final var objectRdfV1 = contentVersionToString(session, ocflObjectId, "v1"); 445 verifyObjectRdf(objectRdfV1); 446 assertThat(objectRdfV1, allOf(containsString("TestObject"), containsString("obj1"))); 447 verifyObjectHeaders(session, ocflObjectId); 448 449 verifyBinary(contentToString(session, ocflObjectId, dsId1), ds1V1); 450 verifyHeaders(session, ocflObjectId, dsId1, ds1V1); 451 final var ds1V1Rdf = verifyDescRdf(session, ocflObjectId, dsId1, ds1V1); 452 assertThat(ds1V1Rdf, allOf(containsString("cat"), not(containsString("dog")))); 453 verifyDescHeaders(session, ocflObjectId, dsId1); 454 455 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v1"), ds2V1); 456 verifyHeaders(session, ocflObjectId, dsId2, ds2V1, "v1"); 457 final var ds2V1Rdf = verifyDescRdf(session, ocflObjectId, dsId2, ds2V1, "v1"); 458 assertThat(ds2V1Rdf, allOf(containsString("dog"), not(containsString("cat")))); 459 verifyDescHeaders(session, ocflObjectId, dsId2, "v1"); 460 461 final var objectRdfV2 = contentToString(session, ocflObjectId); 462 verifyObjectRdf(objectRdfV2); 463 assertThat(objectRdfV2, allOf(containsString("ExampleObject"), 464 containsString("obj1"), not(containsString("TestObject")))); 465 466 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v2"), ds2V2); 467 verifyHeaders(session, ocflObjectId, dsId2, ds2V2, "v2"); 468 final var ds2V2Rdf = verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v2"); 469 assertThat(ds2V2Rdf, allOf(containsString("dog"), not(containsString("cat")))); 470 verifyDescHeaders(session, ocflObjectId, dsId2, "v2"); 471 472 final var ds2V3Rdf = verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v3"); 473 assertThat(ds2V3Rdf, allOf(containsString("frog"), 474 not(containsString("cat")), not(containsString("dog")))); 475 } 476 477 @Test 478 public void processObjectMultipleVersionsWithDeletedDsF6Format() throws IOException { 479 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 480 481 final var pid = "obj2"; 482 final var dsId1 = "ds3"; 483 final var dsId2 = "ds4"; 484 485 final var ds1V1 = datastreamVersion(dsId1, true, true, MANAGED, "application/xml", "<h1>hello</h1>", 486 DS_INACTIVE, null, dsId1 + "-label"); 487 final var ds2V1 = datastreamVersion(dsId2, true, false, MANAGED, "text/plain", "goodbye", 488 DS_DELETED, null, dsId2 + "-label"); 489 490 final var ds2V2 = datastreamVersion(dsId2, false, true, MANAGED, "text/plain", "fedora", 491 DS_DELETED, null, dsId2 + "-label"); 492 493 handler.processObjectVersions(List.of( 494 objectVersionReference(pid, true, List.of(ds1V1, ds2V1)), 495 objectVersionReference(pid, false, List.of(ds2V2)) 496 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 497 498 final var ocflObjectId = addPrefix(pid); 499 final var session = sessionFactory.newSession(ocflObjectId); 500 501 verifyObjectRdf(contentToString(session, ocflObjectId)); 502 verifyObjectHeaders(session, ocflObjectId); 503 504 verifyBinary(contentToString(session, ocflObjectId, dsId1), ds1V1); 505 verifyHeaders(session, ocflObjectId, dsId1, ds1V1); 506 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1); 507 verifyDescHeaders(session, ocflObjectId, dsId1); 508 509 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v1"), ds2V1); 510 verifyHeaders(session, ocflObjectId, dsId2, ds2V1, "v1"); 511 verifyDescRdf(session, ocflObjectId, dsId2, ds2V1, "v1"); 512 verifyDescHeaders(session, ocflObjectId, dsId2, "v1"); 513 514 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v2"), ds2V2); 515 verifyHeaders(session, ocflObjectId, dsId2, ds2V2, "v2"); 516 verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v2"); 517 verifyDescHeaders(session, ocflObjectId, dsId2, "v2"); 518 519 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId2)); 520 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId2)); 521 } 522 523 @Test 524 public void processObjectMultipleVersionsAndDeleteInactiveF6Format() throws IOException { 525 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, true, false); 526 527 final var pid = "obj2"; 528 final var dsId1 = "ds3"; 529 final var dsId2 = "ds4"; 530 531 final var ds1V1 = datastreamVersion(dsId1, true, true, MANAGED, "application/xml", "<h1>hello</h1>", 532 DS_INACTIVE, null, dsId1 + "-label"); 533 final var ds2V1 = datastreamVersion(dsId2, true, false, MANAGED, "text/plain", "goodbye", 534 DS_DELETED, null, dsId2 + "-label"); 535 536 final var ds2V2 = datastreamVersion(dsId2, false, true, MANAGED, "text/plain", "fedora", 537 DS_DELETED, null, dsId2 + "-label"); 538 539 handler.processObjectVersions(List.of( 540 objectVersionReference(pid, true, List.of(ds1V1, ds2V1)), 541 objectVersionReference(pid, false, List.of(ds2V2)) 542 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 543 544 final var ocflObjectId = addPrefix(pid); 545 final var session = sessionFactory.newSession(ocflObjectId); 546 547 verifyObjectRdf(contentToString(session, ocflObjectId)); 548 verifyObjectHeaders(session, ocflObjectId); 549 550 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v1"), ds1V1); 551 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v1"); 552 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v1"); 553 verifyDescHeaders(session, ocflObjectId, dsId1, "v1"); 554 555 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v1"), ds2V1); 556 verifyHeaders(session, ocflObjectId, dsId2, ds2V1, "v1"); 557 verifyDescRdf(session, ocflObjectId, dsId2, ds2V1, "v1"); 558 verifyDescHeaders(session, ocflObjectId, dsId2, "v1"); 559 560 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v2"), ds2V2); 561 verifyHeaders(session, ocflObjectId, dsId2, ds2V2, "v2"); 562 verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v2"); 563 verifyDescHeaders(session, ocflObjectId, dsId2, "v2"); 564 565 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId1)); 566 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId1)); 567 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId2)); 568 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId2)); 569 } 570 571 @Test 572 public void processObjectMultipleVersionsAndObjectDeletedF6Format() throws IOException { 573 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 574 575 final var pid = "obj2"; 576 final var dsId1 = "ds3"; 577 final var dsId2 = "ds4"; 578 579 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 580 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 581 582 final var ds2V2 = datastreamVersion(dsId2, false, MANAGED, "text/plain", "fedora", null); 583 584 handler.processObjectVersions(List.of( 585 objectVersionReference(pid, true, OBJ_DELETED, List.of(ds1V1, ds2V1)), 586 objectVersionReference(pid, false, OBJ_DELETED, List.of(ds2V2)) 587 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 588 589 final var ocflObjectId = addPrefix(pid); 590 final var session = sessionFactory.newSession(ocflObjectId); 591 592 verifyObjectRdf(contentVersionToString(session, ocflObjectId, "v1")); 593 verifyObjectHeaders(session, ocflObjectId, "v1"); 594 595 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v1"), ds1V1); 596 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v1"); 597 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v1"); 598 verifyDescHeaders(session, ocflObjectId, dsId1, "v1"); 599 600 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v1"), ds2V1); 601 verifyHeaders(session, ocflObjectId, dsId2, ds2V1, "v1"); 602 verifyDescRdf(session, ocflObjectId, dsId2, ds2V1, "v1"); 603 verifyDescHeaders(session, ocflObjectId, dsId2, "v1"); 604 605 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v2"), ds2V2); 606 verifyHeaders(session, ocflObjectId, dsId2, ds2V2, "v2"); 607 verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v2"); 608 verifyDescHeaders(session, ocflObjectId, dsId2, "v2"); 609 610 verifyResourceDeleted(session, ocflObjectId); 611 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId1)); 612 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId1)); 613 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId2)); 614 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId2)); 615 } 616 617 @Test 618 public void processObjectMultipleVersionsAndObjectInactiveDeletedF6Format() throws IOException { 619 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, true, false); 620 621 final var pid = "obj2"; 622 final var dsId1 = "ds3"; 623 final var dsId2 = "ds4"; 624 625 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 626 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 627 628 final var ds2V2 = datastreamVersion(dsId2, false, MANAGED, "text/plain", "fedora", null); 629 630 handler.processObjectVersions(List.of( 631 objectVersionReference(pid, true, OBJ_INACTIVE, List.of(ds1V1, ds2V1)), 632 objectVersionReference(pid, false, OBJ_INACTIVE, List.of(ds2V2)) 633 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 634 635 final var ocflObjectId = addPrefix(pid); 636 final var session = sessionFactory.newSession(ocflObjectId); 637 638 verifyObjectRdf(contentVersionToString(session, ocflObjectId, "v1")); 639 verifyObjectHeaders(session, ocflObjectId, "v1"); 640 641 verifyBinary(contentVersionToString(session, ocflObjectId, dsId1, "v1"), ds1V1); 642 verifyHeaders(session, ocflObjectId, dsId1, ds1V1, "v1"); 643 verifyDescRdf(session, ocflObjectId, dsId1, ds1V1, "v1"); 644 verifyDescHeaders(session, ocflObjectId, dsId1, "v1"); 645 646 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v1"), ds2V1); 647 verifyHeaders(session, ocflObjectId, dsId2, ds2V1, "v1"); 648 verifyDescRdf(session, ocflObjectId, dsId2, ds2V1, "v1"); 649 verifyDescHeaders(session, ocflObjectId, dsId2, "v1"); 650 651 verifyBinary(contentVersionToString(session, ocflObjectId, dsId2, "v2"), ds2V2); 652 verifyHeaders(session, ocflObjectId, dsId2, ds2V2, "v2"); 653 verifyDescRdf(session, ocflObjectId, dsId2, ds2V2, "v2"); 654 verifyDescHeaders(session, ocflObjectId, dsId2, "v2"); 655 656 verifyResourceDeleted(session, ocflObjectId); 657 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId1)); 658 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId1)); 659 verifyResourceDeleted(session, resourceId(ocflObjectId, dsId2)); 660 verifyResourceDeleted(session, metadataId(ocflObjectId, dsId2)); 661 } 662 663 @Test 664 public void processObjectMultipleVersionsPlainFormat() throws IOException { 665 final var handler = createHandler(MigrationType.PLAIN_OCFL, false, false, false); 666 667 final var pid = "obj2"; 668 final var dsId1 = "ds3"; 669 final var dsId2 = "ds4"; 670 671 final var ds1V1 = datastreamVersion(dsId1, true, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 672 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 673 674 final var ds2V2 = datastreamVersion(dsId2, false, true, MANAGED, "text/plain", "fedora", null); 675 676 handler.processObjectVersions(List.of( 677 objectVersionReference(pid, true, List.of(ds1V1, ds2V1)), 678 objectVersionReference(pid, false, List.of(ds2V2)) 679 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 680 681 final var rootResourceId = addPrefix(pid); 682 683 verifyFcrepoNotExists(rootResourceId); 684 685 verifyObjectRdf(rawContentToString(rootResourceId, PersistencePaths.rdfResource(rootResourceId, rootResourceId) 686 .getContentFilePath())); 687 688 verifyBinary(rawContentVersionToString(rootResourceId, 689 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId1)).getContentFilePath(), 690 "v1"), ds1V1); 691 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 692 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId1)).getContentFilePath(), 693 "v1"), ds1V1); 694 695 verifyBinary(rawContentVersionToString(rootResourceId, 696 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)).getContentFilePath(), 697 "v1"), ds2V1); 698 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 699 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath(), 700 "v1"), ds2V1); 701 702 verifyBinary(rawContentVersionToString(rootResourceId, 703 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)).getContentFilePath(), 704 "v2"), ds2V2); 705 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 706 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath(), 707 "v2"), ds2V2); 708 } 709 710 @Test 711 public void processObjectMultipleVersionsWithDeletedDsPlainFormat() throws IOException { 712 final var handler = createHandler(MigrationType.PLAIN_OCFL, false, false, false); 713 714 final var pid = "obj2"; 715 final var dsId1 = "ds3"; 716 final var dsId2 = "ds4"; 717 718 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 719 final var ds2V1 = datastreamVersion(dsId2, true, false, MANAGED, "text/plain", "goodbye", 720 DS_DELETED, null, dsId2 + "-label"); 721 722 final var ds2V2 = datastreamVersion(dsId2, false, true, MANAGED, "text/plain", "fedora", 723 DS_DELETED, null, dsId2 + "-label"); 724 725 handler.processObjectVersions(List.of( 726 objectVersionReference(pid, true, List.of(ds1V1, ds2V1)), 727 objectVersionReference(pid, false, List.of(ds2V2)) 728 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 729 730 final var rootResourceId = addPrefix(pid); 731 732 verifyFcrepoNotExists(rootResourceId); 733 734 verifyObjectRdf(rawContentToString(rootResourceId, PersistencePaths.rdfResource(rootResourceId, rootResourceId) 735 .getContentFilePath())); 736 737 verifyBinary(rawContentVersionToString(rootResourceId, 738 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId1)).getContentFilePath(), 739 "v1"), ds1V1); 740 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 741 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId1)).getContentFilePath(), 742 "v1"), ds1V1); 743 744 verifyBinary(rawContentVersionToString(rootResourceId, 745 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)).getContentFilePath(), 746 "v1"), ds2V1); 747 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 748 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath(), 749 "v1"), ds2V1); 750 751 verifyBinary(rawContentVersionToString(rootResourceId, 752 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)).getContentFilePath(), 753 "v2"), ds2V2); 754 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 755 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath(), 756 "v2"), ds2V2); 757 758 rawVerifyDoesNotExist(rootResourceId, 759 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)) 760 .getContentFilePath()); 761 rawVerifyDoesNotExist(rootResourceId, 762 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath()); 763 } 764 765 @Test 766 public void processObjectMultipleVersionsWithInactiveDeletedObjectPlainFormat() throws IOException { 767 final var handler = createHandler(MigrationType.PLAIN_OCFL, false, true, false); 768 769 final var pid = "obj2"; 770 final var dsId1 = "ds3"; 771 final var dsId2 = "ds4"; 772 773 final var ds1V1 = datastreamVersion(dsId1, true, MANAGED, "application/xml", "<h1>hello</h1>", null); 774 final var ds2V1 = datastreamVersion(dsId2, true, MANAGED, "text/plain", "goodbye", null); 775 776 final var ds2V2 = datastreamVersion(dsId2, false, MANAGED, "text/plain", "fedora", null); 777 778 handler.processObjectVersions(List.of( 779 objectVersionReference(pid, true, OBJ_INACTIVE, List.of(ds1V1, ds2V1)), 780 objectVersionReference(pid, false, OBJ_INACTIVE, List.of(ds2V2)) 781 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 782 783 final var rootResourceId = addPrefix(pid); 784 785 verifyFcrepoNotExists(rootResourceId); 786 787 verifyObjectRdf(rawContentVersionToString(rootResourceId, 788 PersistencePaths.rdfResource(rootResourceId, rootResourceId).getContentFilePath(), "v1")); 789 790 verifyBinary(rawContentVersionToString(rootResourceId, 791 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId1)).getContentFilePath(), 792 "v1"), ds1V1); 793 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 794 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId1)).getContentFilePath(), 795 "v1"), ds1V1); 796 797 verifyBinary(rawContentVersionToString(rootResourceId, 798 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)).getContentFilePath(), 799 "v1"), ds2V1); 800 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 801 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath(), 802 "v1"), ds2V1); 803 804 verifyBinary(rawContentVersionToString(rootResourceId, 805 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)).getContentFilePath(), 806 "v2"), ds2V2); 807 verifyPlainDescRdf(rawContentVersionToString(rootResourceId, 808 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath(), 809 "v2"), ds2V2); 810 811 rawVerifyDoesNotExist(rootResourceId, PersistencePaths.rdfResource(rootResourceId, rootResourceId) 812 .getContentFilePath()); 813 814 rawVerifyDoesNotExist(rootResourceId, 815 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId1)) 816 .getContentFilePath()); 817 rawVerifyDoesNotExist(rootResourceId, 818 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId1)).getContentFilePath()); 819 820 rawVerifyDoesNotExist(rootResourceId, 821 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)) 822 .getContentFilePath()); 823 rawVerifyDoesNotExist(rootResourceId, 824 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)).getContentFilePath()); 825 } 826 827 @Test 828 public void processObjectSingleVersionF6FormatWithExtensions() throws IOException { 829 final var handler = createHandler(MigrationType.FEDORA_OCFL, true, false, false); 830 831 final var pid = "obj1"; 832 final var dsId1 = "ds1"; 833 final var dsId2 = "ds2"; 834 final var dsId3 = "ds3"; 835 836 final var ds1 = datastreamVersion(dsId1, true, MANAGED, "text/plain", "text", null); 837 final var ds2 = datastreamVersion(dsId2, true, MANAGED, "application/rdf+xml", "xml", null); 838 final var ds3 = datastreamVersion(dsId3, true, MANAGED, "image/jpeg", "image", null); 839 840 handler.processObjectVersions(List.of( 841 objectVersionReference(pid, true, List.of(ds1, ds2, ds3)) 842 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 843 844 final var ocflObjectId = addPrefix(pid); 845 final var session = sessionFactory.newSession(ocflObjectId); 846 847 verifyObjectRdf(contentToString(session, ocflObjectId)); 848 verifyObjectHeaders(session, ocflObjectId); 849 850 verifyBinary(contentToString(session, ocflObjectId, dsId1), ds1); 851 verifyHeaders(session, ocflObjectId, dsId1, ds1, "v1", "ds1-label.txt"); 852 verifyDescRdf(session, ocflObjectId, dsId1, ds1); 853 verifyDescHeaders(session, ocflObjectId, dsId1); 854 855 verifyBinary(contentToString(session, ocflObjectId, dsId2), ds2); 856 verifyHeaders(session, ocflObjectId, dsId2, ds2, "v1", "ds2-label.rdf"); 857 verifyDescRdf(session, ocflObjectId, dsId2, ds2); 858 verifyDescHeaders(session, ocflObjectId, dsId2); 859 860 verifyBinary(contentToString(session, ocflObjectId, dsId3), ds3); 861 verifyHeaders(session, ocflObjectId, dsId3, ds3, "v1", "ds3-label.jpg"); 862 verifyDescRdf(session, ocflObjectId, dsId3, ds3); 863 verifyDescHeaders(session, ocflObjectId, dsId3); 864 } 865 866 @Test 867 public void processObjectSingleVersionPlainFormatWithExtensions() throws IOException { 868 final var handler = createHandler(MigrationType.PLAIN_OCFL, true, false, false); 869 870 final var pid = "obj1"; 871 final var dsId1 = "ds1"; 872 final var dsId2 = "ds2"; 873 final var dsId3 = "ds3"; 874 875 final var ds1 = datastreamVersion(dsId1, true, MANAGED, "text/plain", "text", null); 876 final var ds2 = datastreamVersion(dsId2, true, MANAGED, "application/rdf+xml", "xml", null); 877 final var ds3 = datastreamVersion(dsId3, true, MANAGED, "image/jpeg", "image", null); 878 879 handler.processObjectVersions(List.of( 880 objectVersionReference(pid, true, List.of(ds1, ds2, ds3)) 881 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 882 883 final var rootResourceId = addPrefix(pid); 884 885 verifyFcrepoNotExists(rootResourceId); 886 887 verifyObjectRdf(rawContentToString(rootResourceId, PersistencePaths.rdfResource(rootResourceId, rootResourceId) 888 .getContentFilePath())); 889 890 verifyBinary(rawContentToString(rootResourceId, 891 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId1)) 892 .getContentFilePath()), 893 ds1); 894 verifyPlainDescRdf(rawContentToString(rootResourceId, 895 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId1)) 896 .getContentFilePath()), 897 ds1); 898 899 verifyBinary(rawContentToString(rootResourceId, 900 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)) 901 .getContentFilePath()), 902 ds2); 903 verifyPlainDescRdf(rawContentToString(rootResourceId, 904 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId2)) 905 .getContentFilePath()), 906 ds2); 907 908 verifyBinary(rawContentToString(rootResourceId, 909 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId3)) 910 .getContentFilePath()), 911 ds3); 912 verifyPlainDescRdf(rawContentToString(rootResourceId, 913 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId3)) 914 .getContentFilePath()), 915 ds3); 916 } 917 918 @Test 919 public void processObjectSingleVersionF6FormatWithExternalBinary() throws IOException { 920 final var handler = createHandler(MigrationType.FEDORA_OCFL, false, false, false); 921 922 final var pid = "obj1"; 923 final var dsId1 = "ds1"; 924 final var dsId2 = "ds2"; 925 final var dsId3 = "ds3"; 926 927 final var ds1 = datastreamVersion(dsId1, true, MANAGED, "text/plain", "hello", null); 928 final var ds2 = datastreamVersion(dsId2, true, PROXY, "text/plain", "", "https://external"); 929 final var ds3 = datastreamVersion(dsId3, true, REDIRECT, "text/plain", "", "https://redirect"); 930 931 handler.processObjectVersions(List.of( 932 objectVersionReference(pid, true, List.of(ds1, ds2, ds3)) 933 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 934 935 final var ocflObjectId = addPrefix(pid); 936 final var session = sessionFactory.newSession(ocflObjectId); 937 938 verifyObjectRdf(contentToString(session, ocflObjectId)); 939 verifyObjectHeaders(session, ocflObjectId); 940 941 verifyBinary(contentToString(session, ocflObjectId, dsId1), ds1); 942 verifyHeaders(session, ocflObjectId, dsId1, ds1); 943 verifyDescRdf(session, ocflObjectId, dsId1, ds1); 944 verifyDescHeaders(session, ocflObjectId, dsId1); 945 946 verifyContentNotExists(session, resourceId(ocflObjectId, dsId2)); 947 verifyHeaders(session, ocflObjectId, dsId2, ds2); 948 verifyDescRdf(session, ocflObjectId, dsId2, ds2); 949 verifyDescHeaders(session, ocflObjectId, dsId2); 950 951 verifyContentNotExists(session, resourceId(ocflObjectId, dsId3)); 952 verifyHeaders(session, ocflObjectId, dsId3, ds3); 953 verifyDescRdf(session, ocflObjectId, dsId3, ds3); 954 verifyDescHeaders(session, ocflObjectId, dsId3); 955 } 956 957 @Test 958 public void processObjectSingleVersionPlainFormatWithExternalBinary() throws IOException { 959 final var handler = createHandler(MigrationType.PLAIN_OCFL, false, false, false); 960 961 final var pid = "obj1"; 962 final var dsId1 = "ds1"; 963 final var dsId2 = "ds2"; 964 final var dsId3 = "ds3"; 965 966 final var ds1 = datastreamVersion(dsId1, true, MANAGED, "text/plain", "hello", null); 967 final var ds2 = datastreamVersion(dsId2, true, PROXY, "text/plain", "", "https://external"); 968 final var ds3 = datastreamVersion(dsId3, true, REDIRECT, "text/plain", "", "https://redirect"); 969 970 handler.processObjectVersions(List.of( 971 objectVersionReference(pid, true, List.of(ds1, ds2, ds3)) 972 ), new DefaultObjectInfo(pid, pid, Files.createTempFile(tempDir.getRoot().toPath(), "foxml", "xml"))); 973 974 final var rootResourceId = addPrefix(pid); 975 976 verifyFcrepoNotExists(rootResourceId); 977 978 verifyObjectRdf(rawContentToString(rootResourceId, PersistencePaths.rdfResource(rootResourceId, rootResourceId) 979 .getContentFilePath())); 980 981 verifyBinary(rawContentToString(rootResourceId, 982 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId1)) 983 .getContentFilePath()), 984 ds1); 985 verifyPlainDescRdf(rawContentToString(rootResourceId, 986 PersistencePaths.rdfResource(rootResourceId, metadataId(rootResourceId, dsId1)).getContentFilePath()), 987 ds1); 988 989 verifyBinary(rawContentToString(rootResourceId, 990 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId2)) 991 .getContentFilePath()), 992 ds2); 993 994 verifyBinary(rawContentToString(rootResourceId, 995 PersistencePaths.nonRdfResource(rootResourceId, resourceId(rootResourceId, dsId3)) 996 .getContentFilePath()), 997 ds3); 998 } 999 1000 private void verifyBinary(final String content, final DatastreamVersion datastreamVersion) { 1001 try { 1002 if ("RE".contains(datastreamVersion.getDatastreamInfo().getControlGroup())) { 1003 assertEquals(datastreamVersion.getExternalOrRedirectURL(), content); 1004 } else { 1005 assertEquals(IOUtils.toString(datastreamVersion.getContent()), content); 1006 } 1007 } catch (IOException e) { 1008 throw new UncheckedIOException(e); 1009 } 1010 } 1011 1012 private void verifyHeaders(final OcflObjectSession session, 1013 final String ocflObjectId, 1014 final String dsId, 1015 final DatastreamVersion datastreamVersion) { 1016 verifyHeaders(session, ocflObjectId, dsId, datastreamVersion, null); 1017 } 1018 1019 private void verifyHeaders(final OcflObjectSession session, 1020 final String ocflObjectId, 1021 final String dsId, 1022 final DatastreamVersion datastreamVersion, 1023 final String versionNumber) { 1024 verifyHeaders(session, ocflObjectId, dsId, datastreamVersion, versionNumber, dsId + "-label"); 1025 } 1026 1027 private void verifyHeaders(final OcflObjectSession session, 1028 final String ocflObjectId, 1029 final String dsId, 1030 final DatastreamVersion datastreamVersion, 1031 final String versionNumber, 1032 final String filename) { 1033 final var resourceId = resourceId(ocflObjectId, dsId); 1034 try (final var content = session.readContent(resourceId, versionNumber)) { 1035 final var headers = content.getHeaders(); 1036 assertEquals(ResourceHeadersVersion.V1_0, headers.getHeadersVersion()); 1037 assertEquals(resourceId, headers.getId()); 1038 assertEquals(ocflObjectId, headers.getParent()); 1039 if (ResourceMigrationType.ARCHIVAL == resourceMigrationType) { 1040 assertEquals(ocflObjectId, headers.getArchivalGroupId()); 1041 assertFalse("not root", headers.isObjectRoot()); 1042 } else { 1043 assertNull("no AG", headers.getArchivalGroupId()); 1044 assertTrue("is root", headers.isObjectRoot()); 1045 } 1046 assertEquals(InteractionModel.NON_RDF.getUri(), headers.getInteractionModel()); 1047 assertFalse("not AG", headers.isArchivalGroup()); 1048 assertFalse("not deleted", headers.isDeleted()); 1049 assertEquals(USER, headers.getCreatedBy()); 1050 assertEquals(USER, headers.getLastModifiedBy()); 1051 assertThat(headers.getLastModifiedDate().toString(), containsString(date)); 1052 assertThat(headers.getMementoCreatedDate().toString(), containsString(date)); 1053 assertThat(headers.getCreatedDate().toString(), containsString(date)); 1054 if (INLINE.equals(datastreamVersion.getDatastreamInfo().getControlGroup())) { 1055 assertNotEquals(datastreamVersion.getSize(), headers.getContentSize()); 1056 } else { 1057 assertEquals(datastreamVersion.getSize(), headers.getContentSize()); 1058 } 1059 assertEquals(datastreamVersion.getMimeType(), headers.getMimeType()); 1060 assertEquals(filename, headers.getFilename()); 1061 assertEquals(DigestUtils.md5Hex( 1062 String.valueOf(Instant.parse(datastreamVersion.getCreated()).toEpochMilli())).toUpperCase(), 1063 headers.getStateToken()); 1064 if (headers.getExternalHandling() != null) { 1065 assertEquals(1, headers.getDigests().size()); 1066 } else { 1067 assertEquals(2, headers.getDigests().size()); 1068 } 1069 assertEquals(datastreamVersion.getExternalOrRedirectURL(), headers.getExternalUrl()); 1070 if (Objects.equals(REDIRECT, datastreamVersion.getDatastreamInfo().getControlGroup())) { 1071 assertEquals("redirect", headers.getExternalHandling()); 1072 } else if (Objects.equals(PROXY, datastreamVersion.getDatastreamInfo().getControlGroup())) { 1073 assertEquals("proxy", headers.getExternalHandling()); 1074 } 1075 } catch (Exception e) { 1076 throw new RuntimeException(e); 1077 } 1078 } 1079 1080 private void verifyDescHeaders(final OcflObjectSession session, 1081 final String ocflObjectId, 1082 final String dsId) { 1083 verifyDescHeaders(session, ocflObjectId, dsId, null); 1084 } 1085 1086 private void verifyDescHeaders(final OcflObjectSession session, 1087 final String ocflObjectId, 1088 final String dsId, 1089 final String versionNumber) { 1090 try (final var content = session.readContent(metadataId(ocflObjectId, dsId), versionNumber)) { 1091 final var headers = content.getHeaders(); 1092 assertEquals(ResourceHeadersVersion.V1_0, headers.getHeadersVersion()); 1093 assertEquals(metadataId(ocflObjectId, dsId), headers.getId()); 1094 assertEquals(resourceId(ocflObjectId, dsId), headers.getParent()); 1095 if (ResourceMigrationType.ARCHIVAL == resourceMigrationType) { 1096 assertEquals(ocflObjectId, headers.getArchivalGroupId()); 1097 } else { 1098 assertNull("no AG", headers.getArchivalGroupId()); 1099 } 1100 assertEquals(InteractionModel.NON_RDF_DESCRIPTION.getUri(), headers.getInteractionModel()); 1101 assertFalse("not AG", headers.isArchivalGroup()); 1102 assertFalse("not root", headers.isObjectRoot()); 1103 assertFalse("not deleted", headers.isDeleted()); 1104 assertEquals(USER, headers.getCreatedBy()); 1105 assertEquals(USER, headers.getLastModifiedBy()); 1106 assertThat(headers.getLastModifiedDate().toString(), containsString(date)); 1107 assertThat(headers.getMementoCreatedDate().toString(), containsString(date)); 1108 assertThat(headers.getCreatedDate().toString(), containsString(date)); 1109 } catch (Exception e) { 1110 throw new RuntimeException(e); 1111 } 1112 } 1113 1114 private void verifyObjectHeaders(final OcflObjectSession session, 1115 final String ocflObjectId) { 1116 verifyObjectHeaders(session, ocflObjectId, null); 1117 } 1118 1119 private void verifyObjectHeaders(final OcflObjectSession session, 1120 final String ocflObjectId, 1121 final String versionNumber) { 1122 try (final var content = session.readContent(ocflObjectId, versionNumber)) { 1123 final var headers = content.getHeaders(); 1124 assertEquals(ResourceHeadersVersion.V1_0, headers.getHeadersVersion()); 1125 assertEquals(ocflObjectId, headers.getId()); 1126 assertEquals(FCREPO_ROOT, headers.getParent()); 1127 assertEquals(InteractionModel.BASIC_CONTAINER.getUri(), headers.getInteractionModel()); 1128 assertEquals("is AG", ResourceMigrationType.ARCHIVAL == resourceMigrationType, 1129 headers.isArchivalGroup()); 1130 assertTrue("is root", headers.isObjectRoot()); 1131 assertFalse("not deleted", headers.isDeleted()); 1132 assertEquals(USER, headers.getCreatedBy()); 1133 assertEquals(USER, headers.getLastModifiedBy()); 1134 assertThat(headers.getLastModifiedDate().toString(), containsString(date)); 1135 assertThat(headers.getMementoCreatedDate().toString(), containsString(date)); 1136 assertThat(headers.getCreatedDate().toString(), containsString(date)); 1137 } catch (Exception e) { 1138 throw new RuntimeException(e); 1139 } 1140 } 1141 1142 private String verifyDescRdf(final OcflObjectSession session, 1143 final String ocflObjectId, 1144 final String dsId, 1145 final DatastreamVersion datastreamVersion) { 1146 return verifyDescRdf(session, ocflObjectId, dsId, datastreamVersion, null); 1147 } 1148 1149 private String verifyDescRdf(final OcflObjectSession session, 1150 final String ocflObjectId, 1151 final String dsId, 1152 final DatastreamVersion datastreamVersion, 1153 final String versionNumber) { 1154 try (final var content = session.readContent(metadataId(ocflObjectId, dsId), versionNumber)) { 1155 final var value = IOUtils.toString(content.getContentStream().get()); 1156 assertThat(value, allOf( 1157 containsString(datastreamVersion.getLabel()), 1158 containsString(datastreamVersion.getFormatUri()), 1159 containsString("objState") 1160 )); 1161 return value; 1162 } catch (Exception e) { 1163 throw new RuntimeException(e); 1164 } 1165 } 1166 1167 private void verifyPlainDescRdf(final String content, 1168 final DatastreamVersion datastreamVersion) { 1169 assertThat(content, allOf( 1170 containsString(datastreamVersion.getLabel()), 1171 containsString(datastreamVersion.getFormatUri()), 1172 containsString(datastreamVersion.getMimeType()), 1173 containsString(datastreamVersion.getDatastreamInfo().getDatastreamId()), 1174 containsString("objState"), 1175 containsString("hasMessageDigest"), 1176 containsString("lastModified"), 1177 containsString(date), 1178 containsString("created"))); 1179 } 1180 1181 private void verifyObjectRdf(final String content) { 1182 assertThat(content, allOf( 1183 containsString("lastModifiedDate"), 1184 containsString(date), 1185 containsString("createdDate") 1186 )); 1187 } 1188 1189 private String contentToString(final OcflObjectSession session, final String ocflObjectId) { 1190 return contentVersionToString(session, ocflObjectId, null); 1191 } 1192 1193 private String contentVersionToString(final OcflObjectSession session, 1194 final String ocflObjectId, 1195 final String versionNumber) { 1196 try (final var content = session.readContent(ocflObjectId, versionNumber)) { 1197 return IOUtils.toString(content.getContentStream().get()); 1198 } catch (IOException e) { 1199 throw new UncheckedIOException(e); 1200 } 1201 } 1202 1203 private String contentToString(final OcflObjectSession session, final String ocflObjectId, final String dsId) { 1204 return contentVersionToString(session, ocflObjectId, dsId, null); 1205 } 1206 1207 private String contentVersionToString(final OcflObjectSession session, 1208 final String ocflObjectId, 1209 final String dsId, 1210 final String versionNumber) { 1211 try (final var content = session.readContent(resourceId(ocflObjectId, dsId), versionNumber)) { 1212 return IOUtils.toString(content.getContentStream().get()); 1213 } catch (IOException e) { 1214 throw new UncheckedIOException(e); 1215 } 1216 } 1217 1218 private String rawContentToString(final String ocflObjectId, final String path) { 1219 try (final var content = ocflRepo.getObject(ObjectVersionId.head(ocflObjectId)) 1220 .getFile(path).getStream()) { 1221 return IOUtils.toString(content); 1222 } catch (IOException e) { 1223 throw new UncheckedIOException(e); 1224 } 1225 } 1226 1227 private String rawContentVersionToString(final String ocflObjectId, final String path, final String versionNumber) { 1228 try (final var content = ocflRepo.getObject( 1229 ObjectVersionId.version(ocflObjectId, versionNumber)).getFile(path).getStream()) { 1230 return IOUtils.toString(content); 1231 } catch (IOException e) { 1232 throw new UncheckedIOException(e); 1233 } 1234 } 1235 1236 private void rawVerifyDoesNotExist(final String ocflObjectId, final String path) { 1237 assertFalse(String.format("object %s not contain path %s", ocflObjectId, path), 1238 ocflRepo.describeVersion(ObjectVersionId.head(ocflObjectId)).containsFile(path)); 1239 } 1240 1241 private ArchiveGroupHandler createHandler(final MigrationType migrationType, 1242 final boolean addExtensions, 1243 final boolean deleteInactive, 1244 final boolean headOnly) { 1245 if (migrationType == MigrationType.PLAIN_OCFL) { 1246 return new ArchiveGroupHandler(plainSessionFactory, migrationType, resourceMigrationType, 1247 addExtensions, deleteInactive, 1248 false, USER, "info:fedora/", headOnly, false, false); 1249 } else { 1250 return new ArchiveGroupHandler(sessionFactory, migrationType, resourceMigrationType, 1251 addExtensions, deleteInactive, false, USER, 1252 "info:fedora/", headOnly, false, false); 1253 } 1254 } 1255 1256 private ObjectVersionReference objectVersionReference(final String pid, 1257 final boolean isFirst, 1258 final List<DatastreamVersion> datastreamVersions) 1259 throws IOException { 1260 return objectVersionReference(pid, isFirst, OBJ_ACTIVE, datastreamVersions); 1261 } 1262 1263 private ObjectVersionReference objectVersionReference(final String pid, 1264 final boolean isFirst, 1265 final String state, 1266 final List<DatastreamVersion> datastreamVersions) 1267 throws IOException { 1268 final var mock = Mockito.mock(ObjectVersionReference.class); 1269 when(mock.isFirstVersion()).thenReturn(isFirst); 1270 if (isFirst) { 1271 final var properties = objectProperties(List.of( 1272 objectProperty("info:fedora/fedora-system:def/view#lastModifiedDate", Instant.now().toString()), 1273 objectProperty("info:fedora/fedora-system:def/model#createdDate", Instant.now().toString()), 1274 objectProperty("info:fedora/fedora-system:def/model#state", state) 1275 )); 1276 when(mock.getObjectProperties()).thenReturn(properties); 1277 } 1278 when(mock.getObject()).thenReturn(null); 1279 when(mock.listChangedDatastreams()).thenReturn(datastreamVersions); 1280 when(mock.getVersionDate()).thenReturn(Instant.now().toString()); 1281 return mock; 1282 } 1283 1284 private ObjectProperties objectProperties(final List<? extends ObjectProperty> properties) { 1285 final var mock = Mockito.mock(ObjectProperties.class); 1286 doReturn(properties).when(mock).listProperties(); 1287 return mock; 1288 } 1289 1290 private ObjectProperty objectProperty(final String name, final String value) { 1291 final var mock = Mockito.mock(ObjectProperty.class); 1292 when(mock.getName()).thenReturn(name); 1293 when(mock.getValue()).thenReturn(value); 1294 return mock; 1295 } 1296 1297 private DatastreamVersion datastreamVersion(final String datastreamId, 1298 final boolean isFirst, 1299 final String controlGroup, 1300 final String mimeType, 1301 final String content, 1302 final String externalUrl) { 1303 return datastreamVersion(datastreamId, isFirst, false, controlGroup, mimeType, 1304 content, DS_ACTIVE, externalUrl, datastreamId + "-label"); 1305 } 1306 1307 private DatastreamVersion datastreamVersion(final String datastreamId, 1308 final boolean isFirst, 1309 final boolean isLast, 1310 final String controlGroup, 1311 final String mimeType, 1312 final String content, 1313 final String externalUrl) { 1314 return datastreamVersion(datastreamId, isFirst, isLast, controlGroup, mimeType, 1315 content, DS_ACTIVE, externalUrl, datastreamId + "-label"); 1316 } 1317 1318 private DatastreamVersion datastreamVersion(final String datastreamId, 1319 final boolean isFirst, 1320 final boolean isLast, 1321 final String controlGroup, 1322 final String mimeType, 1323 final String content, 1324 final String state, 1325 final String externalUrl, 1326 final String label) { 1327 final var mock = Mockito.mock(DatastreamVersion.class); 1328 final var info = datastreamInfo(datastreamId, controlGroup, state); 1329 when(mock.getDatastreamInfo()).thenReturn(info); 1330 when(mock.getMimeType()).thenReturn(mimeType); 1331 try { 1332 when(mock.getContent()).thenAnswer((Answer<InputStream>) invocation -> { 1333 return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); 1334 }); 1335 } catch (IOException e) { 1336 throw new UncheckedIOException(e); 1337 } 1338 when(mock.isLastVersionIn(Mockito.isNull())).thenReturn(isLast); 1339 when(mock.isFirstVersionIn(Mockito.isNull())).thenReturn(isFirst); 1340 when(mock.getCreated()).thenReturn(Instant.now().toString()); 1341 when(mock.getExternalOrRedirectURL()).thenReturn(externalUrl); 1342 when(mock.getSize()).thenReturn((long) content.length()); 1343 final var contentDigest = contentDigest(content); 1344 when(mock.getContentDigest()).thenReturn(contentDigest); 1345 when(mock.getLabel()).thenReturn(label); 1346 when(mock.getFormatUri()).thenReturn("http://format-id"); 1347 return mock; 1348 } 1349 1350 private DatastreamInfo datastreamInfo(final String datastreamId, final String controlGroup, final String state) { 1351 final var mock = Mockito.mock(DatastreamInfo.class); 1352 when(mock.getDatastreamId()).thenReturn(datastreamId); 1353 when(mock.getControlGroup()).thenReturn(controlGroup); 1354 when(mock.getState()).thenReturn(state); 1355 return mock; 1356 } 1357 1358 private ContentDigest contentDigest(final String content) { 1359 final var mock = Mockito.mock(ContentDigest.class); 1360 when(mock.getType()).thenReturn("md5"); 1361 when(mock.getDigest()).thenReturn(DigestUtils.md5Hex(content)); 1362 return mock; 1363 } 1364 1365 private String addPrefix(final String pid) { 1366 return FCREPO_ROOT + pid; 1367 } 1368 1369 private String resourceId(final String ocflObjectId, final String dsId) { 1370 return ocflObjectId + "/" + dsId; 1371 } 1372 1373 private String metadataId(final String ocflObjectId, final String dsId) { 1374 return resourceId(ocflObjectId, dsId) + "/fcr:metadata"; 1375 } 1376 1377 private void verifyFcrepoNotExists(final String ocflObjectId) { 1378 final var count = ocflRepo.describeVersion(ObjectVersionId.head(ocflObjectId)).getFiles().stream() 1379 .map(FileDetails::getPath) 1380 .filter(file -> file.startsWith(".fcrepo/")) 1381 .count(); 1382 assertEquals(0, count); 1383 } 1384 1385 private void verifyContentNotExists(final OcflObjectSession session, final String ocflObjectId) { 1386 try (final var content = session.readContent(ocflObjectId)) { 1387 assertTrue("Content should not exist", content.getContentStream().isEmpty()); 1388 } catch (IOException e) { 1389 throw new UncheckedIOException(e); 1390 } 1391 } 1392 1393 private void verifyResourceDeleted(final OcflObjectSession session, final String ocflObjectId) { 1394 final var headers = session.readHeaders(ocflObjectId); 1395 assertTrue("resource " + ocflObjectId + " should be deleted", headers.isDeleted()); 1396 verifyContentNotExists(session, ocflObjectId); 1397 } 1398 1399}