]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5590 Update projects.authorization_updated_at on project permission changes
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 4 Sep 2014 15:56:17 +0000 (17:56 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 4 Sep 2014 15:56:17 +0000 (17:56 +0200)
28 files changed:
server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/MeasureFilterExecutorTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java
sonar-core/src/main/java/org/sonar/core/permission/PermissionFacade.java
sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
sonar-core/src/main/java/org/sonar/core/resource/ResourceDto.java
sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java
sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml
sonar-core/src/test/java/org/sonar/core/permission/PermissionFacadeTest.java
sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java
sonar-core/src/test/java/org/sonar/core/resource/DefaultResourcePermissionsTest.java
sonar-core/src/test/java/org/sonar/core/resource/ResourceDaoTest.java
sonar-core/src/test/java/org/sonar/core/user/AuthorDaoTest.java
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_add_user_permission-result.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_add_user_permission.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_apply_permission_template.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_delete_group_permission-result.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_delete_group_permission.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_delete_user_permission-result.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_delete_user_permission.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_insert_anyone_group_permission-result.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_insert_anyone_group_permission.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_insert_group_permission-result.xml
sonar-core/src/test/resources/org/sonar/core/permission/PermissionFacadeTest/should_insert_group_permission.xml
sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/fixture.xml
sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/insert-result.xml
sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/update_authorization_date-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/update_authorization_date.xml [new file with mode: 0644]

index 03978792abd63fdc69aa7f4dbc578dfd63f69ebd..374d515ff287bf9db5b091cdf5543fdd85e00aa6 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.utils.System2;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.resource.ResourceDao;
 
@@ -40,7 +41,7 @@ public class ServerIssueStorageTest extends AbstractDaoTestCase {
   public void load_component_id_from_db() throws Exception {
     setupData("load_component_id_from_db");
 
-    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
     long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
 
     assertThat(componentId).isEqualTo(123);
@@ -50,7 +51,7 @@ public class ServerIssueStorageTest extends AbstractDaoTestCase {
   public void fail_to_load_component_id_if_unknown_component() throws Exception {
     setupData("empty");
 
-    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
     try {
       storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
       fail();
@@ -63,7 +64,7 @@ public class ServerIssueStorageTest extends AbstractDaoTestCase {
   public void load_project_id_from_db() throws Exception {
     setupData("load_project_id_from_db");
 
-    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
     long projectId = storage.projectId(new DefaultIssue().setProjectKey("struts"));
 
     assertThat(projectId).isEqualTo(1);
@@ -73,7 +74,7 @@ public class ServerIssueStorageTest extends AbstractDaoTestCase {
   public void fail_to_load_project_id_if_unknown_component() throws Exception {
     setupData("empty");
 
-    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+    ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
     try {
       storage.projectId(new DefaultIssue().setProjectKey("struts"));
       fail();
index 8edc2aa6b5ae926583f217889bdc29ed1a8060e1..527b782b6ce07041bbf6c5617846efbe7d9009c3 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Test;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
 import org.sonar.core.persistence.TestDatabase;
 import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.resource.SnapshotDto;
@@ -59,7 +60,7 @@ public class MeasureFilterExecutorTest {
 
   @Before
   public void before() {
-    executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis()));
+    executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis(), System2.INSTANCE));
   }
 
   @Test
index 8866851b3da2cea818fa6678ca53cd53b9ffc0b0..1d0144ce4eeb22374d575fb6dd286905453956ec 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.utils.System2;
 import org.sonar.batch.ProjectTree;
 import org.sonar.batch.index.SnapshotCache;
 import org.sonar.core.persistence.AbstractDaoTestCase;
@@ -55,7 +56,7 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
 
   @Before
   public void setUp() throws Exception {
-    storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()), projectTree);
+    storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis(), System2.INSTANCE), projectTree);
   }
 
   @Test
index 9c2f39c4fcf6738a91c4d1aba45bdca11ddf8097..f8956373d004f4ce533514012e38bf48d201ded0 100644 (file)
@@ -30,11 +30,7 @@ import org.sonar.api.task.TaskComponent;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.user.GroupDto;
-import org.sonar.core.user.GroupRoleDto;
-import org.sonar.core.user.RoleDao;
-import org.sonar.core.user.UserDao;
-import org.sonar.core.user.UserRoleDto;
+import org.sonar.core.user.*;
 
 import javax.annotation.Nullable;
 
@@ -68,11 +64,14 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     this.settings = settings;
   }
 
-  public void insertUserPermission(@Nullable Long resourceId, Long userId, String permission, @Nullable SqlSession session) {
+  private void insertUserPermission(@Nullable Long resourceId, Long userId, String permission, boolean updateProjectAuthorizationDate, @Nullable SqlSession session) {
     UserRoleDto userRoleDto = new UserRoleDto()
       .setRole(permission)
       .setUserId(userId)
       .setResourceId(resourceId);
+    if (updateProjectAuthorizationDate) {
+      updateProjectAuthorizationDate(resourceId, session);
+    }
     if (session != null) {
       roleDao.insertUserRole(userRoleDto, session);
     } else {
@@ -80,6 +79,10 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     }
   }
 
+  public void insertUserPermission(@Nullable Long resourceId, Long userId, String permission, @Nullable SqlSession session) {
+    insertUserPermission(resourceId, userId, permission, true, session);
+  }
+
   public void insertUserPermission(@Nullable Long resourceId, Long userId, String permission) {
     insertUserPermission(resourceId, userId, permission, null);
   }
@@ -89,6 +92,7 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
       .setRole(permission)
       .setUserId(userId)
       .setResourceId(resourceId);
+    updateProjectAuthorizationDate(resourceId, session);
     if (session != null) {
       roleDao.deleteUserRole(userRoleDto, session);
     } else {
@@ -100,11 +104,12 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     deleteUserPermission(resourceId, userId, permission, null);
   }
 
-  public void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission, @Nullable SqlSession session) {
+  private void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission, boolean updateProjectAuthorizationDate, @Nullable SqlSession session) {
     GroupRoleDto groupRole = new GroupRoleDto()
       .setRole(permission)
       .setGroupId(groupId)
       .setResourceId(resourceId);
+    updateProjectAuthorizationDate(resourceId, session);
     if (session != null) {
       roleDao.insertGroupRole(groupRole, session);
     } else {
@@ -112,6 +117,10 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     }
   }
 
+  private void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission, @Nullable SqlSession session) {
+    insertGroupPermission(resourceId, groupId, permission, true, session);
+  }
+
   public void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission) {
     insertGroupPermission(resourceId, groupId, permission, null);
   }
@@ -132,6 +141,7 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
       .setRole(permission)
       .setGroupId(groupId)
       .setResourceId(resourceId);
+    updateProjectAuthorizationDate(resourceId, session);
     if (session != null) {
       roleDao.deleteGroupRole(groupRole, session);
     } else {
@@ -154,6 +164,19 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     }
   }
 
