/* * Copyright 2014-2021 Andrew Gaul * * Licensed 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 * * https://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.gaul.s3proxy; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Properties; import java.util.Random; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; import com.google.common.io.Files; import com.google.common.io.Resources; import com.google.inject.Module; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.jclouds.Constants; import org.jclouds.ContextBuilder; import org.jclouds.JcloudsVersion; import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; final class TestUtils { @SuppressWarnings("deprecation") static final HashFunction MD5 = Hashing.md5(); private TestUtils() { throw new AssertionError("intentionally unimplemented"); } static ByteSource randomByteSource() { return randomByteSource(0); } static ByteSource randomByteSource(long seed) { return new RandomByteSource(seed); } private static final class RandomByteSource extends ByteSource { private final long seed; RandomByteSource(long seed) { this.seed = seed; } @Override public InputStream openStream() { return new RandomInputStream(seed); } } private static final class RandomInputStream extends InputStream { private final Random random; private boolean closed; RandomInputStream(long seed) { this.random = new Random(seed); } @Override public synchronized int read() throws IOException { if (closed) { throw new IOException("Stream already closed"); } // return value between 0 and 255 return random.nextInt() & 0xff; } @Override public synchronized int read(byte[] b) throws IOException { return read(b, 0, b.length); } @Override public synchronized int read(byte[] b, int off, int len) throws IOException { for (int i = 0; i < len; ++i) { b[off + i] = (byte) read(); } return len; } @Override public void close() throws IOException { super.close(); closed = true; } } static final class S3ProxyLaunchInfo { private S3Proxy s3Proxy; private final Properties properties = new Properties(); private String s3Identity; private String s3Credential; private BlobStore blobStore; private URI endpoint; private URI secureEndpoint; private String servicePath; S3Proxy getS3Proxy() { return s3Proxy; } Properties getProperties() { return properties; } String getS3Identity() { return s3Identity; } String getS3Credential() { return s3Credential; } String getServicePath() { return servicePath; } BlobStore getBlobStore() { return blobStore; } URI getEndpoint() { return endpoint; } URI getSecureEndpoint() { return secureEndpoint; } } static S3ProxyLaunchInfo startS3Proxy(String configFile) throws Exception { S3ProxyLaunchInfo info = new S3ProxyLaunchInfo(); try (InputStream is = Resources.asByteSource(Resources.getResource( configFile)).openStream()) { info.getProperties().load(is); } String provider = info.getProperties().getProperty( Constants.PROPERTY_PROVIDER); String identity = info.getProperties().getProperty( Constants.PROPERTY_IDENTITY); String credential = info.getProperties().getProperty( Constants.PROPERTY_CREDENTIAL); if (provider.equals("google-cloud-storage")) { File credentialFile = new File(credential); if (credentialFile.exists()) { credential = Files.asCharSource(credentialFile, StandardCharsets.UTF_8).read(); } info.getProperties().remove(Constants.PROPERTY_CREDENTIAL); } String endpoint = info.getProperties().getProperty( Constants.PROPERTY_ENDPOINT); ContextBuilder builder = ContextBuilder .newBuilder(provider) .credentials(identity, credential) .modules(ImmutableList.of(new SLF4JLoggingModule())) .overrides(info.getProperties()); if (!Strings.isNullOrEmpty(endpoint)) { builder.endpoint(endpoint); } BlobStoreContext context = builder.build(BlobStoreContext.class); info.blobStore = context.getBlobStore(); String encrypted = info.getProperties().getProperty( S3ProxyConstants.PROPERTY_ENCRYPTED_BLOBSTORE); if (encrypted != null && encrypted.equals("true")) { info.blobStore = EncryptedBlobStore.newEncryptedBlobStore(info.blobStore, info.getProperties()); } S3Proxy.Builder s3ProxyBuilder = S3Proxy.Builder.fromProperties( info.getProperties()); s3ProxyBuilder.blobStore(info.blobStore); info.endpoint = s3ProxyBuilder.getEndpoint(); info.secureEndpoint = s3ProxyBuilder.getSecureEndpoint(); info.s3Identity = s3ProxyBuilder.getIdentity(); info.s3Credential = s3ProxyBuilder.getCredential(); info.servicePath = s3ProxyBuilder.getServicePath(); info.getProperties().setProperty(Constants.PROPERTY_USER_AGENT, String.format("s3proxy/%s jclouds/%s java/%s", TestUtils.class.getPackage().getImplementationVersion(), JcloudsVersion.get(), System.getProperty("java.version"))); // resolve relative path for tests String keyStorePath = info.getProperties().getProperty( S3ProxyConstants.PROPERTY_KEYSTORE_PATH); String keyStorePassword = info.getProperties().getProperty( S3ProxyConstants.PROPERTY_KEYSTORE_PASSWORD); if (keyStorePath != null || keyStorePassword != null) { s3ProxyBuilder.keyStore( Resources.getResource(keyStorePath).toString(), keyStorePassword); } info.s3Proxy = s3ProxyBuilder.build(); info.s3Proxy.start(); while (!info.s3Proxy.getState().equals(AbstractLifeCycle.STARTED)) { Thread.sleep(1); } // reset endpoint to handle zero port info.endpoint = new URI(info.endpoint.getScheme(), info.endpoint.getUserInfo(), info.endpoint.getHost(), info.s3Proxy.getPort(), info.endpoint.getPath(), info.endpoint.getQuery(), info.endpoint.getFragment()); if (info.secureEndpoint != null) { info.secureEndpoint = new URI(info.secureEndpoint.getScheme(), info.secureEndpoint.getUserInfo(), info.secureEndpoint.getHost(), info.s3Proxy.getSecurePort(), info.secureEndpoint.getPath(), info.secureEndpoint.getQuery(), info.secureEndpoint.getFragment()); } return info; } static String createRandomContainerName() { return "container-" + new Random().nextInt(Integer.MAX_VALUE); } static String createRandomBlobName() { return "blob-" + new Random().nextInt(Integer.MAX_VALUE); } }