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