Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.oak.blob.cloud.azure.blobstorage;

import java.lang.reflect.Field;
import java.net.URI;

import org.apache.jackrabbit.core.data.DataIdentifier;
import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordDownloadOptions;
import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUploadOptions;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

/**
* Compatibility tests for direct-download and upload cache configuration in
* {@link AzureBlobStoreBackend}. The assertions are intentionally behavior-
* based and do not depend on a specific cache library.
*/
public class AzureBlobStoreBackendCompatibilityTest {

@Test
public void setHttpDownloadURIExpirySecondsUpdatesField() throws Exception {
// Setter coverage for the direct-download expiry value used by presigned URIs.
AzureBlobStoreBackend backend = new AzureBlobStoreBackend();

backend.setHttpDownloadURIExpirySeconds(3600);

assertEquals(3600, getIntField(backend, "httpDownloadURIExpirySeconds"));
}

@Test
public void setHttpUploadURIExpirySecondsUpdatesField() throws Exception {
// Setter coverage for the direct-upload expiry used during upload initiation.
AzureBlobStoreBackend backend = new AzureBlobStoreBackend();

backend.setHttpUploadURIExpirySeconds(1800);

assertEquals(1800, getIntField(backend, "httpUploadURIExpirySeconds"));
}

@Test
public void setHttpDownloadURICacheSizeCreatesAndDisablesCache() throws Exception {
// Verify the cache-size toggle actually creates and then removes the backing cache.
AzureBlobStoreBackend backend = new AzureBlobStoreBackend();
backend.setHttpDownloadURIExpirySeconds(3600);

backend.setHttpDownloadURICacheSize(100);
assertNotNull(getField(backend, "httpDownloadURICache"));

backend.setHttpDownloadURICacheSize(0);
assertNull(getField(backend, "httpDownloadURICache"));
}

@Test
public void createHttpDownloadURIReturnsNullWhenDisabled() {
// With no download expiry configured, direct download access should stay disabled.
AzureBlobStoreBackend backend = new AzureBlobStoreBackend();

URI downloadURI = backend.createHttpDownloadURI(
new DataIdentifier("test"),
DataRecordDownloadOptions.DEFAULT);

assertNull(downloadURI);
}

@Test
public void initiateHttpUploadReturnsNullWhenDisabled() {
// Upload initiation follows the same disabled-by-default contract until configured.
AzureBlobStoreBackend backend = new AzureBlobStoreBackend();

assertNull(backend.initiateHttpUpload(1024, 1, DataRecordUploadOptions.DEFAULT));
}

private static int getIntField(AzureBlobStoreBackend backend, String fieldName) throws Exception {
Field field = AzureBlobStoreBackend.class.getDeclaredField(fieldName);
field.setAccessible(true);
return (int) field.get(backend);
}

private static Object getField(AzureBlobStoreBackend backend, String fieldName) throws Exception {
Field field = AzureBlobStoreBackend.class.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(backend);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
Expand Down Expand Up @@ -163,6 +166,77 @@
assertReferenceSecret(azureBlobStoreBackend);
}

@Test
public void setHttpDownloadURIExpirySecondsUpdatesField() throws Exception {
// Setter coverage for the v8 direct-download expiry value used by presigned URIs.
AzureBlobStoreBackendV8 backend = new AzureBlobStoreBackendV8();

backend.setHttpDownloadURIExpirySeconds(3600);

assertEquals(3600, getIntField(backend, "httpDownloadURIExpirySeconds"));
}

@Test
public void setHttpUploadURIExpirySecondsUpdatesField() throws Exception {
// Setter coverage for the v8 direct-upload expiry used during upload initiation.
AzureBlobStoreBackendV8 backend = new AzureBlobStoreBackendV8();

backend.setHttpUploadURIExpirySeconds(1800);

assertEquals(1800, getIntField(backend, "httpUploadURIExpirySeconds"));
}

@Test
public void setHttpDownloadURICacheSizeCreatesAndDisablesCache() throws Exception {
// Verify the cache-size toggle actually creates and then removes the backing cache.
AzureBlobStoreBackendV8 backend = new AzureBlobStoreBackendV8();
backend.setHttpDownloadURIExpirySeconds(3600);

backend.setHttpDownloadURICacheSize(100);
assertNotNull(getField(backend, "httpDownloadURICache"));

backend.setHttpDownloadURICacheSize(0);
assertNull(getField(backend, "httpDownloadURICache"));
}

@Test
public void createHttpDownloadURIReturnsNullWhenDisabled() throws DataStoreException {

Check warning on line 203 in oak-blob-cloud-azure/src/test/java/org/apache/jackrabbit/oak/blob/cloud/azure/blobstorage/v8/AzureBlobStoreBackendV8Test.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the declaration of thrown exception 'org.apache.jackrabbit.core.data.DataStoreException', as it cannot be thrown from method's body.

See more on https://sonarcloud.io/project/issues?id=org.apache.jackrabbit%3Ajackrabbit-oak&issues=AZ0aFcYg4T-oZG71Eg05&open=AZ0aFcYg4T-oZG71Eg05&pullRequest=2811
// With no download expiry configured, direct download access should stay disabled.
AzureBlobStoreBackendV8 backend = new AzureBlobStoreBackendV8();

assertNull(backend.createHttpDownloadURI(new org.apache.jackrabbit.core.data.DataIdentifier("test"),
org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordDownloadOptions.DEFAULT));
}

@Test
public void initiateHttpUploadReturnsNullWhenDisabled() throws DataStoreException {

Check warning on line 212 in oak-blob-cloud-azure/src/test/java/org/apache/jackrabbit/oak/blob/cloud/azure/blobstorage/v8/AzureBlobStoreBackendV8Test.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the declaration of thrown exception 'org.apache.jackrabbit.core.data.DataStoreException', as it cannot be thrown from method's body.

See more on https://sonarcloud.io/project/issues?id=org.apache.jackrabbit%3Ajackrabbit-oak&issues=AZ0aFcYg4T-oZG71Eg06&open=AZ0aFcYg4T-oZG71Eg06&pullRequest=2811
// Upload initiation follows the same disabled-by-default contract until configured.
AzureBlobStoreBackendV8 backend = new AzureBlobStoreBackendV8();

assertNull(backend.initiateHttpUpload(1024, 1,
org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordUploadOptions.DEFAULT));
}

@Test
public void createHttpDownloadURIReturnsPreExistingCachedURI() throws Exception {
// Seed a cache entry directly, then verify the externally observable
// behavior that the same URI is returned for the same download request.
AzureBlobStoreBackendV8 backend = new AzureBlobStoreBackendV8();
org.apache.jackrabbit.core.data.DataIdentifier identifier =
new org.apache.jackrabbit.core.data.DataIdentifier("cached");
URI cachedUri = URI.create("https://cached.example/download");

backend.setHttpDownloadURIExpirySeconds(300);
setField(backend, "downloadDomainOverride", "cached.example");
setField(backend, "presignedDownloadURIVerifyExists", false);
backend.setHttpDownloadURICacheSize(10);
putIntoCache(getField(backend, "httpDownloadURICache"),
identifier + "cached.example", cachedUri);

assertEquals(cachedUri, backend.createHttpDownloadURI(identifier,
org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordDownloadOptions.DEFAULT));
}

/* make sure that blob1.txt and blob2.txt are uploaded to AZURE_ACCOUNT_NAME/blobstore container before
* executing this test
* */
Expand Down Expand Up @@ -312,6 +386,30 @@
return UtilsV8.getConnectionString(AzuriteDockerRule.ACCOUNT_NAME, AzuriteDockerRule.ACCOUNT_KEY, azurite.getBlobEndpoint());
}