+  /**
+   * For each modification of permission on a project, update the authorization_updated_at to help ES reindex only relevant changes
+   */
+  private void updateProjectAuthorizationDate(@Nullable Long projectId, @Nullable SqlSession session){
+    if (projectId != null) {
+      if (session != null) {
+        resourceDao.updateAuthorizationDate(projectId, session);
+      } else {
+        resourceDao.updateAuthorizationDate(projectId);
+      }
+    }
+  }
+
   /**
    * Load permission template and load associated collections of users and groups permissions
    */
@@ -174,18 +197,19 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     PermissionTemplateDto permissionTemplate = getPermissionTemplateWithPermissions(templateKey);
     SqlSession session = myBatis.openSession(false);
     try {
+      updateProjectAuthorizationDate(resourceId, session);
       removeAllPermissions(resourceId, session);
       List<PermissionTemplateUserDto> usersPermissions = permissionTemplate.getUsersPermissions();
       if (usersPermissions != null) {
         for (PermissionTemplateUserDto userPermission : usersPermissions) {
-          insertUserPermission(resourceId, userPermission.getUserId(), userPermission.getPermission(), session);
+          insertUserPermission(resourceId, userPermission.getUserId(), userPermission.getPermission(), false, session);
         }
       }
       List<PermissionTemplateGroupDto> groupsPermissions = permissionTemplate.getGroupsPermissions();
       if (groupsPermissions != null) {
         for (PermissionTemplateGroupDto groupPermission : groupsPermissions) {
           Long groupId = groupPermission.getGroupId() == null ? null : groupPermission.getGroupId();
-          insertGroupPermission(resourceId, groupId, groupPermission.getPermission(), session);
+          insertGroupPermission(resourceId, groupId, groupPermission.getPermission(), false, session);
         }
       }
       session.commit();
@@ -198,7 +222,7 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     return roleDao.countResourceGroupRoles(resourceId) + roleDao.countResourceUserRoles(resourceId);
   }
 
