From e1676e22d0f752fcc358aa630e3ce6651a404faa Mon Sep 17 00:00:00 2001 From: Alain Kermis Date: Thu, 8 Jun 2023 16:37:41 +0200 Subject: [PATCH] SONAR-19425 Update logic for SQ container context --- .../sonar/server/telemetry/TelemetryData.java | 4 +- .../telemetry/TelemetryDataJsonWriter.java | 1 + .../TelemetryDataJsonWriterTest.java | 5 +- .../server/platform/ContainerSupport.java | 5 + .../server/platform/ContainerSupportImpl.java | 95 +++++++-- .../telemetry/CloudUsageDataProvider.java | 9 +- .../platform/ContainerSupportImplTest.java | 182 +++++++----------- .../telemetry/CloudUsageDataProviderTest.java | 22 ++- .../TelemetryDataLoaderImplTest.java | 3 +- 9 files changed, 186 insertions(+), 140 deletions(-) diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java index c4938050f15..9531cb16006 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryData.java @@ -352,8 +352,8 @@ public class TelemetryData { record ManagedInstanceInformation(boolean isManaged, @Nullable String provider) { } - record CloudUsage(boolean kubernetes, @Nullable String kubernetesVersion, @Nullable String kubernetesPlatform, - @Nullable String kubernetesProvider, @Nullable String officialHelmChart, boolean officialImage) { + record CloudUsage(boolean kubernetes, @Nullable String kubernetesVersion, @Nullable String kubernetesPlatform, @Nullable String kubernetesProvider, + @Nullable String officialHelmChart, @Nullable String containerRuntime, boolean officialImage) { } public static class ProjectStatistics { diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java index f28b8cdbb22..d78d10f114b 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java @@ -240,6 +240,7 @@ public class TelemetryDataJsonWriter { json.prop("kubernetesPlatform", cloudUsage.kubernetesPlatform()); json.prop("kubernetesProvider", cloudUsage.kubernetesProvider()); json.prop("officialHelmChart", cloudUsage.officialHelmChart()); + json.prop("containerRuntime", cloudUsage.containerRuntime()); json.prop("officialImage", cloudUsage.officialImage()); json.endObject(); } diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java index 27d803053d1..665ce7896f4 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/telemetry/TelemetryDataJsonWriterTest.java @@ -292,7 +292,8 @@ public class TelemetryDataJsonWriterTest { "kubernetesPlatform": "linux/amd64", "kubernetesProvider": "5.4.181-99.354.amzn2.x86_64", "officialHelmChart": "10.1.0", - "officialImage": false + "officialImage": false, + "containerRuntime": "docker" } } """); @@ -604,7 +605,7 @@ public class TelemetryDataJsonWriterTest { .setMessageSequenceNumber(1L) .setPlugins(Collections.emptyMap()) .setManagedInstanceInformation(new TelemetryData.ManagedInstanceInformation(false, null)) - .setCloudUsage(new TelemetryData.CloudUsage(true, "1.27", "linux/amd64", "5.4.181-99.354.amzn2.x86_64", "10.1.0", false)) + .setCloudUsage(new TelemetryData.CloudUsage(true, "1.27", "linux/amd64", "5.4.181-99.354.amzn2.x86_64", "10.1.0", "docker", false)) .setDatabase(new TelemetryData.Database("H2", "11")) .setNcdId(NCD_ID); } diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java index 22a59f5207f..30c18a19b2b 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java @@ -19,10 +19,15 @@ */ package org.sonar.server.platform; +import javax.annotation.CheckForNull; + public interface ContainerSupport { /** * @return {@code true} if we can detect that SQ is running inside a docker container */ boolean isRunningInContainer(); + @CheckForNull + String getContainerContext(); + } diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java index 38997c558f5..e6d81ac1a9b 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java @@ -19,27 +19,100 @@ */ package org.sonar.server.platform; -import java.io.IOException; -import java.nio.file.Files; -import java.util.stream.Stream; +import com.google.common.annotations.VisibleForTesting; +import java.util.Objects; +import java.util.Scanner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.utils.System2; import org.sonar.server.util.Paths2; +import static java.nio.charset.StandardCharsets.UTF_8; + public class ContainerSupportImpl implements ContainerSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ContainerSupportImpl.class); + private static final String CONTAINER_FILE_PATH = "/run/.containerenv"; + private static final String DOCKER = "docker"; + private static final String PODMAN = "podman"; + private static final String BUILDAH = "buildah"; + private static final String CONTAINER_D = "containerd"; + private static final String GENERAL_CONTAINER = "general_container"; + + private static final String[] MOUNT_GREP_COMMAND = {"bash", "-c", "mount | grep 'overlay on /'"}; + private static final String[] CAT_COMMAND = {"bash", "-c", "cat /run/.containerenv"}; + + private final System2 system2; private final Paths2 paths2; + private String containerContextCache; - public ContainerSupportImpl(Paths2 paths2) { + public ContainerSupportImpl(Paths2 paths2, System2 system2) { this.paths2 = paths2; + this.system2 = system2; + + populateCache(); + } + + @VisibleForTesting + void populateCache() { + if (isDocker()) { + containerContextCache = DOCKER; + } else if (isPodman()) { + containerContextCache = PODMAN; + } else if (isBuildah()) { + containerContextCache = BUILDAH; + } else if (isContainerd()) { + containerContextCache = CONTAINER_D; + } else if (isGeneralContainer()) { + containerContextCache = GENERAL_CONTAINER; + } else { + containerContextCache = null; + } } @Override public boolean isRunningInContainer() { - if (paths2.exists("/run/.containerenv")) { - return true; - } - try (Stream stream = Files.lines(paths2.get("/proc/1/cgroup"))) { - return stream.anyMatch(line -> line.contains("/docker") || line.contains("/kubepods") || line.contains("containerd.service") ); - } catch (IOException e) { - return false; + return containerContextCache != null; + } + + @Override + public String getContainerContext() { + return containerContextCache; + } + + private boolean isDocker() { + return executeCommand(MOUNT_GREP_COMMAND).contains("/docker") && paths2.exists("/.dockerenv"); + } + + private boolean isPodman() { + return Objects.equals(system2.envVariable("container"), PODMAN) && paths2.exists(CONTAINER_FILE_PATH); + } + + private boolean isBuildah() { + return paths2.exists(CONTAINER_FILE_PATH) && executeCommand(CAT_COMMAND).contains("engine=\"buildah-"); + } + + private boolean isContainerd() { + return executeCommand(MOUNT_GREP_COMMAND).contains("/containerd"); + } + + private boolean isGeneralContainer() { + return paths2.exists(CONTAINER_FILE_PATH); + } + + @VisibleForTesting + String executeCommand(String[] command) { + try { + Process process = new ProcessBuilder().command(command).start(); + try (Scanner scanner = new Scanner(process.getInputStream(), UTF_8)) { + scanner.useDelimiter("\n"); + return scanner.next(); + } finally { + process.destroy(); + } + } catch (Exception e) { + LOG.debug("Failed to execute command", e); + return ""; } } } diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java index f35f1f026f2..dd10f981ab5 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java @@ -48,6 +48,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.server.ServerSide; import org.sonar.api.utils.System2; +import org.sonar.server.platform.ContainerSupport; import org.sonar.server.util.Paths2; import static java.nio.charset.StandardCharsets.UTF_8; @@ -64,13 +65,15 @@ public class CloudUsageDataProvider { static final String SONAR_HELM_CHART_VERSION = "SONAR_HELM_CHART_VERSION"; static final String DOCKER_RUNNING = "DOCKER_RUNNING"; private static final String[] KUBERNETES_PROVIDER_COMMAND = {"bash", "-c", "uname -r"}; + private final ContainerSupport containerSupport; private final System2 system2; private final Paths2 paths2; private OkHttpClient httpClient; private TelemetryData.CloudUsage cloudUsageData; @Inject - public CloudUsageDataProvider(System2 system2, Paths2 paths2) { + public CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2) { + this.containerSupport = containerSupport; this.system2 = system2; this.paths2 = paths2; if (isOnKubernetes()) { @@ -79,7 +82,8 @@ public class CloudUsageDataProvider { } @VisibleForTesting - CloudUsageDataProvider(System2 system2, Paths2 paths2, OkHttpClient httpClient) { + CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2, OkHttpClient httpClient) { + this.containerSupport = containerSupport; this.system2 = system2; this.paths2 = paths2; this.httpClient = httpClient; @@ -107,6 +111,7 @@ public class CloudUsageDataProvider { kubernetesPlatform, getKubernetesProvider(), getOfficialHelmChartVersion(), + containerSupport.getContainerContext(), isOfficialImageUsed()); return cloudUsageData; diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ContainerSupportImplTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ContainerSupportImplTest.java index 7b3188a2171..56b3406846b 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ContainerSupportImplTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/ContainerSupportImplTest.java @@ -19,140 +19,88 @@ */ package org.sonar.server.platform; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; +import java.util.Arrays; +import java.util.Collection; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.sonar.api.utils.System2; import org.sonar.server.util.Paths2; -import static java.lang.System.lineSeparator; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +@RunWith(Parameterized.class) public class ContainerSupportImplTest { - private static final String CGROUP_DIR = "/proc/1/cgroup"; - private static final String PODMAN_FILE_PATH = "/run/.containerenv"; - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - private Paths2 paths2 = mock(Paths2.class); - private ContainerSupportImpl underTest = new ContainerSupportImpl(paths2); - - @Test - public void isInDocker_returns_false_if_cgroup_file_does_not_exist() throws IOException { - Path emptyFile = temporaryFolder.newFile().toPath(); - Files.delete(emptyFile); - when(paths2.get(CGROUP_DIR)).thenReturn(emptyFile); - - assertThat(underTest.isRunningInContainer()).isFalse(); + private static final String CONTAINER_FILE_PATH = "/run/.containerenv"; + private static final String[] MOUNT_GREP_COMMAND = {"bash", "-c", "mount | grep 'overlay on /'"}; + private static final String[] CAT_COMMAND = {"bash", "-c", "cat /run/.containerenv"}; + private static final String DOCKER = "docker"; + private static final String PODMAN = "podman"; + private static final String BUILDAH = "buildah"; + private static final String CONTAINER_D = "containerd"; + private static final String GENERAL_CONTAINER = "general_container"; + + private final Paths2 paths2 = mock(Paths2.class); + private final System2 system2 = mock(System2.class); + private ContainerSupportImpl underTest = new ContainerSupportImpl(paths2, system2); + + private String containerContext; + + public ContainerSupportImplTest(String containerContext) { + this.containerContext = containerContext; } - @Test - public void isInDocker_returns_false_if_cgroup_file_is_empty() throws IOException { - Path emptyFile = temporaryFolder.newFile().toPath(); - when(paths2.get(CGROUP_DIR)).thenReturn(emptyFile); - - assertThat(underTest.isRunningInContainer()).isFalse(); - } - - @Test - public void isInDocker_returns_false_if_cgroup_dir_contains_no_file_with_slash_docker_string() throws IOException { - Path cgroupFile = temporaryFolder.newFile().toPath(); - String content = "11:name=systemd:/" + lineSeparator() + - "10:hugetlb:/" + lineSeparator() + - "9:perf_event:/" + lineSeparator() + - "8:blkio:/" + lineSeparator() + - "7:freezer:/" + lineSeparator() + - "6:devices:/" + lineSeparator() + - "5:memory:/" + lineSeparator() + - "4:cpuacct:/" + lineSeparator() + - "3:cpu:/" + lineSeparator() + - "2:cpuset:/"; - FileUtils.write(cgroupFile.toFile(), content, StandardCharsets.UTF_8); - when(paths2.get(CGROUP_DIR)).thenReturn(cgroupFile); - - assertThat(underTest.isRunningInContainer()).isFalse(); + @Before + public void setUp() { + if (containerContext == null) { + return; + } + + switch (containerContext) { + case DOCKER -> { + underTest = spy(underTest); + when(underTest.executeCommand(MOUNT_GREP_COMMAND)).thenReturn("/docker"); + when(paths2.exists("/.dockerenv")).thenReturn(true); + } + case PODMAN -> { + when(system2.envVariable("container")).thenReturn("podman"); + when(paths2.exists(CONTAINER_FILE_PATH)).thenReturn(true); + } + case BUILDAH -> { + underTest = spy(underTest); + when(paths2.exists(CONTAINER_FILE_PATH)).thenReturn(true); + when(underTest.executeCommand(CAT_COMMAND)).thenReturn("XXX engine=\"buildah- XXX"); + } + case CONTAINER_D -> { + underTest = spy(underTest); + when(underTest.executeCommand(MOUNT_GREP_COMMAND)).thenReturn("/containerd"); + } + case GENERAL_CONTAINER -> when(paths2.exists(CONTAINER_FILE_PATH)).thenReturn(true); + default -> { + } + } + underTest.populateCache(); } - @Test - public void isInDocker_returns_true_if_cgroup_dir_contains_file_with_slash_docker_string() throws IOException { - Path cgroupFile = temporaryFolder.newFile().toPath(); - String content = "11:name=systemd:/" + lineSeparator() + - "10:hugetlb:/" + lineSeparator() + - "9:perf_event:/" + lineSeparator() + - "8:blkio:/" + lineSeparator() + - "7:freezer:/" + lineSeparator() + - "6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2" + lineSeparator() + - "5:memory:/" + lineSeparator() + - "4:cpuacct:/" + lineSeparator() + - "3:cpu:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2" + lineSeparator() + - "2:cpuset:/"; - FileUtils.write(cgroupFile.toFile(), content, StandardCharsets.UTF_8); - when(paths2.get(CGROUP_DIR)).thenReturn(cgroupFile); - - assertThat(underTest.isRunningInContainer()).isTrue(); - } - - @Test - public void isInDocker_returns_true_if_cgroup_dir_contains_file_with_kubepods_string() throws IOException { - Path cgroupFile = temporaryFolder.newFile().toPath(); - String content = "11:blkio:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "10:cpuset:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "9:net_cls,net_prio:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "8:pids:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "7:perf_event:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "6:freezer:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "5:hugetlb:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "4:memory:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "3:devices:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "2:cpu,cpuacct:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366" + lineSeparator() + - "1:name=systemd:/kubepods/burstable/pod8e9a7fc0-4e11-4497-a424-19b9713eff0e/8953402928cc7fc95c7dc7bdb75b194139fe29e8fa196d7f90924deb29164366"; - FileUtils.write(cgroupFile.toFile(), content, StandardCharsets.UTF_8); - when(paths2.get(CGROUP_DIR)).thenReturn(cgroupFile); - - assertThat(underTest.isRunningInContainer()).isTrue(); - } - - @Test - public void isInDocker_returns_true_if_cgroup_dir_contains_file_with_containerd_string() throws IOException { - Path cgroupFile = temporaryFolder.newFile().toPath(); - String content = "12:blkio:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "11:perf_event:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "10:hugetlb:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "9:pids:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "8:rdma:/" + lineSeparator() + - "7:memory:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "6:cpuset:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "5:net_cls,net_prio:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "4:freezer:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "3:cpu,cpuacct:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "2:devices:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "1:name=systemd:/default/846fe494c3021f068c9156ca6eb8a91038389b7e2a2b1ae9b050b33c3a5c9298" + lineSeparator() + - "0::/system.slice/containerd.service"; - FileUtils.write(cgroupFile.toFile(), content, StandardCharsets.UTF_8); - when(paths2.get(CGROUP_DIR)).thenReturn(cgroupFile); - - assertThat(underTest.isRunningInContainer()).isTrue(); + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(DOCKER, PODMAN, BUILDAH, CONTAINER_D, GENERAL_CONTAINER, null); } @Test - public void isInDocker_returns_true_if_podman_file_exists() throws IOException { - when(paths2.exists(PODMAN_FILE_PATH)).thenReturn(true); - assertThat(underTest.isRunningInContainer()).isTrue(); + public void testGetContainerContext() { + Assert.assertEquals(containerContext, underTest.getContainerContext()); } @Test - public void isInDocker_returns_false_if_podman_file_exists() throws IOException { - when(paths2.exists(PODMAN_FILE_PATH)).thenReturn(false); - Path emptyFile = temporaryFolder.newFile().toPath(); - when(paths2.get(CGROUP_DIR)).thenReturn(emptyFile); - assertThat(underTest.isRunningInContainer()).isFalse(); + public void testIsRunningInContainer() { + boolean expected = containerContext != null; + when(paths2.exists(CONTAINER_FILE_PATH)).thenReturn(expected); + Assert.assertEquals(expected, underTest.isRunningInContainer()); } } diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java index ccefc0cae3c..823848ed9e7 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java @@ -34,6 +34,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.sonar.api.utils.System2; +import org.sonar.server.platform.ContainerSupport; import org.sonar.server.util.Paths2; import org.sonarqube.ws.MediaTypes; @@ -53,7 +54,8 @@ public class CloudUsageDataProviderTest { private final System2 system2 = Mockito.mock(System2.class); private final Paths2 paths2 = Mockito.mock(Paths2.class); private final OkHttpClient httpClient = Mockito.mock(OkHttpClient.class); - private final CloudUsageDataProvider underTest = new CloudUsageDataProvider(system2, paths2, httpClient); + private final ContainerSupport containerSupport = mock(ContainerSupport.class); + private final CloudUsageDataProvider underTest = new CloudUsageDataProvider(containerSupport, system2, paths2, httpClient); @Before public void setUp() throws Exception { @@ -87,6 +89,18 @@ public class CloudUsageDataProviderTest { when(httpClient.newCall(any())).thenReturn(callMock); } + @Test + public void containerRuntime_whenContainerSupportContextExists_shouldNotBeNull() { + when(containerSupport.getContainerContext()).thenReturn("docker"); + assertThat(underTest.getCloudUsage().containerRuntime()).isEqualTo("docker"); + } + + @Test + public void containerRuntime_whenContainerSupportContextMissing_shouldBeNull() { + when(containerSupport.getContainerContext()).thenReturn(null); + assertThat(underTest.getCloudUsage().containerRuntime()).isNull(); + } + @Test public void kubernetes_whenEnvVarExists_shouldReturnTrue() { assertThat(underTest.getCloudUsage().kubernetes()).isTrue(); @@ -171,7 +185,7 @@ public class CloudUsageDataProviderTest { public void initHttpClient_whenValidCertificate_shouldCreateClient() throws URISyntaxException { when(paths2.get(anyString())).thenReturn(Paths.get(requireNonNull(getClass().getResource("dummy.crt")).toURI())); - CloudUsageDataProvider provider = new CloudUsageDataProvider(system2, paths2); + CloudUsageDataProvider provider = new CloudUsageDataProvider(containerSupport, system2, paths2); assertThat(provider.getHttpClient()).isNotNull(); } @@ -180,7 +194,7 @@ public class CloudUsageDataProviderTest { when(paths2.get(anyString())).thenReturn(Paths.get(requireNonNull(getClass().getResource("dummy.crt")).toURI())); when(system2.envVariable(KUBERNETES_SERVICE_HOST)).thenReturn(null); - CloudUsageDataProvider provider = new CloudUsageDataProvider(system2, paths2); + CloudUsageDataProvider provider = new CloudUsageDataProvider(containerSupport, system2, paths2); assertThat(provider.getHttpClient()).isNull(); } @@ -188,7 +202,7 @@ public class CloudUsageDataProviderTest { public void initHttpClient_whenCertificateNotFound_shouldFail() { when(paths2.get(any())).thenReturn(Paths.get("dummy.crt")); - CloudUsageDataProvider provider = new CloudUsageDataProvider(system2, paths2); + CloudUsageDataProvider provider = new CloudUsageDataProvider(containerSupport, system2, paths2); assertThat(provider.getHttpClient()).isNull(); } } diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDataLoaderImplTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDataLoaderImplTest.java index 53e1ab87e28..fe33ad00647 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDataLoaderImplTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDataLoaderImplTest.java @@ -24,7 +24,6 @@ import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.HashSet; @@ -557,7 +556,7 @@ public class TelemetryDataLoaderImplTest { @Test public void load_shouldContainCloudUsage() { - CloudUsage cloudUsage = new CloudUsage(true, "1.27", "linux/amd64", "5.4.181-99.354.amzn2.x86_64", "10.1.0", false); + CloudUsage cloudUsage = new CloudUsage(true, "1.27", "linux/amd64", "5.4.181-99.354.amzn2.x86_64", "10.1.0", "docker", false); when(cloudUsageDataProvider.getCloudUsage()).thenReturn(cloudUsage); TelemetryData data = commercialUnderTest.load(); -- 2.39.5