Feature/acs 1782 impl request DAU in content service (#645)

* Content Service changes both ACS-1781 and 1782

* Ignore test temporarily

* ACS-1782 fix test

* ACS-1782 Test and service updates

* ACS-1781 Tests for Content Service and Store

* ACS-1782 disable rest api DAU

* ACS-1782 fix mocks in unit test

* ACS-1782 Fix integration test
This commit is contained in:
Sara
2021-08-09 15:55:10 +01:00
committed by GitHub
parent eee7e00310
commit 838d758983
14 changed files with 614 additions and 130 deletions

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Data model classes
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,6 +25,8 @@
*/
package org.alfresco.repo.content;
import java.util.Date;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.cmr.repository.ContentAccessor;
import org.alfresco.service.cmr.repository.ContentIOException;
@@ -32,8 +34,8 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.service.cmr.repository.NodeRef;
import java.util.Date;
/**
* Provides low-level retrieval of content
@@ -239,6 +241,58 @@ public interface ContentStore
*/
public boolean delete(String contentUrl);
/**
* Checks if the store supports the retrieving of direct access URLs.
*
* @return {@code true} if direct access URLs retrieving is supported, {@code false} otherwise
*/
default boolean isContentDirectUrlEnabled()
{
return false;
}
/**
* Checks if the store supports the retrieving of a direct access URL for the given node.
*
* @return {@code true} if direct access URLs retrieving is supported for the node, {@code false} otherwise
*/
default boolean isContentDirectUrlEnabled(NodeRef nodeRef)
{
return false;
}
/**
* Gets a presigned URL to directly access the content. It is up to the actual store
* implementation if it can fulfil this request with an expiry time or not.
*
* @param contentUrl A content store {@code URL}
* @param attachment {@code true} if an attachment URL is requested, {@code false} for an embedded {@code URL}.
* @param fileName File name of the content
* @return A direct access {@code URL} object for the content
* @throws UnsupportedOperationException if the store is unable to provide the information
*/
default DirectAccessUrl requestContentDirectUrl(String contentUrl, boolean attachment, String fileName)
{
return requestContentDirectUrl(contentUrl, attachment, fileName, null);
}
/**
* Gets a presigned URL to directly access the content. It is up to the actual store
* implementation if it can fulfil this request with an expiry time or not.
*
* @param contentUrl A content store {@code URL}
* @param attachment {@code true} if an attachment URL is requested, {@code false} for an embedded {@code URL}.
* @param fileName File name of the content
* @param validFor The time at which the direct access {@code URL} will expire.
* @return A direct access {@code URL} object for the content.
* @throws UnsupportedOperationException if the store is unable to provide the information
*/
default DirectAccessUrl requestContentDirectUrl(String contentUrl, boolean attachment, String fileName, Long validFor)
{
throw new UnsupportedOperationException(
"Retrieving direct access URLs is not supported by this content store.");
}
/**
* Gets a presigned URL to directly access a binary content. It is up to the actual store
* implementation if it can fulfil this request with an expiry time or not.
@@ -248,10 +302,11 @@ public interface ContentStore
* @return A direct access URL object for a binary content
* @throws UnsupportedOperationException if the store is unable to provide the information
*/
@Deprecated
default DirectAccessUrl getDirectAccessUrl(String contentUrl, Date expiresAt)
{
throw new UnsupportedOperationException(
"Retrieving direct access URLs is not supported by this content store.");
"Retrieving direct access URLs is not supported by this content store.");
}
/**
@@ -259,6 +314,7 @@ public interface ContentStore
*
* @return true if direct access URLs retrieving is supported, false otherwise
*/
@Deprecated
default boolean isDirectAccessSupported()
{
return false;

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Data model classes
* %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -27,6 +27,7 @@ package org.alfresco.service.cmr.repository;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
import org.alfresco.api.AlfrescoPublicApi;
@@ -36,7 +37,8 @@ public class DirectAccessUrl implements Serializable
private static final long serialVersionUID = -881676208224414139L;
private String contentUrl;
private Date expiresAt;
private Date expiryTime;
private boolean attachment;
public String getContentUrl()
{
@@ -48,13 +50,38 @@ public class DirectAccessUrl implements Serializable
this.contentUrl = contentUrl;
}
public Date getExpiresAt()
public Date getExpiryTime()
{
return expiresAt;
return expiryTime;
}
public void setExpiresAt(Date expiresAt)
public void setExpiryTime(Date expiryTime)
{
this.expiresAt = expiresAt;
this.expiryTime = expiryTime;
}
public boolean isAttachment()
{
return attachment;
}
public void setAttachment(boolean attachment)
{
this.attachment = attachment;
}
@Override public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
DirectAccessUrl that = (DirectAccessUrl) obj;
return attachment == that.attachment && Objects.equals(contentUrl,
that.contentUrl) && Objects.equals(expiryTime, that.expiryTime);
}
@Override public int hashCode()
{
return Objects.hash(contentUrl, expiryTime, attachment);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,12 +25,21 @@
*/
package org.alfresco.repo.content;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.ContentServicePolicies.OnContentPropertyUpdatePolicy;
import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy;
import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy;
import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner;
import org.alfresco.repo.content.directurl.DirectAccessUrlDisabledException;
import org.alfresco.repo.content.directurl.SystemWideDirectUrlConfig;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.ClassPolicyDelegate;
@@ -47,6 +56,7 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.MimetypeServiceAware;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -62,13 +72,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.extensions.surf.util.I18NUtil;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Service implementation acting as a level of indirection between the client
* and the underlying content store.
@@ -82,7 +85,7 @@ import java.util.Set;
*/
public class ContentServiceImpl implements ContentService, ApplicationContextAware
{
private static Log logger = LogFactory.getLog(ContentServiceImpl.class);
private static final Log logger = LogFactory.getLog(ContentServiceImpl.class);
private DictionaryService dictionaryService;
private NodeService nodeService;
@@ -99,6 +102,8 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
/** Should we consider zero byte content to be the same as no content? */
private boolean ignoreEmptyContent;
private SystemWideDirectUrlConfig systemWideDirectUrlConfig;
/**
* The policy component
*/
@@ -140,7 +145,12 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
{
this.store = store;
}
public void setSystemWideDirectUrlConfig(SystemWideDirectUrlConfig systemWideDirectUrlConfig)
{
this.systemWideDirectUrlConfig = systemWideDirectUrlConfig;
}
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
@@ -510,23 +520,10 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
return tempStore.getWriter(ContentContext.NULL_CONTEXT);
}
@Override
@Deprecated
public DirectAccessUrl getDirectAccessUrl(NodeRef nodeRef, Date expiresAt)
{
ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT);
// check that the URL is available
if (contentData == null || contentData.getContentUrl() == null)
{
throw new IllegalArgumentException("The supplied nodeRef " + nodeRef + " has no content.");
}
if (store.isDirectAccessSupported())
{
return store.getDirectAccessUrl(contentData.getContentUrl(), expiresAt);
}
return null;
return requestContentDirectUrl(nodeRef, true, null);
}
/**
@@ -586,4 +583,104 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean isContentDirectUrlEnabled()
{
return systemWideDirectUrlConfig.isEnabled() && store.isContentDirectUrlEnabled();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isContentDirectUrlEnabled(NodeRef nodeRef)
{
boolean contentDirectUrlEnabled = false;
// TODO: update this
if (systemWideDirectUrlConfig.isEnabled())
{
ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT);
// check that the URL is available
if (contentData == null || contentData.getContentUrl() == null)
{
throw new IllegalArgumentException("The supplied nodeRef " + nodeRef + " has no content.");
}
contentDirectUrlEnabled = (store.isContentDirectUrlEnabled(nodeRef));
}
return contentDirectUrlEnabled;
}
/**
* {@inheritDoc}
*/
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor)
{
if (!systemWideDirectUrlConfig.isEnabled())
{
throw new DirectAccessUrlDisabledException("Direct access url isn't available.");
}
String contentUrl = getContentUrl(nodeRef);
String fileName = getFileName(nodeRef);
validFor = adjustValidFor(validFor);
DirectAccessUrl directAccessUrl = null;
if (store.isContentDirectUrlEnabled())
{
try
{
directAccessUrl = store.requestContentDirectUrl(contentUrl, attachment, fileName, validFor);
}
catch (UnsupportedOperationException ex)
{
// expected exception
}
}
return directAccessUrl;
}
protected String getContentUrl(NodeRef nodeRef)
{
ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT);
// check that the URL is available
if (contentData == null || contentData.getContentUrl() == null)
{
throw new IllegalArgumentException("The supplied nodeRef " + nodeRef + " has no content.");
}
return contentData.getContentUrl();
}
protected String getFileName(NodeRef nodeRef)
{
String fileName = null;
try
{
fileName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
}
catch (InvalidNodeRefException ex)
{
}
return fileName;
}
private Long adjustValidFor(Long validFor)
{
if (validFor == null || validFor > systemWideDirectUrlConfig.getDefaultExpiryTimeInSec())
{
validFor = systemWideDirectUrlConfig.getDefaultExpiryTimeInSec();
}
return validFor;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,7 +25,6 @@
*/
package org.alfresco.repo.content.caching;
import java.util.Date;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
@@ -41,6 +40,7 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
@@ -103,7 +103,7 @@ public class CachingContentStore implements ContentStore, ApplicationEventPublis
{
eventPublisher.publishEvent(new CachingContentStoreCreatedEvent(this));
}
@Override
public boolean isContentUrlSupported(String contentUrl)
{
@@ -137,7 +137,7 @@ public class CachingContentStore implements ContentStore, ApplicationEventPublis
/**
* {@inheritDoc}
* <p>
* For {@link #SPOOF_PROTOCOL spoofed} URLs, the URL always exists.
* For {@link FileContentStore#SPOOF_PROTOCOL spoofed} URLs, the URL always exists.
*/
@Override
public boolean exists(String contentUrl)
@@ -478,13 +478,35 @@ public class CachingContentStore implements ContentStore, ApplicationEventPublis
return this.beanName;
}
public boolean isDirectAccessSupported()
/**
* {@inheritDoc}
*/
public boolean isContentDirectUrlEnabled()
{
return backingStore.isDirectAccessSupported();
return backingStore.isContentDirectUrlEnabled();
}
public DirectAccessUrl getDirectAccessUrl(String contentUrl, Date expiresAt)
/**
* {@inheritDoc}
*/
public boolean isContentDirectUrlEnabled(NodeRef nodeRef)
{
return backingStore.getDirectAccessUrl(contentUrl, expiresAt);
return backingStore.isContentDirectUrlEnabled(nodeRef);
}
/**
* {@inheritDoc}
*/
public DirectAccessUrl requestContentDirectUrl(String contentUrl, boolean attachment, String fileName)
{
return backingStore.requestContentDirectUrl(contentUrl, attachment, fileName);
}
/**
* {@inheritDoc}
*/
public DirectAccessUrl requestContentDirectUrl(String contentUrl, boolean attachment, String fileName, Long validFor)
{
return backingStore.requestContentDirectUrl(contentUrl, attachment, fileName, validFor);
}
}