private static int getIntField(AzureBlobStoreBackendV8 backend, String fieldName) throws Exception {
Field field = AzureBlobStoreBackendV8.class.getDeclaredField(fieldName);
field.setAccessible(true);
return (int) field.get(backend);
}

private static Object getField(AzureBlobStoreBackendV8 backend, String fieldName) throws Exception {
Field field = AzureBlobStoreBackendV8.class.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(backend);
}

private static void setField(AzureBlobStoreBackendV8 backend, String fieldName, Object value) throws Exception {
Field field = AzureBlobStoreBackendV8.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(backend, value);
}

private static void putIntoCache(Object cache, Object key, Object value) throws Exception {
Method put = cache.getClass().getMethod("put", Object.class, Object.class);
put.setAccessible(true);
put.invoke(cache, key, value);
}

private static void assertReferenceSecret(AzureBlobStoreBackendV8 azureBlobStoreBackend)
throws DataStoreException {
// assert secret already created on init
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.jackrabbit.oak.blob.cloud.s3;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;

import org.apache.jackrabbit.core.data.DataIdentifier;
import org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.DataRecordDownloadOptions;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

/**
* Compatibility tests for direct-download and upload cache configuration in
* {@link S3Backend}. The assertions are intentionally behavior-based and do
* not reference third-party cache types.
*/
public class S3BackendCompatibilityTest {

@Test
public void setHttpDownloadURIExpirySecondsUpdatesField() throws Exception {
// Setter coverage: direct-download expiry must be stored verbatim because
// later cache/window calculations depend on this value.
S3Backend backend = new S3Backend();

backend.setHttpDownloadURIExpirySeconds(3600);

assertEquals(3600, getIntField(backend, "httpDownloadURIExpirySeconds"));
}

@Test
public void setHttpUploadURIExpirySecondsUpdatesField() throws Exception {
// Setter coverage for the upload-side expiry used by presigned upload URIs.
S3Backend backend = new S3Backend();

backend.setHttpUploadURIExpirySeconds(1800);

assertEquals(1800, getIntField(backend, "httpUploadURIExpirySeconds"));
}

@Test
public void setHttpDownloadURICacheSizeCreatesAndDisablesCache() throws Exception {
// Toggle the cache on and back off again to verify the configuration method
// controls the backing cache lifecycle directly.
S3Backend backend = new S3Backend();
backend.setHttpDownloadURIExpirySeconds(3600);

backend.setHttpDownloadURICacheSize(100);
assertNotNull(getField(backend, "httpDownloadURICache"));

backend.setHttpDownloadURICacheSize(0);
assertNull(getField(backend, "httpDownloadURICache"));
}

@Test
public void createHttpDownloadURIReturnsNullWhenDisabled() {
// With download expiry left at the default disabled state, direct download
// access must stay off and return null immediately.
S3Backend backend = new S3Backend();

URI downloadURI = backend.createHttpDownloadURI(
new DataIdentifier("test"),
DataRecordDownloadOptions.DEFAULT);

assertNull(downloadURI);
}

@Test
public void initiateHttpUploadReturnsNullWhenDisabled() {
// Upload URIs use the same disabled-by-default contract when no expiry is configured.
S3Backend backend = new S3Backend();

assertNull(backend.initiateHttpUpload(1024, 1));
}

@Test
public void createHttpDownloadURIReturnsPreExistingCachedURI() throws Exception {
// Seed a cache entry directly, then verify the externally observable
// behavior that the same URI is returned for the same download request.
S3Backend backend = new S3Backend();
DataIdentifier identifier = new DataIdentifier("cached");
URI cachedUri = URI.create("https://cached.example/download");

backend.setHttpDownloadURIExpirySeconds(300);
backend.setHttpDownloadURICacheSize(10);
setField(backend, "presignedDownloadURIVerifyExists", false);
putIntoCache(getField(backend, "httpDownloadURICache"), identifier, cachedUri);

assertEquals(cachedUri, backend.createHttpDownloadURI(identifier, DataRecordDownloadOptions.DEFAULT));
}

private static int getIntField(S3Backend backend, String fieldName) throws Exception {
Field field = S3Backend.class.getDeclaredField(fieldName);
field.setAccessible(true);
return (int) field.get(backend);
}

private static Object getField(S3Backend backend, String fieldName) throws Exception {
Field field = S3Backend.class.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(backend);
}

private static void setField(S3Backend backend, String fieldName, Object value) throws Exception {
Field field = S3Backend.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(backend, value);
}

private static void putIntoCache(Object cache, Object key, Object value) throws Exception {
Method put = cache.getClass().getMethod("put", Object.class, Object.class);
put.setAccessible(true);
put.invoke(cache, key, value);
}
}
Loading
Loading