Merged in feature/store_for_repositories_v2 (pull request #120)

Feature/store for repositories v2
This commit is contained in:
René Pfeuffer
2018-12-04 17:55:27 +00:00
50 changed files with 943 additions and 400 deletions

3
Jenkinsfile vendored
View File

@@ -107,7 +107,8 @@ void analyzeWith(Maven mvn) {
"-Dsonar.pullrequest.key=${env.CHANGE_ID} " +
"-Dsonar.pullrequest.provider=bitbucketcloud " +
"-Dsonar.pullrequest.bitbucketcloud.owner=sdorra " +
"-Dsonar.pullrequest.bitbucketcloud.repository=scm-manager "
"-Dsonar.pullrequest.bitbucketcloud.repository=scm-manager " +
"-Dsonar.cpd.exclusions=**/*StoreFactory.java,**/*UserPassword.js "
} else {
mvnArgs += " -Dsonar.branch.name=${env.BRANCH_NAME} "
if (!isMainBranch()) {

View File

@@ -810,6 +810,10 @@
<netbeans.hint.license>SCM-BSD</netbeans.hint.license>
<jdk.classifier />
<org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
<!-- Sonar exclusions -->
<sonar.cpd.exclusions>**/*StoreFactory.java</sonar.cpd.exclusions>
</properties>
</project>

View File

@@ -221,5 +221,5 @@
</plugins>
</build>
</project>

View File

@@ -72,9 +72,11 @@ public abstract class AbstractRepositoryHandler<C extends RepositoryConfig>
*
* @param storeFactory
*/
protected AbstractRepositoryHandler(ConfigurationStoreFactory storeFactory)
{
this.store = storeFactory.getStore(getConfigClass(), getType().getName());
protected AbstractRepositoryHandler(ConfigurationStoreFactory storeFactory) {
this.store = storeFactory
.withType(getConfigClass())
.withName(getType().getName())
.build();
}
//~--- get methods ----------------------------------------------------------

View File

@@ -4,7 +4,6 @@ import groovy.lang.Singleton;
import sonia.scm.SCMContextProvider;
import javax.inject.Inject;
import java.io.File;
import java.nio.file.Path;
/**

View File

@@ -32,9 +32,25 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The BlobStoreFactory can be used to create new or get existing
* {@link BlobStore}s.
* The BlobStoreFactory can be used to create a new or get an existing {@link BlobStore}s.
* <br>
* You can either create a global {@link BlobStore} or a {@link BlobStore} for a specific repository. To create a global
* {@link BlobStore} call:
* <code><pre>
* blobStoreFactory
* .withName("name")
* .build();
* </pre></code>
* To create a {@link BlobStore} for a specific repository call:
* <code><pre>
* blobStoreFactory
* .withName("name")
* .forRepository(repository)
* .build();
* </pre></code>
*
* @author Sebastian Sdorra
* @since 1.23
@@ -45,13 +61,68 @@ package sonia.scm.store;
public interface BlobStoreFactory {
/**
* Returns a {@link BlobStore} with the given name, if the {@link BlobStore}
* with the given name does not exists the factory will create a new one.
* Creates a new or gets an existing {@link BlobStore}. Instead of calling this method you should use the floating API
* from {@link #withName(String)}.
*
*
* @param name name of the {@link BlobStore}
*
* @return {@link BlobStore} with the given name
* @param storeParameters The parameters for the blob store.
* @return A new or an existing {@link BlobStore} for the given parameters.
*/
public BlobStore getBlobStore(String name);
BlobStore getStore(final StoreParameters storeParameters);
/**
* Use this to create a new or get an existing {@link BlobStore} with a floating API.
* @param name The name for the {@link BlobStore}.
* @return Floating API to either specify a repository or directly build a global {@link BlobStore}.
*/
default FloatingStoreParameters.Builder withName(String name) {
return new FloatingStoreParameters(this).new Builder(name);
}
}
final class FloatingStoreParameters implements StoreParameters {
private String name;
private Repository repository;
private final BlobStoreFactory factory;
FloatingStoreParameters(BlobStoreFactory factory) {
this.factory = factory;
}
@Override
public String getName() {
return name;
}
@Override
public Repository getRepository() {
return repository;
}
public class Builder {
Builder(String name) {
FloatingStoreParameters.this.name = name;
}
/**
* Use this to create or get a {@link BlobStore} for a specific repository. This step is optional. If you want to
* have a global {@link BlobStore}, omit this.
* @param repository The optional repository for the {@link BlobStore}.
* @return Floating API to finish the call.
*/
public FloatingStoreParameters.Builder forRepository(Repository repository) {
FloatingStoreParameters.this.repository = repository;
return this;
}
/**
* Creates or gets the {@link BlobStore} with the given name and (if specified) the given repository. If no
* repository is given, the {@link BlobStore} will be global.
*/
public BlobStore build(){
return factory.getStore(FloatingStoreParameters.this);
}
}
}

View File

@@ -32,31 +32,104 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The ConfigurationEntryStoreFactory can be used to create new or get existing
* {@link ConfigurationEntryStore}s. <b>Note:</b> the default implementation
* uses the same location as the {@link StoreFactory}, so be sure that the
* store names are unique for all {@link ConfigurationEntryStore}s and
* {@link Store}s.
*
* The ConfigurationEntryStoreFactory can be used to create new or get existing {@link ConfigurationEntryStore}s.
* <br>
* <b>Note:</b> the default implementation uses the same location as the {@link ConfigurationStoreFactory}, so be sure
* that the store names are unique for all {@link ConfigurationEntryStore}s and {@link ConfigurationEntryStore}s.
* <br>
* You can either create a global {@link ConfigurationEntryStore} or a {@link ConfigurationEntryStore} for a specific
* repository. To create a global {@link ConfigurationEntryStore} call:
* <code><pre>
* configurationEntryStoreFactory
* .withType(PersistedType.class)
* .withName("name")
* .build();
* </pre></code>
* To create a {@link ConfigurationEntryStore} for a specific repository call:
* <code><pre>
* configurationEntryStoreFactory
* .withType(PersistedType.class)
* .withName("name")
* .forRepository(repository)
* .build();
* </pre></code>
*
* @author Sebastian Sdorra
* @since 1.31
*
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.ConfigurationEntryStore
*/
public interface ConfigurationEntryStoreFactory
{
public interface ConfigurationEntryStoreFactory {
/**
* Get an existing {@link ConfigurationEntryStore} or create a new one.
* Creates a new or gets an existing {@link ConfigurationEntryStore}. Instead of calling this method you should use
* the floating API from {@link #withType(Class)}.
*
*
* @param type type of the store objects
* @param name name of the store
* @param <T> type of the store objects
*
* @return {@link ConfigurationEntryStore} with given name and type
* @param storeParameters The parameters for the {@link ConfigurationEntryStore}.
* @return A new or an existing {@link ConfigurationEntryStore} for the given parameters.
*/
public <T> ConfigurationEntryStore<T> getStore(Class<T> type, String name);
<T> ConfigurationEntryStore<T> getStore(final TypedStoreParameters<T> storeParameters);
/**
* Use this to create a new or get an existing {@link ConfigurationEntryStore} with a floating API.
* @param type The type for the {@link ConfigurationEntryStore}.
* @return Floating API to set the name and either specify a repository or directly build a global
* {@link ConfigurationEntryStore}.
*/
default <T> TypedFloatingConfigurationEntryStoreParameters<T>.Builder withType(Class<T> type) {
return new TypedFloatingConfigurationEntryStoreParameters<T>(this).new Builder(type);
}
}
final class TypedFloatingConfigurationEntryStoreParameters<T> {
private final TypedStoreParametersImpl<T> parameters = new TypedStoreParametersImpl<>();
private final ConfigurationEntryStoreFactory factory;
TypedFloatingConfigurationEntryStoreParameters(ConfigurationEntryStoreFactory factory) {
this.factory = factory;
}
public class Builder {
Builder(Class<T> type) {
parameters.setType(type);
}
/**
* Use this to set the name for the {@link ConfigurationEntryStore}.
* @param name The name for the {@link ConfigurationEntryStore}.
* @return Floating API to either specify a repository or directly build a global {@link ConfigurationEntryStore}.
*/
public OptionalRepositoryBuilder withName(String name) {
parameters.setName(name);
return new OptionalRepositoryBuilder();
}
}
public class OptionalRepositoryBuilder {
/**
* Use this to create or get a {@link ConfigurationEntryStore} for a specific repository. This step is optional. If
* you want to have a global {@link ConfigurationEntryStore}, omit this.
* @param repository The optional repository for the {@link ConfigurationEntryStore}.
* @return Floating API to finish the call.
*/
public OptionalRepositoryBuilder forRepository(Repository repository) {
parameters.setRepository(repository);
return this;
}
/**
* Creates or gets the {@link ConfigurationEntryStore} with the given name and (if specified) the given repository.
* If no repository is given, the {@link ConfigurationEntryStore} will be global.
*/
public ConfigurationEntryStore<T> build(){
return factory.getStore(parameters);
}
}
}

View File

@@ -33,27 +33,103 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The ConfigurationStoreFactory can be used to create new or get existing
* {@link ConfigurationStore} objects.
* The ConfigurationStoreFactory can be used to create new or get existing {@link ConfigurationStore} objects.
* <br>
* <b>Note:</b> the default implementation uses the same location as the {@link ConfigurationEntryStoreFactory}, so be
* sure that the store names are unique for all {@link ConfigurationEntryStore}s and {@link ConfigurationStore}s.
* <br>
* You can either create a global {@link ConfigurationStore} or a {@link ConfigurationStore} for a specific repository.
* To create a global {@link ConfigurationStore} call:
* <code><pre>
* configurationStoreFactory
* .withType(PersistedType.class)
* .withName("name")
* .build();
* </pre></code>
* To create a {@link ConfigurationStore} for a specific repository call:
* <code><pre>
* configurationStoreFactory
* .withType(PersistedType.class)
* .withName("name")
* .forRepository(repository)
* .build();
* </pre></code>
*
* @author Sebastian Sdorra
*
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.ConfigurationStore
*/
public interface ConfigurationStoreFactory
{
public interface ConfigurationStoreFactory {
/**
* Get an existing {@link ConfigurationStore} or create a new one.
* Creates a new or gets an existing {@link ConfigurationStore}. Instead of calling this method you should use the
* floating API from {@link #withType(Class)}.
*
*
* @param type type of the store objects
* @param name name of the store
* @param <T> type of the store objects
*
* @return {@link ConfigurationStore} of the given type and name
* @param storeParameters The parameters for the {@link ConfigurationStore}.
* @return A new or an existing {@link ConfigurationStore} for the given parameters.
*/
public <T> ConfigurationStore<T> getStore(Class<T> type, String name);
<T> ConfigurationStore<T> getStore(final TypedStoreParameters<T> storeParameters);
/**
* Use this to create a new or get an existing {@link ConfigurationStore} with a floating API.
* @param type The type for the {@link ConfigurationStore}.
* @return Floating API to set the name and either specify a repository or directly build a global
* {@link ConfigurationStore}.
*/
default <T> TypedFloatingConfigurationStoreParameters<T>.Builder withType(Class<T> type) {
return new TypedFloatingConfigurationStoreParameters<T>(this).new Builder(type);
}
}
final class TypedFloatingConfigurationStoreParameters<T> {
private final TypedStoreParametersImpl<T> parameters = new TypedStoreParametersImpl<>();
private final ConfigurationStoreFactory factory;
TypedFloatingConfigurationStoreParameters(ConfigurationStoreFactory factory) {
this.factory = factory;
}
public class Builder {
Builder(Class<T> type) {
parameters.setType(type);
}
/**
* Use this to set the name for the {@link ConfigurationStore}.
* @param name The name for the {@link ConfigurationStore}.
* @return Floating API to either specify a repository or directly build a global {@link ConfigurationStore}.
*/
public OptionalRepositoryBuilder withName(String name) {
parameters.setName(name);
return new OptionalRepositoryBuilder();
}
}
public class OptionalRepositoryBuilder {
/**
* Use this to create or get a {@link ConfigurationStore} for a specific repository. This step is optional. If you
* want to have a global {@link ConfigurationStore}, omit this.
* @param repository The optional repository for the {@link ConfigurationStore}.
* @return Floating API to finish the call.
*/
public OptionalRepositoryBuilder forRepository(Repository repository) {
parameters.setRepository(repository);
return this;
}
/**
* Creates or gets the {@link ConfigurationStore} with the given name and (if specified) the given repository. If no
* repository is given, the {@link ConfigurationStore} will be global.
*/
public ConfigurationStore<T> build(){
return factory.getStore(parameters);
}
}
}

View File

@@ -32,9 +32,27 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The DataStoreFactory can be used to create new or get existing
* {@link DataStore}s.
* The DataStoreFactory can be used to create new or get existing {@link DataStore}s.
* <br>
* You can either create a global {@link DataStore} or a {@link DataStore} for a specific repository.
* To create a global {@link DataStore} call:
* <code><pre>
* dataStoreFactory
* .withType(PersistedType.class)
* .withName("name")
* .build();
* </pre></code>
* To create a {@link DataStore} for a specific repository call:
* <code><pre>
* dataStoreFactory
* .withType(PersistedType.class)
* .withName("name")
* .forRepository(repository)
* .build();
* </pre></code>
*
* @author Sebastian Sdorra
* @since 1.23
@@ -45,14 +63,70 @@ package sonia.scm.store;
public interface DataStoreFactory {
/**
* Get an existing {@link DataStore} or create a new one.
* Creates a new or gets an existing {@link DataStore}. Instead of calling this method you should use the
* floating API from {@link #withType(Class)}.
*
*
* @param type type of the store objects
* @param name name of the store
* @param <T> type of the store objects
*
* @return {@link DataStore} with given name and type
* @param storeParameters The parameters for the {@link DataStore}.
* @return A new or an existing {@link DataStore} for the given parameters.
*/
public <T> DataStore<T> getStore(Class<T> type, String name);
<T> DataStore<T> getStore(final TypedStoreParameters<T> storeParameters);
/**
* Use this to create a new or get an existing {@link DataStore} with a floating API.
* @param type The type for the {@link DataStore}.
* @return Floating API to set the name and either specify a repository or directly build a global
* {@link DataStore}.
*/
default <T> TypedFloatingDataStoreParameters<T>.Builder withType(Class<T> type) {
return new TypedFloatingDataStoreParameters<T>(this).new Builder(type);
}
}
final class TypedFloatingDataStoreParameters<T> {
private final TypedStoreParametersImpl<T> parameters = new TypedStoreParametersImpl<>();
private final DataStoreFactory factory;
TypedFloatingDataStoreParameters(DataStoreFactory factory) {
this.factory = factory;
}
public class Builder {
Builder(Class<T> type) {
parameters.setType(type);
}
/**
* Use this to set the name for the {@link DataStore}.
* @param name The name for the {@link DataStore}.
* @return Floating API to either specify a repository or directly build a global {@link DataStore}.
*/
public OptionalRepositoryBuilder withName(String name) {
parameters.setName(name);
return new OptionalRepositoryBuilder();
}
}
public class OptionalRepositoryBuilder {
/**
* Use this to create or get a {@link DataStore} for a specific repository. This step is optional. If you
* want to have a global {@link DataStore}, omit this.
* @param repository The optional repository for the {@link DataStore}.
* @return Floating API to finish the call.
*/
public OptionalRepositoryBuilder forRepository(Repository repository) {
parameters.setRepository(repository);
return this;
}
/**
* Creates or gets the {@link DataStore} with the given name and (if specified) the given repository. If no
* repository is given, the {@link DataStore} will be global.
*/
public DataStore<T> build(){
return factory.getStore(parameters);
}
}
}

View File

@@ -0,0 +1,16 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The fields of the {@link StoreParameters} are used from the {@link BlobStoreFactory} to create a store.
*
* @author Mohamed Karray
* @since 2.0.0
*/
public interface StoreParameters {
String getName();
Repository getRepository();
}

View File

@@ -0,0 +1,19 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The fields of the {@link TypedStoreParameters} are used from the {@link ConfigurationStoreFactory},
* {@link ConfigurationEntryStoreFactory} and {@link DataStoreFactory} to create a type safe store.
*
* @author Mohamed Karray
* @since 2.0.0
*/
public interface TypedStoreParameters<T> {
Class<T> getType();
String getName();
Repository getRepository();
}

View File

@@ -0,0 +1,36 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
class TypedStoreParametersImpl<T> implements TypedStoreParameters<T> {
private Class<T> type;
private String name;
private Repository repository;
@Override
public Class<T> getType() {
return type;
}
void setType(Class<T> type) {
this.type = type;
}
@Override
public String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
@Override
public Repository getRepository() {
return repository;
}
void setRepository(Repository repository) {
this.repository = repository;
}
}

View File

@@ -64,9 +64,11 @@ public class XmlGroupDAO extends AbstractXmlDAO<Group, XmlGroupDatabase>
* @param storeFactory
*/
@Inject
public XmlGroupDAO(ConfigurationStoreFactory storeFactory)
{
super(storeFactory.getStore(XmlGroupDatabase.class, STORE_NAME));
public XmlGroupDAO(ConfigurationStoreFactory storeFactory) {
super(storeFactory
.withType(XmlGroupDatabase.class)
.withName(STORE_NAME)
.build());
}
//~--- methods --------------------------------------------------------------

View File

@@ -31,18 +31,21 @@
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
//~--- JDK imports ------------------------------------------------------------
/**
* Abstract store factory for file based stores.
*
*
* @author Sebastian Sdorra
*/
public abstract class FileBasedStoreFactory {
@@ -51,39 +54,57 @@ public abstract class FileBasedStoreFactory {
* the logger for FileBasedStoreFactory
*/
private static final Logger LOG = LoggerFactory.getLogger(FileBasedStoreFactory.class);
private SCMContextProvider contextProvider;
private RepositoryLocationResolver repositoryLocationResolver;
private Store store;
private static final String BASE_DIRECTORY = "var";
private File storeDirectory;
private final SCMContextProvider context;
private final String dataDirectoryName;
private File dataDirectory;
protected FileBasedStoreFactory(SCMContextProvider context,
String dataDirectoryName) {
this.context = context;
this.dataDirectoryName = dataDirectoryName;
protected FileBasedStoreFactory(SCMContextProvider contextProvider , RepositoryLocationResolver repositoryLocationResolver, Store store) {
this.contextProvider = contextProvider;
this.repositoryLocationResolver = repositoryLocationResolver;
this.store = store;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns data directory for given name.
*
* @param name name of data directory
*
* @return data directory
*/
protected File getDirectory(String name) {
if (dataDirectory == null) {
dataDirectory = new File(context.getBaseDirectory(),
BASE_DIRECTORY.concat(File.separator).concat(dataDirectoryName));
LOG.debug("create data directory {}", dataDirectory);
}
protected File getStoreLocation(StoreParameters storeParameters) {
return getStoreLocation(storeParameters.getName(), null, storeParameters.getRepository());
}
File storeDirectory = new File(dataDirectory, name);
IOUtil.mkdirs(storeDirectory);
return storeDirectory;
protected File getStoreLocation(TypedStoreParameters storeParameters) {
return getStoreLocation(storeParameters.getName(), storeParameters.getType(), storeParameters.getRepository());
}
protected File getStoreLocation(String name, Class type, Repository repository) {
if (storeDirectory == null) {
if (repository != null) {
LOG.debug("create store with type: {}, name: {} and repository: {}", type, name, repository.getNamespaceAndName());
storeDirectory = this.getStoreDirectory(store, repository);
} else {
LOG.debug("create store with type: {} and name: {} ", type, name);
storeDirectory = this.getStoreDirectory(store);
}
IOUtil.mkdirs(storeDirectory);
}
return new File(this.storeDirectory, name);
}
/**
* Get the store directory of a specific repository
* @param store the type of the store
* @param repository the repo
* @return the store directory of a specific repository
*/
private File getStoreDirectory(Store store, Repository repository) {
return new File(repositoryLocationResolver.getPath(repository.getId()).toFile(), store.getRepositoryStoreDirectory());
}
/**
* Get the global store directory
* @param store the type of the store
* @return the global store directory
*/
private File getStoreDirectory(Store store) {
return new File(contextProvider.getBaseDirectory(), store.getGlobalStoreDirectory());
}
}

View File

@@ -31,14 +31,17 @@
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.security.KeyGenerator;
import sonia.scm.util.IOUtil;
import java.io.File;
/**
* File based store factory.
@@ -48,8 +51,6 @@ import sonia.scm.security.KeyGenerator;
@Singleton
public class FileBlobStoreFactory extends FileBasedStoreFactory implements BlobStoreFactory {
private static final String DIRECTORY_NAME = "blob";
/**
* the logger for FileBlobStoreFactory
*/
@@ -60,21 +61,22 @@ public class FileBlobStoreFactory extends FileBasedStoreFactory implements BlobS
/**
* Constructs a new instance.
*
* @param context scm context
* @param repositoryLocationResolver location resolver
* @param keyGenerator key generator
*/
@Inject
public FileBlobStoreFactory(SCMContextProvider context,
KeyGenerator keyGenerator) {
super(context, DIRECTORY_NAME);
public FileBlobStoreFactory(SCMContextProvider contextProvider ,RepositoryLocationResolver repositoryLocationResolver, KeyGenerator keyGenerator) {
super(contextProvider, repositoryLocationResolver, Store.BLOB);
this.keyGenerator = keyGenerator;
}
@Override
public BlobStore getBlobStore(String name) {
LOG.debug("create new blob with name {}", name);
return new FileBlobStore(keyGenerator, getDirectory(name));
@SuppressWarnings("unchecked")
public BlobStore getStore(StoreParameters storeParameters) {
File storeLocation = getStoreLocation(storeParameters);
IOUtil.mkdirs(storeLocation);
return new FileBlobStore(keyGenerator, storeLocation);
}
}

View File

@@ -1,19 +1,19 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* <p>
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
* <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,97 +24,42 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* <p>
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.security.KeyGenerator;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class JAXBConfigurationEntryStoreFactory
implements ConfigurationEntryStoreFactory
{
public class JAXBConfigurationEntryStoreFactory extends FileBasedStoreFactory
implements ConfigurationEntryStoreFactory {
/**
* the logger for JAXBConfigurationEntryStoreFactory
*/
private static final Logger logger =
LoggerFactory.getLogger(JAXBConfigurationEntryStoreFactory.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param keyGenerator
* @param context
*/
@Inject
public JAXBConfigurationEntryStoreFactory(KeyGenerator keyGenerator,
SCMContextProvider context)
{
this.keyGenerator = keyGenerator;
directory = new File(context.getBaseDirectory(),
StoreConstants.CONFIG_DIRECTORY_NAME);
IOUtil.mkdirs(directory);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param type
* @param name
* @param <T>
*
* @return
*/
@Override
public <T> ConfigurationEntryStore<T> getStore(Class<T> type, String name)
{
logger.debug("create new configuration store for type {} with name {}",
type, name);
//J-
return new JAXBConfigurationEntryStore<T>(
new File(directory,name.concat(StoreConstants.FILE_EXTENSION)),
keyGenerator,
type
);
//J+
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private File directory;
/** Field description */
private KeyGenerator keyGenerator;
@Inject
public JAXBConfigurationEntryStoreFactory(SCMContextProvider contextProvider , RepositoryLocationResolver repositoryLocationResolver, KeyGenerator keyGenerator) {
super(contextProvider, repositoryLocationResolver, Store.CONFIG);
this.keyGenerator = keyGenerator;
}
@Override
public <T> ConfigurationEntryStore<T> getStore(TypedStoreParameters<T> storeParameters) {
return new JAXBConfigurationEntryStore<>(getStoreLocation(storeParameters.getName().concat(StoreConstants.FILE_EXTENSION), storeParameters.getType(), storeParameters.getRepository()), keyGenerator, storeParameters.getType());
}
}

View File

@@ -61,7 +61,7 @@ public class JAXBConfigurationStore<T> extends AbstractStore<T> {
private JAXBContext context;
JAXBConfigurationStore(Class<T> type, File configFile) {
public JAXBConfigurationStore(Class<T> type, File configFile) {
this.type = type;
try {

View File

@@ -32,14 +32,8 @@ package sonia.scm.store;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.util.IOUtil;
import java.io.File;
import sonia.scm.repository.RepositoryLocationResolver;
/**
* JAXB implementation of {@link ConfigurationStoreFactory}.
@@ -47,40 +41,20 @@ import java.io.File;
* @author Sebastian Sdorra
*/
@Singleton
public class JAXBConfigurationStoreFactory implements ConfigurationStoreFactory {
/**
* the logger for JAXBConfigurationStoreFactory
*/
private static final Logger LOG = LoggerFactory.getLogger(JAXBConfigurationStoreFactory.class);
private final File configDirectory;
public class JAXBConfigurationStoreFactory extends FileBasedStoreFactory implements ConfigurationStoreFactory {
/**
* Constructs a new instance.
*
* @param context scm context
* @param repositoryLocationResolver Resolver to get the repository Directory
*/
@Inject
public JAXBConfigurationStoreFactory(SCMContextProvider context) {
configDirectory = new File(context.getBaseDirectory(), StoreConstants.CONFIG_DIRECTORY_NAME);
IOUtil.mkdirs(configDirectory);
public JAXBConfigurationStoreFactory(SCMContextProvider contextProvider, RepositoryLocationResolver repositoryLocationResolver) {
super(contextProvider, repositoryLocationResolver, Store.CONFIG);
}
@Override
public <T> JAXBConfigurationStore<T> getStore(Class<T> type, String name) {
if (configDirectory == null) {
throw new IllegalStateException("store factory is not initialized");
}
File configFile = new File(configDirectory, name.concat(StoreConstants.FILE_EXTENSION));
if (LOG.isDebugEnabled()) {
LOG.debug("create store for {} at {}", type.getName(),
configFile.getPath());
}
return new JAXBConfigurationStore<>(type, configFile);
public <T> JAXBConfigurationStore<T> getStore(TypedStoreParameters<T> storeParameters) {
return new JAXBConfigurationStore<>(storeParameters.getType(), getStoreLocation(storeParameters.getName().concat(StoreConstants.FILE_EXTENSION), storeParameters.getType(), storeParameters.getRepository()));
}
}

View File

@@ -41,7 +41,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.security.KeyGenerator;
import sonia.scm.util.IOUtil;
import java.io.File;
/**
*
@@ -49,57 +53,20 @@ import sonia.scm.security.KeyGenerator;
*/
@Singleton
public class JAXBDataStoreFactory extends FileBasedStoreFactory
implements DataStoreFactory
{
implements DataStoreFactory {
/** Field description */
private static final String DIRECTORY_NAME = "data";
private KeyGenerator keyGenerator;
/**
* the logger for JAXBDataStoreFactory
*/
private static final Logger logger =
LoggerFactory.getLogger(JAXBDataStoreFactory.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param context
* @param keyGenerator
*/
@Inject
public JAXBDataStoreFactory(SCMContextProvider context,
KeyGenerator keyGenerator)
{
super(context, DIRECTORY_NAME);
public JAXBDataStoreFactory(SCMContextProvider contextProvider , RepositoryLocationResolver repositoryLocationResolver, KeyGenerator keyGenerator) {
super(contextProvider, repositoryLocationResolver, Store.DATA);
this.keyGenerator = keyGenerator;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param type
* @param name
* @param <T>
*
* @return
*/
@Override
public <T> DataStore<T> getStore(Class<T> type, String name)
{
logger.debug("create new store for type {} with name {}", type, name);
return new JAXBDataStore<>(keyGenerator, type, getDirectory(name));
public <T> DataStore<T> getStore(TypedStoreParameters<T> storeParameters) {
File storeLocation = getStoreLocation(storeParameters);
IOUtil.mkdirs(storeLocation);
return new JAXBDataStore<>(keyGenerator, storeParameters.getType(), storeLocation);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private KeyGenerator keyGenerator;
}

View File

@@ -0,0 +1,49 @@
package sonia.scm.store;
import java.io.File;
public enum Store {
CONFIG("config"),
DATA("data"),
BLOB("blob");
private static final String GLOBAL_STORE_BASE_DIRECTORY = "var";
private String directory;
Store(String directory) {
this.directory = directory;
}
/**
* Get the relkative store directory path to be stored in the repository root
* <p>
* The repository store directories are:
* repo_base_dir/config/
* repo_base_dir/blob/
* repo_base_dir/data/
*
* @return the relative store directory path to be stored in the repository root
*/
public String getRepositoryStoreDirectory() {
return directory;
}
/**
* Get the relative store directory path to be stored in the global root
* <p>
* The global store directories are:
* base_dir/config/
* base_dir/var/blob/
* base_dir/var/data/
*
* @return the relative store directory path to be stored in the global root
*/
public String getGlobalStoreDirectory() {
if (this.equals(CONFIG)) {
return directory;
}
return GLOBAL_STORE_BASE_DIRECTORY + File.separator + directory;
}
}

View File

@@ -36,11 +36,10 @@ package sonia.scm.user.xml;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.user.User;
import sonia.scm.user.UserDAO;
import sonia.scm.xml.AbstractXmlDAO;
import sonia.scm.store.ConfigurationStoreFactory;
/**
*
@@ -65,7 +64,10 @@ public class XmlUserDAO extends AbstractXmlDAO<User, XmlUserDatabase>
@Inject
public XmlUserDAO(ConfigurationStoreFactory storeFactory)
{
super(storeFactory.getStore(XmlUserDatabase.class, STORE_NAME));
super(storeFactory
.withType(XmlUserDatabase.class)
.withName(STORE_NAME)
.build());
}
//~--- methods --------------------------------------------------------------

View File

@@ -28,7 +28,8 @@ import java.util.concurrent.atomic.AtomicLong;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith({MockitoExtension.class, TempDirectory.class})
@MockitoSettings(strictness = Strictness.LENIENT)

View File

@@ -34,8 +34,15 @@ package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.repository.Repository;
import sonia.scm.security.UUIDKeyGenerator;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
/**
*
* @author Sebastian Sdorra
@@ -52,6 +59,24 @@ public class FileBlobStoreTest extends BlobStoreTestBase
@Override
protected BlobStoreFactory createBlobStoreFactory()
{
return new FileBlobStoreFactory(contextProvider, new UUIDKeyGenerator());
return new FileBlobStoreFactory(contextProvider, repositoryLocationResolver, new UUIDKeyGenerator());
}
@Test
@SuppressWarnings("unchecked")
public void shouldStoreAndLoadInRepository() {
BlobStore store = createBlobStoreFactory()
.withName("test")
.forRepository(new Repository("id", "git", "ns", "n"))
.build();
Blob createdBlob = store.create("abc");
List<Blob> storedBlobs = store.getAll();
assertNotNull(createdBlob);
assertThat(storedBlobs)
.isNotNull()
.hasSize(1)
.usingElementComparatorOnFields("id").containsExactly(createdBlob);
}
}

View File

@@ -37,25 +37,22 @@ package sonia.scm.store;
import com.google.common.io.Closeables;
import com.google.common.io.Resources;
import org.junit.Test;
import sonia.scm.security.AssignedPermission;
import sonia.scm.security.UUIDKeyGenerator;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
@@ -132,13 +129,13 @@ public class JAXBConfigurationEntryStoreTest
public void testStoreAndLoad() throws IOException
{
String name = UUID.randomUUID().toString();
ConfigurationEntryStore<AssignedPermission> store =
createPermissionStore(RESOURCE_FIXED, name);
ConfigurationEntryStore<AssignedPermission> store = createPermissionStore(RESOURCE_FIXED, name);
store.put("a45", new AssignedPermission("tuser4", "repository:create"));
store =
createConfigurationStoreFactory().getStore(AssignedPermission.class,
name);
store = createConfigurationStoreFactory()
.withType(AssignedPermission.class)
.withName(name)
.build();
AssignedPermission ap = store.get("a45");
@@ -147,6 +144,16 @@ public class JAXBConfigurationEntryStoreTest
assertEquals("repository:create", ap.getPermission());
}
@Test
public void shouldStoreAndLoadInRepository() throws IOException
{
repoStore.put("abc", new StoreObject("abc_value"));
StoreObject storeObject = repoStore.get("abc");
assertNotNull(storeObject);
assertEquals("abc_value", storeObject.getValue());
}
/**
* Method description
*
@@ -154,10 +161,9 @@ public class JAXBConfigurationEntryStoreTest
* @return
*/
@Override
protected ConfigurationEntryStoreFactory createConfigurationStoreFactory()
protected ConfigurationEntryStoreFactory createConfigurationStoreFactory()
{
return new JAXBConfigurationEntryStoreFactory(new UUIDKeyGenerator(),
contextProvider);
return new JAXBConfigurationEntryStoreFactory(contextProvider, repositoryLocationResolver, new UUIDKeyGenerator());
}
/**
@@ -225,8 +231,9 @@ public class JAXBConfigurationEntryStoreTest
}
copy(resource, name);
return createConfigurationStoreFactory().getStore(AssignedPermission.class,
name);
return createConfigurationStoreFactory()
.withType(AssignedPermission.class)
.withName(name)
.build();
}
}

View File

@@ -32,9 +32,15 @@
package sonia.scm.store;
import org.junit.Test;
import sonia.scm.repository.Repository;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Unit tests for {@link JAXBConfigurationStore}.
*
*
* @author Sebastian Sdorra
*/
public class JAXBConfigurationStoreTest extends StoreTestBase {
@@ -42,6 +48,24 @@ public class JAXBConfigurationStoreTest extends StoreTestBase {
@Override
protected ConfigurationStoreFactory createStoreFactory()
{
return new JAXBConfigurationStoreFactory(contextProvider);
return new JAXBConfigurationStoreFactory(contextProvider, repositoryLocationResolver);
}
@Test
@SuppressWarnings("unchecked")
public void shouldStoreAndLoadInRepository()
{
ConfigurationStore<StoreObject> store = createStoreFactory()
.withType(StoreObject.class)
.withName("test")
.forRepository(new Repository("id", "git", "ns", "n"))
.build();
store.set(new StoreObject("value"));
StoreObject storeObject = store.get();
assertNotNull(storeObject);
assertEquals("value", storeObject.getValue());
}
}

View File

@@ -34,14 +34,18 @@ package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.repository.Repository;
import sonia.scm.security.UUIDKeyGenerator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
*
* @author Sebastian Sdorra
*/
public class JAXBDataStoreTest extends DataStoreTestBase
{
public class JAXBDataStoreTest extends DataStoreTestBase {
/**
* Method description
@@ -52,6 +56,33 @@ public class JAXBDataStoreTest extends DataStoreTestBase
@Override
protected DataStoreFactory createDataStoreFactory()
{
return new JAXBDataStoreFactory(contextProvider, new UUIDKeyGenerator());
return new JAXBDataStoreFactory(contextProvider, repositoryLocationResolver, new UUIDKeyGenerator());
}
@Override
protected DataStore getDataStore(Class type, Repository repository) {
return createDataStoreFactory()
.withType(type)
.withName("test")
.forRepository(repository)
.build();
}
@Override
protected DataStore getDataStore(Class type) {
return createDataStoreFactory()
.withType(type)
.withName("test")
.build();
}
@Test
public void shouldStoreAndLoadInRepository()
{
repoStore.put("abc", new StoreObject("abc_value"));
StoreObject storeObject = repoStore.get("abc");
assertNotNull(storeObject);
assertEquals("abc_value", storeObject.getValue());
}
}

View File

@@ -74,7 +74,11 @@ public class LfsBlobStoreFactory {
*
* @return blob store for the corresponding scm repository
*/
@SuppressWarnings("unchecked")
public BlobStore getLfsBlobStore(Repository repository) {
return blobStoreFactory.getBlobStore(repository.getId() + GIT_LFS_REPOSITORY_POSTFIX);
return blobStoreFactory
.withName(repository.getId() + GIT_LFS_REPOSITORY_POSTFIX)
.forRepository(repository)
.build();
}
}

View File

@@ -33,6 +33,7 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -44,6 +45,8 @@ import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------
@@ -81,6 +84,10 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
assertTrue(refs.isDirectory());
}
@Before
public void initFactory() {
when(factory.withType(any())).thenCallRealMethod();
}
@Override
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory,

View File

@@ -40,9 +40,12 @@ import org.mockito.junit.MockitoJUnitRunner;
import sonia.scm.repository.Repository;
import sonia.scm.store.BlobStoreFactory;
import static org.mockito.Matchers.matches;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
/**
* Unit tests for {@link LfsBlobStoreFactory}.
@@ -59,15 +62,21 @@ public class LfsBlobStoreFactoryTest {
private LfsBlobStoreFactory lfsBlobStoreFactory;
@Test
public void getBlobStore() throws Exception {
lfsBlobStoreFactory.getLfsBlobStore(new Repository("the-id", "GIT", "space", "the-name"));
public void getBlobStore() {
when(blobStoreFactory.withName(any())).thenCallRealMethod();
Repository repository = new Repository("the-id", "GIT", "space", "the-name");
lfsBlobStoreFactory.getLfsBlobStore(repository);
// just make sure the right parameter is passed, as properly validating the return value is nearly impossible with
// the return value (and should not be part of this test)
verify(blobStoreFactory).getBlobStore(matches("the-id-git-lfs"));
verify(blobStoreFactory).getStore(argThat(blobStoreParameters -> {
assertThat(blobStoreParameters.getName()).isEqualTo("the-id-git-lfs");
assertThat(blobStoreParameters.getRepository()).isEqualTo(repository);
return true;
}));
// make sure there have been no further usages of the factory
verifyNoMoreInteractions(blobStoreFactory);
verify(blobStoreFactory, times(1)).getStore(any());
}
}

View File

@@ -34,6 +34,7 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -44,6 +45,8 @@ import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------
@@ -67,6 +70,11 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
assertTrue(hgDirectory.isDirectory());
}
@Before
public void initFactory() {
when(factory.withType(any())).thenCallRealMethod();
}
@Override
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, RepositoryLocationResolver locationResolver, File directory) {
HgRepositoryHandler handler = new HgRepositoryHandler(factory, new HgContextProvider(), locationResolver);

View File

@@ -0,0 +1,36 @@
package sonia.scm.web;
import org.junit.Test;
import sonia.scm.repository.HgRepositoryHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static sonia.scm.web.HgHookCallbackServlet.PARAM_REPOSITORYID;
public class HgHookCallbackServletTest {
@Test
public void shouldExtractCorrectRepositoryId() throws ServletException, IOException {
HgRepositoryHandler handler = mock(HgRepositoryHandler.class);
HgHookCallbackServlet servlet = new HgHookCallbackServlet(null, handler, null, null);
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
when(request.getContextPath()).thenReturn("http://example.com/scm");
when(request.getRequestURI()).thenReturn("http://example.com/scm/hook/hg/pretxnchangegroup");
String path = "/tmp/hg/12345";
when(request.getParameter(PARAM_REPOSITORYID)).thenReturn(path);
servlet.doPost(request, response);
verify(response, never()).sendError(anyInt());
}
}

View File

@@ -55,6 +55,7 @@ import sonia.scm.logging.SVNKitLogger;
import sonia.scm.plugin.Extension;
import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.repository.spi.SvnRepositoryServiceProvider;
import sonia.scm.store.ConfigurationStore;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.util.Util;

View File

@@ -32,6 +32,7 @@
package sonia.scm.repository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -42,12 +43,14 @@ import sonia.scm.store.ConfigurationStore;
import sonia.scm.store.ConfigurationStoreFactory;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
//~--- JDK imports ------------------------------------------------------------
@@ -55,15 +58,11 @@ import static org.mockito.Mockito.when;
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Mock
private ConfigurationStoreFactory factory;
@Mock
private ConfigurationStore store;
@Mock
private com.google.inject.Provider<RepositoryManager> repositoryManagerProvider;
@@ -71,6 +70,12 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
private HookEventFacade facade = new HookEventFacade(repositoryManagerProvider, hookContextFactory);
@Override
protected void postSetUp() throws IOException, RepositoryPathNotFoundException {
initMocks(this);
super.postSetUp();
}
@Override
protected void checkDirectory(File directory) {
File format = new File(directory, "format");
@@ -102,7 +107,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Test
public void getDirectory() {
when(factory.getStore(any(), any())).thenReturn(store);
when(factory.withType(any())).thenCallRealMethod();
SvnRepositoryHandler repositoryHandler = new SvnRepositoryHandler(factory,
facade, locationResolver);

View File

@@ -46,10 +46,15 @@ import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import sonia.scm.io.DefaultFileSystem;
import sonia.scm.repository.InitialRepositoryLocationResolver;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.util.IOUtil;
import sonia.scm.util.MockUtil;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
//~--- JDK imports ------------------------------------------------------------
@@ -66,10 +71,29 @@ import java.util.logging.Logger;
public class AbstractTestBase
{
/** Field description */
private static ThreadState subjectThreadState;
//~--- methods --------------------------------------------------------------
protected SCMContextProvider contextProvider;
private File tempDirectory;
protected DefaultFileSystem fileSystem;
protected RepositoryDAO repositoryDAO = mock(RepositoryDAO.class);
protected RepositoryLocationResolver repositoryLocationResolver;
@Before
public void setUpTest() throws Exception
{
tempDirectory = new File(System.getProperty("java.io.tmpdir"),
UUID.randomUUID().toString());
assertTrue(tempDirectory.mkdirs());
contextProvider = MockUtil.getSCMContextProvider(tempDirectory);
fileSystem = new DefaultFileSystem();
InitialRepositoryLocationResolver initialRepoLocationResolver = new InitialRepositoryLocationResolver();
repositoryLocationResolver = new RepositoryLocationResolver(contextProvider, repositoryDAO, initialRepoLocationResolver);
postSetUp();
}
/**
* Method description
@@ -165,25 +189,6 @@ public class AbstractTestBase
}
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @throws Exception
*/
@Before
public void setUpTest() throws Exception
{
tempDirectory = new File(System.getProperty("java.io.tmpdir"),
UUID.randomUUID().toString());
assertTrue(tempDirectory.mkdirs());
contextProvider = MockUtil.getSCMContextProvider(tempDirectory);
postSetUp();
}
//~--- methods --------------------------------------------------------------
/**
* Clears Shiro's thread state, ensuring the thread remains clean for
@@ -249,12 +254,4 @@ public class AbstractTestBase
subjectThreadState = createThreadState(subject);
subjectThreadState.bind();
}
//~--- fields ---------------------------------------------------------------
/** Field description */
protected SCMContextProvider contextProvider;
/** Field description */
private File tempDirectory;
}

View File

@@ -37,11 +37,16 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import sonia.scm.repository.InitialRepositoryLocationResolver;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.util.MockUtil;
import java.io.File;
import java.io.IOException;
import static org.mockito.Mockito.mock;
/**
*
* @author Sebastian Sdorra
@@ -55,14 +60,21 @@ public abstract class ManagerTestBase<T extends ModelObject>
public TemporaryFolder tempFolder = new TemporaryFolder();
protected SCMContextProvider contextProvider;
protected RepositoryLocationResolver locationResolver;
protected Manager<T> manager;
protected File temp;
protected File temp ;
@Before
public void setUp() throws IOException {
temp = tempFolder.newFolder();
if (temp == null){
temp = tempFolder.newFolder();
}
contextProvider = MockUtil.getSCMContextProvider(temp);
InitialRepositoryLocationResolver initialRepositoryLocationResolver = new InitialRepositoryLocationResolver();
RepositoryDAO repoDao = mock(RepositoryDAO.class);
locationResolver = new RepositoryLocationResolver(contextProvider, repoDao ,initialRepositoryLocationResolver);
manager = createManager();
manager.init(contextProvider);
}

View File

@@ -43,7 +43,6 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
@@ -99,7 +98,6 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase {
handler.create(repository);
assertTrue(nativeRepoDirectory.exists());
assertTrue(nativeRepoDirectory.isDirectory());
checkDirectory(nativeRepoDirectory);

View File

@@ -35,22 +35,24 @@ package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteStreams;
import org.junit.Before;
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import sonia.scm.repository.RepositoryTestData;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
@@ -58,12 +60,6 @@ import java.util.List;
public abstract class BlobStoreTestBase extends AbstractTestBase
{
/**
* Method description
*
*
* @return
*/
protected abstract BlobStoreFactory createBlobStoreFactory();
/**
@@ -73,7 +69,10 @@ public abstract class BlobStoreTestBase extends AbstractTestBase
@Before
public void createBlobStore()
{
store = createBlobStoreFactory().getBlobStore("test");
store = createBlobStoreFactory()
.withName("test")
.forRepository(RepositoryTestData.createHeartOfGold())
.build();
store.clear();
}

View File

@@ -32,12 +32,13 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
*
* @author Sebastian Sdorra
*/
public abstract class ConfigurationEntryStoreTestBase extends KeyValueStoreTestBase
{
public abstract class ConfigurationEntryStoreTestBase extends KeyValueStoreTestBase {
/**
* Method description
@@ -48,17 +49,20 @@ public abstract class ConfigurationEntryStoreTestBase extends KeyValueStoreTestB
protected abstract ConfigurationEntryStoreFactory createConfigurationStoreFactory();
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected ConfigurationEntryStore<StoreObject> getDataStore()
{
return createConfigurationStoreFactory().getStore(StoreObject.class,
"test");
protected ConfigurationEntryStore getDataStore(Class type) {
return this.createConfigurationStoreFactory()
.withType(type)
.withName(storeName)
.build();
}
@Override
protected ConfigurationEntryStore getDataStore(Class type, Repository repository) {
return this.createConfigurationStoreFactory()
.withType(type)
.withName(repoStoreName)
.forRepository(repository)
.build();
}
}

View File

@@ -33,6 +33,13 @@
package sonia.scm.store;
import org.junit.Test;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryTestData;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
*
* @author Sebastian Sdorra
@@ -48,17 +55,29 @@ public abstract class DataStoreTestBase extends KeyValueStoreTestBase
*/
protected abstract DataStoreFactory createDataStoreFactory();
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected DataStore<StoreObject> getDataStore()
@Test
public void shouldStoreRepositorySpecificData()
{
return createDataStoreFactory().getStore(StoreObject.class, "test");
DataStoreFactory dataStoreFactory = createDataStoreFactory();
StoreObject obj = new StoreObject("test-1");
Repository repository = RepositoryTestData.createHeartOfGold();
DataStore<StoreObject> store = dataStoreFactory
.withType(StoreObject.class)
.withName("test")
.forRepository(repository)
.build();
String id = store.put(obj);
assertNotNull(id);
assertEquals(obj, store.get(id));
}
}

View File

@@ -43,8 +43,7 @@ package sonia.scm.store;
public class InMemoryConfigurationStoreFactory implements ConfigurationStoreFactory {
@Override
public <T> ConfigurationStore<T> getStore(Class<T> type, String name)
{
public ConfigurationStore getStore(TypedStoreParameters storeParameters) {
return new InMemoryConfigurationStore<>();
}
}

View File

@@ -38,6 +38,8 @@ import org.junit.Before;
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryTestData;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -56,13 +58,21 @@ import java.util.Map;
public abstract class KeyValueStoreTestBase extends AbstractTestBase
{
protected Repository repository = RepositoryTestData.createHeartOfGold();
protected DataStore<StoreObject> store;
protected DataStore<StoreObject> repoStore;
protected String repoStoreName = "testRepoStore";
protected String storeName = "testStore";
/**
* Method description
*
*
* @return
*/
protected abstract DataStore<StoreObject> getDataStore();
protected abstract <STORE_OBJECT> DataStore<STORE_OBJECT> getDataStore(Class<STORE_OBJECT> type , Repository repository);
protected abstract <STORE_OBJECT> DataStore<STORE_OBJECT> getDataStore(Class<STORE_OBJECT> type );
//~--- methods --------------------------------------------------------------
@@ -73,8 +83,10 @@ public abstract class KeyValueStoreTestBase extends AbstractTestBase
@Before
public void before()
{
store = getDataStore();
store = getDataStore(StoreObject.class);
repoStore = getDataStore(StoreObject.class, repository);
store.clear();
repoStore.clear();
}
/**
@@ -215,8 +227,5 @@ public abstract class KeyValueStoreTestBase extends AbstractTestBase
assertNull(store.get("2"));
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private DataStore<StoreObject> store;
}

View File

@@ -35,10 +35,11 @@ package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
//~--- JDK imports ------------------------------------------------------------
@@ -65,8 +66,7 @@ public abstract class StoreTestBase extends AbstractTestBase
@Test
public void testGet()
{
ConfigurationStore<StoreObject> store = createStoreFactory().getStore(StoreObject.class,
"test");
ConfigurationStore<StoreObject> store = createStoreFactory().withType(StoreObject.class).withName("test").build();
assertNotNull(store);
@@ -82,8 +82,7 @@ public abstract class StoreTestBase extends AbstractTestBase
@Test
public void testSet()
{
ConfigurationStore<StoreObject> store = createStoreFactory().getStore(StoreObject.class,
"test");
ConfigurationStore<StoreObject> store = createStoreFactory().withType(StoreObject.class).withName("test").build();
assertNotNull(store);

View File

@@ -52,7 +52,7 @@ public final class DebugService
private final Multimap<NamespaceAndName,DebugHookData> receivedHooks = LinkedListMultimap.create();
/**
* Stores {@link DebugHookData} for the given repository.
* Store {@link DebugHookData} for the given repository.
*/
void put(NamespaceAndName namespaceAndName, DebugHookData hookData)
{

View File

@@ -108,9 +108,13 @@ public class DefaultSecuritySystem implements SecuritySystem
* @param storeFactory
*/
@Inject
@SuppressWarnings("unchecked")
public DefaultSecuritySystem(ConfigurationEntryStoreFactory storeFactory)
{
store = storeFactory.getStore(AssignedPermission.class, NAME);
store = storeFactory
.withType(AssignedPermission.class)
.withName(NAME)
.build();
readAvailablePermissions();
}

View File

@@ -87,9 +87,13 @@ public class SecureKeyResolver extends SigningKeyResolverAdapter
* @param storeFactory store factory
*/
@Inject
@SuppressWarnings("unchecked")
public SecureKeyResolver(ConfigurationEntryStoreFactory storeFactory)
{
this.store = storeFactory.getStore(SecureKey.class, STORE_NAME);
store = storeFactory
.withType(SecureKey.class)
.withName(STORE_NAME)
.build();
}
//~--- methods --------------------------------------------------------------

View File

@@ -66,7 +66,8 @@ public class AutoCompleteResourceTest {
ConfigurationStore<Object> storeConfig = mock(ConfigurationStore.class);
xmlDB = mock(XmlDatabase.class);
when(storeConfig.get()).thenReturn(xmlDB);
when(storeFactory.getStore(any(), any())).thenReturn(storeConfig);
when(storeFactory.getStore(any())).thenReturn(storeConfig);
when(storeFactory.withType(any())).thenCallRealMethod();
XmlUserDAO userDao = new XmlUserDAO(storeFactory);
this.userDao = spy(userDao);
XmlGroupDAO groupDAO = new XmlGroupDAO(storeFactory);

View File

@@ -418,10 +418,10 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository> {
private DefaultRepositoryManager createRepositoryManager(boolean archiveEnabled, KeyGenerator keyGenerator) {
DefaultFileSystem fileSystem = new DefaultFileSystem();
Set<RepositoryHandler> handlerSet = new HashSet<>();
ConfigurationStoreFactory factory = new JAXBConfigurationStoreFactory(contextProvider);
InitialRepositoryLocationResolver initialRepositoryLocationResolver = new InitialRepositoryLocationResolver();
XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(contextProvider, initialRepositoryLocationResolver, fileSystem);
RepositoryLocationResolver repositoryLocationResolver = new RepositoryLocationResolver(contextProvider, repositoryDAO, initialRepositoryLocationResolver);
ConfigurationStoreFactory factory = new JAXBConfigurationStoreFactory(contextProvider, repositoryLocationResolver);
handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver));
handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver) {
@Override

View File

@@ -70,8 +70,7 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
public void createSecuritySystem()
{
JAXBConfigurationEntryStoreFactory factory =
new JAXBConfigurationEntryStoreFactory(new UUIDKeyGenerator(),
contextProvider);
new JAXBConfigurationEntryStoreFactory(contextProvider , repositoryLocationResolver, new UUIDKeyGenerator() );
securitySystem = new DefaultSecuritySystem(factory);

View File

@@ -36,20 +36,22 @@ package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import io.jsonwebtoken.Jwts;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import sonia.scm.store.ConfigurationEntryStore;
import sonia.scm.store.ConfigurationEntryStoreFactory;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
*
@@ -122,11 +124,14 @@ public class SecureKeyResolverTest
@Before
public void setUp()
{
ConfigurationEntryStoreFactory factory =
mock(ConfigurationEntryStoreFactory.class);
ConfigurationEntryStoreFactory factory = mock(ConfigurationEntryStoreFactory.class);
when(factory.getStore(SecureKey.class,
SecureKeyResolver.STORE_NAME)).thenReturn(store);
when(factory.withType(any())).thenCallRealMethod();
when(factory.<SecureKey>getStore(argThat(storeParameters -> {
assertThat(storeParameters.getName()).isEqualTo(SecureKeyResolver.STORE_NAME);
assertThat(storeParameters.getType()).isEqualTo(SecureKey.class);
return true;
}))).thenReturn(store);
resolver = new SecureKeyResolver(factory);
}

View File

@@ -45,6 +45,9 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import sonia.scm.NotFoundException;
import sonia.scm.repository.InitialRepositoryLocationResolver;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.store.JAXBConfigurationStoreFactory;
import sonia.scm.user.xml.XmlUserDAO;
@@ -72,7 +75,7 @@ public class DefaultUserManagerTest extends UserManagerTestBase
public ShiroRule shiro = new ShiroRule();
private UserDAO userDAO = mock(UserDAO.class);
private UserDAO userDAO ;
private User trillian;
/**
@@ -182,6 +185,6 @@ public class DefaultUserManagerTest extends UserManagerTestBase
//~--- methods --------------------------------------------------------------
private XmlUserDAO createXmlUserDAO() {
return new XmlUserDAO(new JAXBConfigurationStoreFactory(contextProvider));
return new XmlUserDAO(new JAXBConfigurationStoreFactory(contextProvider, locationResolver));
}
}