]> source.dussan.org Git - sonarqube.git/commitdiff
Read line hashes in streaming
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 21 Jan 2015 14:55:01 +0000 (15:55 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 21 Jan 2015 14:55:01 +0000 (15:55 +0100)
server/sonar-server/src/main/java/org/sonar/server/batch/IssuesAction.java
server/sonar-server/src/main/java/org/sonar/server/source/ws/HashAction.java
server/sonar-server/src/main/java/org/sonar/server/user/UserService.java
server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java
server/sonar-server/src/test/java/org/sonar/server/user/UserServiceMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java
server/sonar-server/src/test/resources/org/sonar/server/source/ws/HashActionTest/no_source.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/source/ws/HashActionTest/shared.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/source/db/FileSourceDao.java
sonar-core/src/test/java/org/sonar/core/source/db/FileSourceDaoTest.java

index c65b965ab9c3643d7581760b8a3624e01092bfe8..95b3a3fcca59ee95181dddec5a55932d270b1e25 100644 (file)
@@ -72,13 +72,13 @@ public class IssuesAction implements RequestHandler {
     UserSession.get().checkGlobalPermission(GlobalPermissions.PREVIEW_EXECUTION);
     final String moduleKey = request.mandatoryParam(PARAM_KEY);
 
+    response.stream().setMediaType(MimeTypes.JSON);
     PreviousIssueHelper previousIssueHelper = PreviousIssueHelper.create(new OutputStreamWriter(response.stream().output(), Charsets.UTF_8));
     DbSession session = dbClient.openSession(false);
     try {
       ComponentDto moduleOrProject = dbClient.componentDao().getByKey(session, moduleKey);
       UserSession.get().checkComponentPermission(UserRole.USER, moduleKey);
 
-      response.stream().setMediaType(MimeTypes.JSON);
       BatchIssueResultHandler batchIssueResultHandler = new BatchIssueResultHandler(previousIssueHelper);
       if (moduleOrProject.isRootProject()) {
         dbClient.issueDao().selectNonClosedIssuesByProjectUuid(session, moduleOrProject.uuid(), batchIssueResultHandler);
index b2914709a71cd747a24f149e93146b348158ef8a..7e67fa58f21da9eaccbcbc2ec6552941ac9fc764 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.source.ws;
 
+import com.google.common.base.Function;
+import com.google.common.io.CharStreams;
 import com.google.common.io.Resources;
 import org.apache.commons.io.Charsets;
 import org.sonar.api.server.ws.Request;
@@ -31,7 +33,9 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.user.UserSession;
 
-import java.io.OutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
 
 public class HashAction implements RequestHandler {
 
@@ -59,17 +63,49 @@ public class HashAction implements RequestHandler {
   @Override
   public void handle(Request request, Response response) throws Exception {
     try (DbSession session = dbClient.openSession(false)) {
-      String componentKey = request.mandatoryParam("key");
+      final String componentKey = request.mandatoryParam("key");
       UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, componentKey);
-      ComponentDto component = dbClient.componentDao().getByKey(session, componentKey);
-      String lineHashes = dbClient.fileSourceDao().selectLineHashes(component.uuid(), session);
-      if (lineHashes == null) {
-        response.noContent();
-      } else {
-        try (OutputStream output = response.stream().setMediaType("text/plain").output()) {
-          output.write(lineHashes.getBytes(Charsets.UTF_8));
+      final ComponentDto component = dbClient.componentDao().getByKey(session, componentKey);
+
+      response.stream().setMediaType("text/plain");
+      OutputStreamWriter writer = new OutputStreamWriter(response.stream().output(), Charsets.UTF_8);
+      try {
+        HashFunction hashFunction = new HashFunction(writer, componentKey);
+        dbClient.fileSourceDao().readLineHashesStream(session, component.uuid(), hashFunction);
+        if (!hashFunction.hasData()) {
+          response.noContent();
         }
+      } finally {
+        writer.close();
+      }
+    }
+  }
+
+  private class HashFunction implements Function<Reader, Void> {
+
+    private final OutputStreamWriter writer;
+    private final String componentKey;
+    private boolean hasData = false;
+
+    public HashFunction(OutputStreamWriter writer, String componentKey) {
+      this.writer = writer;
+      this.componentKey = componentKey;
+    }
+
+    @Override
+    public Void apply(Reader input) {
+      try {
+        hasData = true;
+        CharStreams.copy(input, writer);
+      } catch (IOException e) {
+        throw new IllegalStateException(String.format("Can't read line hashes of file '%s'", componentKey));
       }
+      return null;
+    }
+
+    public boolean hasData() {
+      return hasData;
     }
   }
+
 }
index 11ccd0246d0f7ca9802c9a310c7c5260b7e50bfb..e69d8c3e0d25f025b47ed04ef7e084894dbf6dce 100644 (file)
@@ -62,11 +62,6 @@ public class UserService implements ServerComponent {
     return userIndex.getNullableByLogin(login);
   }
 
-  @CheckForNull
-  public UserDoc getNullableByScmAccount(String scmAccount) {
-    return userIndex.getNullableByScmAccount(scmAccount);
-  }
-
   public void index() {
     userIndexer.index();
   }
index 0815c69955899a65ff583700798c30fd75dafde9..d5ab0f666a0f40897521ce587bfed483b326cbcd 100644 (file)
@@ -40,7 +40,6 @@ import org.sonar.core.user.UserGroupDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.Message;
-import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.user.db.UserGroupDao;
 import org.sonar.server.util.Validation;
 
@@ -116,13 +115,9 @@ public class UserUpdater implements ServerComponent {
   public void update(UpdateUser updateUser) {
     DbSession dbSession = dbClient.openSession(false);
     try {
-      UserDto user = dbClient.userDao().selectNullableByLogin(dbSession, updateUser.login());
-      if (user != null) {
-        updateUserDto(dbSession, updateUser, user);
-        updateUser(dbSession, user);
-      } else {
-        throw new NotFoundException(String.format("User '%s' does not exists", updateUser.login()));
-      }
+      UserDto user = dbClient.userDao().selectByLogin(dbSession, updateUser.login());
+      updateUserDto(dbSession, updateUser, user);
+      updateUser(dbSession, user);
       dbSession.commit();
       notifyNewUser(user.getLogin(), user.getName(), user.getEmail());
     } finally {
index a624fcfd7af0e9758285dd3c1e450a1ce1ebc56a..f8471874de032778fb5028e85dbd3411435869fc 100644 (file)
  */
 package org.sonar.server.source.ws;
 
+import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
 import org.sonar.core.source.db.FileSourceDao;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.db.DbClient;
@@ -37,30 +38,27 @@ import org.sonar.server.ws.WsTester;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class HashActionTest {
 
-  @Mock
-  DbClient dbClient;
+  final static String COMPONENT_KEY = "Action.java";
+  final static String PROJECT_KEY = "struts";
 
-  @Mock
-  ComponentDao componentDao;
+  @Rule
+  public DbTester db = new DbTester();
 
-  @Mock
-  FileSourceDao fileSourceDao;
+  DbSession session;
 
   WsTester tester;
 
   @Before
-  public void setUp() throws Exception {
-    when(dbClient.componentDao()).thenReturn(componentDao);
-    when(dbClient.fileSourceDao()).thenReturn(fileSourceDao);
-    when(dbClient.openSession(false)).thenReturn(mock(DbSession.class));
+  public void before() throws Exception {
+    this.session = db.myBatis().openSession(false);
+
+    DbClient dbClient = new DbClient(db.database(), db.myBatis(), new FileSourceDao(db.myBatis()), new ComponentDao());
+
     tester = new WsTester(
       new SourcesWs(
         mock(ShowAction.class),
@@ -73,39 +71,34 @@ public class HashActionTest {
       );
   }
 
+  @After
+  public void after() {
+    this.session.close();
+  }
+
   @Test
   public void show_hashes() throws Exception {
-    String componentKey = "project:src/File.xoo";
-    String uuid = "polop";
-    ComponentDto component = new ComponentDto().setUuid(uuid);
-    String hashes = "polop\n"
-      + "\n"
-      + "pilip";
-    MockUserSession.set().setLogin("polop").addComponentPermission(UserRole.CODEVIEWER, "palap", componentKey);
-    when(componentDao.getByKey(any(DbSession.class), eq(componentKey))).thenReturn(component);
-    when(fileSourceDao.selectLineHashes(eq(uuid), any(DbSession.class))).thenReturn(hashes);
-    WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", componentKey);
-    assertThat(request.execute().outputAsString()).isEqualTo(hashes);
+    db.prepareDbUnit(getClass(), "shared.xml");
+    MockUserSession.set().setLogin("polop").addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", COMPONENT_KEY);
+    assertThat(request.execute().outputAsString()).isEqualTo("987654");
   }
 
   @Test
   public void hashes_empty_if_no_source() throws Exception {
-    String componentKey = "project:src/File.xoo";
-    String uuid = "polop";
-    ComponentDto component = new ComponentDto().setUuid(uuid);
-    MockUserSession.set().setLogin("polop").addComponentPermission(UserRole.CODEVIEWER, "palap", componentKey);
-    when(componentDao.getByKey(any(DbSession.class), eq(componentKey))).thenReturn(component);
-    WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", componentKey);
+    db.prepareDbUnit(getClass(), "no_source.xml");
+    MockUserSession.set().setLogin("polop").addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_KEY);
+
+    WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", COMPONENT_KEY);
     request.execute().assertNoContent();
   }
 
   @Test
   public void fail_to_show_hashes_if_file_does_not_exist() throws Exception {
-    String componentKey = "project:src/File.xoo";
-    MockUserSession.set().setLogin("polop").addComponentPermission(UserRole.CODEVIEWER, "palap", componentKey);
-    when(componentDao.getByKey(any(DbSession.class), eq(componentKey))).thenThrow(NotFoundException.class);
+    MockUserSession.set().setLogin("polop").addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_KEY);
     try {
-      WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", componentKey);
+      WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", COMPONENT_KEY);
       request.execute();
       fail();
     } catch (Exception e) {
@@ -115,11 +108,9 @@ public class HashActionTest {
 
   @Test(expected = ForbiddenException.class)
   public void fail_on_missing_permission() throws Exception {
-    String componentKey = "project:src/File.xoo";
-    String uuid = "polop";
-    ComponentDto component = new ComponentDto().setUuid(uuid);
+    db.prepareDbUnit(getClass(), "shared.xml");
+
     MockUserSession.set().setLogin("polop");
-    when(componentDao.getByKey(any(DbSession.class), eq(componentKey))).thenReturn(component);
-    tester.newGetRequest("api/sources", "hash").setParam("key", componentKey).execute();
+    tester.newGetRequest("api/sources", "hash").setParam("key", COMPONENT_KEY).execute();
   }
 }
index 58b84c8ef386aa009f6131833253b4759b6f13c6..f33f226b4548075f0cba7abb3d49afa4b2138eee 100644 (file)
@@ -167,13 +167,6 @@ public class UserServiceMediumTest {
     assertThat(service.getByLogin("user")).isNotNull();
   }
 
-  @Test
-  public void get_nullable_by_scm_account() throws Exception {
-    createSampleUser();
-
-    assertThat(service.getNullableByScmAccount("u1")).isNotNull();
-  }
-
   @Test
   public void index() throws Exception {
     UserDto userDto = new UserDto().setLogin("user").setEmail("user@mail.com").setCreatedAt(System.currentTimeMillis()).setUpdatedAt(System.currentTimeMillis());
index f58774250c162c2057f73105529740792a43a59d..3121e0133c657e154bebf7b1c98e019daec54ac0 100644 (file)
@@ -44,7 +44,6 @@ import org.sonar.core.user.UserDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.Message;
-import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.user.db.GroupDao;
 import org.sonar.server.user.db.UserDao;
 import org.sonar.server.user.db.UserGroupDao;
@@ -743,21 +742,6 @@ public class UserUpdaterTest {
     assertThat(membership.groups().get(0).isMember()).isTrue();
   }
 
-  @Test
-  public void fail_to_update_unknown_user() throws Exception {
-    try {
-      userUpdater.update(UpdateUser.create("marius")
-        .setName("Marius2")
-        .setEmail("marius2@mail.com")
-        .setPassword("password2")
-        .setPasswordConfirmation("password2")
-        .setScmAccounts(newArrayList("ma2")));
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("User 'marius' does not exists");
-    }
-  }
-
   @Test
   public void fail_to_update_user_when_scm_account_is_already_used() throws Exception {
     db.prepareDbUnit(getClass(), "fail_to_update_user_when_scm_account_is_already_used.xml");
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/HashActionTest/no_source.xml b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/HashActionTest/no_source.xml
new file mode 100644 (file)
index 0000000..1b668bf
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <projects id="100" kee="struts" root_id="[null]" qualifier="TRK" scope="PRJ" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="." path="[null]"/>
+  <projects id="101" kee="Action.java" root_id="100" qualifier="CLA" scope="PRJ" uuid="CDEF" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD."
+            path="src/main/java/Action.java"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/HashActionTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/HashActionTest/shared.xml
new file mode 100644 (file)
index 0000000..756dbac
--- /dev/null
@@ -0,0 +1,13 @@
+<dataset>
+
+  <projects id="100" kee="struts" root_id="[null]" qualifier="TRK" scope="PRJ" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="." path="[null]"/>
+  <projects id="101" kee="Action.java" root_id="100" qualifier="CLA" scope="PRJ" uuid="CDEF" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD."
+            path="src/main/java/Action.java"/>
+
+  <file_sources id="101" project_uuid="ABCD" file_uuid="CDEF"
+                data="aef12a,alice,2014-04-25T12:34:56+0100,,class Foo" data_hash="hash"
+                line_hashes="987654"
+                src_hash="12345"
+                created_at="1414597442000" updated_at="1414683842000"/>
+
+</dataset>
index 731a4ccd80f4c9d11990a12b056adb6ac6634a43..c0a75f7a4122fa7cffc1054ee58c8bb79de7ef22 100644 (file)
@@ -58,27 +58,17 @@ public class FileSourceDao implements BatchComponent, ServerComponent, DaoCompon
 
   public <T> void readDataStream(String fileUuid, Function<Reader, T> function) {
     DbSession dbSession = mybatis.openSession(false);
-    Connection connection = dbSession.getConnection();
-    PreparedStatement pstmt = null;
-    ResultSet rs = null;
-    Reader reader = null;
     try {
-      pstmt = connection.prepareStatement("select data from file_sources where file_uuid = ?");
-      pstmt.setString(1, fileUuid);
-      rs = pstmt.executeQuery();
-      if (rs.next()) {
-        reader = rs.getCharacterStream(1);
-        function.apply(reader);
-      }
-    } catch (SQLException e) {
-      throw new IllegalStateException("Fail to read FILE_SOURCES.DATA of file " + fileUuid, e);
+      readColumnStream(dbSession, fileUuid, function, "data");
     } finally {
-      IOUtils.closeQuietly(reader);
-      DbUtils.closeQuietly(connection, pstmt, rs);
       MyBatis.closeQuietly(dbSession);
     }
   }
 
+  public <T> void readLineHashesStream(DbSession dbSession, String fileUuid, Function<Reader, T> function) {
+    readColumnStream(dbSession, fileUuid, function, "line_hashes");
+  }
+
   public void insert(FileSourceDto dto) {
     DbSession session = mybatis.openSession(false);
     try {
@@ -99,8 +89,24 @@ public class FileSourceDao implements BatchComponent, ServerComponent, DaoCompon
     }
   }
 
-  @CheckForNull
-  public String selectLineHashes(String fileUuid, DbSession session) {
-    return session.getMapper(FileSourceMapper.class).selectLineHashes(fileUuid);
+  private <T> void readColumnStream(DbSession dbSession, String fileUuid, Function<Reader, T> function, String column) {
+    Connection connection = dbSession.getConnection();
+    PreparedStatement pstmt = null;
+    ResultSet rs = null;
+    Reader reader = null;
+    try {
+      pstmt = connection.prepareStatement("SELECT " + column + " FROM file_sources WHERE file_uuid = ?");
+      pstmt.setString(1, fileUuid);
+      rs = pstmt.executeQuery();
+      if (rs.next()) {
+        reader = rs.getCharacterStream(1);
+        function.apply(reader);
+      }
+    } catch (SQLException e) {
+      throw new IllegalStateException("Fail to read FILE_SOURCES." + column.toUpperCase() + " of file " + fileUuid, e);
+    } finally {
+      IOUtils.closeQuietly(reader);
+      DbUtils.closeQuietly(connection, pstmt, rs);
+    }
   }
 }
index 22bf2b89910631542d5abad27b6bffa8795b79ce..dc8dc262db2c2dfaedb2333b8a2a9c409c8a7639 100644 (file)
 
 package org.sonar.core.source.db;
 
+import com.google.common.base.Function;
+import org.apache.commons.io.IOUtils;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
 
+import java.io.IOException;
+import java.io.Reader;
 import java.util.Date;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class FileSourceDaoTest extends AbstractDaoTestCase {
 
-  private FileSourceDao dao;
+  DbSession session;
+
+  FileSourceDao dao;
 
   @Before
   public void setUpTestData() {
+    session = getMyBatis().openSession(false);
     dao = new FileSourceDao(getMyBatis());
-    setupData("shared");
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    session.close();
   }
 
   @Test
   public void select() throws Exception {
+    setupData("shared");
+
     FileSourceDto fileSourceDto = dao.select("ab12");
 
     assertThat(fileSourceDto.getData()).isEqualTo("aef12a,alice,2014-04-25T12:34:56+0100,,class Foo");
@@ -53,20 +67,39 @@ public class FileSourceDaoTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void selectLineHashes() throws Exception {
-    DbSession session = getMyBatis().openSession(false);
-    String lineHashes = null;
-    try {
-      lineHashes = dao.selectLineHashes("ab12", session);
-    } finally {
-      session.close();
-    }
+  public void select_data() throws Exception {
+    setupData("shared");
+
+    StringParser stringParser = new StringParser();
+    dao.readDataStream("ab12", stringParser);
+
+    assertThat(stringParser.getResult()).isEqualTo("aef12a,alice,2014-04-25T12:34:56+0100,,class Foo");
+  }
+
+  @Test
+  public void select_line_hashes() throws Exception {
+    setupData("shared");
+
+    StringParser stringParser = new StringParser();
+    dao.readLineHashesStream(session, "ab12", stringParser);
+
+    assertThat(stringParser.getResult()).isEqualTo("truc");
+  }
+
+  @Test
+  public void no_line_hashes_on_unknown_file() throws Exception {
+    setupData("shared");
 
-    assertThat(lineHashes).isEqualTo("truc");
+    StringParser stringParser = new StringParser();
+    dao.readLineHashesStream(session, "unknown", stringParser);
+
+    assertThat(stringParser.getResult()).isEmpty();
   }
 
   @Test
   public void insert() throws Exception {
+    setupData("shared");
+
     dao.insert(new FileSourceDto().setProjectUuid("prj").setFileUuid("file").setData("bla bla")
       .setDataHash("hash2")
       .setLineHashes("foo\nbar")
@@ -79,6 +112,8 @@ public class FileSourceDaoTest extends AbstractDaoTestCase {
 
   @Test
   public void update() throws Exception {
+    setupData("shared");
+
     dao.update(new FileSourceDto().setId(101L).setProjectUuid("prj").setFileUuid("file")
       .setData("updated data")
       .setDataHash("hash2")
@@ -88,4 +123,23 @@ public class FileSourceDaoTest extends AbstractDaoTestCase {
 
     checkTable("update", "file_sources");
   }
+
+  class StringParser implements Function<Reader, String> {
+
+    String result = "";
+
+    @Override
+    public String apply(Reader input) {
+      try {
+        result = IOUtils.toString(input);
+        return IOUtils.toString(input);
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    public String getResult() {
+      return result;
+    }
+  }
 }