]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-16097 Rename 'previousAnalysisCache' to 'previousCache'
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Mon, 21 Mar 2022 18:20:18 +0000 (13:20 -0500)
committersonartech <sonartech@sonarsource.com>
Thu, 24 Mar 2022 20:03:07 +0000 (20:03 +0000)
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/scannercache/ws/GetAction.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/scannercache/ws/GetActionTest.java
sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheLoader.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/cache/AnalysisCacheLoaderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/ModuleSensorContextTest.java

index 1d6137f5dbd5d8b8055d58ebcbe65fef20f8e0d5..b7f17b328b8e9dba0cc24c13d7966f963b89a77c 100644 (file)
@@ -47,8 +47,6 @@ public class ReportComputationSteps extends AbstractComputationSteps {
     ExecuteStatelessInitExtensionsStep.class,
     BuildComponentTreeStep.class,
     ValidateProjectStep.class,
-
-    PersistScannerAnalysisCacheStep.class,
     LoadQualityProfilesStep.class,
 
     // load project related stuffs
@@ -89,6 +87,7 @@ public class ReportComputationSteps extends AbstractComputationSteps {
     HandleUnanalyzedLanguagesStep.class,
 
     // Persist data
+    PersistScannerAnalysisCacheStep.class,
     PersistComponentsStep.class,
     PersistAnalysisStep.class,
     PersistAnalysisPropertiesStep.class,
index ba95c5e639306fc342eb2fdf50f0529cc8b2d34c..8cc9792e51deb6f4fea1ee82ce0c3cc04c9f1759 100644 (file)
@@ -28,8 +28,8 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.web.UserRole;
-import org.sonar.db.DbInputStream;
 import org.sonar.db.DbClient;
+import org.sonar.db.DbInputStream;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.component.ComponentFinder;
@@ -41,10 +41,12 @@ import static org.sonar.db.permission.GlobalPermission.SCAN;
 import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
 import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001;
 
 public class GetAction implements AnalysisCacheWsAction {
   private static final String PROJECT = "project";
   private static final String BRANCH = "branch";
+  private static final String PR = "pullRequest";
 
   private final DbClient dbClient;
   private final UserSession userSession;
@@ -76,20 +78,26 @@ public class GetAction implements AnalysisCacheWsAction {
       .setDescription("Branch key. If not provided, main branch will be used.")
       .setExampleValue(KEY_BRANCH_EXAMPLE_001)
       .setRequired(false);
+
+    action.createParam(PR)
+      .setDescription("Pull request id. Not available in the community edition.")
+      .setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001)
+      .setRequired(false);
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
     String projectKey = request.mandatoryParam(PROJECT);
     String branchKey = request.param(BRANCH);
+    String prKey = request.param(PR);
 
     try (DbSession dbSession = dbClient.openSession(false)) {
-      ComponentDto component = componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, projectKey, branchKey, null);
+      ComponentDto component = componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, projectKey, branchKey, prKey);
       checkPermission(component);
 
       try (DbInputStream dbInputStream = cache.get(component.uuid())) {
         if (dbInputStream == null) {
-          throw new NotFoundException("No cache for given branch");
+          throw new NotFoundException("No cache for given branch or pull request");
         }
 
         boolean compressed = requestedCompressedData(request);
index 312df15ca6b0921de7a399944a0df08a20ecb440..1aec02807f4fbfd67ae9eb1c42210c0186600551 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.BranchType;
 import org.sonar.db.project.ProjectDto;
 import org.sonar.db.scannercache.ScannerAnalysisCacheDao;
 import org.sonar.server.component.ComponentFinder;
@@ -114,6 +115,24 @@ public class GetActionTest {
     assertThat(compressedInputStreamToString(response.getInputStream())).isEqualTo("test data2");
   }
 
+  @Test
+  public void get_data_for_pr() throws IOException {
+    ProjectDto project1 = dbTester.components().insertPrivateProjectDto();
+    BranchDto branch = dbTester.components().insertProjectBranch(project1, b -> b.setBranchType(BranchType.PULL_REQUEST));
+
+    dao.insert(dbTester.getSession(), project1.getUuid(), stringToCompressedInputStream("test data1"));
+    dao.insert(dbTester.getSession(), branch.getUuid(), stringToCompressedInputStream("test data2"));
+
+    userSession.logIn().addProjectPermission(SCAN, project1);
+    TestResponse response = wsTester.newRequest()
+      .setParam("project", project1.getKey())
+      .setParam("pullRequest", branch.getKey())
+      .setHeader("Accept-Encoding", "gzip")
+      .execute();
+
+    assertThat(compressedInputStreamToString(response.getInputStream())).isEqualTo("test data2");
+  }
+
   @Test
   public void return_not_found_if_project_not_found() {
     TestRequest request = wsTester
@@ -122,6 +141,19 @@ public class GetActionTest {
     assertThatThrownBy(request::execute).isInstanceOf(NotFoundException.class);
   }
 
+  @Test
+  public void return_not_found_if_branch_mixed_with_pr() {
+    ProjectDto project1 = dbTester.components().insertPrivateProjectDto();
+    BranchDto branch = dbTester.components().insertProjectBranch(project1);
+
+    userSession.logIn().addProjectPermission(SCAN, project1);
+    TestRequest request = wsTester.newRequest()
+      .setParam("project", project1.getKey())
+      .setParam("pullRequest", branch.getKey());
+
+    assertThatThrownBy(request::execute).isInstanceOf(NotFoundException.class);
+  }
+
   @Test
   public void return_not_found_if_cache_not_found() {
     ProjectDto project1 = dbTester.components().insertPrivateProjectDto();
index 9cbe24f4eeb307141f85d714d6a011aa22861959..dc5acf17136a0dd99d1763c53bdff8f76bafa467 100644 (file)
@@ -423,12 +423,12 @@ public class SensorContextTester implements SensorContext {
   }
 
   @Override
-  public ReadCache previousAnalysisCache() {
+  public ReadCache previousCache() {
     return readCache;
   }
 
 
-  public void setPreviousAnalysisCache(ReadCache cache) {
+  public void setPreviousCache(ReadCache cache) {
     this.readCache = cache;
   }
 
index 12e42d9b3fff8d9e7e469cd989aed5f709e500b3..99f28cb066b3675c15b57ae7115358ad15249160 100644 (file)
@@ -87,18 +87,18 @@ public class SensorContextTesterTest {
   @Test
   public void testPluginCache() {
     assertThat(tester.nextCache()).isNull();
-    assertThat(tester.previousAnalysisCache()).isNull();
+    assertThat(tester.previousCache()).isNull();
     assertThat(tester.isCacheEnabled()).isFalse();
 
     ReadCache readCache = mock(ReadCache.class);
     WriteCache writeCache = mock(WriteCache.class);
 
-    tester.setPreviousAnalysisCache(readCache);
+    tester.setPreviousCache(readCache);
     tester.setNextCache(writeCache);
     tester.setCacheEnabled(true);
 
     assertThat(tester.nextCache()).isEqualTo(writeCache);
-    assertThat(tester.previousAnalysisCache()).isEqualTo(readCache);
+    assertThat(tester.previousCache()).isEqualTo(readCache);
     assertThat(tester.isCacheEnabled()).isTrue();
   }
 
index da9578d0c981ab26f245460aa2fed4d4b0434428..9f1a282543dd57b6d4c5507841a5e3236f353b0b 100644 (file)
@@ -239,13 +239,13 @@ public interface SensorContext {
    * @since 9.4
    */
   @Beta
-  ReadCache previousAnalysisCache();
+  ReadCache previousCache();
 
   /**
    * Returns true if caching is enabled.
    * This API is experimental and can be changed or dropped at any time.
    * @see #nextCache()
-   * @see #previousAnalysisCache()
+   * @see #previousCache()
    * @since 9.4
    */
   @Beta
index f582e1220795e5e805f2549956cf9d5bcd4f330f..035d3cf00102d5b58a943fc9d3be655bb8c6852d 100644 (file)
@@ -21,10 +21,10 @@ package org.sonar.scanner.cache;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.HttpURLConnection;
 import java.util.Optional;
 import java.util.zip.InflaterInputStream;
 import org.sonar.api.scanner.fs.InputProject;
+import org.sonar.api.utils.MessageException;
 import org.sonar.core.util.Protobuf;
 import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
 import org.sonar.scanner.protocol.internal.ScannerInternal;
@@ -32,6 +32,7 @@ import org.sonar.scanner.protocol.internal.ScannerInternal.AnalysisCacheMsg;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.branch.BranchType;
 import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.HttpException;
 import org.sonarqube.ws.client.WsResponse;
 
 /**
@@ -56,24 +57,26 @@ public class AnalysisCacheLoader {
     String url = URL + "?project=" + project.key();
     if (branchConfiguration.branchType() == BranchType.BRANCH && branchConfiguration.branchName() != null) {
       url = url + "&branch=" + branchConfiguration.branchName();
+    } else if (branchConfiguration.isPullRequest()) {
+      url = url + "&pullRequest=" + branchConfiguration.pullRequestKey();
     }
 
     GetRequest request = new GetRequest(url).setHeader(ACCEPT_ENCODING, "gzip");
 
-    try (WsResponse response = wsClient.call(request)) {
-      if (response.code() == HttpURLConnection.HTTP_NOT_FOUND) {
-        return Optional.empty();
+    try (WsResponse response = wsClient.call(request); InputStream is = response.contentStream()) {
+      Optional<String> contentEncoding = response.header(CONTENT_ENCODING);
+      if (contentEncoding.isPresent() && contentEncoding.get().equals("gzip")) {
+        return Optional.of(decompress(is));
+      } else {
+        return Optional.of(Protobuf.read(is, AnalysisCacheMsg.parser()));
       }
-      try (InputStream is = response.contentStream()) {
-        Optional<String> contentEncoding = response.header(CONTENT_ENCODING);
-        if (contentEncoding.isPresent() && contentEncoding.get().equals("gzip")) {
-          return Optional.of(decompress(is));
-        } else {
-          return Optional.of(Protobuf.read(is, AnalysisCacheMsg.parser()));
-        }
-      } catch (IOException e) {
-        throw new IllegalStateException("Failed to download cache", e);
+    } catch (HttpException e) {
+      if (e.code() == 404) {
+        return Optional.empty();
       }
+      throw MessageException.of("Failed to download analysis cache: " + DefaultScannerWsClient.createErrorMessage(e));
+    } catch (Exception e) {
+      throw new IllegalStateException("Failed to download analysis cache", e);
     }
   }
 
@@ -81,7 +84,7 @@ public class AnalysisCacheLoader {
     try (InflaterInputStream iis = new InflaterInputStream(is)) {
       return Protobuf.read(iis, ScannerInternal.AnalysisCacheMsg.parser());
     } catch (IOException e) {
-      throw new IllegalStateException("Failed to decompress plugin cache", e);
+      throw new IllegalStateException("Failed to decompress analysis cache", e);
     }
   }
 }
index c3cd0ac05216bf2517d816db5aa7fcc1b4269b1d..a4cd85157d67e9d59aabb3c75e9502c8eb097ed7 100644 (file)
@@ -199,7 +199,7 @@ public class ProjectSensorContext implements SensorContext {
   }
 
   @Override
-  public ReadCache previousAnalysisCache() {
+  public ReadCache previousCache() {
     return readCache;
   }
 
index 8ccdcafdb2d143eacc294d5505b1246e8eda3ec6..1c1a04c7e08b24fae2e64228c0db58b2b070979d 100644 (file)
@@ -29,20 +29,29 @@ import java.util.Optional;
 import java.util.zip.DeflaterInputStream;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 import org.sonar.api.scanner.fs.InputProject;
+import org.sonar.api.utils.MessageException;
 import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
-import org.sonar.scanner.protocol.internal.ScannerInternal;
 import org.sonar.scanner.protocol.internal.ScannerInternal.AnalysisCacheMsg;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonarqube.ws.client.HttpException;
+import org.sonarqube.ws.client.WsRequest;
 import org.sonarqube.ws.client.WsResponse;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.sonar.scanner.cache.AnalysisCacheLoader.CONTENT_ENCODING;
 
 public class AnalysisCacheLoaderTest {
+  private final static AnalysisCacheMsg MSG = AnalysisCacheMsg.newBuilder()
+    .putMap("key", ByteString.copyFrom("value", StandardCharsets.UTF_8))
+    .build();
   private final WsResponse response = mock(WsResponse.class);
   private final DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
   private final InputProject project = mock(InputProject.class);
@@ -51,35 +60,75 @@ public class AnalysisCacheLoaderTest {
 
   @Before
   public void before() {
+    when(project.key()).thenReturn("myproject");
     when(wsClient.call(any())).thenReturn(response);
   }
 
   @Test
   public void loads_content() throws IOException {
-    ScannerInternal.AnalysisCacheMsg expected = ScannerInternal.AnalysisCacheMsg.newBuilder()
-      .putMap("key", ByteString.copyFrom("value", StandardCharsets.UTF_8))
-      .build();
-    setResponse(expected);
+    setResponse(MSG);
     AnalysisCacheMsg msg = loader.load().get();
-    assertThat(msg).isEqualTo(expected);
+    assertThat(msg).isEqualTo(MSG);
+    assertRequestPath("api/analysis_cache/get?project=myproject");
+  }
+
+  @Test
+  public void loads_content_for_branch() throws IOException {
+    when(branchConfiguration.branchType()).thenReturn(BranchType.BRANCH);
+    when(branchConfiguration.branchName()).thenReturn("name");
+
+    setResponse(MSG);
+    AnalysisCacheMsg msg = loader.load().get();
+
+    assertThat(msg).isEqualTo(MSG);
+    assertRequestPath("api/analysis_cache/get?project=myproject&branch=name");
+  }
+
+  @Test
+  public void loads_content_for_pr() throws IOException {
+    when(branchConfiguration.isPullRequest()).thenReturn(true);
+    when(branchConfiguration.pullRequestKey()).thenReturn("key");
+    setResponse(MSG);
+    AnalysisCacheMsg msg = loader.load().get();
+    assertThat(msg).isEqualTo(MSG);
+    assertRequestPath("api/analysis_cache/get?project=myproject&pullRequest=key");
   }
 
   @Test
   public void loads_compressed_content() throws IOException {
-    AnalysisCacheMsg expected = AnalysisCacheMsg.newBuilder()
-      .putMap("key", ByteString.copyFrom("value", StandardCharsets.UTF_8))
-      .build();
-    setCompressedResponse(expected);
+    setCompressedResponse(MSG);
     AnalysisCacheMsg msg = loader.load().get();
-    assertThat(msg).isEqualTo(expected);
+    assertThat(msg).isEqualTo(MSG);
   }
 
   @Test
   public void returns_empty_if_404() {
-    when(response.code()).thenReturn(404);
+    when(wsClient.call(any())).thenThrow(new HttpException("url", 404, "content"));
     assertThat(loader.load()).isEmpty();
   }
 
+  @Test
+  public void throw_error_if_http_exception_not_404() {
+    when(wsClient.call(any())).thenThrow(new HttpException("url", 401, "content"));
+    assertThatThrownBy(loader::load)
+      .isInstanceOf(MessageException.class)
+      .hasMessage("Failed to download analysis cache: HTTP code 401: content");
+  }
+
+  @Test
+  public void throw_error_if_cant_decompress_content() {
+    setInvalidCompressedResponse();
+    assertThatThrownBy(loader::load)
+      .isInstanceOf(IllegalStateException.class)
+      .hasMessage("Failed to download analysis cache");
+  }
+
+  private void assertRequestPath(String expectedPath) {
+    ArgumentCaptor<WsRequest> requestCaptor = ArgumentCaptor.forClass(WsRequest.class);
+    verify(wsClient).call(requestCaptor.capture());
+    assertThat(requestCaptor.getValue().getPath()).isEqualTo(expectedPath);
+  }
+
   private void setResponse(AnalysisCacheMsg msg) throws IOException {
     when(response.contentStream()).thenReturn(createInputStream(msg));
   }
@@ -89,6 +138,11 @@ public class AnalysisCacheLoaderTest {
     when(response.header(CONTENT_ENCODING)).thenReturn(Optional.of("gzip"));
   }
 
+  private void setInvalidCompressedResponse() {
+    when(response.contentStream()).thenReturn(new ByteArrayInputStream(new byte[] {1, 2, 3}));
+    when(response.header(CONTENT_ENCODING)).thenReturn(Optional.of("gzip"));
+  }
+
   private InputStream createInputStream(AnalysisCacheMsg analysisCacheMsg) throws IOException {
     ByteArrayOutputStream serialized = new ByteArrayOutputStream(analysisCacheMsg.getSerializedSize());
     analysisCacheMsg.writeTo(serialized);
index 1063283716e554c2e9c0317eca80df773f64a857..d40c7344bee310180d9740620763d886e7693a5b 100644 (file)
@@ -89,7 +89,7 @@ public class ModuleSensorContextTest {
     assertThat(adaptor.canSkipUnchangedFiles()).isFalse();
 
     assertThat(adaptor.nextCache()).isEqualTo(writeCache);
-    assertThat(adaptor.previousAnalysisCache()).isEqualTo(readCache);
+    assertThat(adaptor.previousCache()).isEqualTo(readCache);
 
     assertThat(adaptor.newIssue()).isNotNull();
     assertThat(adaptor.newExternalIssue()).isNotNull();