View File

@@ -0,0 +1,44 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content.directurl;
import org.alfresco.error.AlfrescoRuntimeException;
/**
* Runtime exception thrown when direct access URLs are disabled.
*
* @author Sara Aspery
*/
public class DirectAccessUrlDisabledException extends AlfrescoRuntimeException
{
private static final long serialVersionUID = -6506082117146782993L;
public DirectAccessUrlDisabledException(String msg)
{
super(msg);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,7 +25,6 @@
*/
package org.alfresco.repo.content.replication;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
@@ -41,6 +40,7 @@ import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -65,7 +65,7 @@ import org.apache.commons.logging.LogFactory;
*/
public class AggregatingContentStore extends AbstractContentStore
{
private static Log logger = LogFactory.getLog(AggregatingContentStore.class);
private static final Log logger = LogFactory.getLog(AggregatingContentStore.class);
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
@@ -266,33 +266,58 @@ public class AggregatingContentStore extends AbstractContentStore
}
/**
* @return Returns <tt>true</tt> if at least one store supports direct access
* @return Returns {@code true} if at least one store supports direct access URLs
*/
public boolean isDirectAccessSupported()
public boolean isContentDirectUrlEnabled()
{
// Check the primary store
boolean isDirectAccessSupported = primaryStore.isDirectAccessSupported();
boolean isContentDirectUrlEnabled = primaryStore.isContentDirectUrlEnabled();
if (!isDirectAccessSupported)
if (!isContentDirectUrlEnabled)
{
// Direct access is not supported by the primary store so we have to check the
// other stores
for (ContentStore store : secondaryStores)
{
isContentDirectUrlEnabled = store.isContentDirectUrlEnabled();
isDirectAccessSupported = store.isDirectAccessSupported();
if (isDirectAccessSupported)
if (isContentDirectUrlEnabled)
{
break;
}
}
}
return isDirectAccessSupported;
return isContentDirectUrlEnabled;
}
public DirectAccessUrl getDirectAccessUrl(String contentUrl, Date expiresAt)
/**
* @return Returns {@code true} if at least one store supports direct access URL for node
*/
public boolean isContentDirectUrlEnabled(NodeRef nodeRef)
{
// Check the primary store
boolean isContentDirectUrlEnabled = primaryStore.isContentDirectUrlEnabled(nodeRef);
if (!isContentDirectUrlEnabled)
{
// Direct access is not supported by the primary store so we have to check the
// other stores
for (ContentStore store : secondaryStores)
{
isContentDirectUrlEnabled = store.isContentDirectUrlEnabled(nodeRef);
if (isContentDirectUrlEnabled)
{
break;
}
}
}
return isContentDirectUrlEnabled;
}
public DirectAccessUrl requestContentDirectUrl(String contentUrl, boolean attachment, String fileName, Long validFor)
{
if (primaryStore == null)
{
@@ -312,13 +337,13 @@ public class AggregatingContentStore extends AbstractContentStore
// Check the primary store
try
{
directAccessUrl = primaryStore.getDirectAccessUrl(contentUrl, expiresAt);
directAccessUrl = primaryStore.requestContentDirectUrl(contentUrl, attachment, fileName, validFor);
}
catch (UnsupportedOperationException e)
{
// The store does not support direct access URL
directAccessUrlSupported = false;
}
}
catch (UnsupportedContentUrlException e)
{
// The store can't handle the content URL
@@ -335,7 +360,7 @@ public class AggregatingContentStore extends AbstractContentStore
{
try
{
directAccessUrl = store.getDirectAccessUrl(contentUrl, expiresAt);
directAccessUrl = store.requestContentDirectUrl(contentUrl, attachment, fileName, validFor);
}
catch (UnsupportedOperationException e)
{

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,13 +25,13 @@
*/
package org.alfresco.service.cmr.repository;
import java.util.Date;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.Auditable;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.namespace.QName;
import java.util.Date;
/**
* Provides methods for accessing and transforming content.
* <p>
@@ -168,6 +168,48 @@ public interface ContentService
* @return A direct access URL object for a binary content or returns null if not supported
* @throws IllegalArgumentException if there is no binary content for the node
*/
@Deprecated
@Auditable(parameters = {"nodeRef", "expiresAt"})
public DirectAccessUrl getDirectAccessUrl(NodeRef nodeRef, Date expiresAt);
/**
* Checks if the system and at least one store supports the retrieving of direct access URLs.
*
* @return {@code true} if direct access URLs retrieving is supported, {@code false} otherwise
*/
boolean isContentDirectUrlEnabled();
/**
* Checks if the system and store supports the retrieving of a direct access {@code URL} for the given node.
*
* @return {@code true} if direct access URLs retrieving is supported for the node, {@code false} otherwise
*/
boolean isContentDirectUrlEnabled(NodeRef nodeRef);
/**
* Gets a presigned URL to directly access the content. It is up to the actual store
* implementation if it can fulfil this request with an expiry time or not.
*
* @param nodeRef Node ref for which to obtain the direct access {@code URL}.
* @param attachment {@code true} if an attachment URL is requested, {@code false} for an embedded {@code URL}.
* @return A direct access {@code URL} object for the content.
* @throws UnsupportedOperationException if the store is unable to provide the information.
*/
default DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment)
{
return requestContentDirectUrl(nodeRef, attachment, null);
}
/**
* Gets a presigned URL to directly access the content. It is up to the actual store
* implementation if it can fulfil this request with an expiry time or not.
*
* @param nodeRef Node ref for which to obtain the direct access {@code URL}.
* @param attachment {@code true} if an attachment URL is requested, {@code false} for an embedded {@code URL}.
* @param validFor The time at which the direct access {@code URL} will expire.
* @return A direct access {@code URL} object for the content.
* @throws UnsupportedOperationException if the store is unable to provide the information.
*/
@Auditable(parameters = {"nodeRef", "validFor"})
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor);
}

View File

@@ -161,6 +161,9 @@
<property name="ignoreEmptyContent" >
<value>${policy.content.update.ignoreEmpty}</value>
</property>
<property name="systemWideDirectUrlConfig" >
<ref bean="systemWideDirectUrlConfig" />
</property>
</bean>
<bean id="contentService" parent="baseContentService">

View File

@@ -1291,7 +1291,7 @@ connector.s3.directAccessUrl.maxExpiryTimeInSec=300
# Configure the REST API configuration settings for direct access urls.
#
# Controls whether direct access url requests via the REST API are enabled.
restApi.directAccessUrl.enabled=true
restApi.directAccessUrl.enabled=false
# Sets the expiry time for all the direct access urls requested via a REST call.
# Its value cannot exceed the system-wide max expiry time configuration, it can only be equal or lower (REST API DAUs
# disabled otherwise).

View File

@@ -180,6 +180,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.audit.AuditableAnnotationTest.class,
org.alfresco.repo.audit.PropertyAuditFilterTest.class,
org.alfresco.repo.audit.access.NodeChangeTest.class,
org.alfresco.repo.content.ContentServiceImplUnitTest.class,
org.alfresco.repo.content.directurl.SystemWideDirectUrlConfigUnitTest.class,
org.alfresco.repo.content.directurl.ContentStoreDirectUrlConfigUnitTest.class,
org.alfresco.repo.content.LimitedStreamCopierTest.class,

View File

@@ -0,0 +1,160 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.content;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.directurl.DirectAccessUrlDisabledException;
import org.alfresco.repo.content.directurl.SystemWideDirectUrlConfig;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
/**
* Unit tests for content service implementation.
*
* @author Sara Aspery
*/
public class ContentServiceImplUnitTest
{
private static final Boolean ENABLED = Boolean.TRUE;
private static final Boolean DISABLED = Boolean.FALSE;
private static final Long SYS_DEFAULT_EXPIRY_TIME_IN_SECS = 30L;
private static final Long SYS_MAX_EXPIRY_TIME_IN_SECS = 300L;
private static final NodeRef NODE_REF = new NodeRef("content://Node/Ref");
@InjectMocks
private ContentServiceImpl contentService;
@Mock
private ContentStore mockContentStore;
@Mock
private NodeService mockNodeService;
@Mock
private ContentData mockContentData;
@Before
public void setup()
{
openMocks(this);
when(mockNodeService.getProperty(NODE_REF, ContentModel.PROP_CONTENT)).thenReturn(mockContentData);
when(mockContentData.getContentUrl()).thenReturn("someContentUrl");
when(mockNodeService.getProperty(NODE_REF, ContentModel.PROP_NAME)).thenReturn("someFilename");
}
@Test
public void testIsContentDirectUrlEnabled_SystemWideIsDisabled()
{
setupSystemWideDirectAccessConfig(DISABLED);
assertFalse("Expected contentDirectUrl to be disabled", contentService.isContentDirectUrlEnabled());
verify(mockContentStore, never()).isContentDirectUrlEnabled();
}
@Test
public void testIsContentDirectUrlEnabled_SystemWideIsEnabledButStoreIsDisabled()
{
setupSystemWideDirectAccessConfig(ENABLED);
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(DISABLED);
assertFalse("Expected contentDirectUrl to be disabled", contentService.isContentDirectUrlEnabled());
}
@Test
public void testIsContentDirectUrlEnabled_SystemWideIsEnabledAndStoreIsEnabled()
{
setupSystemWideDirectAccessConfig(ENABLED);
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(ENABLED);
assertTrue("Expected contentDirectUrl to be enabled", contentService.isContentDirectUrlEnabled());
}
@Test
public void testRequestContentDirectUrl_SystemWideIsDisabled()
{
setupSystemWideDirectAccessConfig(DISABLED);
try
{
contentService.requestContentDirectUrl(NODE_REF, true, 20L);
fail("Expected DirectAccessUrlDisabledException");
}
catch (DirectAccessUrlDisabledException ex)
{
verify(mockContentStore, never()).isContentDirectUrlEnabled();
}
}
@Test
public void testRequestContentDirectUrl_SystemWideIsEnabledButStoreIsDisabled()
{
setupSystemWideDirectAccessConfig(ENABLED);
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(DISABLED);
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(NODE_REF, true, 20L);
assertNull(directAccessUrl);
verify(mockContentStore, never()).requestContentDirectUrl(anyString(), eq(true), anyString(), anyLong());
}
@Test
public void testRequestContentDirectUrl_StoreIsEnabledButNotImplemented()
{
setupSystemWideDirectAccessConfig(ENABLED);
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(ENABLED);
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(NODE_REF, true, 20L);
assertNull(directAccessUrl);
verify(mockContentStore, times(1)).requestContentDirectUrl(anyString(), eq(true), anyString(), anyLong());
}
/* Helper method to set system-wide direct access url configuration settings */
private void setupSystemWideDirectAccessConfig(Boolean isEnabled)
{
SystemWideDirectUrlConfig sysConfig = new SystemWideDirectUrlConfig();
sysConfig.setEnabled(isEnabled);
sysConfig.setDefaultExpiryTimeInSec(SYS_DEFAULT_EXPIRY_TIME_IN_SECS);
sysConfig.setMaxExpiryTimeInSec(SYS_MAX_EXPIRY_TIME_IN_SECS);
sysConfig.validate();
contentService.setSystemWideDirectUrlConfig(sysConfig);
}
}

View File

@@ -35,6 +35,7 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -493,10 +494,10 @@ public class CachingContentStoreTest
@Test
public void isDirectAccessSupported()
{
assertFalse(cachingStore.isDirectAccessSupported());
assertFalse(cachingStore.isContentDirectUrlEnabled());
when(backingStore.isDirectAccessSupported()).thenReturn(true);
assertTrue(cachingStore.isDirectAccessSupported());
when(backingStore.isContentDirectUrlEnabled()).thenReturn(true);
assertTrue(cachingStore.isContentDirectUrlEnabled());
}
@Test
@@ -504,8 +505,8 @@ public class CachingContentStoreTest
{
try
{
when(backingStore.getDirectAccessUrl(anyString(), any())).thenThrow(new UnsupportedOperationException());
cachingStore.getDirectAccessUrl("url", null);
when(backingStore.requestContentDirectUrl(anyString(), eq(true), anyString(), anyLong())).thenThrow(new UnsupportedOperationException());
cachingStore.requestContentDirectUrl("url", true,"someFile", 30L);
fail();
}
catch (UnsupportedOperationException e)
@@ -517,7 +518,7 @@ public class CachingContentStoreTest
@Test
public void getDirectAccessUrl()
{
when(backingStore.getDirectAccessUrl(anyString(), any())).thenReturn(new DirectAccessUrl());
cachingStore.getDirectAccessUrl("url", null);
when(backingStore.requestContentDirectUrl(anyString(), eq(true), anyString(), anyLong())).thenReturn(new DirectAccessUrl());
cachingStore.requestContentDirectUrl("url", true,"someFile", 30L);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -56,9 +56,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@@ -191,7 +189,7 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
}
@Test
public void testIsDirectAccessSupported()
public void testIsContentDirectUrlEnabled()
{
// Create the aggregating store
AggregatingContentStore aggStore = new AggregatingContentStore();
@@ -199,21 +197,21 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
aggStore.setSecondaryStores(List.of(secondaryStoreMock));
// By default it is unsupported
assertFalse(aggStore.isDirectAccessSupported());
assertFalse(aggStore.isContentDirectUrlEnabled());
// Supported if at least one store supports direct access
{
when(primaryStoreMock.isDirectAccessSupported()).thenReturn(false);
when(secondaryStoreMock.isDirectAccessSupported()).thenReturn(true);
assertTrue(aggStore.isDirectAccessSupported());
when(primaryStoreMock.isContentDirectUrlEnabled()).thenReturn(false);
when(secondaryStoreMock.isContentDirectUrlEnabled()).thenReturn(true);
assertTrue(aggStore.isContentDirectUrlEnabled());
when(primaryStoreMock.isDirectAccessSupported()).thenReturn(true);
when(secondaryStoreMock.isDirectAccessSupported()).thenReturn(true);
assertTrue(aggStore.isDirectAccessSupported());
when(primaryStoreMock.isContentDirectUrlEnabled()).thenReturn(true);
when(secondaryStoreMock.isContentDirectUrlEnabled()).thenReturn(true);
assertTrue(aggStore.isContentDirectUrlEnabled());
when(primaryStoreMock.isDirectAccessSupported()).thenReturn(true);
when(secondaryStoreMock.isDirectAccessSupported()).thenReturn(false);
assertTrue(aggStore.isDirectAccessSupported());
when(primaryStoreMock.isContentDirectUrlEnabled()).thenReturn(true);
when(secondaryStoreMock.isContentDirectUrlEnabled()).thenReturn(false);
assertTrue(aggStore.isContentDirectUrlEnabled());
}
}
@@ -229,15 +227,15 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
UnsupportedContentUrlException unsupportedContentUrlExc = new UnsupportedContentUrlException(aggStore, "");
// By default it is unsupported
DirectAccessUrl directAccessUrl = aggStore.getDirectAccessUrl("url", null);
DirectAccessUrl directAccessUrl = aggStore.requestContentDirectUrl("url", true, "anyfilename", 30L);
assertNull(directAccessUrl);
// Direct access not supported
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
aggStore.getDirectAccessUrl("urlDANotSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlDANotSupported"), any(), any(), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.requestContentDirectUrl(eq("urlDANotSupported"), any(), any(), any())).thenThrow(unsupportedExc);
aggStore.requestContentDirectUrl(eq("urlDANotSupported"), true, "anyfilename", 30L);
fail();
}
catch (UnsupportedOperationException e)
@@ -247,9 +245,9 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
aggStore.getDirectAccessUrl("urlDANotSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlDANotSupported"), any(), any(), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.requestContentDirectUrl(eq("urlDANotSupported"), any(), any(), any())).thenThrow(unsupportedExc);
aggStore.requestContentDirectUrl("urlDANotSupported", true, "anyfilename", 30L);
fail();
}
catch (UnsupportedOperationException e)
@@ -259,9 +257,9 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlDANotSupported"), any())).thenThrow(unsupportedContentUrlExc);
aggStore.getDirectAccessUrl("urlDANotSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlDANotSupported"), any(), any(), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.requestContentDirectUrl(eq("urlDANotSupported"), any(), any(), any())).thenThrow(unsupportedContentUrlExc);
aggStore.requestContentDirectUrl("urlDANotSupported", true, "anyfilename", 30L);
fail();
}
catch (UnsupportedOperationException e)
@@ -272,9 +270,9 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
// Content url not supported
try
{
when(primaryStoreMock.getDirectAccessUrl(eq("urlNotSupported"), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlNotSupported"), any())).thenThrow(unsupportedContentUrlExc);
aggStore.getDirectAccessUrl("urlNotSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlNotSupported"), any(), any(), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.requestContentDirectUrl(eq("urlNotSupported"), any(), any(), any())).thenThrow(unsupportedContentUrlExc);
aggStore.requestContentDirectUrl("urlNotSupported", true, "anyfilename", 30L);
fail();
}
catch (UnsupportedContentUrlException e)
@@ -282,31 +280,31 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes
// Expected
}
when(primaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenThrow(unsupportedExc);
directAccessUrl = aggStore.getDirectAccessUrl("urlPriSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlPriSupported"), any(), any(), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.requestContentDirectUrl(eq("urlPriSupported"), any(), any(), any())).thenThrow(unsupportedExc);
directAccessUrl = aggStore.requestContentDirectUrl("urlPriSupported", true, "anyfilename", 30L);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenThrow(unsupportedContentUrlExc);
directAccessUrl = aggStore.getDirectAccessUrl("urlPriSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlPriSupported"), any(), any(), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.requestContentDirectUrl(eq("urlPriSupported"), any(), any(), any())).thenThrow(unsupportedContentUrlExc);
directAccessUrl = aggStore.requestContentDirectUrl("urlPriSupported", true, "anyfilename", 30L);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.getDirectAccessUrl("urlSecSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlSecSupported"), any(), any(), any())).thenThrow(unsupportedExc);
when(secondaryStoreMock.requestContentDirectUrl(eq("urlSecSupported"), any(), any(), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.requestContentDirectUrl("urlSecSupported", true, "anyfilename", 30L);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.getDirectAccessUrl("urlSecSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlSecSupported"), any(), any(), any())).thenThrow(unsupportedContentUrlExc);
when(secondaryStoreMock.requestContentDirectUrl(eq("urlSecSupported"), any(), any(), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.requestContentDirectUrl("urlSecSupported", true, "anyfilename", 30L);
assertNotNull(directAccessUrl);
when(primaryStoreMock.getDirectAccessUrl(eq("urlPriSupported"), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.getDirectAccessUrl(eq("urlSecSupported"), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.getDirectAccessUrl("urlPriSupported", null);
when(primaryStoreMock.requestContentDirectUrl(eq("urlPriSupported"), any(), any(), any())).thenReturn(new DirectAccessUrl());
when(secondaryStoreMock.requestContentDirectUrl(eq("urlSecSupported"), any(), any(), any())).thenReturn(new DirectAccessUrl());
directAccessUrl = aggStore.requestContentDirectUrl("urlPriSupported", true, "anyfilename", 30L);
assertNotNull(directAccessUrl);
directAccessUrl = aggStore.getDirectAccessUrl("urlSecSupported", null);
directAccessUrl = aggStore.requestContentDirectUrl("urlSecSupported", true, "anyfilename", 30L);
assertNotNull(directAccessUrl);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,18 +25,16 @@
*/
package org.alfresco.repo.version;
import org.alfresco.error.AlfrescoRuntimeException;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.EmptyContentReader;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.MimetypeMapTest;
import org.alfresco.repo.content.directurl.SystemWideDirectUrlConfig;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NoTransformerException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.namespace.QName;
import org.alfresco.test_category.OwnJVMTestsCategory;
@@ -44,10 +42,11 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* Tests for getting content readers and writers.
@@ -57,7 +56,9 @@ import java.util.Date;
@Category(OwnJVMTestsCategory.class)
@Transactional
public class ContentServiceImplTest extends BaseVersionStoreTest
{
{
private static final Boolean ENABLED = Boolean.TRUE;
/**
* Test content data
*/
@@ -66,9 +67,14 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
/**
* The version content store
*/
@InjectMocks
private ContentService contentService;
private ContentStore contentStore;
@Mock
private SystemWideDirectUrlConfig mockSystemWideDirectUrlConfig;
@Before
public void before() throws Exception
{
@@ -139,15 +145,17 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
}
@Test
public void testWhenGetDirectAccessUrlIsNotSupported()
public void testWhenRequestContentDirectUrlIsNotSupported()
{
assertFalse(contentStore.isDirectAccessSupported());
openMocks(this);
when(mockSystemWideDirectUrlConfig.isEnabled()).thenReturn(ENABLED);
when(mockSystemWideDirectUrlConfig.getDefaultExpiryTimeInSec()).thenReturn(30L);
when(mockSystemWideDirectUrlConfig.getMaxExpiryTimeInSec()).thenReturn(300L);
assertFalse(contentStore.isContentDirectUrlEnabled());
// Set the presigned URL to expire after one minute.
Date expiresAt = new Date();
long expTimeMillis = expiresAt.getTime();
expTimeMillis += 1000 * 60;
expiresAt.setTime(expTimeMillis);
Long validFor = 60L;
try
{
@@ -155,7 +163,7 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
NodeRef nodeRef = this.dbNodeService
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}MyNoContentNode"), TEST_TYPE_QNAME, this.nodeProperties).getChildRef();
assertEquals(null, contentService.getDirectAccessUrl(nodeRef, expiresAt));
assertNull(contentService.requestContentDirectUrl(nodeRef, true, validFor));
fail("nodeRef has no content");
}
catch (IllegalArgumentException e)
@@ -165,7 +173,7 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
try
{
assertEquals(null, contentService.getDirectAccessUrl(null, null));
assertNull(contentService.requestContentDirectUrl(null, true, null));
fail("nodeRef is null");
}
catch (IllegalArgumentException e)
@@ -176,7 +184,7 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
// Create a node with content
NodeRef nodeRef = createNewVersionableNode();
assertEquals(null, contentService.getDirectAccessUrl(nodeRef, null));
assertEquals(null, contentService.getDirectAccessUrl(nodeRef, expiresAt));
assertNull(contentService.requestContentDirectUrl(nodeRef, true, null));
assertNull(contentService.requestContentDirectUrl(nodeRef, true, validFor));
}
}