Skip to content

Commit

Permalink
Merge pull request #363 from groldan/bug/azure_blob_store
Browse files Browse the repository at this point in the history
Fix AzureBlobStore regression due to wrong netty version after dependencyConvergence maven rule
  • Loading branch information
groldan authored Oct 7, 2023
2 parents d15b804 + 0afab42 commit 55486fb
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/apps/geoserver/gwc/src/main/resources/bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ spring:
- org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
- org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
- org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
- org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration

# override default of true, this service does not use the registry (when eureka client is enabled)
eureka.client.fetch-registry: false
Expand Down
3 changes: 3 additions & 0 deletions src/apps/geoserver/gwc/src/test/resources/bootstrap-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ spring:
cloud.config.enabled: false
cloud.config.discovery.enabled: false
cloud.discovery.enabled: false
cloud.bus.enabled: false
eureka.client.enabled: false
geoserver:
acl.enabled: false
Expand All @@ -16,7 +17,9 @@ logging:
root: warn
org.geotools: warn
org.geoserver: warn
org.geoserver.security: error
org.geoserver.cloud: info
org.geoserver.cloud.config.catalog: warn
org.geoserver.cloud.config.factory: info
org.geowebcache.config.XMLConfiguration: off
org.springframework.test: info
Expand Down
1 change: 1 addition & 0 deletions src/apps/infrastructure/gateway/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<properties>
<dockerfile.skip>false</dockerfile.skip>
<docker.image.name>geoserver-cloud-gateway</docker.image.name>
<netty.version>4.1.94.Final</netty.version>
</properties>
<dependencies>
<dependency>
Expand Down
5 changes: 5 additions & 0 deletions src/gwc/backends/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* (c) 2023 Open Source Geospatial Foundation - all rights reserved This code is licensed under the
* GPL 2.0 license, available at the root application directory.
*/
package org.geoserver.cloud.gwc.config.blobstore;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.commons.io.IOUtils;
import org.geowebcache.GeoWebCacheEnvironment;
import org.geowebcache.GeoWebCacheExtensions;
import org.geowebcache.azure.AzureBlobStore;
import org.geowebcache.azure.AzureBlobStoreInfo;
import org.geowebcache.io.ByteArrayResource;
import org.geowebcache.io.Resource;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.layer.TileLayerDispatcher;
import org.geowebcache.locks.MemoryLockProvider;
import org.geowebcache.storage.BlobStore;
import org.geowebcache.storage.StorageException;
import org.geowebcache.storage.TileObject;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.util.Map;

