aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-process/src/test/java/org/sonar/process/ProcessPropertiesTest.java
blob: 8ee413bbc9e6ec99eae75aeacfe071524c1d6944 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
 * SonarQube
 * Copyright (C) 2009-2025 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.process;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.net.InetAddress;
import java.util.Map;
import java.util.Properties;
import org.junit.Test;
import org.sonar.core.extension.CoreExtension;
import org.sonar.core.extension.ServiceLoaderWrapper;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.process.ProcessProperties.parseTimeoutMs;

public class ProcessPropertiesTest {

  private final ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
  private final ProcessProperties processProperties = new ProcessProperties(serviceLoaderWrapper);

  @Test
  public void completeDefaults_adds_default_values() {
    Props props = new Props(new Properties());

    processProperties.completeDefaults(props);

    assertThat(props.value("sonar.search.javaOpts")).contains("-Xmx");
    assertThat(props.valueAsInt("sonar.jdbc.maxActive")).isEqualTo(60);
    assertThat(props.valueAsBoolean("sonar.updatecenter.activate")).isTrue();
  }

  @Test
  public void completeDefaults_does_not_override_existing_properties() {
    Properties p = new Properties();
    p.setProperty("sonar.jdbc.username", "angela");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    assertThat(props.value("sonar.jdbc.username")).isEqualTo("angela");
  }

  @Test
  public void completeDefaults_sets_default_values_for_sonar_search_host_and_sonar_search_port_and_random_port_for_sonar_es_port_in_non_cluster_mode() throws Exception {
    Properties p = new Properties();
    p.setProperty("sonar.cluster.enabled", "false");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    String address = props.value("sonar.search.host");
    assertThat(address).isNotEmpty();
    assertThat(InetAddress.getByName(address).isLoopbackAddress()).isTrue();
    assertThat(props.valueAsInt("sonar.search.port")).isEqualTo(9001);
    assertThat(props.valueAsInt("sonar.es.port")).isPositive();
  }

  @Test
  public void completeDefaults_does_not_set_default_values_for_sonar_search_host_and_sonar_search_port_and_sonar_es_port_in_cluster_mode() {
    Properties p = new Properties();
    p.setProperty("sonar.cluster.enabled", "true");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    assertThat(props.contains("sonar.search.port")).isFalse();
    assertThat(props.contains("sonar.search.port")).isFalse();
    assertThat(props.contains("sonar.es.port")).isFalse();
  }

  @Test
  public void completeDefaults_sets_the_http_port_of_elasticsearch_if_value_is_zero_in_standalone_mode() {
    Properties p = new Properties();
    p.setProperty("sonar.search.port", "0");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    assertThat(props.valueAsInt("sonar.search.port")).isPositive();
  }

  @Test
  public void completeDefaults_does_not_fall_back_to_default_if_transport_port_of_elasticsearch_set_in_standalone_mode() {
    Properties p = new Properties();
    p.setProperty("sonar.es.port", "9002");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    assertThat(props.valueAsInt("sonar.es.port")).isEqualTo(9002);
  }

  @Test
  public void completeDefaults_does_not_set_the_http_port_of_elasticsearch_if_value_is_zero_in_search_node_in_cluster() {
    Properties p = new Properties();
    p.setProperty("sonar.cluster.enabled", "true");
    p.setProperty("sonar.search.port", "0");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    assertThat(props.valueAsInt("sonar.search.port")).isZero();
  }

  @Test
  public void completeDefaults_does_not_set_the_transport_port_of_elasticsearch_if_value_is_zero_in_search_node_in_cluster() {
    Properties p = new Properties();
    p.setProperty("sonar.cluster.enabled", "true");
    p.setProperty("sonar.es.port", "0");
    Props props = new Props(p);

    processProperties.completeDefaults(props);

    assertThat(props.valueAsInt("sonar.es.port")).isZero();
  }

  @Test
  public void defaults_loads_properties_defaults_from_base_and_extensions() {
    Props p = new Props(new Properties());
    when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of(new FakeExtension1(), new FakeExtension3()));

    processProperties.completeDefaults(p);

    assertThat(p.value("sonar.some.property")).isEqualTo("1");
    assertThat(p.value("sonar.some.property2")).isEqualTo("455");
    assertThat(p.value("sonar.some.property4")).isEqualTo("abc");
    assertThat(p.value("sonar.some.property5")).isEqualTo("def");
    assertThat(p.value("sonar.some.property5")).isEqualTo("def");
    assertThat(p.value("sonar.search.port")).isEqualTo("9001");
  }

  @Test
  public void defaults_throws_exception_on_same_property_defined_more_than_once_in_extensions() {
    Props p = new Props(new Properties());
    when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of(new FakeExtension1(), new FakeExtension2()));

    assertThatThrownBy(() -> processProperties.completeDefaults(p))
      .isInstanceOf(IllegalStateException.class)
      .hasMessage("Configuration error: property definition named 'sonar.some.property2' found in multiple extensions.");
  }

  private static class FakeExtension1 implements CoreExtension {

    @Override
    public String getName() {
      return "fakeExt1";
    }

    @Override
    public void load(Context context) {
      // do nothing
    }

    @Override
    public Map<String, String> getExtensionProperties() {
      return ImmutableMap.of(
        "sonar.some.property", "1",
        "sonar.some.property2", "455");
    }
  }

  private static class FakeExtension2 implements CoreExtension {

    @Override
    public String getName() {
      return "fakeExt2";
    }

    @Override
    public void load(Context context) {
      // do nothing
    }

    @Override
    public Map<String, String> getExtensionProperties() {
      return ImmutableMap.of(
        "sonar.some.property2", "5435",
        "sonar.some.property3", "32131");
    }
  }

  private static class FakeExtension3 implements CoreExtension {

    @Override
    public String getName() {
      return "fakeExt3";
    }

    @Override
    public void load(Context context) {
      // do nothing
    }

    @Override
    public Map<String, String> getExtensionProperties() {
      return ImmutableMap.of(
        "sonar.some.property4", "abc",
        "sonar.some.property5", "def");
    }
  }

  @Test
  public void parseTimeoutMs_throws_NumberFormat_exception_if_value_is_not_long() {
    assertThatThrownBy(() -> parseTimeoutMs(ProcessProperties.Property.WEB_GRACEFUL_STOP_TIMEOUT, "tru"))
      .isInstanceOf(NumberFormatException.class);
  }

  @Test
  public void parseTimeoutMs_returns_long_from_value() {
    long expected = 5_999_664;

    long res = parseTimeoutMs(ProcessProperties.Property.WEB_GRACEFUL_STOP_TIMEOUT, expected + "");

    assertThat(res).isEqualTo(expected);
  }

  @Test
  public void parseTimeoutMs_throws_ISE_if_value_is_0() {
    assertThatThrownBy(() -> parseTimeoutMs(ProcessProperties.Property.WEB_GRACEFUL_STOP_TIMEOUT, 0 + ""))
      .isInstanceOf(IllegalStateException.class)
      .hasMessage("value of WEB_GRACEFUL_STOP_TIMEOUT must be >= 1");
  }

  @Test
  public void parseTimeoutMs_throws_ISE_if_value_is_less_than_0() {
    int timeoutValue = -5_999_664;
    assertThatThrownBy(() -> parseTimeoutMs(ProcessProperties.Property.WEB_GRACEFUL_STOP_TIMEOUT, timeoutValue + ""))
      .isInstanceOf(IllegalStateException.class)
      .hasMessage("value of WEB_GRACEFUL_STOP_TIMEOUT must be >= 1");
  }
}