mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 17:56:17 +01:00
Fix path computation and resolving
This commit is contained in:
@@ -12,6 +12,8 @@ import java.nio.file.Path;
|
||||
import java.time.Clock;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A Location Resolver for File based Repository Storage.
|
||||
@@ -22,7 +24,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* Please use the {@link sonia.scm.store.BlobStoreFactory } and the {@link sonia.scm.store.BlobStore} classes to store binary files<br>
|
||||
* Please use the {@link sonia.scm.store.ConfigurationStoreFactory} and the {@link sonia.scm.store.ConfigurationStore} classes to store configurations
|
||||
*
|
||||
* @author Mohamed Karray
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocationResolver<Path> {
|
||||
@@ -32,8 +33,6 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation
|
||||
private final SCMContextProvider contextProvider;
|
||||
private final InitialRepositoryLocationResolver initialRepositoryLocationResolver;
|
||||
|
||||
private final SCMContextProvider context;
|
||||
|
||||
private final PathDatabase pathDatabase;
|
||||
private final Map<String, Path> pathById;
|
||||
|
||||
@@ -43,15 +42,14 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation
|
||||
private Long lastModified;
|
||||
|
||||
@Inject
|
||||
public PathBasedRepositoryLocationResolver(SCMContextProvider contextProvider, InitialRepositoryLocationResolver initialRepositoryLocationResolver, SCMContextProvider context) {
|
||||
this(contextProvider, initialRepositoryLocationResolver, context, Clock.systemUTC());
|
||||
public PathBasedRepositoryLocationResolver(SCMContextProvider contextProvider, InitialRepositoryLocationResolver initialRepositoryLocationResolver) {
|
||||
this(contextProvider, initialRepositoryLocationResolver, Clock.systemUTC());
|
||||
}
|
||||
|
||||
public PathBasedRepositoryLocationResolver(SCMContextProvider contextProvider, InitialRepositoryLocationResolver initialRepositoryLocationResolver, SCMContextProvider context, Clock clock) {
|
||||
public PathBasedRepositoryLocationResolver(SCMContextProvider contextProvider, InitialRepositoryLocationResolver initialRepositoryLocationResolver, Clock clock) {
|
||||
super(Path.class);
|
||||
this.contextProvider = contextProvider;
|
||||
this.initialRepositoryLocationResolver = initialRepositoryLocationResolver;
|
||||
this.context = context;
|
||||
this.pathById = new ConcurrentHashMap<>();
|
||||
|
||||
this.clock = clock;
|
||||
@@ -65,13 +63,11 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation
|
||||
@Override
|
||||
protected <T> RepositoryLocationResolverInstance<T> create(Class<T> type) {
|
||||
return repositoryId -> {
|
||||
Path path;
|
||||
if (pathById.containsKey(repositoryId)) {
|
||||
path = pathById.get(repositoryId);
|
||||
return (T) contextProvider.resolve(pathById.get(repositoryId));
|
||||
} else {
|
||||
path = create(repositoryId);
|
||||
return (T) create(repositoryId);
|
||||
}
|
||||
return (T) contextProvider.resolve(path);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -79,13 +75,17 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation
|
||||
Path path = initialRepositoryLocationResolver.getPath(repositoryId);
|
||||
pathById.put(repositoryId, path);
|
||||
writePathDatabase();
|
||||
return path;
|
||||
return contextProvider.resolve(path);
|
||||
}
|
||||
|
||||
Path remove(String repositoryId) {
|
||||
Path removedPath = pathById.remove(repositoryId);
|
||||
writePathDatabase();
|
||||
return removedPath;
|
||||
return contextProvider.resolve(removedPath);
|
||||
}
|
||||
|
||||
void forAllPaths(BiConsumer<String, Path> consumer) {
|
||||
pathById.forEach((id, path) -> consumer.accept(id, contextProvider.resolve(path)));
|
||||
}
|
||||
|
||||
private void writePathDatabase() {
|
||||
@@ -117,23 +117,11 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation
|
||||
|
||||
|
||||
private void onLoadRepository(String id, Path repositoryPath) {
|
||||
// Path metadataPath = resolveMetadataPath(context.resolve(repositoryPath));
|
||||
//
|
||||
// Repository repository = metadataStore.read(metadataPath);
|
||||
//
|
||||
// byId.put(id, repository);
|
||||
// byNamespaceAndName.put(repository.getNamespaceAndName(), repository);
|
||||
pathById.put(id, repositoryPath);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Path resolveMetadataPath(Path repositoryPath) {
|
||||
return repositoryPath.resolve(StoreConstants.REPOSITORY_METADATA.concat(StoreConstants.FILE_EXTENSION));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Path resolveStorePath() {
|
||||
return context.getBaseDirectory()
|
||||
private Path resolveStorePath() {
|
||||
return contextProvider.getBaseDirectory()
|
||||
.toPath()
|
||||
.resolve(StoreConstants.CONFIG_DIRECTORY_NAME)
|
||||
.resolve(STORE_NAME.concat(StoreConstants.FILE_EXTENSION));
|
||||
|
||||
@@ -69,23 +69,26 @@ public class XmlRepositoryDAO implements RepositoryDAO {
|
||||
private final Map<String, Repository> byId;
|
||||
private final Map<NamespaceAndName, Repository> byNamespaceAndName;
|
||||
|
||||
private Long creationTime;
|
||||
private Long lastModified;
|
||||
|
||||
@Inject
|
||||
public XmlRepositoryDAO(SCMContextProvider context, PathBasedRepositoryLocationResolver repositoryLocationResolver, InitialRepositoryLocationResolver initialLocationResolver, FileSystem fileSystem) {
|
||||
this(context, repositoryLocationResolver, initialLocationResolver, fileSystem, Clock.systemUTC());
|
||||
}
|
||||
|
||||
XmlRepositoryDAO(SCMContextProvider context, PathBasedRepositoryLocationResolver repositoryLocationResolver, InitialRepositoryLocationResolver initialLocationResolver, FileSystem fileSystem, Clock clock) {
|
||||
public XmlRepositoryDAO(SCMContextProvider context, PathBasedRepositoryLocationResolver repositoryLocationResolver, FileSystem fileSystem) {
|
||||
this.context = context;
|
||||
this.repositoryLocationResolver = repositoryLocationResolver;
|
||||
this.fileSystem = fileSystem;
|
||||
|
||||
this.byId = new ConcurrentHashMap<>();
|
||||
this.byNamespaceAndName = new ConcurrentHashMap<>();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
repositoryLocationResolver.forAllPaths((repositoryId, repositoryPath) -> {
|
||||
Path metadataPath = resolveDataPath(repositoryPath);
|
||||
Repository repository = metadataStore.read(metadataPath);
|
||||
byNamespaceAndName.put(repository.getNamespaceAndName(), repository);
|
||||
byId.put(repositoryId, repository);
|
||||
});
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Path resolveDataPath(Path repositoryPath) {
|
||||
@@ -101,11 +104,10 @@ public class XmlRepositoryDAO implements RepositoryDAO {
|
||||
public void add(Repository repository) {
|
||||
Repository clone = repository.clone();
|
||||
|
||||
|
||||
try {
|
||||
synchronized (this) {
|
||||
Path repositoryPath = repositoryLocationResolver.create(repository.getId());
|
||||
Path resolvedPath = context.resolve(repositoryPath);
|
||||
Path resolvedPath = repositoryPath;
|
||||
fileSystem.create(resolvedPath.toFile());
|
||||
|
||||
Path metadataPath = resolveDataPath(resolvedPath);
|
||||
@@ -165,7 +167,7 @@ public class XmlRepositoryDAO implements RepositoryDAO {
|
||||
byNamespaceAndName.put(clone.getNamespaceAndName(), clone);
|
||||
}
|
||||
|
||||
Path repositoryPath = context.resolve(repositoryLocationResolver.create(Path.class).getLocation(repository.getId()));
|
||||
Path repositoryPath = repositoryLocationResolver.create(Path.class).getLocation(repository.getId());
|
||||
Path metadataPath = resolveDataPath(repositoryPath);
|
||||
metadataStore.write(metadataPath, clone);
|
||||
}
|
||||
@@ -181,8 +183,6 @@ public class XmlRepositoryDAO implements RepositoryDAO {
|
||||
path = repositoryLocationResolver.remove(repository.getId());
|
||||
}
|
||||
|
||||
path = context.resolve(path);
|
||||
|
||||
try {
|
||||
fileSystem.destroy(path.toFile());
|
||||
} catch (IOException e) {
|
||||
@@ -192,11 +192,11 @@ public class XmlRepositoryDAO implements RepositoryDAO {
|
||||
|
||||
@Override
|
||||
public Long getCreationTime() {
|
||||
return creationTime;
|
||||
return repositoryLocationResolver.getCreationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLastModified() {
|
||||
return lastModified;
|
||||
return repositoryLocationResolver.getLastModified();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,11 @@ package sonia.scm.repository.xml;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.repository.InitialRepositoryLocationResolver;
|
||||
@@ -19,27 +22,21 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith({MockitoExtension.class})
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class PathBasedRepositoryLocationResolverTest {
|
||||
|
||||
@Mock
|
||||
private SCMContextProvider contextProvider;
|
||||
|
||||
@Mock
|
||||
private RepositoryDAO repositoryDAO;
|
||||
|
||||
@Mock
|
||||
private InitialRepositoryLocationResolver initialRepositoryLocationResolver;
|
||||
|
||||
@Mock
|
||||
private SCMContextProvider context;
|
||||
private PathBasedRepositoryLocationResolver resolver;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
when(contextProvider.resolve(any(Path.class))).then((Answer<Path>) invocationOnMock -> invocationOnMock.getArgument(0));
|
||||
}
|
||||
|
||||
private PathBasedRepositoryLocationResolver createResolver(RepositoryDAO pathBasedRepositoryDAO) {
|
||||
return new PathBasedRepositoryLocationResolver(contextProvider, initialRepositoryLocationResolver, context);
|
||||
resolver = new PathBasedRepositoryLocationResolver(contextProvider, initialRepositoryLocationResolver);
|
||||
}
|
||||
|
||||
// TODO implement tests
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junitpioneer.jupiter.TempDirectory;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
@@ -39,13 +40,13 @@ import static org.mockito.Mockito.when;
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class XmlRepositoryDAOTest {
|
||||
|
||||
private static final Repository REPOSITORY = createRepository("42");
|
||||
|
||||
@Mock
|
||||
private SCMContextProvider context;
|
||||
|
||||
@Mock
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private PathBasedRepositoryLocationResolver locationResolver;
|
||||
@Mock
|
||||
private InitialRepositoryLocationResolver initialLocationResolver;
|
||||
|
||||
private FileSystem fileSystem = new DefaultFileSystem();
|
||||
|
||||
@@ -60,8 +61,8 @@ class XmlRepositoryDAOTest {
|
||||
this.baseDirectory = baseDirectory;
|
||||
this.atomicClock = new AtomicLong();
|
||||
|
||||
when(initialLocationResolver.getPath("42")).thenReturn(Paths.get("repos", "42"));
|
||||
when(initialLocationResolver.getPath("42+1")).thenReturn(Paths.get("repos", "puzzle"));
|
||||
when(locationResolver.create("42")).thenReturn(Paths.get("repos", "42"));
|
||||
when(locationResolver.create("23")).thenReturn(Paths.get("repos", "puzzle"));
|
||||
|
||||
when(context.getBaseDirectory()).thenReturn(baseDirectory.toFile());
|
||||
when(context.resolve(any(Path.class))).then(ic -> {
|
||||
@@ -76,41 +77,37 @@ class XmlRepositoryDAOTest {
|
||||
Clock clock = mock(Clock.class);
|
||||
when(clock.millis()).then(ic -> atomicClock.incrementAndGet());
|
||||
|
||||
return new XmlRepositoryDAO(context, locationResolver, initialLocationResolver, fileSystem, clock);
|
||||
return new XmlRepositoryDAO(context, locationResolver, fileSystem);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnXmlType() {
|
||||
assertThat(dao.getType()).isEqualTo("xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnCreationTimeOfLocationResolver() {
|
||||
long now = atomicClock.get();
|
||||
when(locationResolver.getCreationTime()).thenReturn(now);
|
||||
assertThat(dao.getCreationTime()).isEqualTo(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnLasModifiedOfLocationResolver() {
|
||||
long now = atomicClock.get();
|
||||
when(locationResolver.getLastModified()).thenReturn(now);
|
||||
assertThat(dao.getLastModified()).isEqualTo(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnTrueForEachContainsMethod() {
|
||||
dao.add(REPOSITORY);
|
||||
|
||||
assertThat(dao.contains(REPOSITORY)).isTrue();
|
||||
assertThat(dao.contains(REPOSITORY.getId())).isTrue();
|
||||
assertThat(dao.contains(REPOSITORY.getNamespaceAndName())).isTrue();
|
||||
}
|
||||
|
||||
// @Test
|
||||
// void shouldReturnXmlType() {
|
||||
// assertThat(dao.getType()).isEqualTo("xml");
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void shouldReturnCreationTimeAfterCreation() {
|
||||
// long now = atomicClock.get();
|
||||
// assertThat(dao.getCreationTime()).isEqualTo(now);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void shouldNotReturnLastModifiedAfterCreation() {
|
||||
// assertThat(dao.getLastModified()).isNull();
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void shouldReturnTrueForEachContainsMethod() {
|
||||
// Repository heartOfGold = createHeartOfGold();
|
||||
// dao.add(heartOfGold);
|
||||
//
|
||||
// assertThat(dao.contains(heartOfGold)).isTrue();
|
||||
// assertThat(dao.contains(heartOfGold.getId())).isTrue();
|
||||
// assertThat(dao.contains(heartOfGold.getNamespaceAndName())).isTrue();
|
||||
// }
|
||||
//
|
||||
// private Repository createHeartOfGold() {
|
||||
// Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
||||
// heartOfGold.setId("42");
|
||||
// return heartOfGold;
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void shouldReturnFalseForEachContainsMethod() {
|
||||
// Repository heartOfGold = createHeartOfGold();
|
||||
@@ -377,4 +374,8 @@ class XmlRepositoryDAOTest {
|
||||
// assertThat(dao.getCreationTime()).isEqualTo(creationTime);
|
||||
// assertThat(dao.getLastModified()).isEqualTo(lastModified);
|
||||
// }
|
||||
|
||||
private static Repository createRepository(String id) {
|
||||
return new Repository(id, "xml", "space", "id");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user