選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

ScannerMediumTester.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  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.
  10. *
  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.
  15. *
  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.
  19. */
  20. package org.sonar.scanner.mediumtest;
  21. import com.google.common.collect.Maps;
  22. import java.io.File;
  23. import java.io.FileInputStream;
  24. import java.io.IOException;
  25. import java.io.InputStreamReader;
  26. import java.io.Reader;
  27. import java.nio.charset.StandardCharsets;
  28. import java.nio.file.Path;
  29. import java.util.ArrayList;
  30. import java.util.Collections;
  31. import java.util.Date;
  32. import java.util.HashMap;
  33. import java.util.LinkedList;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.Properties;
  37. import java.util.function.Supplier;
  38. import javax.annotation.CheckForNull;
  39. import javax.annotation.Nullable;
  40. import org.apache.commons.io.FileUtils;
  41. import org.junit.rules.ExternalResource;
  42. import org.sonar.api.Plugin;
  43. import org.sonar.api.measures.CoreMetrics;
  44. import org.sonar.api.measures.Metric;
  45. import org.sonar.api.rule.RuleKey;
  46. import org.sonar.api.server.rule.RulesDefinition;
  47. import org.sonar.api.server.rule.RulesDefinition.Repository;
  48. import org.sonar.api.utils.DateUtils;
  49. import org.sonar.batch.bootstrapper.Batch;
  50. import org.sonar.batch.bootstrapper.EnvironmentInformation;
  51. import org.sonar.batch.bootstrapper.LogOutput;
  52. import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
  53. import org.sonar.scanner.repository.FileData;
  54. import org.sonar.scanner.repository.MetricsRepository;
  55. import org.sonar.scanner.repository.MetricsRepositoryLoader;
  56. import org.sonar.scanner.repository.ProjectRepositories;
  57. import org.sonar.scanner.repository.ProjectRepositoriesLoader;
  58. import org.sonar.scanner.repository.QualityProfileLoader;
  59. import org.sonar.scanner.repository.SingleProjectRepository;
  60. import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
  61. import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
  62. import org.sonar.scanner.rule.ActiveRulesLoader;
  63. import org.sonar.scanner.rule.LoadedActiveRule;
  64. import org.sonar.scanner.rule.RulesLoader;
  65. import org.sonar.scanner.scan.ScanProperties;
  66. import org.sonar.scanner.scan.branch.BranchConfiguration;
  67. import org.sonar.scanner.scan.branch.BranchConfigurationLoader;
  68. import org.sonar.scanner.scan.branch.BranchType;
  69. import org.sonar.scanner.scan.branch.ProjectBranches;
  70. import org.sonar.scanner.scan.branch.ProjectPullRequests;
  71. import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
  72. import org.sonarqube.ws.Rules.ListResponse.Rule;
  73. /**
  74. * Main utility class for writing scanner medium tests.
  75. *
  76. */
  77. public class ScannerMediumTester extends ExternalResource {
  78. private static Path userHome = null;
  79. private Map<String, String> globalProperties = new HashMap<>();
  80. private final FakeMetricsRepositoryLoader globalRefProvider = new FakeMetricsRepositoryLoader();
  81. private final FakeBranchConfigurationLoader branchConfigurationLoader = new FakeBranchConfigurationLoader();
  82. private final FakeBranchConfiguration branchConfiguration = new FakeBranchConfiguration();
  83. private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader();
  84. private final FakePluginInstaller pluginInstaller = new FakePluginInstaller();
  85. private final FakeGlobalSettingsLoader globalSettingsLoader = new FakeGlobalSettingsLoader();
  86. private final FakeProjectSettingsLoader projectSettingsLoader = new FakeProjectSettingsLoader();
  87. private final FakeRulesLoader rulesLoader = new FakeRulesLoader();
  88. private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
  89. private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
  90. private LogOutput logOutput = null;
  91. private static void createWorkingDirs() throws IOException {
  92. destroyWorkingDirs();
  93. userHome = java.nio.file.Files.createTempDirectory("mediumtest-userHome");
  94. }
  95. private static void destroyWorkingDirs() throws IOException {
  96. if (userHome != null) {
  97. FileUtils.deleteDirectory(userHome.toFile());
  98. userHome = null;
  99. }
  100. }
  101. public ScannerMediumTester setLogOutput(LogOutput logOutput) {
  102. this.logOutput = logOutput;
  103. return this;
  104. }
  105. public ScannerMediumTester registerPlugin(String pluginKey, File location) {
  106. return registerPlugin(pluginKey, location, 1L);
  107. }
  108. public ScannerMediumTester registerPlugin(String pluginKey, File location, long lastUpdatedAt) {
  109. pluginInstaller.add(pluginKey, location, lastUpdatedAt);
  110. return this;
  111. }
  112. public ScannerMediumTester registerPlugin(String pluginKey, Plugin instance) {
  113. return registerPlugin(pluginKey, instance, 1L);
  114. }
  115. public ScannerMediumTester registerPlugin(String pluginKey, Plugin instance, long lastUpdatedAt) {
  116. pluginInstaller.add(pluginKey, instance, lastUpdatedAt);
  117. return this;
  118. }
  119. public ScannerMediumTester registerCoreMetrics() {
  120. for (Metric<?> m : CoreMetrics.getMetrics()) {
  121. registerMetric(m);
  122. }
  123. return this;
  124. }
  125. public ScannerMediumTester registerMetric(Metric<?> metric) {
  126. globalRefProvider.add(metric);
  127. return this;
  128. }
  129. public ScannerMediumTester addQProfile(String language, String name) {
  130. qualityProfiles.add(language, name);
  131. return this;
  132. }
  133. public ScannerMediumTester addRule(Rule rule) {
  134. rulesLoader.addRule(rule);
  135. return this;
  136. }
  137. public ScannerMediumTester addRule(String key, String repoKey, String internalKey, String name) {
  138. Rule.Builder builder = Rule.newBuilder();
  139. builder.setKey(key);
  140. builder.setRepository(repoKey);
  141. if (internalKey != null) {
  142. builder.setInternalKey(internalKey);
  143. }
  144. builder.setName(name);
  145. rulesLoader.addRule(builder.build());
  146. return this;
  147. }
  148. public ScannerMediumTester addRules(RulesDefinition rulesDefinition) {
  149. RulesDefinition.Context context = new RulesDefinition.Context();
  150. rulesDefinition.define(context);
  151. List<Repository> repositories = context.repositories();
  152. for (Repository repo : repositories) {
  153. for (RulesDefinition.Rule rule : repo.rules()) {
  154. this.addRule(rule.key(), rule.repository().key(), rule.internalKey(), rule.name());
  155. }
  156. }
  157. return this;
  158. }
  159. public ScannerMediumTester addDefaultQProfile(String language, String name) {
  160. addQProfile(language, name);
  161. return this;
  162. }
  163. public ScannerMediumTester bootstrapProperties(Map<String, String> props) {
  164. globalProperties.putAll(props);
  165. return this;
  166. }
  167. public ScannerMediumTester activateRule(LoadedActiveRule activeRule) {
  168. activeRules.addActiveRule(activeRule);
  169. return this;
  170. }
  171. public ScannerMediumTester addActiveRule(String repositoryKey, String ruleKey, @Nullable String templateRuleKey, String name, @Nullable String severity,
  172. @Nullable String internalKey, @Nullable String language) {
  173. LoadedActiveRule r = new LoadedActiveRule();
  174. r.setInternalKey(internalKey);
  175. r.setRuleKey(RuleKey.of(repositoryKey, ruleKey));
  176. r.setName(name);
  177. r.setTemplateRuleKey(templateRuleKey);
  178. r.setLanguage(language);
  179. r.setSeverity(severity);
  180. activeRules.addActiveRule(r);
  181. return this;
  182. }
  183. public ScannerMediumTester addFileData(String path, FileData fileData) {
  184. projectRefProvider.addFileData(path, fileData);
  185. return this;
  186. }
  187. public ScannerMediumTester addGlobalServerSettings(String key, String value) {
  188. globalSettingsLoader.getGlobalSettings().put(key, value);
  189. return this;
  190. }
  191. public ScannerMediumTester addProjectServerSettings(String key, String value) {
  192. projectSettingsLoader.getProjectSettings().put(key, value);
  193. return this;
  194. }
  195. @Override
  196. protected void before() throws Throwable {
  197. try {
  198. createWorkingDirs();
  199. } catch (IOException e) {
  200. throw new IllegalStateException(e);
  201. }
  202. registerCoreMetrics();
  203. globalProperties.put(GlobalAnalysisMode.MEDIUM_TEST_ENABLED, "true");
  204. globalProperties.put(ScanProperties.KEEP_REPORT_PROP_KEY, "true");
  205. globalProperties.put("sonar.userHome", userHome.toString());
  206. }
  207. @Override
  208. protected void after() {
  209. try {
  210. destroyWorkingDirs();
  211. } catch (IOException e) {
  212. throw new IllegalStateException(e);
  213. }
  214. }
  215. public AnalysisBuilder newAnalysis() {
  216. return new AnalysisBuilder(this);
  217. }
  218. public AnalysisBuilder newAnalysis(File sonarProps) {
  219. Properties prop = new Properties();
  220. try (Reader reader = new InputStreamReader(new FileInputStream(sonarProps), StandardCharsets.UTF_8)) {
  221. prop.load(reader);
  222. } catch (Exception e) {
  223. throw new IllegalStateException("Unable to read configuration file", e);
  224. }
  225. AnalysisBuilder builder = new AnalysisBuilder(this);
  226. builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath());
  227. for (Map.Entry<Object, Object> entry : prop.entrySet()) {
  228. builder.property(entry.getKey().toString(), entry.getValue().toString());
  229. }
  230. return builder;
  231. }
  232. public static class AnalysisBuilder {
  233. private final Map<String, String> taskProperties = new HashMap<>();
  234. private ScannerMediumTester tester;
  235. public AnalysisBuilder(ScannerMediumTester tester) {
  236. this.tester = tester;
  237. }
  238. public AnalysisResult execute() {
  239. AnalysisResult result = new AnalysisResult();
  240. Map<String, String> props = new HashMap<>();
  241. props.putAll(tester.globalProperties);
  242. props.putAll(taskProperties);
  243. Batch.builder()
  244. .setGlobalProperties(props)
  245. .setEnableLoggingConfiguration(true)
  246. .addComponents(new EnvironmentInformation("mediumTest", "1.0"),
  247. tester.pluginInstaller,
  248. tester.globalRefProvider,
  249. tester.qualityProfiles,
  250. tester.rulesLoader,
  251. tester.branchConfigurationLoader,
  252. tester.projectRefProvider,
  253. tester.activeRules,
  254. tester.globalSettingsLoader,
  255. tester.projectSettingsLoader,
  256. result)
  257. .setLogOutput(tester.logOutput)
  258. .build().execute();
  259. return result;
  260. }
  261. public AnalysisBuilder properties(Map<String, String> props) {
  262. taskProperties.putAll(props);
  263. return this;
  264. }
  265. public AnalysisBuilder property(String key, String value) {
  266. taskProperties.put(key, value);
  267. return this;
  268. }
  269. }
  270. private static class FakeRulesLoader implements RulesLoader {
  271. private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>();
  272. public FakeRulesLoader addRule(Rule rule) {
  273. rules.add(rule);
  274. return this;
  275. }
  276. @Override
  277. public List<Rule> load() {
  278. return rules;
  279. }
  280. }
  281. private static class FakeActiveRulesLoader implements ActiveRulesLoader {
  282. private List<LoadedActiveRule> activeRules = new LinkedList<>();
  283. public void addActiveRule(LoadedActiveRule activeRule) {
  284. this.activeRules.add(activeRule);
  285. }
  286. @Override
  287. public List<LoadedActiveRule> load(String qualityProfileKey) {
  288. return activeRules;
  289. }
  290. }
  291. private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader {
  292. private int metricId = 1;
  293. private List<Metric> metrics = new ArrayList<>();
  294. @Override
  295. public MetricsRepository load() {
  296. return new MetricsRepository(metrics);
  297. }
  298. public FakeMetricsRepositoryLoader add(Metric<?> metric) {
  299. metric.setId(metricId++);
  300. metrics.add(metric);
  301. metricId++;
  302. return this;
  303. }
  304. }
  305. private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {
  306. private Map<String, FileData> fileDataMap = Maps.newHashMap();
  307. @Override
  308. public ProjectRepositories load(String projectKey, @Nullable String branchBase) {
  309. return new SingleProjectRepository(fileDataMap);
  310. }
  311. public FakeProjectRepositoriesLoader addFileData(String path, FileData fileData) {
  312. fileDataMap.put(path, fileData);
  313. return this;
  314. }
  315. }
  316. private static class FakeBranchConfiguration implements BranchConfiguration {
  317. private BranchType branchType = BranchType.LONG;
  318. private String branchName = null;
  319. private String branchTarget = null;
  320. private String longLivingSonarReferenceBranch = null;
  321. @Override
  322. public BranchType branchType() {
  323. return branchType;
  324. }
  325. @CheckForNull
  326. @Override
  327. public String branchName() {
  328. return branchName;
  329. }
  330. @CheckForNull
  331. @Override
  332. public String targetScmBranch() {
  333. return branchTarget;
  334. }
  335. @CheckForNull
  336. @Override
  337. public String longLivingSonarReferenceBranch() {
  338. return longLivingSonarReferenceBranch;
  339. }
  340. @Override
  341. public String pullRequestKey() {
  342. throw new UnsupportedOperationException();
  343. }
  344. }
  345. public ScannerMediumTester setBranchType(BranchType branchType) {
  346. branchConfiguration.branchType = branchType;
  347. return this;
  348. }
  349. public ScannerMediumTester setBranchName(String branchName) {
  350. this.branchConfiguration.branchName = branchName;
  351. return this;
  352. }
  353. public ScannerMediumTester setBranchTarget(String branchTarget) {
  354. this.branchConfiguration.branchTarget = branchTarget;
  355. return this;
  356. }
  357. public ScannerMediumTester setLongLivingSonarReferenceBranch(String longLivingSonarReferenceBranch) {
  358. this.branchConfiguration.longLivingSonarReferenceBranch = longLivingSonarReferenceBranch;
  359. return this;
  360. }
  361. private class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
  362. @Override
  363. public BranchConfiguration load(Map<String, String> localSettings, Supplier<Map<String, String>> settingsSupplier, ProjectBranches branches, ProjectPullRequests pullRequests) {
  364. return branchConfiguration;
  365. }
  366. }
  367. private static class FakeQualityProfileLoader implements QualityProfileLoader {
  368. private List<QualityProfile> qualityProfiles = new LinkedList<>();
  369. public void add(String language, String name) {
  370. qualityProfiles.add(QualityProfile.newBuilder()
  371. .setLanguage(language)
  372. .setKey(name)
  373. .setName(name)
  374. .setRulesUpdatedAt(DateUtils.formatDateTime(new Date(1234567891212L)))
  375. .build());
  376. }
  377. @Override
  378. public List<QualityProfile> load(String projectKey) {
  379. return qualityProfiles;
  380. }
  381. @Override
  382. public List<QualityProfile> loadDefault() {
  383. return qualityProfiles;
  384. }
  385. }
  386. private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
  387. private Map<String, String> globalSettings = new HashMap<>();
  388. public Map<String, String> getGlobalSettings() {
  389. return globalSettings;
  390. }
  391. @Override
  392. public Map<String, String> loadGlobalSettings() {
  393. return Collections.unmodifiableMap(globalSettings);
  394. }
  395. }
  396. private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {
  397. private Map<String, String> projectSettings = new HashMap<>();
  398. public Map<String, String> getProjectSettings() {
  399. return projectSettings;
  400. }
  401. @Override
  402. public Map<String, String> loadProjectSettings() {
  403. return Collections.unmodifiableMap(projectSettings);
  404. }
  405. }
  406. }