3 * Copyright (C) 2009-2020 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.measure.ws;
22 import java.util.List;
23 import java.util.stream.LongStream;
24 import org.junit.Before;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.ExpectedException;
28 import org.sonar.api.measures.Metric.ValueType;
29 import org.sonar.api.server.ws.WebService;
30 import org.sonar.api.server.ws.WebService.Param;
31 import org.sonar.api.utils.System2;
32 import org.sonar.api.web.UserRole;
33 import org.sonar.core.util.stream.MoreCollectors;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.component.ComponentDto;
38 import org.sonar.db.component.SnapshotDto;
39 import org.sonar.db.measure.MeasureDto;
40 import org.sonar.db.metric.MetricDto;
41 import org.sonar.db.organization.OrganizationDto;
42 import org.sonar.server.component.TestComponentFinder;
43 import org.sonar.server.exceptions.ForbiddenException;
44 import org.sonar.server.exceptions.NotFoundException;
45 import org.sonar.server.measure.ws.SearchHistoryAction.SearchHistoryRequest;
46 import org.sonar.server.tester.UserSessionRule;
47 import org.sonar.server.ws.TestRequest;
48 import org.sonar.server.ws.WsActionTester;
49 import org.sonarqube.ws.Common.Paging;
50 import org.sonarqube.ws.Measures.SearchHistoryResponse;
51 import org.sonarqube.ws.Measures.SearchHistoryResponse.HistoryMeasure;
52 import org.sonarqube.ws.Measures.SearchHistoryResponse.HistoryValue;
54 import static java.lang.Double.parseDouble;
55 import static java.lang.String.format;
56 import static java.util.Arrays.asList;
57 import static java.util.Collections.singletonList;
58 import static java.util.Optional.ofNullable;
59 import static org.assertj.core.api.Assertions.assertThat;
60 import static org.assertj.core.api.Assertions.tuple;
61 import static org.sonar.api.utils.DateUtils.formatDateTime;
62 import static org.sonar.api.utils.DateUtils.parseDateTime;
63 import static org.sonar.db.component.BranchType.PULL_REQUEST;
64 import static org.sonar.db.component.ComponentTesting.newFileDto;
65 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
66 import static org.sonar.db.component.SnapshotDto.STATUS_UNPROCESSED;
67 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
68 import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
69 import static org.sonar.db.metric.MetricTesting.newMetricDto;
70 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH;
71 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_COMPONENT;
72 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_FROM;
73 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRICS;
74 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST;
75 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_TO;
76 import static org.sonar.test.JsonAssert.assertJson;
78 public class SearchHistoryActionTest {
81 public UserSessionRule userSession = UserSessionRule.standalone();
83 public ExpectedException expectedException = ExpectedException.none();
85 public DbTester db = DbTester.create();
87 private DbClient dbClient = db.getDbClient();
88 private DbSession dbSession = db.getSession();
90 private WsActionTester ws = new WsActionTester(new SearchHistoryAction(dbClient, TestComponentFinder.from(db), userSession));
92 private ComponentDto project;
93 private SnapshotDto analysis;
94 private MetricDto complexityMetric;
95 private MetricDto nclocMetric;
96 private MetricDto newViolationMetric;
97 private MetricDto stringMetric;
100 public void setUp() {
101 project = newPrivateProjectDto(db.getDefaultOrganization());
102 analysis = db.components().insertProjectAndSnapshot(project);
103 userSession.addProjectPermission(UserRole.USER, project);
104 nclocMetric = insertNclocMetric();
105 complexityMetric = insertComplexityMetric();
106 newViolationMetric = insertNewViolationMetric();
107 stringMetric = insertStringMetric();
111 public void empty_response() {
112 project = db.components().insertPrivateProject();
113 userSession.addProjectPermission(UserRole.USER, project);
114 SearchHistoryRequest request = SearchHistoryRequest.builder()
115 .setComponent(project.getDbKey())
116 .setMetrics(singletonList(complexityMetric.getKey()))
119 SearchHistoryResponse result = call(request);
121 assertThat(result.getMeasuresList()).hasSize(1);
122 assertThat(result.getMeasures(0).getHistoryCount()).isZero();
124 assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal)
125 // pagination is applied to the number of analyses
126 .containsExactly(1, 100, 0);
130 public void analyses_but_no_measure() {
131 project = db.components().insertPrivateProject();
132 analysis = db.components().insertSnapshot(project);
133 userSession.addProjectPermission(UserRole.USER, project);
135 SearchHistoryRequest request = SearchHistoryRequest.builder()
136 .setComponent(project.getDbKey())
137 .setMetrics(singletonList(complexityMetric.getKey()))
140 SearchHistoryResponse result = call(request);
142 assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsExactly(1, 100, 1);
143 assertThat(result.getMeasuresList()).hasSize(1);
144 assertThat(result.getMeasures(0).getHistoryList()).extracting(HistoryValue::hasDate, HistoryValue::hasValue).containsExactly(tuple(true, false));
148 public void return_metrics() {
149 dbClient.measureDao().insert(dbSession, newMeasureDto(complexityMetric, project, analysis).setValue(42.0d));
152 SearchHistoryRequest request = SearchHistoryRequest.builder()
153 .setComponent(project.getDbKey())
154 .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey()))
157 SearchHistoryResponse result = call(request);
159 assertThat(result.getMeasuresList()).hasSize(3)
160 .extracting(HistoryMeasure::getMetric)
161 .containsExactly(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey());
165 public void return_measures() {
166 SnapshotDto laterAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(analysis.getCreatedAt() + 42_000));
167 ComponentDto file = db.components().insertComponent(newFileDto(project));
168 dbClient.measureDao().insert(dbSession,
169 newMeasureDto(complexityMetric, project, analysis).setValue(101d),
170 newMeasureDto(complexityMetric, project, laterAnalysis).setValue(100d),
171 newMeasureDto(complexityMetric, file, analysis).setValue(42d),
172 newMeasureDto(nclocMetric, project, analysis).setValue(201d),
173 newMeasureDto(newViolationMetric, project, analysis).setVariation(5d),
174 newMeasureDto(newViolationMetric, project, laterAnalysis).setVariation(10d));
177 SearchHistoryRequest request = SearchHistoryRequest.builder()
178 .setComponent(project.getDbKey())
179 .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey()))
181 SearchHistoryResponse result = call(request);
183 assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal)
184 .containsExactly(1, 100, 2);
185 assertThat(result.getMeasuresList()).extracting(HistoryMeasure::getMetric).hasSize(3)
186 .containsExactly(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey());
187 String analysisDate = formatDateTime(analysis.getCreatedAt());
188 String laterAnalysisDate = formatDateTime(laterAnalysis.getCreatedAt());
189 // complexity measures
190 HistoryMeasure complexityMeasures = result.getMeasures(0);
191 assertThat(complexityMeasures.getMetric()).isEqualTo(complexityMetric.getKey());
192 assertThat(complexityMeasures.getHistoryList()).extracting(HistoryValue::getDate, HistoryValue::getValue)
193 .containsExactly(tuple(analysisDate, "101"), tuple(laterAnalysisDate, "100"));
195 HistoryMeasure nclocMeasures = result.getMeasures(1);
196 assertThat(nclocMeasures.getMetric()).isEqualTo(nclocMetric.getKey());
197 assertThat(nclocMeasures.getHistoryList()).extracting(HistoryValue::getDate, HistoryValue::getValue, HistoryValue::hasValue).containsExactly(
198 tuple(analysisDate, "201", true), tuple(laterAnalysisDate, "", false));
199 // new_violation measures
200 HistoryMeasure newViolationMeasures = result.getMeasures(2);
201 assertThat(newViolationMeasures.getMetric()).isEqualTo(newViolationMetric.getKey());
202 assertThat(newViolationMeasures.getHistoryList()).extracting(HistoryValue::getDate, HistoryValue::getValue)
203 .containsExactly(tuple(analysisDate, "5"), tuple(laterAnalysisDate, "10"));
207 public void pagination_applies_to_analyses() {
208 project = db.components().insertPrivateProject();
209 userSession.addProjectPermission(UserRole.USER, project);
210 List<String> analysisDates = LongStream.rangeClosed(1, 9)
211 .mapToObj(i -> dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(i * 1_000_000_000)))
212 .peek(a -> dbClient.measureDao().insert(dbSession, newMeasureDto(complexityMetric, project, a).setValue(101d)))
213 .map(a -> formatDateTime(a.getCreatedAt()))
214 .collect(MoreCollectors.toList());
217 SearchHistoryRequest request = SearchHistoryRequest.builder()
218 .setComponent(project.getDbKey())
219 .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey()))
223 SearchHistoryResponse result = call(request);
225 assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsExactly(2, 3, 9);
226 assertThat(result.getMeasures(0).getHistoryList()).extracting(HistoryValue::getDate).containsExactly(
227 analysisDates.get(3), analysisDates.get(4), analysisDates.get(5));
231 public void inclusive_from_and_to_dates() {
232 project = db.components().insertPrivateProject();
233 userSession.addProjectPermission(UserRole.USER, project);
234 List<String> analysisDates = LongStream.rangeClosed(1, 9)
235 .mapToObj(i -> dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(System2.INSTANCE.now() + i * 1_000_000_000L)))
236 .peek(a -> dbClient.measureDao().insert(dbSession, newMeasureDto(complexityMetric, project, a).setValue(Double.valueOf(a.getCreatedAt()))))
237 .map(a -> formatDateTime(a.getCreatedAt()))
238 .collect(MoreCollectors.toList());
241 SearchHistoryRequest request = SearchHistoryRequest.builder()
242 .setComponent(project.getDbKey())
243 .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey()))
244 .setFrom(analysisDates.get(1))
245 .setTo(analysisDates.get(3))
247 SearchHistoryResponse result = call(request);
249 assertThat(result.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsExactly(1, 100, 3);
250 assertThat(result.getMeasures(0).getHistoryList()).extracting(HistoryValue::getDate).containsExactly(
251 analysisDates.get(1), analysisDates.get(2), analysisDates.get(3));
255 public void return_best_values_for_files() {
256 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("optimized").setValueType(ValueType.INT.name()).setOptimizedBestValue(true).setBestValue(456d));
257 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("new_optimized").setValueType(ValueType.INT.name()).setOptimizedBestValue(true).setBestValue(789d));
259 ComponentDto file = db.components().insertComponent(newFileDto(project));
261 SearchHistoryRequest request = SearchHistoryRequest.builder()
262 .setComponent(file.getDbKey())
263 .setMetrics(asList("optimized", "new_optimized"))
265 SearchHistoryResponse result = call(request);
267 assertThat(result.getMeasuresCount()).isEqualTo(2);
268 assertThat(result.getMeasuresList().get(0).getHistoryList()).extracting(HistoryValue::getValue).containsExactly("789");
269 assertThat(result.getMeasuresList().get(1).getHistoryList()).extracting(HistoryValue::getValue).containsExactly("456");
271 // Best value is not applied to project
272 request = SearchHistoryRequest.builder()
273 .setComponent(project.getDbKey())
274 .setMetrics(asList("optimized", "new_optimized"))
276 result = call(request);
277 assertThat(result.getMeasuresList().get(0).getHistoryCount()).isEqualTo(1);
278 assertThat(result.getMeasuresList().get(0).getHistory(0).hasDate()).isTrue();
279 assertThat(result.getMeasuresList().get(0).getHistory(0).hasValue()).isFalse();
283 public void do_not_return_unprocessed_analyses() {
284 dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setStatus(STATUS_UNPROCESSED));
287 SearchHistoryRequest request = SearchHistoryRequest.builder()
288 .setComponent(project.getDbKey())
289 .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey()))
291 SearchHistoryResponse result = call(request);
293 // one analysis in setUp method
294 assertThat(result.getPaging().getTotal()).isEqualTo(1);
298 public void branch() {
299 ComponentDto project = db.components().insertPrivateProject();
300 userSession.addProjectPermission(UserRole.USER, project);
301 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
302 ComponentDto file = db.components().insertComponent(newFileDto(branch));
303 SnapshotDto analysis = db.components().insertSnapshot(branch);
304 MeasureDto measure = db.measures().insertMeasure(file, analysis, nclocMetric, m -> m.setValue(2d));
306 SearchHistoryResponse result = ws.newRequest()
307 .setParam(PARAM_COMPONENT, file.getKey())
308 .setParam(PARAM_BRANCH, "my_branch")
309 .setParam(PARAM_METRICS, "ncloc")
310 .executeProtobuf(SearchHistoryResponse.class);
312 assertThat(result.getMeasuresList()).extracting(HistoryMeasure::getMetric).hasSize(1);
313 HistoryMeasure historyMeasure = result.getMeasures(0);
314 assertThat(historyMeasure.getMetric()).isEqualTo(nclocMetric.getKey());
315 assertThat(historyMeasure.getHistoryList())
316 .extracting(m -> parseDouble(m.getValue()))
317 .containsExactlyInAnyOrder(measure.getValue());
321 public void pull_request() {
322 ComponentDto project = db.components().insertPrivateProject();
323 userSession.addProjectPermission(UserRole.USER, project);
324 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST));
325 ComponentDto file = db.components().insertComponent(newFileDto(branch));
326 SnapshotDto analysis = db.components().insertSnapshot(branch);
327 MeasureDto measure = db.measures().insertMeasure(file, analysis, nclocMetric, m -> m.setValue(2d));
329 SearchHistoryResponse result = ws.newRequest()
330 .setParam(PARAM_COMPONENT, file.getKey())
331 .setParam(PARAM_PULL_REQUEST, "pr-123")
332 .setParam(PARAM_METRICS, "ncloc")
333 .executeProtobuf(SearchHistoryResponse.class);
335 assertThat(result.getMeasuresList()).extracting(HistoryMeasure::getMetric).hasSize(1);
336 HistoryMeasure historyMeasure = result.getMeasures(0);
337 assertThat(historyMeasure.getMetric()).isEqualTo(nclocMetric.getKey());
338 assertThat(historyMeasure.getHistoryList())
339 .extracting(m -> parseDouble(m.getValue()))
340 .containsExactlyInAnyOrder(measure.getValue());
344 public void fail_when_using_branch_db_key() {
345 OrganizationDto organization = db.organizations().insert();
346 ComponentDto project = db.components().insertPrivateProject(organization);
347 userSession.logIn().addProjectPermission(UserRole.USER, project);
348 ComponentDto branch = db.components().insertProjectBranch(project);
350 expectedException.expect(NotFoundException.class);
351 expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey()));
354 .setParam(PARAM_COMPONENT, branch.getDbKey())
355 .setParam(PARAM_METRICS, "ncloc")
360 public void fail_if_unknown_metric() {
361 SearchHistoryRequest request = SearchHistoryRequest.builder()
362 .setComponent(project.getDbKey())
363 .setMetrics(asList(complexityMetric.getKey(), nclocMetric.getKey(), "METRIC_42", "42_METRIC"))
366 expectedException.expect(IllegalArgumentException.class);
367 expectedException.expectMessage("Metrics 42_METRIC, METRIC_42 are not found");
373 public void fail_if_not_enough_permissions() {
374 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
375 SearchHistoryRequest request = SearchHistoryRequest.builder()
376 .setComponent(project.getDbKey())
377 .setMetrics(singletonList(complexityMetric.getKey()))
380 expectedException.expect(ForbiddenException.class);
386 public void fail_if_unknown_component() {
387 SearchHistoryRequest request = SearchHistoryRequest.builder()
388 .setComponent("__UNKNOWN__")
389 .setMetrics(singletonList(complexityMetric.getKey()))
392 expectedException.expect(NotFoundException.class);
398 public void fail_when_component_is_removed() {
399 ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()));
400 db.components().insertComponent(newFileDto(project).setDbKey("file-key").setEnabled(false));
401 userSession.addProjectPermission(UserRole.USER, project);
403 expectedException.expect(NotFoundException.class);
404 expectedException.expectMessage("Component key 'file-key' not found");
407 .setParam(PARAM_COMPONENT, "file-key")
408 .setParam(PARAM_METRICS, "ncloc")
413 public void fail_if_branch_does_not_exist() {
414 ComponentDto project = db.components().insertPrivateProject();
415 ComponentDto file = db.components().insertComponent(newFileDto(project));
416 userSession.addProjectPermission(UserRole.USER, project);
417 db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
419 expectedException.expect(NotFoundException.class);
420 expectedException.expectMessage(String.format("Component '%s' on branch '%s' not found", file.getKey(), "another_branch"));
423 .setParam(PARAM_COMPONENT, file.getKey())
424 .setParam(PARAM_BRANCH, "another_branch")
425 .setParam(PARAM_METRICS, "ncloc")
430 public void definition() {
431 WebService.Action definition = ws.getDef();
433 assertThat(definition.key()).isEqualTo("search_history");
434 assertThat(definition.responseExampleAsString()).isNotEmpty();
435 assertThat(definition.isPost()).isFalse();
436 assertThat(definition.isInternal()).isFalse();
437 assertThat(definition.since()).isEqualTo("6.3");
438 assertThat(definition.params()).hasSize(8);
440 Param branch = definition.param("branch");
441 assertThat(branch.since()).isEqualTo("6.6");
442 assertThat(branch.isInternal()).isFalse();
443 assertThat(branch.isRequired()).isFalse();
447 public void json_example() {
448 project = db.components().insertPrivateProject();
449 userSession.addProjectPermission(UserRole.USER, project);
450 long now = parseDateTime("2017-01-23T17:00:53+0100").getTime();
451 LongStream.rangeClosed(0, 2)
452 .mapToObj(i -> dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setCreatedAt(now + i * 24 * 1_000 * 60 * 60)))
453 .forEach(analysis -> dbClient.measureDao().insert(dbSession,
454 newMeasureDto(complexityMetric, project, analysis).setValue(45d),
455 newMeasureDto(newViolationMetric, project, analysis).setVariation(46d),
456 newMeasureDto(nclocMetric, project, analysis).setValue(47d)));
459 String result = ws.newRequest()
460 .setParam(PARAM_COMPONENT, project.getDbKey())
461 .setParam(PARAM_METRICS, String.join(",", asList(complexityMetric.getKey(), nclocMetric.getKey(), newViolationMetric.getKey())))
462 .execute().getInput();
464 assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString());
468 public void measure_without_values() {
469 dbClient.measureDao().insert(dbSession, newMeasureDto(stringMetric, project, analysis).setValue(null).setData(null));
472 SearchHistoryRequest request = SearchHistoryRequest.builder()
473 .setComponent(project.getDbKey())
474 .setMetrics(singletonList(stringMetric.getKey()))
476 SearchHistoryResponse result = call(request);
478 HistoryMeasure measure = result.getMeasuresList().stream()
479 .filter(m -> m.getMetric().equals(stringMetric.getKey()))
482 assertThat(measure.getHistoryList()).hasSize(1);
483 assertThat(measure.getHistory(0).hasValue()).isFalse();
486 private SearchHistoryResponse call(SearchHistoryRequest request) {
487 TestRequest testRequest = ws.newRequest();
489 testRequest.setParam(PARAM_COMPONENT, request.getComponent());
490 testRequest.setParam(PARAM_METRICS, String.join(",", request.getMetrics()));
491 ofNullable(request.getFrom()).ifPresent(from -> testRequest.setParam(PARAM_FROM, from));
492 ofNullable(request.getTo()).ifPresent(to -> testRequest.setParam(PARAM_TO, to));
493 ofNullable(request.getPage()).ifPresent(p -> testRequest.setParam(Param.PAGE, String.valueOf(p)));
494 ofNullable(request.getPageSize()).ifPresent(ps -> testRequest.setParam(Param.PAGE_SIZE, String.valueOf(ps)));
496 return testRequest.executeProtobuf(SearchHistoryResponse.class);
499 private static MetricDto newMetricDtoWithoutOptimization() {
500 return newMetricDto()
502 .setOptimizedBestValue(false)
504 .setUserManaged(false);
507 private MetricDto insertNclocMetric() {
508 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization()
510 .setShortName("Lines of code")
511 .setDescription("Non Commenting Lines of Code")
515 .setQualitative(false)
517 .setUserManaged(false));
522 private MetricDto insertComplexityMetric() {
523 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization()
524 .setKey("complexity")
525 .setShortName("Complexity")
526 .setDescription("Cyclomatic complexity")
527 .setDomain("Complexity")
530 .setQualitative(false)
532 .setUserManaged(false));
537 private MetricDto insertNewViolationMetric() {
538 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization()
539 .setKey("new_violations")
540 .setShortName("New issues")
541 .setDescription("New Issues")
545 .setQualitative(true)
547 .setUserManaged(false));
552 private MetricDto insertStringMetric() {
553 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDtoWithoutOptimization()
555 .setShortName("A String")
556 .setValueType("STRING"));