All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.beam.it.testcontainers.TestContainerResourceManager Maven / Gradle / Ivy

There is a newer version: 2.61.0
Show newest version
/*
 * 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.beam.it.testcontainers;

import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import org.apache.beam.it.common.ResourceManager;
import org.apache.beam.it.common.TestProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;

/**
 * Abstract class for managing TestContainers resources in integration tests.
 *
 * 

Resource managers that extend this class will use TestContainers as a backend to spin up * resources. * *

Optionally, a static resource can be specified by calling the useStaticContainer() method in * the {@link Builder} class. A static resource is a pre-configured database or other resource that * is ready to be connected to by the resource manager. This could be a pre-existing TestContainer * that has not been closed, a local database instance, a remote VM, or any other source that can be * connected to. If a static container is used, the host and port must also be configured using the * Builder's setHost() and setPort() methods, respectively. */ public abstract class TestContainerResourceManager> implements ResourceManager { private static final Logger LOG = LoggerFactory.getLogger(TestContainerResourceManager.class); protected static final String HOST_IP = TestProperties.hostIp(); private final T container; private final boolean usingStaticContainer; private final String host; protected int port; protected > TestContainerResourceManager(T container, B builder) { this(container, builder, null); } protected > TestContainerResourceManager( T container, B builder, @Nullable Callable setup) { this.container = container; this.usingStaticContainer = builder.useStaticContainer; this.host = builder.host == null ? HOST_IP : builder.host; this.port = builder.port; if (setup != null) { try { setup.call(); } catch (Exception e) { throw new TestContainerResourceManagerException("Error running setup function.", e); } } if (!usingStaticContainer) { // TODO(pranavbhandari): Change this to use log.getUtf8StringWithoutLineEnding() when // testcontainers dependency is updated. container .withLogConsumer( log -> LOG.info("{}: {}", container.getDockerImageName(), log.getUtf8String())) .start(); } else if (builder.host == null || builder.port < 0) { throw new TestContainerResourceManagerException( "This manager was configured to use a static resource, but the host and port were not properly set."); } } protected String getDockerImageName() { return container.getDockerImageName(); } /** * Returns the host that the resource is running on. If a host was specified in the builder, then * this method will return that value. Otherwise, the host will default to localhost. * * @return the host that the resource is running on */ public String getHost() { return host; } /** * Returns the port that the resource is actually mapped to on the host. When using a non-static * resource, the TestContainers framework will map the resource port to a random port on the host. * This method will return the mapped port that the resource traffic is routed through. * *

Note: When using a static container, the port that was specified in the builder will be * returned regardless of what is passed into this method as a parameter. * * @param mappedPort the port the resource was configured to listen on * @return the mapped port on the host */ protected int getPort(int mappedPort) { if (port < 0) { return container.getMappedPort(mappedPort); } return port; } /** * Deletes all created resources (VM's, etc.) and stops the container, making the manager object * unusable. * * @throws TestContainerResourceManagerException if there is an error deleting the TestContainers * resources. */ @Override public void cleanupAll() throws TestContainerResourceManagerException { if (usingStaticContainer) { LOG.info("This manager was configured to use a static resource that will not be cleaned up."); return; } LOG.info("Attempting to cleanup TestContainers manager."); try { container.close(); LOG.info("TestContainers manager successfully cleaned up."); } catch (Exception e) { throw new TestContainerResourceManagerException("Failed to close TestContainer resources", e); } } /** Builder for {@link TestContainerResourceManager}. */ public abstract static class Builder> { public String testId; public String containerImageName; public String containerImageTag; public @Nullable String host; public int port; public boolean useStaticContainer; public Builder(String testId, String containerImageName, String containerImageTag) { this.testId = testId; this.containerImageName = containerImageName; this.containerImageTag = containerImageTag; this.host = null; this.port = -1; } /** * Sets the name of the test container image. The tag is typically the version of the image. * * @param containerName The name of the container image. * @return this builder object with the image name set. */ public Builder setContainerImageName(String containerName) { this.containerImageName = containerName; return this; } /** * Sets the tag for the test container. The tag is typically the version of the image. * * @param containerTag The tag to use for the container. * @return this builder object with the tag set. */ public Builder setContainerImageTag(String containerTag) { this.containerImageTag = containerTag; return this; } /** * Sets the host of the resource that the resource manager will connect to. This will default to * localhost if not set. * * @param containerHost the resource host address. * @return this builder object with the host set. */ public Builder setHost(String containerHost) { this.host = containerHost; return this; } /** * Sets the port that the resource is hosted on. * * @param port the port the resource is hosted on. * @return this builder object with the port set. */ public Builder setPort(int port) { this.port = port; return this; } /** * Configures the resource manager to use a static resource instead of creating a new * TestContainer instance of the resource. This can be another TestContainer or any other VM or * server hosting the resource. * *

Note: When this option is enabled, the setPort() and setHost() methods must also be called * to configure the static resource address. * * @return this builder object with the useStaticContainer option enabled. */ public Builder useStaticContainer() { this.useStaticContainer = true; return this; } /** * Builds and returns a Resource Manager that extends TestContainerResourceManager. * * @return an instance of TestContainerResourceManager */ public abstract T build(); } }