From 8ae8c29a76361942a1d22d0ecdeee009417525c3 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Fri, 1 Jul 2011 11:56:20 +0000 Subject: [PATCH] Fix date sort checking to handle equality, which applies to both ascending and descending git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28752 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repo/blog/BlogServiceImplTest.java | 1116 +++++++++-------- 1 file changed, 561 insertions(+), 555 deletions(-) diff --git a/source/java/org/alfresco/repo/blog/BlogServiceImplTest.java b/source/java/org/alfresco/repo/blog/BlogServiceImplTest.java index a4196b2cf8..eccdddaf82 100644 --- a/source/java/org/alfresco/repo/blog/BlogServiceImplTest.java +++ b/source/java/org/alfresco/repo/blog/BlogServiceImplTest.java @@ -1,555 +1,561 @@ -/* - * Copyright (C) 2005-2011 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.blog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -import org.alfresco.model.ContentModel; -import org.alfresco.query.PagingRequest; -import org.alfresco.query.PagingResults; -import org.alfresco.repo.blog.BlogService.BlogPostInfo; -import org.alfresco.repo.policy.BehaviourFilter; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.site.SiteModel; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.MutableAuthenticationService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.cmr.site.SiteInfo; -import org.alfresco.service.cmr.site.SiteService; -import org.alfresco.service.cmr.site.SiteVisibility; -import org.alfresco.service.cmr.tagging.TaggingService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.Pair; -import org.alfresco.util.PropertyMap; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.context.ApplicationContext; - -/** - * Test cases for {@link BlogServiceImpl}. - * - * @author Neil Mc Erlean - * @since 4.0 - */ -public class BlogServiceImplTest -{ - - private static final ApplicationContext testContext = ApplicationContextHelper.getApplicationContext(); - - // injected services - private static MutableAuthenticationService AUTHENTICATION_SERVICE; - private static BehaviourFilter BEHAVIOUR_FILTER; - private static BlogService BLOG_SERVICE; - private static DictionaryService DICTIONARY_SERVICE; - private static NodeService NODE_SERVICE; - private static PersonService PERSON_SERVICE; - private static RetryingTransactionHelper TRANSACTION_HELPER; - private static SiteService SITE_SERVICE; - private static TaggingService TAGGING_SERVICE; - - private static final String TEST_USER = BlogServiceImplTest.class.getSimpleName() + "_testuser"; - private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName(); - - - /** - * Temporary test nodes (created during a test method) that need deletion after the test method. - */ - private List testNodesToTidy = new ArrayList(); - /** - * Temporary test nodes (created BeforeClass) that need deletion after this test class. - */ - private static List CLASS_TEST_NODES_TO_TIDY = new ArrayList(); - - private static NodeRef BLOG_CONTAINER_NODE; - - @BeforeClass public static void initTestsContext() throws Exception - { - AUTHENTICATION_SERVICE = (MutableAuthenticationService)testContext.getBean("authenticationService"); - BEHAVIOUR_FILTER = (BehaviourFilter)testContext.getBean("policyBehaviourFilter"); - BLOG_SERVICE = (BlogService)testContext.getBean("blogService"); - DICTIONARY_SERVICE = (DictionaryService)testContext.getBean("dictionaryService"); - NODE_SERVICE = (NodeService)testContext.getBean("nodeService"); - PERSON_SERVICE = (PersonService)testContext.getBean("personService"); - TRANSACTION_HELPER = (RetryingTransactionHelper)testContext.getBean("retryingTransactionHelper"); - SITE_SERVICE = (SiteService)testContext.getBean("siteService"); - TAGGING_SERVICE = (TaggingService)testContext.getBean("TaggingService"); - - AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); - createUser(TEST_USER); - - // We need to create the test site as the test user so that they can contribute content to it in tests below. - AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); - createTestSiteWithBlogContainer(); - } - - private static void createTestSiteWithBlogContainer() throws Exception - { - BLOG_CONTAINER_NODE = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public NodeRef execute() throws Throwable - { - SiteInfo site = SITE_SERVICE.createSite("BlogSitePreset", BlogServiceImplTest.class.getSimpleName() + "_testSite" + System.currentTimeMillis(), - "test site title", "test site description", SiteVisibility.PUBLIC); - CLASS_TEST_NODES_TO_TIDY.add(site.getNodeRef()); - - NodeRef result = SITE_SERVICE.getContainer(site.getShortName(), "blog"); - - if (result == null) - { - result = NODE_SERVICE.createNode(site.getNodeRef(), ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "blog"), ContentModel.TYPE_FOLDER, null).getChildRef(); - CLASS_TEST_NODES_TO_TIDY.add(result); - } - - return result; - } - }); - } - - /** - * By default, all tests are run as the admin user. - */ - @Before public void setAdminUser() - { - AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); - } - - @After public void deleteTestNodes() throws Exception - { - performDeletionOfNodes(testNodesToTidy); - } - - @AfterClass public static void deleteClassTestNodesAndUsers() throws Exception - { - performDeletionOfNodes(CLASS_TEST_NODES_TO_TIDY); - deleteUser(TEST_USER); - } - - /** - * Deletes the specified NodeRefs, if they exist. - * @param nodesToDelete - */ - private static void performDeletionOfNodes(final List nodesToDelete) - { - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); - - for (NodeRef node : nodesToDelete) - { - if (NODE_SERVICE.exists(node)) - { - // st:site nodes can only be deleted via the SiteService - if (NODE_SERVICE.getType(node).equals(SiteModel.TYPE_SITE)) - { - - SiteInfo siteInfo = SITE_SERVICE.getSite(node); - SITE_SERVICE.deleteSite(siteInfo.getShortName()); - } - else - { - NODE_SERVICE.deleteNode(node); - } - } - } - - return null; - } - }); - } - - @Test public void createDraftBlogPostsAndGetPagedResults() throws Exception - { - final int arbitraryNumberGreaterThanPageSize = 42; - final List submittedBlogPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() - { - @Override - public List execute() throws Throwable - { - List results = new ArrayList(); - - for (int i = 0; i < arbitraryNumberGreaterThanPageSize; i++) - { - ChildAssociationRef newBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "title_" + i, "Hello world", true); - - results.add(newBlogPost.getChildRef()); - testNodesToTidy.add(newBlogPost.getChildRef()); - } - - return results; - } - }); - - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - List recoveredBlogPosts = new ArrayList(arbitraryNumberGreaterThanPageSize); - - final int pageSize = 10; - PagingRequest pagingReq = new PagingRequest(0, pageSize, null); - - PagingResults pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); - assertEquals("Wrong total result count.", arbitraryNumberGreaterThanPageSize, (int)pagedResults.getTotalResultCount().getFirst()); - - while (pagedResults.hasMoreItems()) - { - recoveredBlogPosts.addAll(pagedResults.getPage()); - pagingReq = new PagingRequest(pagingReq.getSkipCount() + pageSize, pageSize, null); - pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); - } - // and the last page, which only has 2 items in it. - recoveredBlogPosts.addAll(pagedResults.getPage()); - - assertEquals("Wrong number of blog posts.", submittedBlogPosts.size(), recoveredBlogPosts.size()); - - // Check the list is sorted by cm:created, descending order. - assertNodeRefsAreSortedBy(recoveredBlogPosts, ContentModel.PROP_CREATED, false); - - return null; - } - }); - } - - /** - * This method asserts that the given List has NodeRefs in order of the specified date property. - * - * @param blogPosts - * @param property a Date property - * @param ascendingOrder true if ascending order, false for descending. - */ - private void assertNodeRefsAreSortedBy(List blogPosts, QName property, boolean ascendingOrder) - { - final PropertyDefinition propertyDef = DICTIONARY_SERVICE.getProperty(property); - assertNotNull("Property not recognised.", propertyDef); - assertEquals("Property was not a Date", DataTypeDefinition.DATETIME, propertyDef.getDataType().getName()); - - if (blogPosts.size() > 1) - { - for (int i = 0; i < blogPosts.size() - 1; i++) - { - NodeRef nodeRef1 = blogPosts.get(i).getNodeRef(); - NodeRef nodeRef2 = blogPosts.get(i + 1).getNodeRef(); - Date date1 = (Date) NODE_SERVICE.getProperty(nodeRef1, property); - Date date2 = (Date) NODE_SERVICE.getProperty(nodeRef2, property); - - if (ascendingOrder) - { - assertTrue("BlogPosts not asc-sorted by " + property + ". Error at index " + i, date1.before(date2)); - } - else - { - assertTrue("BlogPosts not desc-sorted by " + property + ". Error at index " + i, date1.after(date2)); - } - } - } - } - - @Test public void createTaggedDraftBlogPost() throws Exception - { - final List tags = Arrays.asList(new String[]{"foo", "bar"}); - - final NodeRef blogPost = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - - @Override - public NodeRef execute() throws Throwable - { - ChildAssociationRef newBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "draftWithTag", "Hello world", true); - TAGGING_SERVICE.addTags(newBlogPost.getChildRef(), tags); - testNodesToTidy.add(newBlogPost.getChildRef()); - - return newBlogPost.getChildRef(); - } - }); - - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - PagingRequest pagingReq = new PagingRequest(0, 10, null); - - PagingResults pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); - assertEquals("Expected one blog post", 1, pagedResults.getPage().size()); - - NodeRef blogNode = pagedResults.getPage().get(0).getNodeRef(); - assertEquals("Incorrect NodeRef.", blogNode, blogPost); - - List recoveredTags = TAGGING_SERVICE.getTags(blogNode); - assertEquals("Incorrect tags.", tags, recoveredTags); - - return null; - } - }); - } - - /** - * This test uses two different users to create draft and internally published blog posts. - * Then it ensures that each user sees the correct posts when they retrieve them from the service. - */ - @Test public void multipleUsersCreateDraftsAndPublishedPostsAndBrowse() throws Exception - { - // Admin creates a draft and an internally-published blog post. - final Pair adminPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() - { - - @Override - public Pair execute() throws Throwable - { - ChildAssociationRef newDraftBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "adminDraft", "", true); - testNodesToTidy.add(newDraftBlogPost.getChildRef()); - - ChildAssociationRef newPublishedBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "adminPublished", "", false); - testNodesToTidy.add(newPublishedBlogPost.getChildRef()); - - return new Pair(newDraftBlogPost.getChildRef(), newPublishedBlogPost.getChildRef()); - } - }); - - // Then another user does the same. - AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); - final Pair userPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() - { - - @Override - public Pair execute() throws Throwable - { - ChildAssociationRef newDraftBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "userDraft", "", true); - testNodesToTidy.add(newDraftBlogPost.getChildRef()); - - ChildAssociationRef newPublishedBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "userPublished", "", false); - testNodesToTidy.add(newPublishedBlogPost.getChildRef()); - - return new Pair(newDraftBlogPost.getChildRef(), newPublishedBlogPost.getChildRef()); - } - }); - - // Now check what we see from the service. - AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); - - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - PagingRequest pagingReq = new PagingRequest(0, 10, null); - - PagingResults pagedDraftResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); - assertEquals("Wrong number of admin draft blog posts", 1, pagedDraftResults.getPage().size()); - NodeRef blogNode = pagedDraftResults.getPage().get(0).getNodeRef(); - assertEquals("Incorrect admin draft NodeRef.", blogNode, adminPosts.getFirst()); - - PagingResults pagedPublishedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, null, null, ADMIN_USER, pagingReq); - assertEquals("Wrong number of admin published blog posts", 1, pagedPublishedResults.getPage().size()); - blogNode = pagedPublishedResults.getPage().get(0).getNodeRef(); - assertEquals("Incorrect admin published NodeRef.", blogNode, adminPosts.getSecond()); - - return null; - } - }); - - - AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); - - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - PagingRequest pagingReq = new PagingRequest(0, 10, null); - - PagingResults pagedDraftResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, TEST_USER, pagingReq); - assertEquals("Wrong number of user draft blog posts", 1, pagedDraftResults.getPage().size()); - NodeRef blogNode = pagedDraftResults.getPage().get(0).getNodeRef(); - assertEquals("Incorrect user draft NodeRef.", blogNode, userPosts.getFirst()); - - PagingResults pagedPublishedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, null, null, TEST_USER, pagingReq); - assertEquals("Wrong number of user published blog posts", 1, pagedPublishedResults.getPage().size()); - blogNode = pagedPublishedResults.getPage().get(0).getNodeRef(); - assertEquals("Incorrect user published NodeRef.", blogNode, userPosts.getSecond()); - - return null; - } - }); - } - - @Test public void getBlogPostsFilteredByDateRange() throws Exception - { - final int numberOfPosts = 31 + 31 + 29; - - final List posts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() - { - @Override - public List execute() throws Throwable - { - List results = new ArrayList(); - - for (int i = 0; i < numberOfPosts; i++) - { - ChildAssociationRef newBlogPost = - BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "date-specific-post" + i, "", false); - testNodesToTidy.add(newBlogPost.getChildRef()); - - results.add(newBlogPost.getChildRef()); - } - - return results; - } - }); - - // Now go through and set their creation dates to specific points in the past. - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - // FROM 1st December 1999 - final Calendar current = Calendar.getInstance(); - current.set(1999, 11, 1, 11, 0); - - // should give us: - // 31 posts in december 99 - // 31 posts in january 00 - // 29 posts in february 00 - - Date currentDate = current.getTime(); - for (NodeRef nr : posts) - { - // We'll permanently turn off auditing on this node. - // This should allow us to set the cm:created date without auditing overwriting our value. - // These nodes get deleted after the test anyway. - BEHAVIOUR_FILTER.disableBehaviour(nr, ContentModel.ASPECT_AUDITABLE); - - // Yes, cm:published will be before cm:created. But I don't think that matter. - NODE_SERVICE.setProperty(nr, ContentModel.PROP_PUBLISHED, currentDate); - - current.add(Calendar.DATE, 1); - currentDate = current.getTime(); - - } - - return null; - } - }); - - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - PagingRequest pagingReq = new PagingRequest(0, 100, null); - - Calendar cal = Calendar.getInstance(); - cal.set(1999, 11, 1, 0, 0, 0); - Date firstDec99 = cal.getTime(); - - cal.set(2000, 0, 1, 0, 0, 0); - Date firstJan00 = cal.getTime(); - - cal.set(2000, 1, 1, 0, 0, 0); - Date firstFeb00 = cal.getTime(); - - cal.set(2000, 2, 1, 0, 0, 0); - Date firstMar00 = cal.getTime(); - - PagingResults pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstDec99, firstJan00, null, pagingReq); - assertEquals("Wrong number of user blog posts", 31, pagedResults.getPage().size()); - - pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstFeb00, firstMar00, null, pagingReq); - assertEquals("Wrong number of user blog posts", 29, pagedResults.getPage().size()); - - pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstJan00, firstMar00, null, pagingReq); - assertEquals("Wrong number of user blog posts", 31 + 29, pagedResults.getPage().size()); - - return null; - } - }); - } - - private static void createUser(final String userName) - { - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - if (!AUTHENTICATION_SERVICE.authenticationExists(userName)) - { - AUTHENTICATION_SERVICE.createAuthentication(userName, "PWD".toCharArray()); - } - - if (!PERSON_SERVICE.personExists(userName)) - { - PropertyMap ppOne = new PropertyMap(); - ppOne.put(ContentModel.PROP_USERNAME, userName); - ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName"); - ppOne.put(ContentModel.PROP_LASTNAME, "lastName"); - ppOne.put(ContentModel.PROP_EMAIL, "email@email.com"); - ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle"); - - PERSON_SERVICE.createPerson(ppOne); - } - - return null; - } - }); - } - - private static void deleteUser(final String userName) - { - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - if (PERSON_SERVICE.personExists(userName)) - { - PERSON_SERVICE.deletePerson(userName); - } - - return null; - } - }); - } -} +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.blog; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.repo.blog.BlogService.BlogPostInfo; +import org.alfresco.repo.policy.BehaviourFilter; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.site.SiteModel; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; +import org.alfresco.service.cmr.site.SiteVisibility; +import org.alfresco.service.cmr.tagging.TaggingService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.Pair; +import org.alfresco.util.PropertyMap; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.ApplicationContext; + +/** + * Test cases for {@link BlogServiceImpl}. + * + * @author Neil Mc Erlean + * @since 4.0 + */ +public class BlogServiceImplTest +{ + + private static final ApplicationContext testContext = ApplicationContextHelper.getApplicationContext(); + + // injected services + private static MutableAuthenticationService AUTHENTICATION_SERVICE; + private static BehaviourFilter BEHAVIOUR_FILTER; + private static BlogService BLOG_SERVICE; + private static DictionaryService DICTIONARY_SERVICE; + private static NodeService NODE_SERVICE; + private static PersonService PERSON_SERVICE; + private static RetryingTransactionHelper TRANSACTION_HELPER; + private static SiteService SITE_SERVICE; + private static TaggingService TAGGING_SERVICE; + + private static final String TEST_USER = BlogServiceImplTest.class.getSimpleName() + "_testuser"; + private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName(); + + + /** + * Temporary test nodes (created during a test method) that need deletion after the test method. + */ + private List testNodesToTidy = new ArrayList(); + /** + * Temporary test nodes (created BeforeClass) that need deletion after this test class. + */ + private static List CLASS_TEST_NODES_TO_TIDY = new ArrayList(); + + private static NodeRef BLOG_CONTAINER_NODE; + + @BeforeClass public static void initTestsContext() throws Exception + { + AUTHENTICATION_SERVICE = (MutableAuthenticationService)testContext.getBean("authenticationService"); + BEHAVIOUR_FILTER = (BehaviourFilter)testContext.getBean("policyBehaviourFilter"); + BLOG_SERVICE = (BlogService)testContext.getBean("blogService"); + DICTIONARY_SERVICE = (DictionaryService)testContext.getBean("dictionaryService"); + NODE_SERVICE = (NodeService)testContext.getBean("nodeService"); + PERSON_SERVICE = (PersonService)testContext.getBean("personService"); + TRANSACTION_HELPER = (RetryingTransactionHelper)testContext.getBean("retryingTransactionHelper"); + SITE_SERVICE = (SiteService)testContext.getBean("siteService"); + TAGGING_SERVICE = (TaggingService)testContext.getBean("TaggingService"); + + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + createUser(TEST_USER); + + // We need to create the test site as the test user so that they can contribute content to it in tests below. + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); + createTestSiteWithBlogContainer(); + } + + private static void createTestSiteWithBlogContainer() throws Exception + { + BLOG_CONTAINER_NODE = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public NodeRef execute() throws Throwable + { + SiteInfo site = SITE_SERVICE.createSite("BlogSitePreset", BlogServiceImplTest.class.getSimpleName() + "_testSite" + System.currentTimeMillis(), + "test site title", "test site description", SiteVisibility.PUBLIC); + CLASS_TEST_NODES_TO_TIDY.add(site.getNodeRef()); + + NodeRef result = SITE_SERVICE.getContainer(site.getShortName(), "blog"); + + if (result == null) + { + result = NODE_SERVICE.createNode(site.getNodeRef(), ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "blog"), ContentModel.TYPE_FOLDER, null).getChildRef(); + CLASS_TEST_NODES_TO_TIDY.add(result); + } + + return result; + } + }); + } + + /** + * By default, all tests are run as the admin user. + */ + @Before public void setAdminUser() + { + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + } + + @After public void deleteTestNodes() throws Exception + { + performDeletionOfNodes(testNodesToTidy); + } + + @AfterClass public static void deleteClassTestNodesAndUsers() throws Exception + { + performDeletionOfNodes(CLASS_TEST_NODES_TO_TIDY); + deleteUser(TEST_USER); + } + + /** + * Deletes the specified NodeRefs, if they exist. + * @param nodesToDelete + */ + private static void performDeletionOfNodes(final List nodesToDelete) + { + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + + for (NodeRef node : nodesToDelete) + { + if (NODE_SERVICE.exists(node)) + { + // st:site nodes can only be deleted via the SiteService + if (NODE_SERVICE.getType(node).equals(SiteModel.TYPE_SITE)) + { + + SiteInfo siteInfo = SITE_SERVICE.getSite(node); + SITE_SERVICE.deleteSite(siteInfo.getShortName()); + } + else + { + NODE_SERVICE.deleteNode(node); + } + } + } + + return null; + } + }); + } + + @Test public void createDraftBlogPostsAndGetPagedResults() throws Exception + { + final int arbitraryNumberGreaterThanPageSize = 42; + final List submittedBlogPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() + { + @Override + public List execute() throws Throwable + { + List results = new ArrayList(); + + for (int i = 0; i < arbitraryNumberGreaterThanPageSize; i++) + { + ChildAssociationRef newBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "title_" + i, "Hello world", true); + + results.add(newBlogPost.getChildRef()); + testNodesToTidy.add(newBlogPost.getChildRef()); + } + + return results; + } + }); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + List recoveredBlogPosts = new ArrayList(arbitraryNumberGreaterThanPageSize); + + final int pageSize = 10; + PagingRequest pagingReq = new PagingRequest(0, pageSize, null); + + PagingResults pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); + assertEquals("Wrong total result count.", arbitraryNumberGreaterThanPageSize, (int)pagedResults.getTotalResultCount().getFirst()); + + while (pagedResults.hasMoreItems()) + { + recoveredBlogPosts.addAll(pagedResults.getPage()); + pagingReq = new PagingRequest(pagingReq.getSkipCount() + pageSize, pageSize, null); + pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); + } + // and the last page, which only has 2 items in it. + recoveredBlogPosts.addAll(pagedResults.getPage()); + + assertEquals("Wrong number of blog posts.", submittedBlogPosts.size(), recoveredBlogPosts.size()); + + // Check the list is sorted by cm:created, descending order. + assertNodeRefsAreSortedBy(recoveredBlogPosts, ContentModel.PROP_CREATED, false); + + return null; + } + }); + } + + /** + * This method asserts that the given List has NodeRefs in order of the specified date property. + * + * @param blogPosts + * @param property a Date property + * @param ascendingOrder true if ascending order, false for descending. + */ + private void assertNodeRefsAreSortedBy(List blogPosts, QName property, boolean ascendingOrder) + { + final PropertyDefinition propertyDef = DICTIONARY_SERVICE.getProperty(property); + assertNotNull("Property not recognised.", propertyDef); + assertEquals("Property was not a Date", DataTypeDefinition.DATETIME, propertyDef.getDataType().getName()); + + if (blogPosts.size() > 1) + { + for (int i = 0; i < blogPosts.size() - 1; i++) + { + NodeRef nodeRef1 = blogPosts.get(i).getNodeRef(); + NodeRef nodeRef2 = blogPosts.get(i + 1).getNodeRef(); + Date date1 = (Date) NODE_SERVICE.getProperty(nodeRef1, property); + Date date2 = (Date) NODE_SERVICE.getProperty(nodeRef2, property); + + // Equal dates are applicable to either sort order + if (date1.equals(date2)) + { + continue; + } + + if (ascendingOrder) + { + assertTrue("BlogPosts not asc-sorted by " + property + ". Error at index " + i, date1.before(date2)); + } + else + { + assertTrue("BlogPosts not desc-sorted by " + property + ". Error at index " + i, date1.after(date2)); + } + } + } + } + + @Test public void createTaggedDraftBlogPost() throws Exception + { + final List tags = Arrays.asList(new String[]{"foo", "bar"}); + + final NodeRef blogPost = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + + @Override + public NodeRef execute() throws Throwable + { + ChildAssociationRef newBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "draftWithTag", "Hello world", true); + TAGGING_SERVICE.addTags(newBlogPost.getChildRef(), tags); + testNodesToTidy.add(newBlogPost.getChildRef()); + + return newBlogPost.getChildRef(); + } + }); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + PagingRequest pagingReq = new PagingRequest(0, 10, null); + + PagingResults pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); + assertEquals("Expected one blog post", 1, pagedResults.getPage().size()); + + NodeRef blogNode = pagedResults.getPage().get(0).getNodeRef(); + assertEquals("Incorrect NodeRef.", blogNode, blogPost); + + List recoveredTags = TAGGING_SERVICE.getTags(blogNode); + assertEquals("Incorrect tags.", tags, recoveredTags); + + return null; + } + }); + } + + /** + * This test uses two different users to create draft and internally published blog posts. + * Then it ensures that each user sees the correct posts when they retrieve them from the service. + */ + @Test public void multipleUsersCreateDraftsAndPublishedPostsAndBrowse() throws Exception + { + // Admin creates a draft and an internally-published blog post. + final Pair adminPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() + { + + @Override + public Pair execute() throws Throwable + { + ChildAssociationRef newDraftBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "adminDraft", "", true); + testNodesToTidy.add(newDraftBlogPost.getChildRef()); + + ChildAssociationRef newPublishedBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "adminPublished", "", false); + testNodesToTidy.add(newPublishedBlogPost.getChildRef()); + + return new Pair(newDraftBlogPost.getChildRef(), newPublishedBlogPost.getChildRef()); + } + }); + + // Then another user does the same. + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); + final Pair userPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() + { + + @Override + public Pair execute() throws Throwable + { + ChildAssociationRef newDraftBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "userDraft", "", true); + testNodesToTidy.add(newDraftBlogPost.getChildRef()); + + ChildAssociationRef newPublishedBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "userPublished", "", false); + testNodesToTidy.add(newPublishedBlogPost.getChildRef()); + + return new Pair(newDraftBlogPost.getChildRef(), newPublishedBlogPost.getChildRef()); + } + }); + + // Now check what we see from the service. + AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + PagingRequest pagingReq = new PagingRequest(0, 10, null); + + PagingResults pagedDraftResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq); + assertEquals("Wrong number of admin draft blog posts", 1, pagedDraftResults.getPage().size()); + NodeRef blogNode = pagedDraftResults.getPage().get(0).getNodeRef(); + assertEquals("Incorrect admin draft NodeRef.", blogNode, adminPosts.getFirst()); + + PagingResults pagedPublishedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, null, null, ADMIN_USER, pagingReq); + assertEquals("Wrong number of admin published blog posts", 1, pagedPublishedResults.getPage().size()); + blogNode = pagedPublishedResults.getPage().get(0).getNodeRef(); + assertEquals("Incorrect admin published NodeRef.", blogNode, adminPosts.getSecond()); + + return null; + } + }); + + + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + PagingRequest pagingReq = new PagingRequest(0, 10, null); + + PagingResults pagedDraftResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, TEST_USER, pagingReq); + assertEquals("Wrong number of user draft blog posts", 1, pagedDraftResults.getPage().size()); + NodeRef blogNode = pagedDraftResults.getPage().get(0).getNodeRef(); + assertEquals("Incorrect user draft NodeRef.", blogNode, userPosts.getFirst()); + + PagingResults pagedPublishedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, null, null, TEST_USER, pagingReq); + assertEquals("Wrong number of user published blog posts", 1, pagedPublishedResults.getPage().size()); + blogNode = pagedPublishedResults.getPage().get(0).getNodeRef(); + assertEquals("Incorrect user published NodeRef.", blogNode, userPosts.getSecond()); + + return null; + } + }); + } + + @Test public void getBlogPostsFilteredByDateRange() throws Exception + { + final int numberOfPosts = 31 + 31 + 29; + + final List posts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback>() + { + @Override + public List execute() throws Throwable + { + List results = new ArrayList(); + + for (int i = 0; i < numberOfPosts; i++) + { + ChildAssociationRef newBlogPost = + BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "date-specific-post" + i, "", false); + testNodesToTidy.add(newBlogPost.getChildRef()); + + results.add(newBlogPost.getChildRef()); + } + + return results; + } + }); + + // Now go through and set their creation dates to specific points in the past. + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + // FROM 1st December 1999 + final Calendar current = Calendar.getInstance(); + current.set(1999, 11, 1, 11, 0); + + // should give us: + // 31 posts in december 99 + // 31 posts in january 00 + // 29 posts in february 00 + + Date currentDate = current.getTime(); + for (NodeRef nr : posts) + { + // We'll permanently turn off auditing on this node. + // This should allow us to set the cm:created date without auditing overwriting our value. + // These nodes get deleted after the test anyway. + BEHAVIOUR_FILTER.disableBehaviour(nr, ContentModel.ASPECT_AUDITABLE); + + // Yes, cm:published will be before cm:created. But I don't think that matter. + NODE_SERVICE.setProperty(nr, ContentModel.PROP_PUBLISHED, currentDate); + + current.add(Calendar.DATE, 1); + currentDate = current.getTime(); + + } + + return null; + } + }); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + PagingRequest pagingReq = new PagingRequest(0, 100, null); + + Calendar cal = Calendar.getInstance(); + cal.set(1999, 11, 1, 0, 0, 0); + Date firstDec99 = cal.getTime(); + + cal.set(2000, 0, 1, 0, 0, 0); + Date firstJan00 = cal.getTime(); + + cal.set(2000, 1, 1, 0, 0, 0); + Date firstFeb00 = cal.getTime(); + + cal.set(2000, 2, 1, 0, 0, 0); + Date firstMar00 = cal.getTime(); + + PagingResults pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstDec99, firstJan00, null, pagingReq); + assertEquals("Wrong number of user blog posts", 31, pagedResults.getPage().size()); + + pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstFeb00, firstMar00, null, pagingReq); + assertEquals("Wrong number of user blog posts", 29, pagedResults.getPage().size()); + + pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstJan00, firstMar00, null, pagingReq); + assertEquals("Wrong number of user blog posts", 31 + 29, pagedResults.getPage().size()); + + return null; + } + }); + } + + private static void createUser(final String userName) + { + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (!AUTHENTICATION_SERVICE.authenticationExists(userName)) + { + AUTHENTICATION_SERVICE.createAuthentication(userName, "PWD".toCharArray()); + } + + if (!PERSON_SERVICE.personExists(userName)) + { + PropertyMap ppOne = new PropertyMap(); + ppOne.put(ContentModel.PROP_USERNAME, userName); + ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName"); + ppOne.put(ContentModel.PROP_LASTNAME, "lastName"); + ppOne.put(ContentModel.PROP_EMAIL, "email@email.com"); + ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle"); + + PERSON_SERVICE.createPerson(ppOne); + } + + return null; + } + }); + } + + private static void deleteUser(final String userName) + { + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (PERSON_SERVICE.personExists(userName)) + { + PERSON_SERVICE.deletePerson(userName); + } + + return null; + } + }); + } +}