Skip to content

Commit

Permalink
Add more tests!
Browse files Browse the repository at this point in the history
  • Loading branch information
avojak committed Mar 29, 2019
1 parent 1961501 commit cc21fdb
Show file tree
Hide file tree
Showing 16 changed files with 785 additions and 31 deletions.
10 changes: 10 additions & 0 deletions aws-p2-repository-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,21 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.avojak.webapp.aws.p2.repository.service.cache;

import com.avojak.webapp.aws.p2.repository.model.project.Project;
import com.avojak.webapp.aws.p2.repository.service.configuration.ServiceProperties;
import com.google.common.base.Ticker;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* Factory class to create new instances of {@link LoadingCache}.
*/
@Component
public class LoadingCacheFactory {

private final ProjectCacheLoader cacheLoader;
private final Ticker ticker;
private final ServiceProperties properties;

/**
* Constructor.
*
* @param cacheLoader
* The {@link ProjectCacheLoader}. Cannot be null.
* @param ticker
* The {@link Ticker}. Cannot be null.
* @param properties
* The {@link ServiceProperties}. Cannot be null.
*/
@Autowired
public LoadingCacheFactory(final ProjectCacheLoader cacheLoader, final Ticker ticker,
final ServiceProperties properties) {
this.cacheLoader = checkNotNull(cacheLoader, "cacheLoader cannot be null");
this.ticker = checkNotNull(ticker, "ticker cannot be null");
this.properties = checkNotNull(properties, "properties cannot be null");
}

/**
* Creates a new instance of {@link LoadingCache}.
*
* @return The new, non-null {@link LoadingCache}.
*/
public LoadingCache<Boolean, Map<String, Project>> create() {
return CacheBuilder.newBuilder()
.expireAfterWrite(properties.getCacheExpirationDuration(), properties.getCacheExpirationUnits())
.ticker(ticker)
.build(cacheLoader);
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.avojak.webapp.aws.p2.repository.service.cache;

import com.avojak.webapp.aws.p2.repository.model.project.Project;
import com.avojak.webapp.aws.p2.repository.service.configuration.ServiceProperties;
import com.google.common.base.Ticker;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -31,15 +28,9 @@ public class ProjectCache {
private final LoadingCache<Boolean, Map<String, Project>> cache;

@Autowired
public ProjectCache(final ProjectCacheLoader cacheLoader, final Ticker ticker, final ServiceProperties properties) {
checkNotNull(cacheLoader, "cacheLoader cannot be null");
checkNotNull(ticker, "ticker cannot be null");
checkNotNull(properties, "properties cannot be null");

cache = CacheBuilder.newBuilder()
.expireAfterWrite(properties.getCacheExpirationDuration(), properties.getCacheExpirationUnits())
.ticker(ticker)
.build(cacheLoader);
public ProjectCache(final LoadingCacheFactory cacheFactory) {
checkNotNull(cacheFactory, "cacheFactory cannot be null");
cache = cacheFactory.create();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.Optional;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* Implementation of {@link CacheLoader} for the {@link ProjectCache}.
*/
Expand All @@ -30,14 +32,27 @@ public class ProjectCacheLoader extends CacheLoader<Boolean, Map<String, Project
private static final String KEY_DELIM = "/";
private static final String P2_INDEX_KEY_ELEM = "p2.index";

private final S3BucketRepository s3BucketRepository;
private final MetadataRepository metadataRepository;
private final ServiceProperties properties;

/**
* Constructor.
*
* @param s3BucketRepository
* The {@link S3BucketRepository}. Cannot be null.
* @param metadataRepository
* The {@link MetadataRepository}. Cannot be null.
* @param properties
* The {@link ServiceProperties}. Cannot be null.
*/
@Autowired
private S3BucketRepository s3BucketRepository;

@Autowired
private MetadataRepository metadataRepository;

@Autowired
private ServiceProperties properties;
public ProjectCacheLoader(final S3BucketRepository s3BucketRepository, final MetadataRepository metadataRepository,
final ServiceProperties properties) {
this.s3BucketRepository = checkNotNull(s3BucketRepository, "s3BucketRepository cannot be null");
this.metadataRepository = checkNotNull(metadataRepository, "metadataRepository cannot be null");
this.properties = checkNotNull(properties, "properties cannot be null");
}

// TODO: Refactor this
@Override
Expand Down Expand Up @@ -87,7 +102,7 @@ public Map<String, Project> load(final Boolean k) {
}

// Update the most recent summary and version
if (!mostRecentSummary.isPresent() || (version.compareTo(mostRecentVersion.get()) > 1)) {
if (!mostRecentSummary.isPresent() || (version.compareTo(mostRecentVersion.get()) < 1)) {
mostRecentSummary = Optional.of(summary);
mostRecentVersion = Optional.of(version);
}
Expand All @@ -102,8 +117,8 @@ public Map<String, Project> load(final Boolean k) {
Collections.sort(releases);

// Create the new project object, overriding the name from the metadata with the project name
final String url = mostRecentSummary.get().getKey().replace(KEY_DELIM + P2_INDEX_KEY_ELEM, "");
final P2Repository metadata = metadataRepository.getMetadata(s3BucketRepository.getHostingUrl(url));
final String key = mostRecentSummary.get().getKey().replace(KEY_DELIM + P2_INDEX_KEY_ELEM, "");
final P2Repository metadata = metadataRepository.getMetadata(s3BucketRepository.getHostingUrl(key));
final P2Repository updatedMetadata = new P2Repository(name, metadata.getLocation(), metadata.isCompressed(),
metadata.getLastModified(), metadata.getGroups());
final String customDomain = properties.getCustomDomain();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import java.util.concurrent.TimeUnit;

/**
* Service configuration class.
*/
@Configuration
public class ServiceConfiguration {

Expand All @@ -28,11 +31,21 @@ public class ServiceConfiguration {
@Value("${aws.p2.repo.webapp.custom.domain}")
private String customDomain;

/**
* Creates a new {@link Ticker}.
*
* @return The new, non-null {@link Ticker}.
*/
@Bean
public Ticker ticker() {
return Ticker.systemTicker();
}

/**
* Creates the service properties.
*
* @return The new, non-null {@link ServiceProperties}.
*/
@Bean
public ServiceProperties serviceProperties() {
return new ServiceProperties(cacheExpirationDuration, cacheExpirationUnits, latestSnapshotContentUrlFormat,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

import java.util.concurrent.TimeUnit;

/**
* Models the service properties.
*/
@Component
public class ServiceProperties {
public final class ServiceProperties {

private final long cacheExpirationDuration;
private final TimeUnit cacheExpirationUnits;
Expand All @@ -18,9 +21,25 @@ public class ServiceProperties {
private final String genericContentUrlFormat;
private final String customDomain;

ServiceProperties(final long cacheExpirationDuration, final TimeUnit cacheExpirationUnits,
final String latestSnapshotContentUrlFormat, final String latestReleaseContentUrlFormat,
final String genericContentUrlFormat, final String customDomain) {
/**
* Constructor.
*
* @param cacheExpirationDuration
* The cache expiration duration.
* @param cacheExpirationUnits
* The units of the cache expiration duration.
* @param latestSnapshotContentUrlFormat
* The format of the URL for the latest snapshot content.
* @param latestReleaseContentUrlFormat
* The format of the URL for the latest release content.
* @param genericContentUrlFormat
* The format of the URL for generic version content.
* @param customDomain
* The custom domain name.
*/
public ServiceProperties(final long cacheExpirationDuration, final TimeUnit cacheExpirationUnits,
final String latestSnapshotContentUrlFormat, final String latestReleaseContentUrlFormat,
final String genericContentUrlFormat, final String customDomain) {
this.cacheExpirationDuration = cacheExpirationDuration;
this.cacheExpirationUnits = cacheExpirationUnits;
this.latestSnapshotContentUrlFormat = latestSnapshotContentUrlFormat;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

Expand All @@ -33,6 +32,7 @@ public class DataServiceImpl implements DataService {

private final S3BucketRepository repository;
private final ProjectCache projectCache;
private final InputStreamResourceFactory inputStreamResourceFactory;
private final ApplicationContext context;

/**
Expand All @@ -47,9 +47,11 @@ public class DataServiceImpl implements DataService {
*/
@Autowired
public DataServiceImpl(final S3BucketRepository repository, final ProjectCache projectCache,
final InputStreamResourceFactory inputStreamResourceFactory,
final ApplicationContext context) {
this.repository = checkNotNull(repository, "repository cannot be null");
this.projectCache = checkNotNull(projectCache, "projectCache cannot be null");
this.inputStreamResourceFactory = checkNotNull(inputStreamResourceFactory, "inputStreamResourceFactory cannot be null");
this.context = checkNotNull(context, "context cannot be null");
}

Expand Down Expand Up @@ -102,7 +104,7 @@ private Optional<String> getLatestVersion(final String name, final Qualifier qua
private Optional<Resource> getResource(final String key) {
final Optional<S3Object> object = repository.getObject(key);
if (object.isPresent()) {
return Optional.of(new InputStreamResource(object.get().getObjectContent()));
return Optional.of(inputStreamResourceFactory.create(object.get().getObjectContent()));
}
LOGGER.debug("No object found for key [{}]", key);
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.avojak.webapp.aws.p2.repository.service.impl;

import com.amazonaws.services.s3.model.S3ObjectInputStream;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Component;

/**
* Factory class to create instances of {@link InputStreamResource}.
*/
@Component
public class InputStreamResourceFactory {

/**
* Creates a new input stream resource for the given S3 object input stream.
*
* @param s3ObjectInputStream
* The {@link S3ObjectInputStream}.
*
* @return The new, non-null {@link InputStreamResource}.
*/
public InputStreamResource create(final S3ObjectInputStream s3ObjectInputStream) {
return new InputStreamResource(s3ObjectInputStream);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.avojak.webapp.aws.p2.repository.service.cache;

import com.avojak.webapp.aws.p2.repository.service.configuration.ServiceProperties;
import com.google.common.base.Ticker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertNotNull;

/**
* Test class for {@link LoadingCacheFactory}.
*/
@RunWith(MockitoJUnitRunner.class)
public class LoadingCacheFactoryTest {

@Mock
private ProjectCacheLoader projectCacheLoader;

@Mock
private Ticker ticker;

private ServiceProperties properties;

@Before
public void setup() {
properties = new ServiceProperties(30000L, TimeUnit.SECONDS, "{0}", "{0}", "{0}", "p2.avojak.com");
}

@Test(expected = NullPointerException.class)
public void testConstructor_NullCacheLoader() {
new LoadingCacheFactory(null, ticker, properties);
}

@Test(expected = NullPointerException.class)
public void testConstructor_NullTicker() {
new LoadingCacheFactory(projectCacheLoader, null, properties);
}

@Test(expected = NullPointerException.class)
public void testConstructor_NullServiceProperties() {
new LoadingCacheFactory(projectCacheLoader, ticker, null);
}

@Test
public void testCreate() {
assertNotNull(new LoadingCacheFactory(projectCacheLoader, ticker, properties).create());
}

}

0 comments on commit cc21fdb

Please sign in to comment.