content: /*
   * Copyright The OpenTelemetry Authors
   * SPDX-License-Identifier: Apache-2.0
   */
  
  package io.opentelemetry.smoketest;
  
  import java.io.IOException;
  import java.time.Duration;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  import java.util.function.Consumer;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.testcontainers.containers.Container;
  import org.testcontainers.containers.ContainerLaunchException;
  import org.testcontainers.containers.GenericContainer;
  import org.testcontainers.containers.Network;
  import org.testcontainers.containers.output.OutputFrame;
  import org.testcontainers.containers.output.Slf4jLogConsumer;
  import org.testcontainers.containers.output.ToStringConsumer;
  import org.testcontainers.containers.wait.strategy.Wait;
  import org.testcontainers.utility.DockerImageName;
  import org.testcontainers.utility.MountableFile;
  
  public class LinuxTestContainerManager extends AbstractTestContainerManager {
    private static final Logger logger = LoggerFactory.getLogger(LinuxTestContainerManager.class);
    private static final Logger backendLogger = LoggerFactory.getLogger("Backend");
    private static final Logger appLogger = LoggerFactory.getLogger("App");
  
    private final Network network = Network.newNetwork();
    private GenericContainer<?> backend = null;
    private GenericContainer<?> target = null;
  
    @Override
    protected void startEnvironment() {
      backend =
          new GenericContainer<>(
                  DockerImageName.parse(
                      "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-fake-backend:20221127.3559314891"))
              .withExposedPorts(BACKEND_PORT)
              .withEnv("JAVA_TOOL_OPTIONS", "-Xmx128m")
              .waitingFor(Wait.forHttp("/health").forPort(BACKEND_PORT))
              .withNetwork(network)
              .withNetworkAliases(BACKEND_ALIAS)
              .withLogConsumer(new Slf4jLogConsumer(backendLogger));
      backend.start();
    }
  
    @Override
    protected void stopEnvironment() {
      if (backend != null) {
        backend.stop();
        backend = null;
      }
  
      network.close();
    }
  
    @Override
    public int getBackendMappedPort() {
      return backend.getMappedPort(BACKEND_PORT);
    }
  
    @Override
    public int getTargetMappedPort(int originalPort) {
      return target.getMappedPort(originalPort);
    }
  
    @Override
    public Consumer<OutputFrame> startTarget(
        String targetImageName,
        String agentPath,
        String jvmArgsEnvVarName,
        Map<String, String> extraEnv,
        boolean setServiceName,
        List<ResourceMapping> extraResources,
        List<Integer> extraPorts,
        TargetWaitStrategy waitStrategy,
        String[] command) {
  
      Consumer<OutputFrame> output = new ToStringConsumer();
      List<Integer> ports = new ArrayList<>();
      ports.add(TARGET_PORT);
      if (extraPorts != null) {
        ports.addAll(extraPorts);
      }
      target =
          new GenericContainer<>(DockerImageName.parse(targetImageName))
              .withStartupTimeout(Duration.ofMinutes(5))
              .withExposedPorts(ports.toArray(new Integer[0]))
              .withNetwork(network)
              .withLogConsumer(output)
              .withLogConsumer(new Slf4jLogConsumer(appLogger))
              .withCopyFileToContainer(
                  MountableFile.forHostPath(agentPath), "/" + TARGET_AGENT_FILENAME)
              .withEnv(getAgentEnvironment(jvmArgsEnvVarName, setServiceName))
              .withEnv(extraEnv);
  
      for (ResourceMapping resource : extraResources) {
        target.withCopyFileToContainer(
            MountableFile.forClasspathResource(resource.resourcePath()), resource.containerPath());
      }
  
      if (waitStrategy != null) {
        if (waitStrategy instanceof TargetWaitStrategy.Log) {
          target =
              target.waitingFor(
                  Wait.forLogMessage(((TargetWaitStrategy.Log) waitStrategy).regex, 1)
                      .withStartupTimeout(waitStrategy.timeout));
        }
      }
  
      if (command != null) {
        target = target.withCommand(command);
      }
  
      try {
        target.start();
      } catch (ContainerLaunchException launchException) {
        // when container failed to start try to force a thread dump
        try {
          Container.ExecResult execResult = target.execInContainer("killall", "-3", "java");
          if (execResult.getExitCode() != 0) {
            logger.warn("Command execution failed {}", execResult);
          }
        } catch (IOException exception) {
          logger.warn("Command execution failed", exception);
        } catch (InterruptedException exception) {
          Thread.currentThread().interrupt();
        }
  
        throw launchException;
      }
  
      return output;
    }
  
    @Override
    public void stopTarget() {
      if (target != null) {
        target.stop();
        target = null;
      }
    }
  }
  