3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.telemetry;
22 import java.io.ByteArrayInputStream;
23 import java.io.IOException;
24 import java.net.URISyntaxException;
25 import java.nio.file.Paths;
26 import javax.annotation.Nullable;
28 import okhttp3.MediaType;
29 import okhttp3.OkHttpClient;
30 import okhttp3.Protocol;
31 import okhttp3.Request;
32 import okhttp3.Response;
33 import okhttp3.ResponseBody;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.mockito.Mockito;
37 import org.sonar.api.utils.System2;
38 import org.sonar.server.platform.ContainerSupport;
39 import org.sonar.server.util.Paths2;
40 import org.sonarqube.ws.MediaTypes;
42 import static java.util.Objects.requireNonNull;
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.mockito.ArgumentMatchers.any;
45 import static org.mockito.ArgumentMatchers.anyString;
46 import static org.mockito.Mockito.mock;
47 import static org.mockito.Mockito.when;
48 import static org.sonar.server.telemetry.CloudUsageDataProvider.DOCKER_RUNNING;
49 import static org.sonar.server.telemetry.CloudUsageDataProvider.KUBERNETES_SERVICE_HOST;
50 import static org.sonar.server.telemetry.CloudUsageDataProvider.KUBERNETES_SERVICE_PORT;
51 import static org.sonar.server.telemetry.CloudUsageDataProvider.SONAR_HELM_CHART_VERSION;
53 public class CloudUsageDataProviderTest {
55 private final System2 system2 = Mockito.mock(System2.class);
56 private final Paths2 paths2 = Mockito.mock(Paths2.class);
57 private final OkHttpClient httpClient = Mockito.mock(OkHttpClient.class);
58 private final ContainerSupport containerSupport = mock(ContainerSupport.class);
59 private final ProcessBuilder processBuilder = mock(ProcessBuilder.class);
60 private final CloudUsageDataProvider underTest = new CloudUsageDataProvider(containerSupport, system2, paths2, () -> processBuilder,
64 public void setUp() throws Exception {
65 when(system2.envVariable(KUBERNETES_SERVICE_HOST)).thenReturn("localhost");
66 when(system2.envVariable(KUBERNETES_SERVICE_PORT)).thenReturn("443");
68 mockHttpClientCall(200, "OK", ResponseBody.create("""
72 "gitVersion": "v1.25.3",
73 "gitCommit": "434bfd82814af038ad94d62ebe59b133fcb50506",
74 "gitTreeState": "clean",
75 "buildDate": "2022-11-02T03:24:50Z",
76 "goVersion": "go1.19.2",
78 "platform": "linux/arm64"
80 """, MediaType.parse(MediaTypes.JSON)));
83 private void mockHttpClientCall(int code, String message, @Nullable ResponseBody body) throws IOException {
84 Call callMock = mock(Call.class);
85 when(callMock.execute()).thenReturn(new Response.Builder()
86 .request(new Request.Builder().url("http://any.test/").build())
87 .protocol(Protocol.HTTP_1_1)
92 when(httpClient.newCall(any())).thenReturn(callMock);
96 public void containerRuntime_whenContainerSupportContextExists_shouldNotBeNull() {
97 when(containerSupport.getContainerContext()).thenReturn("docker");
98 assertThat(underTest.getCloudUsage().containerRuntime()).isEqualTo("docker");
102 public void containerRuntime_whenContainerSupportContextMissing_shouldBeNull() {
103 when(containerSupport.getContainerContext()).thenReturn(null);
104 assertThat(underTest.getCloudUsage().containerRuntime()).isNull();
108 public void kubernetes_whenEnvVarExists_shouldReturnTrue() {
109 assertThat(underTest.getCloudUsage().kubernetes()).isTrue();
113 public void kubernetes_whenEnvVarDoesNotExist_shouldReturnFalse() {
114 when(system2.envVariable(KUBERNETES_SERVICE_HOST)).thenReturn(null);
115 assertThat(underTest.getCloudUsage().kubernetes()).isFalse();
119 public void kubernetesVersion_whenOnKubernetes_shouldReturnValue() {
120 assertThat(underTest.getCloudUsage().kubernetesVersion()).isEqualTo("1.25");
124 public void kubernetesVersion_whenNotOnKubernetes_shouldReturnNull() {
125 when(system2.envVariable(KUBERNETES_SERVICE_HOST)).thenReturn(null);
126 assertThat(underTest.getCloudUsage().kubernetesVersion()).isNull();
130 public void kubernetesVersion_whenApiCallFails_shouldReturnNull() throws IOException {
131 mockHttpClientCall(404, "not found", null);
132 assertThat(underTest.getCloudUsage().kubernetesVersion()).isNull();
136 public void kubernetesPlatform_whenOnKubernetes_shouldReturnValue() {
137 assertThat(underTest.getCloudUsage().kubernetesPlatform()).isEqualTo("linux/arm64");
141 public void kubernetesPlatform_whenNotOnKubernetes_shouldReturnNull() {
142 when(system2.envVariable(KUBERNETES_SERVICE_HOST)).thenReturn(null);
143 assertThat(underTest.getCloudUsage().kubernetesPlatform()).isNull();
147 public void kubernetesPlatform_whenApiCallFails_shouldReturnNull() throws IOException {
148 mockHttpClientCall(404, "not found", null);
149 assertThat(underTest.getCloudUsage().kubernetesPlatform()).isNull();
153 public void kubernetesProvider_shouldReturnValue() throws IOException {
154 Process processMock = mock(Process.class);
155 when(processMock.getInputStream()).thenReturn(new ByteArrayInputStream("some-provider".getBytes()));
156 when(processBuilder.command(any(String[].class))).thenReturn(processBuilder);
157 when(processBuilder.start()).thenReturn(processMock);
159 assertThat(underTest.getCloudUsage().kubernetesProvider()).isEqualTo("some-provider");
163 public void kubernetesProvider_whenValueContainsNullChars_shouldReturnValueWithoutNullChars() throws IOException {
164 Process processMock = mock(Process.class);
165 when(processMock.getInputStream()).thenReturn(new ByteArrayInputStream("so\u0000me-prov\u0000ider".getBytes()));
166 when(processBuilder.command(any(String[].class))).thenReturn(processBuilder);
167 when(processBuilder.start()).thenReturn(processMock);
169 assertThat(underTest.getCloudUsage().kubernetesProvider()).isEqualTo("some-provider");
173 public void officialHelmChart_whenEnvVarExists_shouldReturnValue() {
174 when(system2.envVariable(SONAR_HELM_CHART_VERSION)).thenReturn("10.1.0");
175 assertThat(underTest.getCloudUsage().officialHelmChart()).isEqualTo("10.1.0");
179 public void officialHelmChart_whenEnvVarDoesNotExist_shouldReturnNull() {
180 when(system2.envVariable(SONAR_HELM_CHART_VERSION)).thenReturn(null);
181 assertThat(underTest.getCloudUsage().officialHelmChart()).isNull();
185 public void officialImage_whenEnvVarTrue_shouldReturnTrue() {
186 when(system2.envVariable(DOCKER_RUNNING)).thenReturn("True");
187 assertThat(underTest.getCloudUsage().officialImage()).isTrue();
191 public void officialImage_whenEnvVarFalse_shouldReturnFalse() {
192 when(system2.envVariable(DOCKER_RUNNING)).thenReturn("False");
193 assertThat(underTest.getCloudUsage().officialImage()).isFalse();
197 public void officialImage_whenEnvVarDoesNotExist_shouldReturnFalse() {
198 when(system2.envVariable(DOCKER_RUNNING)).thenReturn(null);
199 assertThat(underTest.getCloudUsage().officialImage()).isFalse();
203 public void initHttpClient_whenValidCertificate_shouldCreateClient() throws URISyntaxException {
204 when(paths2.get(anyString())).thenReturn(Paths.get(requireNonNull(getClass().getResource("dummy.crt")).toURI()));
206 CloudUsageDataProvider provider = new CloudUsageDataProvider(containerSupport, system2, paths2);
207 assertThat(provider.getHttpClient()).isNotNull();
211 public void initHttpClient_whenNotOnKubernetes_shouldNotCreateClient() throws URISyntaxException {
212 when(paths2.get(anyString())).thenReturn(Paths.get(requireNonNull(getClass().getResource("dummy.crt")).toURI()));
213 when(system2.envVariable(KUBERNETES_SERVICE_HOST)).thenReturn(null);
215 CloudUsageDataProvider provider = new CloudUsageDataProvider(containerSupport, system2, paths2);
216 assertThat(provider.getHttpClient()).isNull();
220 public void initHttpClient_whenCertificateNotFound_shouldFail() {
221 when(paths2.get(any())).thenReturn(Paths.get("dummy.crt"));
223 CloudUsageDataProvider provider = new CloudUsageDataProvider(containerSupport, system2, paths2);
224 assertThat(provider.getHttpClient()).isNull();