/**
* Verify {@link AzureBlobStore} works by connecting to an Azurite container
*
* @see AzuriteContainer
*/
@Testcontainers
public class AzureBlobStoreTest {

@Container static AzuriteContainer azurite = new AzuriteContainer();

protected AzureBlobStoreInfo newAzureBlobStoreInfo() {
AzureBlobStoreInfo bsi = new AzureBlobStoreInfo();

String accountName = azurite.getAccountName();
String accountKey = azurite.getAccountKey();
String blobsUrl = azurite.getBlobsUrl();

bsi.setAccountName(accountName);
bsi.setAccountKey(accountKey);
bsi.setServiceURL(blobsUrl);
bsi.setUseHTTPS(false);
bsi.setContainer("azureblobstoretest");
bsi.setName("AzureBlobStoreTest");
bsi.setEnabled(true);
// bsi.setPrefix("/gwc/");
return bsi;
}

static StaticApplicationContext stubAppContext;

static @BeforeAll void setUpContext() {
GeoWebCacheExtensions extensions = new GeoWebCacheExtensions();
GeoWebCacheEnvironment environment = new GeoWebCacheEnvironment();

stubAppContext = new StaticApplicationContext();
stubAppContext.registerBean(GeoWebCacheExtensions.class, () -> extensions);
stubAppContext.registerBean(GeoWebCacheEnvironment.class, () -> environment);
stubAppContext.refresh();
}

static @AfterAll void closeContext() {
stubAppContext.close();
}

public @Test void createBlobStore() throws StorageException {
AzureBlobStoreInfo info = newAzureBlobStoreInfo();
BlobStore store =
info.createInstance(mock(TileLayerDispatcher.class), new MemoryLockProvider());
assertThat(store).isInstanceOf(AzureBlobStore.class);
}

public @Test void testPutGet() throws Exception {
TileLayerDispatcher layers = mock(TileLayerDispatcher.class);

AzureBlobStoreInfo info = newAzureBlobStoreInfo();
AzureBlobStore store =
(AzureBlobStore) info.createInstance(layers, new MemoryLockProvider());

final String layerName = "FakeLayer";
final long[] xyz = new long[] {0, 0, 0};
final String gridSetId = "EPSG:3857";
final String format = "image/png";
final Map<String, String> parameters = null;
byte[] contents = new byte[] {1, 2, 3, 4, 5, 6, 7};
final Resource blob = new ByteArrayResource(contents);

TileLayer tileLayer = mock(TileLayer.class);
when(tileLayer.getId()).thenReturn(layerName);
when(layers.getTileLayer(eq(layerName))).thenReturn(tileLayer);

TileObject tile =
TileObject.createCompleteTileObject(
layerName, xyz, gridSetId, format, parameters, blob);
store.put(tile);

TileObject query =
TileObject.createQueryTileObject(layerName, xyz, gridSetId, format, parameters);

// can't really test get, see https://github.com/Azure/Azurite/issues/217
if (true) return;
assertThat(store.get(query)).isTrue();
assertThat(query.getBlob()).isNotNull();
byte[] readContents = IOUtils.toByteArray(query.getBlob().getInputStream());
assertThat(readContents).isEqualTo(contents);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.geoserver.cloud.gwc.config.blobstore;

import lombok.Getter;
import lombok.NonNull;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

/**
* {@link Testcontainers} container for AWS Azurite blobstore test environment.
*
* <p>Runs the <a href=
* "https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&bc=%2Fazure%2Fstorage%2Fblobs%2Fbreadcrumb%2Ftoc.json&tabs=docker-hub">Azurite
* emulator</a> for local Azure Storage development with testcontainers.
*
* <p>Azurite accepts the same well-known account and key used by the legacy Azure Storage Emulator.
*
* <ul>
* <li>Account name: {@code devstoreaccount1}
* <li>Account key: {@code
* Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==}
* </ul>
*/
public class AzuriteContainer extends GenericContainer<AzuriteContainer> {

private static final @NonNull DockerImageName IMAGE_NAME =
DockerImageName.parse("mcr.microsoft.com/azure-storage/azurite:latest");

public final @Getter String accountName = "devstoreaccount1";
public final @Getter String accountKey =
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";

private final int blobsPort = 10_000;

public AzuriteContainer() {
super(IMAGE_NAME);
super.setWaitStrategy(Wait.forListeningPort());
super.addExposedPort(blobsPort);
}

public int getBlobsPort() {
return super.getMappedPort(blobsPort);
}

public String getBlobsUrl() {
return "http://localhost:%d/%s".formatted(getBlobsPort(), getAccountName());
}
}
16 changes: 16 additions & 0 deletions src/gwc/backends/src/test/resources/logback-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger [%X{instance-id}] %msg%n</pattern>
</encoder>
</appender>

<root level="info">
<appender-ref ref="STDOUT" />
</root>

<logger name="org.springframework.test" level="ERROR" />
<logger name="org.springframework.boot.test" level="ERROR" />
<logger name="com.microsoft.azure.storage.blob" level="WARN" />

</configuration>
29 changes: 14 additions & 15 deletions src/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@
<gs.community.version>2.23-CLOUD</gs.community.version>
<gt.version>29-SNAPSHOT</gt.version>
<acl.version>1.0.2</acl.version>
<!-- downgrade netty.version used by spring-boot to the one used by
geoserver azure client -->
<!-- (software.amazon.awssdk:netty-nio-client:jar:2.9.24) for COG and
GWC Azure plugin -->
<!-- Downgrade netty.version used by spring-boot to the one used by geoserver azure client
(software.amazon.awssdk:netty-nio-client:jar:2.9.24) for COG and GWC Azure plugin -->
<netty.version>4.1.41.Final</netty.version>
<lombok.version>1.18.30</lombok.version>
<mapstruct.version>1.4.2.Final</mapstruct.version>
Expand Down Expand Up @@ -904,6 +902,7 @@
<inherited>true</inherited>
<configuration>
<reuseForks>false</reuseForks>
<argLine>--add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.desktop/sun.awt.image=ALL-UNNAMED --add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED</argLine>
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -1113,57 +1112,57 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-socks</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler-proxy</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-unix-common</artifactId>
<version>4.1.94.Final</version>
<version>${netty.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Expand Down

0 comments on commit 55486fb

Please sign in to comment.