001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.kernel.impl.models; 007 008import org.apache.jena.graph.Node; 009import org.apache.jena.graph.NodeFactory; 010import org.apache.jena.graph.Triple; 011import org.fcrepo.kernel.api.RdfLexicon; 012import org.fcrepo.kernel.api.Transaction; 013import org.fcrepo.kernel.api.exception.PathNotFoundException; 014import org.fcrepo.kernel.api.identifiers.FedoraId; 015import org.fcrepo.kernel.api.models.FedoraResource; 016import org.fcrepo.kernel.api.models.ResourceFactory; 017import org.fcrepo.kernel.api.services.VersionService; 018import org.fcrepo.persistence.api.PersistentStorageSession; 019import org.fcrepo.persistence.api.PersistentStorageSessionManager; 020import org.fcrepo.persistence.api.exceptions.PersistentStorageException; 021import org.junit.Before; 022import org.junit.Test; 023import org.junit.runner.RunWith; 024import org.mockito.Mock; 025import org.mockito.junit.MockitoJUnitRunner; 026 027import java.net.URI; 028import java.time.Instant; 029import java.util.ArrayList; 030import java.util.Collections; 031import java.util.List; 032import java.util.UUID; 033import java.util.stream.Collectors; 034 035import static org.fcrepo.kernel.api.FedoraTypes.FCR_VERSIONS; 036import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_ID_PREFIX; 037import static org.hamcrest.Matchers.contains; 038import static org.junit.Assert.assertEquals; 039import static org.junit.Assert.assertSame; 040import static org.junit.Assert.assertThat; 041import static org.junit.Assert.assertTrue; 042import static org.mockito.Mockito.mock; 043import static org.mockito.Mockito.when; 044 045/** 046 * @author pwinckles 047 */ 048@RunWith(MockitoJUnitRunner.Silent.class) 049public class TimeMapImplTest { 050 051 @Mock 052 private PersistentStorageSessionManager sessionManager; 053 054 @Mock 055 private PersistentStorageSession session; 056 057 @Mock 058 private ResourceFactory resourceFactory; 059 060 @Mock 061 private Transaction transaction; 062 063 private final String defaultId = FEDORA_ID_PREFIX + "/resource"; 064 065 private TimeMapImpl timeMap; 066 067 @Before 068 public void setup() { 069 when(transaction.getId()).thenReturn(UUID.randomUUID().toString()); 070 when(transaction.isShortLived()).thenReturn(true); 071 timeMap = createTimeMap(defaultId); 072 073 when(sessionManager.getReadOnlySession()).thenReturn(session); 074 } 075 076 @Test 077 public void copyParentPropsWhenCreatingTimeMap() { 078 final var parent = createParent(FEDORA_ID_PREFIX + "id"); 079 final var timeMap = new TimeMapImpl(parent, transaction, sessionManager, resourceFactory); 080 081 assertEquals(parent.getId(), timeMap.getId()); 082 assertEquals(parent.getCreatedBy(), timeMap.getCreatedBy()); 083 assertEquals(parent.getCreatedDate(), timeMap.getCreatedDate()); 084 assertEquals(parent.getLastModifiedBy(), timeMap.getLastModifiedBy()); 085 assertEquals(parent.getLastModifiedDate(), timeMap.getLastModifiedDate()); 086 assertEquals(parent.getEtagValue(), timeMap.getEtagValue()); 087 assertEquals(parent.getStateToken(), timeMap.getStateToken()); 088 assertSame(parent, timeMap.getOriginalResource()); 089 assertSame(timeMap, timeMap.getTimeMap()); 090 } 091 092 @Test 093 public void shouldHaveTimeMapTypes() { 094 assertTrue(timeMap.getTypes().containsAll( 095 List.of( 096 URI.create(RdfLexicon.VERSIONING_TIMEMAP.getURI()) 097 )) 098 ); 099 } 100 101 @Test 102 public void returnChildMementosWhenExist() throws PersistentStorageException, PathNotFoundException { 103 final var version1 = instant("20200225131900"); 104 final var version2 = instant("20200226131900"); 105 106 mockListVersions(defaultId, version1, version2); 107 108 final var children = timeMap.getChildren(); 109 110 assertTrue(children.map(FedoraResource::getMementoDatetime) 111 .collect(Collectors.toList()).containsAll(List.of(version1, version2))); 112 } 113 114 @Test 115 public void returnNoMementosWhenNoneExist() throws PersistentStorageException, PathNotFoundException { 116 mockListVersions(defaultId); 117 118 final var children = timeMap.getChildren(); 119 120 assertEquals(0, children.count()); 121 } 122 123 @Test 124 public void returnTriples() throws PersistentStorageException, PathNotFoundException { 125 final var version1 = instant("20200225131900"); 126 final var version2 = instant("20200226131900"); 127 128 final var mementos = mockListVersions(defaultId, version1, version2); 129 130 final var triples = timeMap.getTriples(); 131 132 final var timeMapUri = node(timeMap); 133 134 assertThat(triples.collect(Collectors.toList()), contains( 135 Triple.create(timeMapUri, RdfLexicon.CONTAINS.asNode(), node(mementos.get(1))), 136 Triple.create(timeMapUri, RdfLexicon.CONTAINS.asNode(), node(mementos.get(0))), 137 Triple.create(timeMapUri, RdfLexicon.MEMENTO_ORIGINAL_RESOURCE.asNode(), 138 NodeFactory.createURI(defaultId)))); 139 } 140 141 private List<FedoraResource> mockListVersions(final String id, final Instant... versions) 142 throws PersistentStorageException, PathNotFoundException { 143 if (versions.length == 0) { 144 when(session.listVersions(FedoraId.create(id))).thenReturn(Collections.emptyList()); 145 } else { 146 when(session.listVersions(FedoraId.create(id))).thenReturn(List.of(versions)); 147 } 148 149 final var mementos = new ArrayList<FedoraResource>(); 150 151 for (final var version : versions) { 152 final var memento = createMemento(id, version); 153 mementos.add(memento); 154 final FedoraId mementoID = FedoraId.create(id, FCR_VERSIONS, instantStr(version)); 155 when(memento.getFedoraId()).thenReturn(mementoID); 156 when(resourceFactory.getResource(transaction, mementoID)).thenReturn(memento); 157 } 158 return mementos; 159 } 160 161 private Node node(final FedoraResource memento) { 162 return NodeFactory.createURI(memento.getFedoraId().getFullId()); 163 } 164 165 private Instant instant(final String instantStr) { 166 return Instant.from(VersionService.MEMENTO_LABEL_FORMATTER.parse(instantStr)); 167 } 168 169 private String instantStr(final Instant instant) { 170 return VersionService.MEMENTO_LABEL_FORMATTER.format(instant); 171 } 172 173 private FedoraResource createMemento(final String id, final Instant version) { 174 final var mock = mock(FedoraResource.class); 175 when(mock.getId()).thenReturn(id); 176 when(mock.isMemento()).thenReturn(true); 177 when(mock.getMementoDatetime()).thenReturn(version); 178 return mock; 179 } 180 181 private TimeMapImpl createTimeMap(final String id) { 182 return new TimeMapImpl(createParent(id), transaction, sessionManager, resourceFactory); 183 } 184 185 private FedoraResource createParent(final String id) { 186 final var fedoraId = FedoraId.create(id); 187 final var parent = new ContainerImpl(fedoraId, transaction, sessionManager, resourceFactory, null); 188 189 parent.setCreatedBy("createdBy"); 190 parent.setCreatedDate(Instant.now()); 191 parent.setLastModifiedBy("modifiedBy"); 192 parent.setLastModifiedDate(Instant.now()); 193 parent.setEtag("etag"); 194 parent.setStateToken("stateToken"); 195 196 return parent; 197 } 198 199}