/*
* Copyright 2002 - 2013 Pentaho Corporation. All rights reserved.
*
* This software was developed by Pentaho Corporation and is provided under the terms
* of the Mozilla Public License, Version 1.1, or any later version. You may not use
* this file except in compliance with the license. If you need a copy of the license,
* please go to http://www.mozilla.org/MPL/MPL-1.1.txt. TThe Initial Developer is Pentaho Corporation.
*
* Software distributed under the Mozilla Public License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
* the license for the specific language governing your rights and limitations.
*/
package org.pentaho.platform.web.http.api.resources;
import com.sun.jersey.core.header.FormDataContentDisposition;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.pentaho.platform.api.engine.PentahoAccessControlException;
import org.pentaho.platform.plugin.services.importer.PlatformImportException;
import org.pentaho.platform.web.http.api.resources.services.RepositoryPublishService;
import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import static javax.ws.rs.core.Response.Status.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import static org.pentaho.platform.plugin.services.importer.PlatformImportException.PUBLISH_GENERAL_ERROR;
import static org.pentaho.platform.plugin.services.importer.PlatformImportException.PUBLISH_USERNAME_PASSWORD_FAIL;
public class RepositoryPublishResourceTest {
RepositoryPublishResource repositoryPublishResource;
@Before
public void setUp() {
repositoryPublishResource = spy( new RepositoryPublishResource() );
repositoryPublishResource.repositoryPublishService = mock( RepositoryPublishService.class );
}
@After
public void tearDown() {
repositoryPublishResource = null;
}
@Test
public void testWriteFile() throws Exception {
String pathId = "pathId";
InputStream fileContents = emptyStream();
FormDataContentDisposition mockFormDataContentDisposition = mock( FormDataContentDisposition.class );
doNothing().when( repositoryPublishResource.repositoryPublishService )
.writeFile( pathId, fileContents, true );
String okResponseText = "SUCCESS";
Response testResponse =
repositoryPublishResource.writeFile( pathId, fileContents, true, mockFormDataContentDisposition );
assertResponse( testResponse, OK, okResponseText );
verify( repositoryPublishResource.repositoryPublishService, times( 1 ) )
.writeFile( pathId, fileContents, true );
verify( repositoryPublishResource, times( 1 ) ).buildPlainTextOkResponse( okResponseText );
}
@Test
public void testWriteFileError() throws Exception {
String pathId = "pathId";
InputStream fileContents = mock( InputStream.class );
Boolean overwriteFile = Boolean.TRUE;
FormDataContentDisposition mockFormDataContentDisposition = mock( FormDataContentDisposition.class );
Response mockUnauthorizedResponse = mock( Response.class );
doReturn( mockUnauthorizedResponse ).when( repositoryPublishResource )
.buildStatusResponse( UNAUTHORIZED, PlatformImportException.PUBLISH_USERNAME_PASSWORD_FAIL );
int errorStatus = 0;
Response mockPreconditionFailedResponse = mock( Response.class );
doReturn( mockPreconditionFailedResponse ).when( repositoryPublishResource )
.buildStatusResponse( PRECONDITION_FAILED, errorStatus );
Response mockServerErrorResponse = mock( Response.class );
doReturn( mockServerErrorResponse ).when( repositoryPublishResource )
.buildServerErrorResponse( PUBLISH_GENERAL_ERROR );
// Test 1
Exception mockPentahoAccessControlException = mock( PentahoAccessControlException.class );
doThrow( mockPentahoAccessControlException ).when( repositoryPublishResource.repositoryPublishService )
.writeFile( pathId, fileContents, overwriteFile );
Response testResponse =
repositoryPublishResource.writeFile( pathId, fileContents, overwriteFile, mockFormDataContentDisposition );
assertEquals( mockUnauthorizedResponse, testResponse );
// Test 2
PlatformImportException mockPlatformImportException = mock( PlatformImportException.class );
doReturn( errorStatus ).when( mockPlatformImportException ).getErrorStatus();
doThrow( mockPlatformImportException ).when( repositoryPublishResource.repositoryPublishService )
.writeFile( pathId, fileContents, overwriteFile );
testResponse =
repositoryPublishResource.writeFile( pathId, fileContents, overwriteFile, mockFormDataContentDisposition );
assertEquals( mockPreconditionFailedResponse, testResponse );
// Test 3
Exception mockException = mock( RuntimeException.class );
doThrow( mockException ).when( repositoryPublishResource.repositoryPublishService )
.writeFile( pathId, fileContents, overwriteFile );
testResponse =
repositoryPublishResource.writeFile( pathId, fileContents, overwriteFile, mockFormDataContentDisposition );
assertEquals( mockServerErrorResponse, testResponse );
verify( repositoryPublishResource.repositoryPublishService, times( 3 ) )
.writeFile( pathId, fileContents, overwriteFile );
verify( repositoryPublishResource, times( 1 ) ).buildStatusResponse( UNAUTHORIZED,
PlatformImportException.PUBLISH_USERNAME_PASSWORD_FAIL );
verify( repositoryPublishResource, times( 1 ) ).buildStatusResponse( PRECONDITION_FAILED, errorStatus );
verify( repositoryPublishResource, times( 1 ) )
.buildServerErrorResponse( PUBLISH_GENERAL_ERROR );
}
@Test
public void writeFileWithEncodedName_Returns200_OnSuccess() throws Exception {
final String originalFile = "my-ktr.ktr";
final String originalPath = "/public/" + originalFile;
doReturn( false ).when( repositoryPublishResource ).invalidPath( originalPath );
Response shouldBeOk = repositoryPublishResource
.writeFileWithEncodedName( encode( originalPath ), emptyStream(), true, dummyInfo( originalFile ) );
assertResponse( shouldBeOk, OK, "SUCCESS" );
verify( repositoryPublishResource.repositoryPublishService, times( 1 ) )
.publishFile( eq( originalPath ), any( InputStream.class ), eq( true ) );
}
@Test
public void writeFileWithEncodedName_Returns422_OnPathWithReservedChars() throws Exception {
final String originalFile = "my\nktr.ktr";
final String originalPath = "/public/" + originalFile;
doReturn( true ).when( repositoryPublishResource ).invalidPath( originalPath );
Response shouldBeUnprocessableEntity = repositoryPublishResource
.writeFileWithEncodedName( encode( originalPath ), emptyStream(), true, dummyInfo( originalFile ) );
assertResponse( shouldBeUnprocessableEntity, 422,
"Cannot publish [" + originalPath + "] because it contains reserved character(s)" );
verify( repositoryPublishResource.repositoryPublishService, never() )
.writeFile( eq( originalPath ), any( InputStream.class ), eq( true ) );
}
@Test
public void writeFileWithEncodedName_Returns500_OnUnexpectedError() throws Exception {
testWriteFileWithEncodedName_OnError(
new RuntimeException( "unexpected" ),
INTERNAL_SERVER_ERROR, PUBLISH_GENERAL_ERROR );
}
@Test
public void writeFileWithEncodedName_Returns401_OnUnauthorizedAccess() throws Exception {
testWriteFileWithEncodedName_OnError(
new PentahoAccessControlException( "unauthorized" ),
UNAUTHORIZED, PUBLISH_USERNAME_PASSWORD_FAIL );
}
@Test
public void writeFileWithEncodedName_Returns412_OnPlatformImportException() throws Exception {
final int someCode = 50;
testWriteFileWithEncodedName_OnError(
new PlatformImportException( "import exception", someCode ),
PRECONDITION_FAILED, someCode );
}
private void testWriteFileWithEncodedName_OnError( Exception thrownException, Response.Status expectedStatus,
int expectedErrorCode ) throws Exception {
final String originalFile = "my-ktr.ktr";
final String originalPath = "/public/" + originalFile;
doReturn( false ).when( repositoryPublishResource ).invalidPath( originalPath );
doThrow( thrownException ).when( repositoryPublishResource.repositoryPublishService )
.publishFile( eq( originalPath ), any( InputStream.class ), eq( true ) );
Response response = repositoryPublishResource
.writeFileWithEncodedName( encode( originalPath ), emptyStream(), true, dummyInfo( originalFile ) );
assertResponse( response, expectedStatus, String.valueOf( expectedErrorCode ) );
}
@Test
public void writeFileWithEncodedName_DecodesPathAndName() throws Exception {
final String originalFile = "my-\"quoted\".ktr";
final String originalPath = "/public/" + originalFile;
doReturn( false ).when( repositoryPublishResource ).invalidPath( originalPath );
repositoryPublishResource.writeFileWithEncodedName(
encode( originalPath ), emptyStream(), true, dummyInfo( originalFile ) );
// decodes path
verify( repositoryPublishResource.repositoryPublishService, times( 1 ) )
.publishFile( eq( originalPath ), any( InputStream.class ), eq( true ) );
}
private static String encode( String originalPath ) throws UnsupportedEncodingException {
return URLEncoder.encode( originalPath, "UTF-8" );
}
private static InputStream emptyStream() {
return new ByteArrayInputStream( new byte[ 0 ] );
}
private static FormDataContentDisposition dummyInfo( String fileName ) throws Exception {
return FormDataContentDisposition
.name( "name" ).size( 1 ).fileName( encode( fileName ) )
.creationDate( new Date( 0 ) )
.modificationDate( new Date( 1 ) )
.readDate( new Date( 2 ) )
.build();
}
private static void assertResponse( Response actual, Response.Status expectedStatus, Object expectedEntity ) {
assertResponse( actual, expectedStatus.getStatusCode(), expectedEntity );
}
private static void assertResponse( Response actual, int expectedCode, Object expectedEntity ) {
assertNotNull( "Response should not be null", actual );
assertEquals( expectedCode, actual.getStatus() );
assertEquals( expectedEntity, actual.getEntity() );
}
}