-  public void removeAllPermissions(Long resourceId, SqlSession session) {
+  protected void removeAllPermissions(Long resourceId, SqlSession session) {
     roleDao.deleteGroupRolesByResourceId(resourceId, session);
     roleDao.deleteUserRolesByResourceId(resourceId, session);
   }
index 94b54f042b65266c13b2898a113d6582d9960c17..901bf3a15070f789238e0ba879e4b95a2a0e4adf 100644 (file)
@@ -24,6 +24,7 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.component.Component;
+import org.sonar.api.utils.System2;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
@@ -41,9 +42,11 @@ import static com.google.common.collect.Lists.newArrayList;
 
 public class ResourceDao implements DaoComponent {
   private MyBatis mybatis;
+  private System2 system2;
 
-  public ResourceDao(MyBatis mybatis) {
+  public ResourceDao(MyBatis mybatis, System2 system2) {
     this.mybatis = mybatis;
+    this.system2 = system2;
   }
 
   public List<ResourceDto> getResources(ResourceQuery query) {
@@ -141,10 +144,12 @@ public class ResourceDao implements DaoComponent {
   public ResourceDao insertOrUpdate(ResourceDto... resources) {
     SqlSession session = mybatis.openSession(false);
     ResourceMapper mapper = session.getMapper(ResourceMapper.class);
+    Date now = new Date(system2.now());
     try {
       for (ResourceDto resource : resources) {
         if (resource.getId() == null) {
-          resource.setCreatedAt(new Date());
+          resource.setCreatedAt(now);
+          resource.setAuthorizationUpdatedAt(now);
           mapper.insert(resource);
         } else {
           mapper.update(resource);
@@ -157,6 +162,23 @@ public class ResourceDao implements DaoComponent {
     return this;
   }
 
+  public void updateAuthorizationDate(Long projectId, SqlSession session) {
+    session.getMapper(ResourceMapper.class).updateAuthorizationDate(projectId, new Date(system2.now()));
+  }
+
+  /**
+   * Should not be called from batch side (used to reindex permission in E/S)
+   */
+  public void updateAuthorizationDate(Long projectId) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      updateAuthorizationDate(projectId, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
   public Collection<ComponentDto> selectComponentsByIds(Collection<Long> ids) {
     if (ids.isEmpty()) {
       return Collections.emptyList();
index 93dff81318e91018367c182bde66fcda60d16ab5..5cdcf247ced905245a43cfc0fb675ded578f835c 100644 (file)
@@ -38,6 +38,7 @@ public class ResourceDto {
   private Long copyResourceId;
   private Long personId;
   private Date createdAt;
+  private Date authorizationUpdatedAt;
 
   public Long getId() {
     return id;
@@ -173,4 +174,13 @@ public class ResourceDto {
     this.createdAt = date;// NOSONAR May expose internal representation by incorporating reference to mutable object
     return this;
   }
+
+  public Date getAuthorizationUpdatedAt() {
+    return authorizationUpdatedAt;
+  }
+
+  public ResourceDto setAuthorizationUpdatedAt(Date authorizationUpdatedAt) {
+    this.authorizationUpdatedAt = authorizationUpdatedAt;
+    return this;
+  }
 }
index f40caa1a42649666e545ec2a78b02e4b6445cfd4..259a1228b6765dd90e2ca4f945ab4a7324e6e954 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.core.component.ComponentDto;
 import javax.annotation.Nullable;
 
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 
 public interface ResourceMapper {
@@ -86,4 +87,6 @@ public interface ResourceMapper {
 
   void update(ResourceDto resource);
 
+  void updateAuthorizationDate(@Param("projectId") Long projectId, @Param("authorizationDate") Date authorizationDate);
+
 }
index f32095b71dab393bf907140bebe594251c806add..d7cf97970f61a4f5900072353c92badaa28dd87b 100644 (file)
@@ -18,7 +18,8 @@
     p.language as language,
     p.copy_resource_id as copyResourceId,
     p.person_id as personId,
-    p.created_at as createdAt
+    p.created_at as createdAt,
+    p.authorization_updated_at as authorizationUpdatedAt
   </sql>
 
   <sql id="componentColumns">
@@ -81,6 +82,7 @@
     <result property="copyResourceId" column="copy_resource_id"/>
     <result property="personId" column="person_id"/>
     <result property="createdAt" column="created_at"/>
+    <result property="authorizationUpdatedAt" column="authorization_updated_at"/>
   </resultMap>
 
   <select id="selectResources" parameterType="map" resultMap="resourceResultMap">
 
   <insert id="insert" parameterType="Resource" keyColumn="id" useGeneratedKeys="true" keyProperty="id" >
     insert into projects
-    (name, long_name, description, scope, qualifier, kee, deprecated_kee, path, language, root_id, copy_resource_id, person_id, enabled, created_at)
+    (name, long_name, description, scope, qualifier, kee, deprecated_kee, path, language, root_id, copy_resource_id, person_id, enabled, authorization_updated_at, created_at)
     values (
     #{name}, #{longName}, #{description}, #{scope}, #{qualifier},
     #{key}, #{deprecatedKey}, #{path}, #{language}, #{rootId}, #{copyResourceId},
-    #{personId}, #{enabled}, #{createdAt}
+    #{personId}, #{enabled}, #{authorizationUpdatedAt}, #{createdAt}
     )
   </insert>
 
     language=#{language}, root_id=#{rootId}, copy_resource_id=#{copyResourceId},
     person_id=#{personId}, enabled=#{enabled} where id=#{id}
   </update>
+
+  <update id="updateAuthorizationDate" parameterType="map">
+    update projects set authorization_updated_at=#{authorizationDate}
+    <where>
+      AND id=#{projectId}
+    </where>
+  </update>
+
 </mapper>
 
index 9b1596d7d55a9395dd1850e518474bc5b20e7861..2d6149002b7a7fe7656ec90f02343fc675c6df7e 100644 (file)
@@ -26,6 +26,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.Settings;
+import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.persistence.AbstractDaoTestCase;
@@ -43,16 +44,22 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
   @Rule
   public ExpectedException throwable = ExpectedException.none();
 
+  private System2 system2;
   private PermissionFacade permissionFacade;
   private PermissionTemplateDao permissionTemplateDao;
+  private ResourceDao resourceDao;
 
   @Before
   public void setUp() {
+    system2 = mock(System2.class);
+    when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
+
     RoleDao roleDao = new RoleDao(getMyBatis());
     UserDao userDao = new UserDao(getMyBatis());
     permissionTemplateDao = new PermissionTemplateDao(getMyBatis(), System2.INSTANCE);
     Settings settings = new Settings();
-    permissionFacade = new PermissionFacade(getMyBatis(), roleDao, userDao, new ResourceDao(getMyBatis()), permissionTemplateDao, settings);
+    resourceDao = new ResourceDao(getMyBatis(), system2);
+    permissionFacade = new PermissionFacade(getMyBatis(), roleDao, userDao, resourceDao, permissionTemplateDao, settings);
   }
 
   @Test
@@ -71,6 +78,8 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     assertThat(permissionFacade.selectGroupPermissions("Anyone", 123L)).containsOnly("user", "codeviewer");
 
     assertThat(permissionFacade.selectUserPermissions("marius", 123L)).containsOnly("admin");
+
+    assertThat(resourceDao.getResource(123L).getAuthorizationUpdatedAt()).isEqualTo(DateUtils.parseDate("2014-09-03"));
   }
 
   @Test
@@ -87,6 +96,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     permissionFacade.insertUserPermission(123L, 200L, UserRole.ADMIN);
 
     checkTable("should_add_user_permission", "user_roles", "user_id", "resource_id", "role");
+    checkTable("should_add_user_permission", "projects", "authorization_updated_at");
   }
 
   @Test
@@ -96,6 +106,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     permissionFacade.deleteUserPermission(123L, 200L, UserRole.ADMIN);
 
     checkTable("should_delete_user_permission", "user_roles", "user_id", "resource_id", "role");
+    checkTable("should_delete_user_permission", "projects", "authorization_updated_at");
   }
 
   @Test
@@ -111,6 +122,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     }
 
     checkTable("should_insert_group_permission", "group_roles", "group_id", "resource_id", "role");
+    checkTable("should_insert_group_permission", "projects", "authorization_updated_at");
   }
 
   @Test
@@ -126,6 +138,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     }
 
     checkTable("should_insert_group_permission", "group_roles", "group_id", "resource_id", "role");
+    checkTable("should_insert_group_permission", "projects", "authorization_updated_at");
   }
 
   @Test
@@ -141,6 +154,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     }
 
     checkTable("should_insert_anyone_group_permission", "group_roles", "group_id", "resource_id", "role");
+    checkTable("should_insert_anyone_group_permission", "projects", "authorization_updated_at");
   }
 
   @Test
@@ -150,6 +164,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     permissionFacade.deleteGroupPermission(123L, 100L, UserRole.USER);
 
     checkTable("should_delete_group_permission", "group_roles", "group_id", "resource_id", "role");
+    checkTable("should_delete_group_permission", "projects", "authorization_updated_at");
   }
 
   @Test
@@ -165,6 +180,7 @@ public class PermissionFacadeTest extends AbstractDaoTestCase {
     }
 
     checkTable("should_delete_group_permission", "group_roles", "group_id", "resource_id", "role");
+    checkTable("should_delete_group_permission", "projects", "authorization_updated_at");
   }
 
   @Test
index fa19f41100a358cbe58549b3b1759824ddc5fdb3..ec86b0a4121fb9c1f99e8997ae342e165758ceff 100644 (file)
@@ -44,7 +44,7 @@ public class PurgeDaoTest extends AbstractDaoTestCase {
     system2 = mock(System2.class);
     when(system2.now()).thenReturn(DateUtils.parseDate("2014-04-09").getTime());
 
-    dao = new PurgeDao(getMyBatis(), new ResourceDao(getMyBatis()), new PurgeProfiler());
+    dao = new PurgeDao(getMyBatis(), new ResourceDao(getMyBatis(), system2), new PurgeProfiler());
   }
 
   @Test
index eb0cb230752be82f495c53a99170a45ffbbb6526..d1aed3aee66e1d46f47f1c91244123b13ff19750 100644 (file)
@@ -53,7 +53,7 @@ public class DefaultResourcePermissionsTest extends AbstractDaoTestCase {
     project = new Project("project").setId(PROJECT_ID.intValue());
     settings = new Settings();
     permissionFacade = new PermissionFacade(getMyBatis(),
-      new RoleDao(getMyBatis()), new UserDao(getMyBatis()), new ResourceDao(getMyBatis()), new PermissionTemplateDao(getMyBatis(), System2.INSTANCE), settings);
+      new RoleDao(getMyBatis()), new UserDao(getMyBatis()), new ResourceDao(getMyBatis(), System2.INSTANCE), new PermissionTemplateDao(getMyBatis(), System2.INSTANCE), settings);
     permissions = new DefaultResourcePermissions(getMyBatis(), permissionFacade);
   }
 
index 756136fd3800fa998b225a7e3c10260f9a4842c5..95b36b80ff3153037c66f80104f6616239087ff4 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.api.component.Component;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
@@ -41,17 +42,22 @@ import java.util.List;
 
 import static com.google.common.collect.Lists.newArrayList;
 import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class ResourceDaoTest extends AbstractDaoTestCase {
 
   private DbSession session;
 
   private ResourceDao dao;
+  private System2 system2;
 
   @Before
   public void createDao() {
     session = getMyBatis().openSession(false);
-    dao = new ResourceDao(getMyBatis());
+    system2 = mock(System2.class);
+    when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
+    dao = new ResourceDao(getMyBatis(), system2);
   }
 
   @After
@@ -90,6 +96,8 @@ public class ResourceDaoTest extends AbstractDaoTestCase {
     assertThat(resource.getDescription()).isEqualTo("the description");
     assertThat(resource.getLanguage()).isEqualTo("java");
     assertThat(resource.isEnabled()).isTrue();
+    assertThat(resource.getAuthorizationUpdatedAt()).isNotNull();
+    assertThat(resource.getCreatedAt()).isNotNull();
   }
 
   @Test
@@ -298,11 +306,12 @@ public class ResourceDaoTest extends AbstractDaoTestCase {
 
     assertThat(file1.getId()).isNotNull();
     assertThat(file2.getId()).isNotNull();
-    checkTables("insert", new String[] {"created_at"}, "projects");
+    checkTables("insert", "projects");
 
     // SONAR-3636 : created_at must be fed when inserting a new entry in the 'projects' table
     ResourceDto fileLoadedFromDB = dao.getResource(file1.getId());
     assertThat(fileLoadedFromDB.getCreatedAt()).isNotNull();
+    assertThat(fileLoadedFromDB.getAuthorizationUpdatedAt()).isNotNull();
   }
 
   @Test
@@ -480,6 +489,16 @@ public class ResourceDaoTest extends AbstractDaoTestCase {
     assertThat(dao.getLastSnapshotByResourceId(42L, session)).isNull();
   }
 
+  @Test
+  public void update_authorization_date() {
+    setupData("update_authorization_date");
+
+    when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
+    dao.updateAuthorizationDate(1L);
+
+    checkTables("update_authorization_date", "projects");
+  }
+
   private List<String> getKeys(final List<Component> components) {
     return newArrayList(Iterables.transform(components, new Function<Component, String>() {
       @Override
index 03192a96181ab461fc62b20b18857d26e1c2a4fa..3e6dfcb9437fc9bfd3c0f31baf86555180f766ce 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.core.user;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.utils.System2;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.resource.ResourceDto;
@@ -34,7 +35,7 @@ public class AuthorDaoTest extends AbstractDaoTestCase {
 
   @Before
   public void setUp() {
-    dao = new AuthorDao(getMyBatis(), new ResourceDao(getMyBatis()));
+    dao = new AuthorDao(getMyBatis(), new ResourceDao(getMyBatis(), System2.INSTANCE));
   }
 
   @Test
index f3749db4f0c9d30453f623c64b8351015d2476c2..e3bec368812381343a3c30e219ad6d47a5583f70 100644 (file)
@@ -5,4 +5,8 @@
   <user_roles id="1" user_id="200" resource_id="123" role="user"/>
   <user_roles id="2" user_id="200" resource_id="123" role="admin"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="100" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
index 000c018550bcde53048c98f9a46ee7ba8610a9d2..48f61b2505a327112ab1097bb32fd00a36a60506 100644 (file)
@@ -4,4 +4,8 @@
 
   <user_roles id="1" user_id="200" resource_id="123" role="user"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2010-01-01"/>
+
+</dataset>
index 6c0f5c018480539d3ed0791d660a8596d0713b23..8c761b5daaa53a9d913cf6acb6d64e82596541aa 100644 (file)
@@ -1,5 +1,9 @@
 <dataset>
 
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2010-01-01"/>
+
   <groups id="100" name="sonar-administrators" />
   <groups id="101" name="sonar-users" />
 
index cfce89a776c5861a34f35d6d0593cbab5181bff0..fc6722d58dd3ff05bd39424a15bf7bbeecd1e94b 100644 (file)
@@ -4,4 +4,8 @@
 
   <group_roles id="1" group_id="100" resource_id="123" role="admin"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
index f57c7f9eb5e1e84b5ffae34490d7b3dc99c2868c..70eb158107d357b68b26bc33acbaf0c7bbd6c7c7 100644 (file)
@@ -5,4 +5,8 @@
   <group_roles id="1" group_id="100" resource_id="123" role="admin"/>
   <group_roles id="2" group_id="100" resource_id="123" role="user"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+</dataset>
index 000c018550bcde53048c98f9a46ee7ba8610a9d2..72df0ea9490c107591ff28b1c5511d41c8895df5 100644 (file)
@@ -4,4 +4,8 @@
 
   <user_roles id="1" user_id="200" resource_id="123" role="user"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
index f3749db4f0c9d30453f623c64b8351015d2476c2..2e96b7096200e4d0585c5c90ed37d78b5562d360 100644 (file)
@@ -5,4 +5,8 @@
   <user_roles id="1" user_id="200" resource_id="123" role="user"/>
   <user_roles id="2" user_id="200" resource_id="123" role="admin"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+</dataset>
index a81f3abe68d9de75a8d534fa7fd931e02950e52d..badbf13378a1f0e39198cccf5cfe48ce5720ad5f 100644 (file)
@@ -5,4 +5,9 @@
   <group_roles id="1" group_id="100" resource_id="123" role="admin"/>
   <group_roles id="2" group_id="[null]" resource_id="123" role="user"/>
 
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+
 </dataset>
index cfce89a776c5861a34f35d6d0593cbab5181bff0..4c9370a070b96750869383e845b5e44288f511ef 100644 (file)
@@ -4,4 +4,9 @@
 
   <group_roles id="1" group_id="100" resource_id="123" role="admin"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+
+</dataset>
index f57c7f9eb5e1e84b5ffae34490d7b3dc99c2868c..59fefdb74455dfcecf8fcab888adbbfeb5e5c757 100644 (file)
@@ -5,4 +5,8 @@
   <group_roles id="1" group_id="100" resource_id="123" role="admin"/>
   <group_roles id="2" group_id="100" resource_id="123" role="user"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
index cfce89a776c5861a34f35d6d0593cbab5181bff0..a67a1967f9a464cdbf3f5f70498f083b3d35cebe 100644 (file)
@@ -4,4 +4,8 @@
 
   <group_roles id="1" group_id="100" resource_id="123" role="admin"/>
 
-</dataset>
\ No newline at end of file
+  <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+</dataset>
index 477deb8163ee829a3d54000bea4d6845e4789b9a..de0d44f007a3da9a881ee44a7737147e69025297 100644 (file)
@@ -7,7 +7,8 @@
   <!-- root project -->
   <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
             description="the description" long_name="Apache Struts"
-            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="[null]"/>
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]"
+            created_at="2008-12-02" authorization_updated_at="2014-09-03"/>
   <snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
                status="P" islast="[true]" purge_status="[null]"
                period1_mode="[null]" period1_param="[null]" period1_date="[null]"
@@ -30,7 +31,8 @@
   <!-- module -->
   <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
             scope="PRJ" qualifier="BRC" long_name="Struts Core"
-            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]"/>
+            description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+            created_at="2008-12-02" authorization_updated_at="[null]"/>
   <snapshots id="2" project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
                status="P" islast="[true]" purge_status="[null]"
                period1_mode="[null]" period1_param="[null]" period1_date="[null]"
@@ -45,7 +47,8 @@
   <projects long_name="org.struts" id="3" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
               name="src/org/struts" root_id="2"
               description="[null]"
-              enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]"/>
+              enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts"
+              created_at="2008-12-02" authorization_updated_at="[null]"/>
   <snapshots id="3" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
                status="P" islast="[true]" purge_status="[null]"
                period1_mode="[null]" period1_param="[null]" period1_date="[null]"
@@ -60,7 +63,8 @@
   <projects long_name="org.struts.RequestContext" id="4" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
             name="RequestContext.java" root_id="2"
             description="[null]"
-            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]"/>
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java"
+            created_at="2008-12-02" authorization_updated_at="[null]"/>
 
   <snapshots id="4" project_id="4" parent_snapshot_id="3" root_project_id="1" root_snapshot_id="1"
                status="P" islast="[true]" purge_status="[null]"
index 3f1f7b78bcc71cd3772c3e2295125971939987b9..58216ea9682dd377376c90930539be2b3a38b232 100644 (file)
@@ -2,12 +2,12 @@
 
   <projects id="1" root_id="[null]" scope="FIL" qualifier="FIL" kee="org.struts:struts:/src/main/java/org/struts/Action.java" name="Action"
             description="[null]" long_name="org.struts.Action"
-            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="[null]" path="/foo/bar" deprecated_kee="org.struts:struts:org.struts.Action"
-            authorization_updated_at="[null]"/>
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="2014-09-03" path="/foo/bar" deprecated_kee="org.struts:struts:org.struts.Action"
+            authorization_updated_at="2014-09-03"/>
 
   <projects id="2" root_id="[null]" scope="FIL" qualifier="FIL" kee="org.struts:struts:/src/main/java/org/struts/Filter.java" name="Filter"
             description="[null]" long_name="org.struts.Filter"
-            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="[null]" path="[null]" deprecated_kee="org.struts:struts:org.struts.Filter"
-            authorization_updated_at="[null]"/>
+            enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="2014-09-03" path="[null]" deprecated_kee="org.struts:struts:org.struts.Filter"
+            authorization_updated_at="2014-09-03"/>
 
 </dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/update_authorization_date-result.xml b/sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/update_authorization_date-result.xml
new file mode 100644 (file)
index 0000000..2061ff9
--- /dev/null
@@ -0,0 +1,8 @@
+<dataset>
+
+  <projects id="1" root_id="200" scope="PRJ" qualifier="TRK" kee="old key" name="old name"
+            description="old name" long_name="old long name"
+            enabled="[false]" language="old" copy_resource_id="2" person_id="3" created_at="[null]" path="/old/foo/bar" deprecated_kee="old deprecated key"
+            authorization_updated_at="2014-09-03"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/update_authorization_date.xml b/sonar-core/src/test/resources/org/sonar/core/resource/ResourceDaoTest/update_authorization_date.xml
new file mode 100644 (file)
index 0000000..a735a55
--- /dev/null
@@ -0,0 +1,8 @@
+<dataset>
+
+  <projects id="1" root_id="200" scope="PRJ" qualifier="TRK" kee="old key" name="old name"
+            description="old name" long_name="old long name"
+            enabled="[false]" language="old" copy_resource_id="2" person_id="3" created_at="[null]" path="/old/foo/bar" deprecated_kee="old deprecated key"
+            authorization_updated_at="[null]"/>
+
+</dataset>