/*
 * #%L
 * Alfresco Repository
 * %%
 * Copyright (C) 2005 - 2016 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.filesys.repo;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.transaction.UserTransaction;
import javax.xml.ws.Holder;

import junit.framework.TestCase;

import org.alfresco.filesys.alfresco.ExtendedDiskInterface;
import org.alfresco.jlan.server.NetworkServer;
import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.auth.ClientInfo;
import org.alfresco.jlan.server.config.ServerConfiguration;
import org.alfresco.jlan.server.core.DeviceContextException;
import org.alfresco.jlan.server.core.SharedDevice;
import org.alfresco.jlan.server.filesys.AccessDeniedException;
import org.alfresco.jlan.server.filesys.AccessMode;
import org.alfresco.jlan.server.filesys.DiskSharedDevice;
import org.alfresco.jlan.server.filesys.FileAction;
import org.alfresco.jlan.server.filesys.FileAttribute;
import org.alfresco.jlan.server.filesys.FileExistsException;
import org.alfresco.jlan.server.filesys.FileInfo;
import org.alfresco.jlan.server.filesys.FileOpenParams;
import org.alfresco.jlan.server.filesys.NetworkFile;
import org.alfresco.jlan.server.filesys.NetworkFileServer;
import org.alfresco.jlan.server.filesys.PermissionDeniedException;
import org.alfresco.jlan.server.filesys.SearchContext;
import org.alfresco.jlan.server.filesys.TreeConnection;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.management.subsystems.ApplicationContextFactory;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.transfer.TransferModel;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionCondition;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
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.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.rule.RuleType;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.test_category.BaseSpringTestsCategory;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;

/**
 * Unit tests for Alfresco Repository ContentDiskDriver
 */
@Category(BaseSpringTestsCategory.class)
public class ContentDiskDriverTest extends TestCase
{
    private static final String TEST_PROTOTYPE_NAME = "test";
    private static final String TEST_REMOTE_NAME = "remoteName";
    private static final String TEST_SERVER_NAME = "testServer";

    private static final String TEST_USER_AUTHORITY = "userx";

    private Repository repositoryHelper;
    private CifsHelper cifsHelper;
    private ExtendedDiskInterface driver;
    private NodeService mlAwareNodeService;
    private NodeService nodeService;
    private TransactionService transactionService;
    private ContentService contentService;
    private RuleService ruleService;
    private ActionService actionService;
    private PersonService personService;
    private MutableAuthenticationService authenticationService;
    private PermissionService permissionService;
    private OwnableService ownableService;
    private FileFolderService fileFolderService;
    private CheckOutCheckInService checkOutCheckInService;
    
    private static Log logger = LogFactory.getLog(ContentDiskDriverTest.class);

    final String SHARE_NAME = "test";
    final String STORE_NAME = "workspace://SpacesStore";
    final String ROOT_PATH = "/app:company_home";
    
    private ApplicationContext applicationContext;
    
    private final String TEST_ROOT_PATH="ContentDiskDriverTest";
    private final String TEST_ROOT_DOS_PATH="\\"+TEST_ROOT_PATH;
    
    @Override
    protected void setUp() throws Exception
    {
        applicationContext = ApplicationContextHelper.getApplicationContext();
        repositoryHelper = (Repository)this.applicationContext.getBean("repositoryHelper");
        ApplicationContextFactory fileServers = (ApplicationContextFactory) this.applicationContext.getBean("fileServers");
        cifsHelper = (CifsHelper) fileServers.getApplicationContext().getBean("cifsHelper");
        driver = (ExtendedDiskInterface)this.applicationContext.getBean("contentDiskDriver");
        mlAwareNodeService = (NodeService) this.applicationContext.getBean("mlAwareNodeService"); 
        nodeService = (NodeService)applicationContext.getBean("nodeService");
        transactionService = (TransactionService)applicationContext.getBean("transactionService");
        contentService = (ContentService)applicationContext.getBean("contentService");
        ruleService = (RuleService)applicationContext.getBean("ruleService");
        actionService = (ActionService)this.applicationContext.getBean("actionService");
        personService = (PersonService) this.applicationContext.getBean("personService");
        authenticationService = (MutableAuthenticationService) this.applicationContext.getBean("authenticationService");
        permissionService = (PermissionService) this.applicationContext.getBean("permissionService");
        ownableService = (OwnableService) this.applicationContext.getBean("ownableService");
        fileFolderService = (FileFolderService) this.applicationContext.getBean("fileFolderService");
        checkOutCheckInService = (CheckOutCheckInService) this.applicationContext.getBean("checkOutCheckInService");
        
        assertNotNull("content disk driver is null", driver);
        assertNotNull("repositoryHelper is null", repositoryHelper);
        assertNotNull("mlAwareNodeService is null", mlAwareNodeService);
        assertNotNull("nodeService is null", nodeService);
        assertNotNull("transactionService is null", transactionService);
        assertNotNull("contentService is null", contentService);
        assertNotNull("ruleService is null", ruleService);
        assertNotNull("actionService is null", actionService);
        assertNotNull("cifsHelper", cifsHelper);
        assertNotNull("checkOutCheckInService", checkOutCheckInService);
        
        AuthenticationUtil.setRunAsUserSystem();
        
        // remove our test root 
        RetryingTransactionCallback<Void> removeRootCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef rootNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, TEST_ROOT_PATH);
                if(rootNode != null)
                {
                    logger.debug("Clean up test root node");
                    nodeService.deleteNode(rootNode);
                }
                return null;
            }
        };
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        tran.doInTransaction(removeRootCB, false, true);
        
    }
    
    @Override
    protected void tearDown() throws Exception
    {
    }

    private DiskSharedDevice getDiskSharedDevice() throws DeviceContextException
    {
        
        ContentContext ctx = new ContentContext( "testContext", STORE_NAME, ROOT_PATH, repositoryHelper.getCompanyHome());
      
        DiskSharedDevice share = new DiskSharedDevice("test", driver, ctx);        
        return share;
    }
    
    /**
     * Test Get File Information
     */
    public void testGetFileInformation() throws Exception
    {
        logger.debug("testGetFileInformation");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        class TestContext
        {     
            NodeRef testNodeRef;    
        };
        
        final TestContext testContext = new TestContext();

        /**
         * Test 1 : Get the root info
         */
        FileInfo finfo = driver.getFileInformation(testSession, testConnection, "");
        assertNotNull("root info is null", finfo);
        assertEquals("root has a unexpected file name", "", finfo.getFileName());
        
    }

    /**
     * Test Create File
     */
    public void testCreateFile() throws Exception
    {
        logger.debug("testCreatedFile");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        class TestContext
        {     
            NodeRef testNodeRef;    
        };
        
        final TestContext testContext = new TestContext();
      
        /**
          * Step 1 : Create a new file in read/write mode and add some content.
           */
        int openAction = FileAction.CreateNotExist;
        

        final String FILE_NAME="testCreateFileX.new";
        final String FILE_PATH="\\"+FILE_NAME;
                  
        FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                
        final NetworkFile file = driver.createFile(testSession, testConnection, params);
        assertNotNull("file is null", file);
        assertFalse("file is read only, should be read-write", file.isReadOnly());
        assertFalse("file is not closed ", file.isClosed());
        
        RetryingTransactionCallback<Void> writeStuffCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                byte[] stuff = "Hello World".getBytes();
                driver.writeFile(testSession, testConnection, file, stuff, 0, stuff.length, 0);
                driver.closeFile(testSession, testConnection, file); 
                return null;
            }
        };
        tran.doInTransaction(writeStuffCB);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                testContext.testNodeRef = newNode;
                assertNotNull("can't find new node", newNode);
                Serializable content = nodeService.getProperty(newNode, ContentModel.PROP_CONTENT);
                assertNotNull("content is null", content);       
                return null;
            }
        };
        tran.doInTransaction(validateCB);
        
        // now validate that the new node is in the correct location and has the correct name
        FileInfo info = driver.getFileInformation(testSession, testConnection, FILE_PATH);
        assertNotNull("info is null", info);
        
        NodeRef n2 = getNodeForPath(testConnection, FILE_PATH);
        assertEquals("get Node For Path returned different node", testContext.testNodeRef, n2);
        
        /**
         * Step 2 : Negative Test Attempt to create the same file again
         */
        try
        {
            driver.createFile(testSession, testConnection, params);
            fail("File exists not detected");
        }
        catch (FileExistsException fe)
        {
            // expect to go here
        }
        
        // Clean up so we could run the test again
        driver.deleteFile(testSession, testConnection, FILE_PATH);

        /**
         * Step 3 : create a file in a new directory in read only mode
         */        
        String FILE2_PATH = TEST_ROOT_DOS_PATH + FILE_PATH;
        
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, openAction, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);
        
        FileOpenParams file2Params = new FileOpenParams(FILE2_PATH, openAction, AccessMode.ReadOnly, FileAttribute.NTNormal, 0);
        NetworkFile file2 = driver.createFile(testSession, testConnection, file2Params);
        
        // clean up so we could run the test again
        driver.deleteFile(testSession, testConnection, FILE2_PATH);
    }
    
    /**
     * Unit test of delete file
     */
    public void testDeleteFile() throws Exception
    {
        logger.debug("testDeleteFile");
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();

        TreeConnection testConnection = testServer.getTreeConnection(share);
        
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Step 1 : Create a new file in read/write mode and add some content.
         */
        int openAction = FileAction.CreateNotExist;
        String FILE_PATH="\\testDeleteFile.new";
          
        FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                
        final NetworkFile file = driver.createFile(testSession, testConnection, params);
        assertNotNull("file is null", file);
        assertFalse("file is read only, should be read-write", file.isReadOnly());
            
        RetryingTransactionCallback<Void> writeStuffCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                byte[] stuff = "Hello World".getBytes();
                file.writeFile(stuff, stuff.length, 0, 0);
                file.close();  // needed to actually flush content to node
                return null;
            }
        };
        tran.doInTransaction(writeStuffCB);
                 
        /**
          * Step 1: Delete file by path
          */
        driver.deleteFile(testSession, testConnection, FILE_PATH);
        
        /**
         * Step 2: Negative test - Delete file again
         */
        try
        {
            driver.deleteFile(testSession, testConnection, FILE_PATH);
            fail("delete a non existent file");
        }
        catch (IOException fe)
        {
                // expect to go here
        }
    }
    
    /**
     * Test Set Info
     * 
     * Three flags set
     * <ol>
     * <li>SetDeleteOnClose</li>
     * <li>SetCreationDate</li>
     * <li>SetModifyDate</li>
     * </ol>
     */
    public void testSetFileInfo() throws Exception
    {
        logger.debug("testSetFileInfo");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        Date now = new Date();
        
        // CREATE 6 hours ago
        final Date CREATED = new Date(now.getTime() - 1000 * 60 * 60 * 6);
        // Modify one hour ago
        final Date MODIFIED = new Date(now.getTime() - 1000 * 60 * 60 * 1);
        
        class TestContext
        {     
            NodeRef testNodeRef;    
        };
        
        final TestContext testContext = new TestContext();
        

      
        /**
          * Step 1 : Create a new file in read/write mode and add some content.
          * Call SetInfo to set the creation date
          */
        int openAction = FileAction.CreateNotExist;
        
        final String FILE_NAME="testSetFileInfo.txt";
        final String FILE_PATH="\\"+FILE_NAME;
        
        // Clean up junk if it exists
        try
        {
            driver.deleteFile(testSession, testConnection, FILE_PATH);
        }
        catch (IOException ie)
        {
           // expect to go here
        }
                  
        final FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                
        final NetworkFile file = driver.createFile(testSession, testConnection, params);
        assertNotNull("file is null", file);
        assertFalse("file is read only, should be read-write", file.isReadOnly());
        
        RetryingTransactionCallback<Void> writeStuffCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                byte[] stuff = "Hello World".getBytes();
                
                driver.writeFile(testSession, testConnection, file, stuff, 0, stuff.length, 0);
                driver.closeFile(testSession, testConnection, file);
                              
                FileInfo info = driver.getFileInformation(testSession, testConnection, FILE_PATH);
                info.setFileInformationFlags(FileInfo.SetModifyDate);
                info.setModifyDateTime(MODIFIED.getTime());
                driver.setFileInformation(testSession, testConnection, FILE_PATH, info);
                return null;
            }
        };
        tran.doInTransaction(writeStuffCB);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                testContext.testNodeRef = newNode;
                assertNotNull("can't find new node", newNode);
                Serializable content = nodeService.getProperty(newNode, ContentModel.PROP_CONTENT);
                assertNotNull("content is null", content);     
                Date modified = (Date)nodeService.getProperty(newNode, ContentModel.PROP_MODIFIED);
                assertEquals("modified time not set correctly", MODIFIED, modified);
                return null;
            }
        };
        tran.doInTransaction(validateCB);
        
        /**
         * Step 2: Change the created date
         */
        logger.debug("Step 2: Change the created date");
        RetryingTransactionCallback<Void> changeCreatedCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileInfo info = driver.getFileInformation(testSession, testConnection, FILE_PATH);
                info.setFileInformationFlags(FileInfo.SetCreationDate);
                info.setCreationDateTime(CREATED.getTime());
                driver.setFileInformation(testSession, testConnection, FILE_PATH, info);
                return null;
            }
        };
        tran.doInTransaction(changeCreatedCB);
  
        RetryingTransactionCallback<Void> validateCreatedCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                testContext.testNodeRef = newNode;
                assertNotNull("can't find new node", newNode);
                Serializable content = nodeService.getProperty(newNode, ContentModel.PROP_CONTENT);
                assertNotNull("content is null", content);     
                Date created = (Date)nodeService.getProperty(newNode, ContentModel.PROP_CREATED);
                assertEquals("created time not set correctly", CREATED, created);
                return null;
            }
        };
        tran.doInTransaction(validateCreatedCB);
        
        /**
         * Step 3: Test 
         */
        logger.debug("Step 3: test deleteOnClose");
        RetryingTransactionCallback<Void> deleteOnCloseCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NetworkFile f2 = driver.openFile(testSession, testConnection, params);
                 
               FileInfo info = driver.getFileInformation(testSession, testConnection, FILE_PATH);
               info.setFileInformationFlags(FileInfo.SetDeleteOnClose);
               driver.setFileInformation(testSession, testConnection, FILE_PATH, info);
               file.setDeleteOnClose(true);
               
               byte[] stuff = "Update".getBytes();              
               driver.writeFile(testSession, testConnection, file, stuff, 0, stuff.length, 0);
               driver.closeFile(testSession, testConnection, file);
             
               return null;
            }
        };
        tran.doInTransaction(deleteOnCloseCB);
  
        RetryingTransactionCallback<Void> validateDeleteOnCloseCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                assertNull("can still find new node", newNode);
                return null;
            }
        };
        tran.doInTransaction(validateDeleteOnCloseCB);
        
        // clean up so we could run the test again
        //driver.deleteFile(testSession, testConnection, FILE_PATH);    
        
    } // test set file info

    
    /**
     * Test Open File
     */
    public void testOpenFile() throws Exception
    {    
        logger.debug("testOpenFile");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        class TestContext
        {
            NodeRef testDirNodeRef;
        };
        
        final TestContext testContext = new TestContext();
        
        final String FILE_NAME="testOpenFile.txt";
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);  
        
        testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_ROOT_DOS_PATH);

        /**
         * Step 1 : Negative test - try to open a file that does not exist
         */
        final String FILE_PATH= TEST_ROOT_DOS_PATH + "\\" + FILE_NAME;
          
        FileOpenParams params = new FileOpenParams(FILE_PATH, FileAction.CreateNotExist, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        try
        {
            NetworkFile file = driver.openFile(testSession, testConnection, params);
            fail ("managed to open non existant file!");
        }
        catch (IOException ie)
        {
           // expect to go here
        }
        
        /**
         * Step 2: Now create the file through the node service and open it.
         */
        logger.debug("Step 2) Open file created by node service");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                ChildAssociationRef ref = nodeService.createNode(testContext.testDirNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FILE_NAME), ContentModel.TYPE_CONTENT);
                nodeService.setProperty(ref.getChildRef(), ContentModel.PROP_NAME, FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        NetworkFile file = driver.openFile(testSession, testConnection, params);
        assertNotNull(file);
        assertFalse("file is closed", file.isClosed());
        
        /**
         * Step 3: Open the root directory.
         */
        logger.debug("Step 3) Open the root directory");
        
        FileOpenParams rootParams = new FileOpenParams("\\", FileAction.CreateNotExist, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        NetworkFile file3 = driver.openFile(testSession, testConnection, rootParams);
        assertNotNull(file3);
        assertFalse("file is closed", file3.isClosed());

                
    } // testOpenFile

    
    /**
     * Unit test of file exists
     */
    public void testFileExists() throws Exception
    {
        logger.debug("testFileExists");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        final String FILE_PATH= TEST_ROOT_DOS_PATH + "\\testFileExists.new";
        
        class TestContext
        {
        };
        
        final TestContext testContext = new TestContext();
       
        /**
         * Step 1 : Call FileExists for a directory which does not exist
         */
        logger.debug("Step 1, negative test dir does not exist");
        int status = driver.fileExists(testSession, testConnection, TEST_ROOT_DOS_PATH);
        assertEquals(status, 0);
  
        /**
         * Step 2 : Call FileExists for a file which does not exist
         */
        logger.debug("Step 2, negative test file does not exist");
        status = driver.fileExists(testSession, testConnection, FILE_PATH);
        assertEquals(status, 0);
        
        /**
         * Step 3: Create a new file in read/write mode and add some content.
         */
        int openAction = FileAction.CreateNotExist;

        FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
 
        driver.createDirectory(testSession, testConnection, dirParams);        
        final NetworkFile file = driver.createFile(testSession, testConnection, params);
        assertNotNull("file is null", file);
        assertFalse("file is read only, should be read-write", file.isReadOnly());
        
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                byte[] stuff = "Hello World".getBytes();
                file.writeFile(stuff, stuff.length, 0, 0);
                driver.closeFile(testSession, testConnection, file);
            
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
         
        status = driver.fileExists(testSession, testConnection, FILE_PATH);
        assertEquals(status, 1);
         
        /**
          * Step 4 : Delete the node - check status goes back to 0
          */
        logger.debug("Step 4, successfully delete node");
        driver.deleteFile(testSession, testConnection, FILE_PATH);
        
        status = driver.fileExists(testSession, testConnection, FILE_PATH);
        assertEquals(status, 0);  
   
    } // testFileExists
    
    /**
     * Unit test of rename file
     */
    public void testRenameFile() throws Exception
    {  
        logger.debug("testRenameFile");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);

        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
 
        final String FILE_PATH1=TEST_ROOT_DOS_PATH + "\\SourceFile1.new";
        final String FILE_NAME2 = "SourceFile2.new";
        final String FILE_PATH2=TEST_ROOT_DOS_PATH +"\\" + FILE_NAME2;
        final String FILE_PATH3=TEST_ROOT_DOS_PATH +"\\SourceFile3.new";
        
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);

        FileOpenParams params1 = new FileOpenParams(FILE_PATH1, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        final NetworkFile file1 = driver.createFile(testSession, testConnection, params1);
  
        FileOpenParams params3 = new FileOpenParams(FILE_PATH3, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        final NetworkFile file3 = driver.createFile(testSession, testConnection, params3);
        
        /**
         * Step 1 : Negative test, Call Rename for a file which does not exist
        */
        try
        {
            driver.renameFile(testSession, testConnection, "\\Wibble\\wobble", FILE_PATH1);
            fail("rename did not detect missing file");
        }
        catch (IOException e)
        {
            // expect to go here
        }
          
        /**
         * Step 2: Negative test, Call Rename for a destination that does not exist.
         */
        try
        {
            driver.renameFile(testSession, testConnection, FILE_PATH1, "\\wibble\\wobble");
            fail("rename did not detect missing file");
        }
        catch (IOException e)
        {
            // expect to go here
        }
        
        /**
         * Step 3: Rename a file to a destination that is a file rather than a directory
         */
        try
        {
            driver.renameFile(testSession, testConnection, FILE_PATH1, FILE_PATH3);
            fail("rename did not detect missing file");
        }
        catch (IOException e)
        {
            // expect to go here
        }
                 
        /**
         * Step 4: Successfully rename a file - check the name, props and content.
         */
        final String LAST_NAME= "Bloggs";
        
        RetryingTransactionCallback<Void> setPropertiesCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                final NodeRef file1NodeRef = getNodeForPath(testConnection, FILE_PATH1);
                assertNotNull("node ref not found", file1NodeRef);
                nodeService.setProperty(file1NodeRef, ContentModel.PROP_LASTNAME, LAST_NAME);
         
                return null;
            }
        };
        tran.doInTransaction(setPropertiesCB, false, true);
        
        driver.renameFile(testSession, testConnection, FILE_PATH1, FILE_PATH2);
       
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef file2NodeRef = getNodeForPath(testConnection, FILE_PATH2);
                //assertEquals("node ref has changed on a rename", file1NodeRef, file2NodeRef);
                assertEquals(nodeService.getProperty(file2NodeRef, ContentModel.PROP_LASTNAME), LAST_NAME);
                ChildAssociationRef parentRef = nodeService.getPrimaryParent(file2NodeRef);
                assertTrue("file has wrong assoc local name", parentRef.getQName().getLocalName().equals(FILE_NAME2));
                assertTrue("not primary assoc", parentRef.isPrimary());

                return null;
            }
        };
        tran.doInTransaction(validateCB, false, true);

        /**
         * Step 5: Rename to another directory
         */
        String DIR_NEW_PATH = TEST_ROOT_DOS_PATH + "\\NewDir";
        final String NEW_PATH = DIR_NEW_PATH + "\\File2";
        FileOpenParams params5 = new FileOpenParams(DIR_NEW_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        driver.createDirectory(testSession, testConnection, params5);
        
        final NodeRef newDirNodeRef = getNodeForPath(testConnection, DIR_NEW_PATH);
        
        driver.renameFile(testSession, testConnection, FILE_PATH2, NEW_PATH);
        
        RetryingTransactionCallback<Void> validateStep5CB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef file5NodeRef = getNodeForPath(testConnection, NEW_PATH);
                ChildAssociationRef parentRef5 = nodeService.getPrimaryParent(file5NodeRef);
                
                assertTrue(parentRef5.getParentRef().equals(newDirNodeRef));
          
                return null;
            }
        };
        tran.doInTransaction(validateStep5CB, false, true);
        
//        /** 
//         * Step 5: rename to self - check no damage.
//         */
//        try
//        {
//            driver.renameFile(testSession, testConnection, FILE_PATH2, FILE_PATH2);
//            fail("rename did not detect rename to self");
//        }
//        catch (IOException e)
//        {
            // expect to go here
//        }
        
    } // testRenameFile


    /**
     * Unit test of rename versionable file
     */
    public void testScenarioRenameVersionableFile() throws Exception
    {  
        logger.debug("testScenarioRenameVersionableFile");
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        final String FILE_PATH1=TEST_ROOT_DOS_PATH + "\\SourceFile1.new";
        final String FILE_PATH2=TEST_ROOT_DOS_PATH + "\\SourceFile2.new";
        
        class TestContext
        {
        };
        
        final TestContext testContext = new TestContext();
   
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);

        FileOpenParams params1 = new FileOpenParams(FILE_PATH1, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        NetworkFile file1 = driver.createFile(testSession, testConnection, params1);
        
        /**
         * Make Node 1 versionable
         */
        final String LAST_NAME= "Bloggs";
         
        RetryingTransactionCallback<Void> makeVersionableCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef file1NodeRef = getNodeForPath(testConnection, FILE_PATH1);
                nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                ContentWriter contentWriter2 = contentService.getWriter(file1NodeRef, ContentModel.PROP_CONTENT, true);
                contentWriter2.putContent("test rename versionable");
                
                nodeService.setProperty(file1NodeRef, ContentModel.PROP_LASTNAME, LAST_NAME);
                nodeService.setProperty(file1NodeRef, TransferModel.PROP_ENDPOINT_PROTOCOL, "http");

                return null;
            }
        };
        tran.doInTransaction(makeVersionableCB, false, true);
  
        /**
         * Step 1: Successfully rename a versionable file - check the name, props and content.
         * TODO Check primary assoc, peer assocs, child assocs, modified date, created date, nodeid, permissions.
         */
        driver.renameFile(testSession, testConnection, FILE_PATH1, FILE_PATH2);
        
        RetryingTransactionCallback<Void> validateVersionableCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef file2NodeRef = getNodeForPath(testConnection, FILE_PATH2);
                assertNotNull("file2 node ref is null", file2NodeRef);
                //assertEquals(nodeService.getProperty(file2NodeRef, ContentModel.PROP_LASTNAME), LAST_NAME);
                assertTrue("does not have versionable aspect", nodeService.hasAspect(file2NodeRef, ContentModel.ASPECT_VERSIONABLE));   
                assertTrue("sample property is null", nodeService.getProperty(file2NodeRef, TransferModel.PROP_ENDPOINT_PROTOCOL) != null);     
                
                return null;
            }
        };
        tran.doInTransaction(validateVersionableCB, false, true);

    } // testRenameVersionable
    

    /**
     * This test tries to simulate the shuffling that is done by MS Word 2003 upon file save
     * 
     * a) TEST.DOC
     * b) Save to ~WRDnnnn.TMP
     * c) Delete ~WRLnnnn.TMP
     * d) Rename TEST.DOC ~WDLnnnn.TMP
     * e) Delete TEST.DOC
     * f) Rename ~WRDnnnn.TMP to TEST.DOC
     * g) Delete ~WRLnnnn.TMP
     * 
     * We need to check that properties, aspects, primary assocs, secondary assocs, peer assocs, node type, 
     * version history, creation date are maintained.
     */
    public void testScenarioMSWord2003SaveShuffle() throws Exception
    {
        logger.debug("testScenarioMSWord2003SaveShuffle");
        final String FILE_NAME = "TEST.DOC";
        final String FILE_TITLE = "Test document";
        final String FILE_DESCRIPTION = "This is a test document to test CIFS shuffle";
        final String FILE_OLD_TEMP = "~WRL0002.TMP";
        final String FILE_NEW_TEMP = "~WRD0002.TMP";
        
        final QName RESIDUAL_MTTEXT = QName.createQName("{gsxhjsx}", "whatever");
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;
            NetworkFile oldFileHandle;
            
            NodeRef testNodeRef;   // node ref of test.doc
            
            Serializable testCreatedDate;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSWord2003SaveShuffle";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
  
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // now load up the node with lots of other stuff that we will test to see if it gets preserved during the
                // shuffle.
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                
                // test non CM namespace property
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                // test CM property not related to an aspect
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_ADDRESSEE, "Fred");
                
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_TITLE, FILE_TITLE);
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_DESCRIPTION, FILE_DESCRIPTION);
                
                /**
                 * MLText value - also a residual value in a non cm namespace
                 */
                MLText mltext = new MLText();
                mltext.addValue(Locale.FRENCH, "Bonjour");
                mltext.addValue(Locale.ENGLISH, "Hello");
                mltext.addValue(Locale.ITALY, "Buongiorno");
                mlAwareNodeService.setProperty(testContext.testNodeRef, RESIDUAL_MTTEXT, mltext);

                // classifiable chosen since its not related to any properties.
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_CLASSIFIABLE, null);
                //nodeService.createAssociation(testContext.testNodeRef, targetRef, assocTypeQName);
        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        /**
         * Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "MS Word 2003 shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();   
                
                testContext.testCreatedDate = nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_CREATED);
                
                MLText multi = (MLText)mlAwareNodeService.getProperty(testContext.testNodeRef, RESIDUAL_MTTEXT) ;
                multi.getValues();
     
     
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * b) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "MS Word 2003 shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.newFileHandle.close();
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB, false, true);
        
        /**
         * rename the old file
         */
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
        

        RetryingTransactionCallback<Void> validateOldFileGoneCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                try
                {
                    driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                }
                catch (IOException e)
                { 
                    // expect to go here since previous step renamed the file.
                }
                
                return null;
            }
        };
        tran.doInTransaction(validateOldFileGoneCB, false, true);
        
        logger.debug("Shuffle step next");
        /**
         * Move the new file into place, stuff should get shuffled
         */
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        logger.debug("end of shuffle step");
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
           
               // Check trx:enabled has been shuffled.
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               // check my residual MLText has been transferred
               assertTrue(props.containsKey(RESIDUAL_MTTEXT));
               
               // Check the titled aspect is correct
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );
               assertEquals("title wrong", FILE_TITLE, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_TITLE) );
               assertEquals("description wrong", FILE_DESCRIPTION, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_DESCRIPTION) );

               // ALF-7641 - CIFS shuffle, does not preseve MLText values.
               Map<QName, Serializable> mlProps = mlAwareNodeService.getProperties(shuffledNodeRef);
               
               MLText multi = (MLText)mlAwareNodeService.getProperty(shuffledNodeRef, RESIDUAL_MTTEXT) ;
               assertTrue("MLText has lost values", multi.getValues().size() > 2);
               
//               // ALF-7635 check auditable properties 
               assertEquals("creation date not preserved", ((java.util.Date)testContext.testCreatedDate).getTime(), ((java.util.Date)nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_CREATED)).getTime());
               
               // ALF-7628 - preserve addressee and classifiable
               assertEquals("ADDRESSEE PROPERTY Not copied", "Fred", nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_ADDRESSEE));
               assertTrue("CLASSIFIABLE aspect not present", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_CLASSIFIABLE));
               
               // ALF-7584 - preserve node ref.
               assertEquals("noderef changed", testContext.testNodeRef, shuffledNodeRef);
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        
        tran.doInTransaction(deleteOldFileCB, false, true);
        
    } // testScenarioMSWord2003SaveShuffle
    
    
    /**
     * This test tries to simulate the shuffling that is done by MS Word 2003 
     * with backup enabled upon file save
     * 
     * a) TEST.DOC
     * b) Save to ~WRDnnnn.TMP
     * c) Delete "Backup of TEST.DOC"
     * d) Rename TEST.DOC to "Backup of TEST.DOC"
     * e) Delete TEST.DOC
     * f) Rename ~WRDnnnn.TMP to TEST.DOC
     * 
     * We need to check that properties, aspects, primary assocs, secondary assocs, peer assocs, node type, 
     * version history, creation date are maintained.
     */
    public void testScenarioMSWord2003SaveShuffleWithBackup() throws Exception
    {
        logger.debug("testScenarioMSWord2003SaveShuffleWithBackup");
        final String FILE_NAME = "TEST.DOC";
        final String FILE_OLD_TEMP = "Backup of TEST.DOC";
        final String FILE_NEW_TEMP = "~WRD0002.TMP";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMSWord2003SaveShuffleWithBackup";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
             
        /**
         * Create a file in the test directory
         */            
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // now load up the node with lots of other stuff that we will test to see if it gets preserved during the
                // shuffle.
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                // test non CM namespace property
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                // test CM property not related to an aspect
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_ADDRESSEE, "Fred");
                nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_CREATED);
                // classifiable chosen since its not related to any properties.
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_CLASSIFIABLE, null);
                //nodeService.createAssociation(testContext.testNodeRef, targetRef, assocTypeQName);
        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        /**
         * Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "MS Word 2003 shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();            
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * b) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "MS Word 2003 shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.newFileHandle.close();
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB, false, true);
        
        /**
         * rename the old file
         */
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
        

        RetryingTransactionCallback<Void> validateOldFileGoneCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                try
                {
                    driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                }
                catch (IOException e)
                { 
                    // expect to go here since previous step renamed the file.
                }
                
                return null;
            }
        };
        tran.doInTransaction(validateOldFileGoneCB, false, true);
        
        /**
         * Move the new file into place, stuff should get shuffled
         */
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );
               
               // commented out due to ALF-7628 
               //assertEquals("ADDRESSEE PROPERTY Not copied", "Fred", nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_ADDRESSEE));
               //assertEquals("created date changed", testContext.testCreatedDate, (Date)nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_CREATED));
               
               // assertTrue("CLASSIFIABLE aspect not present", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_CLASSIFIABLE));
               
               //assertEquals("noderef changed", testContext.testNodeRef, shuffledNodeRef);
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, false, true);

    } // testScenarioMSWord2003SaveShuffleWithBackup
    
    /**
     * This test tries to simulate the cifs shuffling that is done to
     * support MS Word 2007 
     * 
     * a) TEST.DOCX
     * b) Save new to 00000001.TMP
     * c) Rename TEST.DOCX to 00000002.TMP
     * d) Rename 000000001.TMP to TEST.DOCX
     * e) Delete 000000002.TMP
     */
    public void testScenarioMSWord2007Save() throws Exception
    {
        logger.debug("testScenarioMSWord2007SaveShuffle");
        final String FILE_NAME = "TEST.DOCX";
        final String FILE_OLD_TEMP = "788A1D3D.tmp";
        final String FILE_NEW_TEMP = "19ECA1A.tmp";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMSWord2007Save";
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        /**
         * Create a file in the test directory
         */           
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // no need to test lots of different properties, that's already been tested above
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        /**
         * a) Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "MS Word 2007 shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();            
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * b) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "MS Word 2007 shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.newFileHandle.close();
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB, false, true);
        
        /**
         * c) rename the old file
         */
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
        
        
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(deleteOldFileCB, false, true);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );    
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, false, true);

    } // testScenarioWord2007 save
    
    /**
     * This test tries to simulate the cifs shuffling that is done to
     * support EMACS 
     * 
     * a) emacsTest.txt
     * b) Rename original file to emacsTest.txt~
     * c) Create emacsTest.txt
     */
    public void DISABLED_testScenarioEmacsSave() throws Exception
    {
        logger.debug("testScenarioEmacsSave");
        final String FILE_NAME = "emacsTest.txt";
        final String FILE_OLD_TEMP = "emacsTest.txt~";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioEmacsSave";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
                
        /**
         * Create a file in the test directory
         */    
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // no need to test lots of different properties, that's already been tested above
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB);
        
        /**
         * a) Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "Emacs shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();            
                return null;
            }
        };
        tran.doInTransaction(writeFileCB);
        
        /**
         * b) rename the old file out of the way
         */
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB);
        
        /**
         * c) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "EMACS shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.newFileHandle.close();
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               return null;
            }
        };
        
        tran.doInTransaction(validateCB);

    } // testScenarioEmacs save

    /**
     * This test tries to simulate the cifs shuffling that is done to
     * support vi 
     * 
     * a) viTest.txt
     * b) Rename original file to viTest.txt~
     * c) Create viTest.txt
     * d) Delete viTest.txt~
     */
    public void testScenarioViSave() throws Exception
    {
        logger.debug("testScenarioViSave");
        final String FILE_NAME = "viTest.txt";
        final String FILE_OLD_TEMP = "viTest.txt~";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioViSave";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
            
        /**
         * Create a file in the test directory
         */            
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // no need to test lots of different properties, that's already been tested above
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB);
        
        /**
         * a) Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "Emacs shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);            
                return null;
            }
        };
        tran.doInTransaction(writeFileCB);
        
        /**
         * b) rename the old file out of the way
         */
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB);
        
        /**
         * c) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "Vi shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                driver.closeFile(testSession, testConnection, testContext.newFileHandle);            
                logger.debug("delete temporary file - which will trigger shuffle");
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               assertNotNull("shuffledNodeRef is null", shuffledNodeRef);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );   
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
 
               return null;
            }
        };
        
        tran.doInTransaction(validateCB);

    } // testScenarioViSave
    
    /**
     * This test tries to simulate the cifs shuffling that is done to
     * support smultron 
     * 
     * a) smultronTest.txt
     * b) Save new file to .dat04cd.004
     * c) Delete smultronTest.txt
     * c) Rename .dat04cd.004 to smultronTest.txt
     */
    public void testScenarioSmultronSave() throws Exception
    {
        logger.debug("testScenarioSmultronSave");
        final String FILE_NAME = "smultronTest.txt";
        final String FILE_NEW_TEMP = ".dat04cd.004";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioSmultronSave";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
          
        /**
         * Create a file in the test directory
         */           
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // no need to test lots of different properties, that's already been tested above
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB);
        
        /**
         * a) Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "Smultron shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);            
                return null;
            }
        };
        tran.doInTransaction(writeFileCB);
        
        /**
         * b) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "Smultron shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                driver.closeFile(testSession, testConnection, testContext.newFileHandle);
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB);
        
        /**
         * c) Delete the old file
         */
        RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(deleteOldFileCB);
          
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );    
               return null;
            }
        };
        
        tran.doInTransaction(validateCB);
        
    } // testScenarioSmultronSave

    
    /**
     * This time we create a file through the ContentDiskDriver and then delete it 
     * through the repo.   We check its no longer found by the driver.
     */
    public void testScenarioDeleteViaNodeService() throws Exception
    {
        logger.debug("testScenarioDeleteViaNodeService");
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
              
        int openAction = FileAction.CreateNotExist;
        final String FILE_NAME="testDeleteFileViaNodeService.new";
        final String FILE_PATH="\\" + FILE_NAME;

          
        FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                
        final NetworkFile file = driver.createFile(testSession, testConnection, params);
        
        assertNotNull("file is null", file);
        assertFalse("file is read only, should be read-write", file.isReadOnly());
              
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {

                byte[] stuff = "Hello World".getBytes();
                file.writeFile(stuff, stuff.length, 0, 0);
                file.close();
                
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                assertNotNull("can't find new node", newNode);
             
                     
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * Step 1: Delete the new node via the node service
         */
        RetryingTransactionCallback<Void> deleteNodeCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {

                
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                assertNotNull("can't find new node", newNode);
                nodeService.deleteNode(newNode);
                return null;
            }
        };
        tran.doInTransaction(deleteNodeCB, false, true);
        
        try
        {
            getNodeForPath(testConnection, FILE_PATH);
            fail("getNode for path unexpectedly succeeded");
        } 
        catch (IOException ie)
        {
            // expect to go here
        }
        
        /**
         * Delete file by path - file should no longer exist
         */
        try
        {
            driver.deleteFile(testSession, testConnection, FILE_PATH);
            fail("delete unexpectedly succeeded");
        } 
        catch (IOException ie)
        {
            // expect to go here
        }
        
    }
    
    /**
     * This test tries to simulate the shuffling that is done by MS Word 2003 
     * with regard to metadata extraction.
     * <p>
     * 1: Setup an inbound rule for ContentMetadataExtractor.
     * 2: Write ContentDiskDriverTest1 file to ContentDiskDriver.docx
     * 3: Check metadata extraction for non update test
     * Simulate a WORD 2003 CIFS shuffle
     * 4: Write ContentDiskDriverTest2 file to ~WRD0003.TMP
     * 5: Rename ContentDiskDriver.docx to ~WRL0003.TMP
     * 6: Rename ~WRD0003.TMP to ContentDiskDriver.docx
     * 7: Check metadata extraction
     */
    public void testMetadataExtraction() throws Exception
    {
        logger.debug("testMetadataExtraction");
        final String FILE_NAME = "ContentDiskDriver.docx";
        final String FILE_OLD_TEMP = "~WRL0003.TMP";
        final String FILE_NEW_TEMP = "~WRD0003.TMP";
         
        class TestContext
        {
            NodeRef testDirNodeRef;
            NodeRef testNodeRef;
            NetworkFile firstFileHandle;
            NetworkFile secondFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testMetadataExtraction";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteDirectory(testSession, testConnection, TEST_DIR);
                return null;
            }
        };
        
        try
        {
            tran.doInTransaction(deleteGarbageDirCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("create Test directory" + TEST_DIR);
        RetryingTransactionCallback<Void> createTestDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_DIR);
                assertNotNull("testDirNodeRef is null", testContext.testDirNodeRef);   
                
                UserTransaction txn = transactionService.getUserTransaction();
              
                return null;
                
                
            }
        };                
        tran.doInTransaction(createTestDirCB);
        logger.debug("Create rule on test dir");
        
        RetryingTransactionCallback<Void> createRuleCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {                 
                Rule rule = new Rule();
                rule.setRuleType(RuleType.INBOUND);
                rule.applyToChildren(true);
                rule.setRuleDisabled(false);
                rule.setTitle("Extract Metadata from content");
                rule.setDescription("ContentDiskDriverTest");
                
                Map<String, Serializable> props = new HashMap<String, Serializable>(1);
                Action extractAction = actionService.createAction("extract-metadata", props);
                
                ActionCondition noCondition1 = actionService.createActionCondition(NoConditionEvaluator.NAME);
                extractAction.addActionCondition(noCondition1);
                
                ActionCondition noCondition2 = actionService.createActionCondition(NoConditionEvaluator.NAME);
                CompositeAction compAction = actionService.createCompositeAction();
                compAction.setTitle("Extract Metadata");
                compAction.setDescription("Content Disk Driver Test - Extract Metadata");
                compAction.addAction(extractAction);
                compAction.addActionCondition(noCondition2);

                rule.setAction(compAction);           
                         
                ruleService.saveRule(testContext.testDirNodeRef, rule);
                
                logger.debug("rule created");
                     
                return null;
            }
        };
        tran.doInTransaction(createRuleCB, false, true);

        /**
         * Create a file in the test directory
         */  
        logger.debug("create test file in test directory");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {               
                /**
                 * Create the file we are going to use to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // now load up the node with lots of other stuff that we will test to see if it gets preserved during the
                // shuffle.
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                assertNotNull("testContext.testNodeRef is null", testContext.testNodeRef);
                
                // test non CM namespace property
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        logger.debug("step b: write content to test file");
        
        /**
         * Write ContentDiskDriverTest1.docx to the test file,
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest1.docx");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest1.docx", fileResource);
                writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
            
                logger.debug("close the file, firstFileHandle");
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        logger.debug("Step c: validate metadata has been extracted.");
        
        /**
         * c: check simple case of meta-data extraction has worked.
         */
        RetryingTransactionCallback<Void> validateFirstExtractionCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                Map<QName, Serializable> props = nodeService.getProperties(testContext.testNodeRef);
                
                assertTrue("Enabled property has been lost", props.containsKey(TransferModel.PROP_ENABLED));
                
                ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                assertEquals("size is wrong", 11302, data.getSize());
                assertEquals("mimeType is wrong", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", data.getMimetype());
                
                // These metadata values should be extracted.
                assertEquals("description is not correct", "This is a test file", nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_DESCRIPTION));
                assertEquals("title is not correct", "ContentDiskDriverTest", nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_TITLE));
                assertEquals("author is not correct", "mrogers", nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_AUTHOR));
                
    
                        
                return null;
            }
        };
        tran.doInTransaction(validateFirstExtractionCB, false, true);
        
        
        /**
         * d: Save the new file as an update file in the test directory
         */
        logger.debug("Step d: create update file in test directory " + FILE_NEW_TEMP);
        RetryingTransactionCallback<Void> createUpdateFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {               
                /**
                 * Create the file we are going to use to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.secondFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.secondFileHandle);
                  
                return null;
            }
        };
        tran.doInTransaction(createUpdateFileCB, false, true);

        RetryingTransactionCallback<Void> writeFile2CB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest2.docx");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest2.docx", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.secondFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
            
                driver.closeFile(testSession, testConnection, testContext.secondFileHandle);
                    
                return null;
            }
        };
        tran.doInTransaction(writeFile2CB, false, true);
        
        /**
         * rename the old file
         */
        logger.debug("move old file out of the way.");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
  
        /**
         * Check the old file has gone.
         */
        RetryingTransactionCallback<Void> validateOldFileGoneCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                try
                {
                    driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                }
                catch (IOException e)
                { 
                    // expect to go here since previous step renamed the file.
                }
                
                return null;
            }
        };
        tran.doInTransaction(validateOldFileGoneCB, false, true);
        
//        /**
//         * Check metadata extraction on intermediate new file
//         */
//        RetryingTransactionCallback<Void> validateIntermediateCB = new RetryingTransactionCallback<Void>() {
//
//            @Override
//            public Void execute() throws Throwable
//            {
//               NodeRef updateNodeRef = driver.getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP);
//               
//               Map<QName, Serializable> props = nodeService.getProperties(updateNodeRef);
//                        
//               // These metadata values should be extracted from file2.
//               assertEquals("intermediate file description is not correct", "Content Disk Test 2", props.get(ContentModel.PROP_DESCRIPTION));
//               assertEquals("intermediate file title is not correct", "Updated", props.get(ContentModel.PROP_TITLE));
//               assertEquals("intermediate file author is not correct", "mrogers", props.get(ContentModel.PROP_AUTHOR));
//
//               return null;
//            }
//        };
//        
//        tran.doInTransaction(validateIntermediateCB, true, true);
        
        /**
         * Move the new file into place, stuff should get shuffled
         */
        logger.debug("move new file into place.");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        logger.debug("validate update has run correctly.");
        RetryingTransactionCallback<Void> validateUpdateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               // Check trx:enabled has been shuffled and not lost.
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertEquals("mimeType is wrong", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", data.getMimetype());
               assertEquals("size is wrong", 11265, data.getSize());
           
               // These metadata values should be extracted from file2.   However they will not be applied in PRAGMATIC mode.
//               assertEquals("description is not correct", "Content Disk Test 2", props.get(ContentModel.PROP_DESCRIPTION));
//               assertEquals("title is not correct", "Updated", props.get(ContentModel.PROP_TITLE));
//               assertEquals("author is not correct", "mrogers", props.get(ContentModel.PROP_AUTHOR));
               
                    return null;
            }
        };
        
        tran.doInTransaction(validateUpdateCB, true, true);
        
    } // testScenarioShuffleMetadataExtraction
    
    
    /**
     * ALF-12812
     * 
     * This test tries to simulate the shuffling that is done by MS Word 2011 for Mac 
     * with regard to metadata extraction.  In particular the temporary file names are
     * different.
     * <p>
     * 1: Setup an update rule for ContentMetadataExtractor.
     * Simulate a WORD 2011 for Mac Create
     * 2: Write "Word Work File D_1725484373.tmp"
     * 3: Close file
     * 4: Rename "Word Work File D_1725484373.tmp" to ContentDiskDriver.docx
     * 5: Check metadata extraction
     */
    public void testMetadataExtractionForMac() throws Exception
    {
        logger.debug("testMetadataExtractionForMac");
        final String FILE_NAME = "ContentDiskDriver.docx";
        //final String FILE_OLD_TEMP = "._Word Work File D_1725484373.tmp";
        final String FILE_NEW_TEMP = "Word Work File D_1725484373.tmp";
                 
        class TestContext
        {
            NodeRef testDirNodeRef;
            NodeRef testNodeRef;
            NetworkFile firstFileHandle;
//            NetworkFile secondFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testMetadataExtractionForMac";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteDirectory(testSession, testConnection, TEST_DIR);
                return null;
            }
        };
        
        try
        {
            tran.doInTransaction(deleteGarbageDirCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("create Test directory" + TEST_DIR);
        RetryingTransactionCallback<Void> createTestDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_DIR);
                assertNotNull("testDirNodeRef is null", testContext.testDirNodeRef);   
                
                UserTransaction txn = transactionService.getUserTransaction();
              
                return null;
                
                
            }
        };                
        tran.doInTransaction(createTestDirCB);
        logger.debug("Create rule on test dir");
        
        RetryingTransactionCallback<Void> createRuleCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {                 
                Rule rule = new Rule();
                rule.setRuleType(RuleType.UPDATE);
                rule.applyToChildren(true);
                rule.setRuleDisabled(false);
                rule.setTitle("Extract Metadata from update content");
                rule.setDescription("ContentDiskDriverTest");
                
                Map<String, Serializable> props = new HashMap<String, Serializable>(1);
                Action extractAction = actionService.createAction("extract-metadata", props);
                
                ActionCondition noCondition1 = actionService.createActionCondition(NoConditionEvaluator.NAME);
                extractAction.addActionCondition(noCondition1);
                
                ActionCondition noCondition2 = actionService.createActionCondition(NoConditionEvaluator.NAME);
                CompositeAction compAction = actionService.createCompositeAction();
                compAction.setTitle("Extract Metadata");
                compAction.setDescription("Content Disk Driver Test - Extract Metadata");
                compAction.addAction(extractAction);
                compAction.addActionCondition(noCondition2);

                rule.setAction(compAction);           
                         
                ruleService.saveRule(testContext.testDirNodeRef, rule);
                
                logger.debug("rule created");
                     
                return null;
            }
        };
        tran.doInTransaction(createRuleCB, false, true);

        /**
         * Create a file in the test directory
         */  
        logger.debug("create test file in test directory");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {               
                /**
                 * Create the file we are going to use to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull("first file Handle is null", testContext.firstFileHandle);
                
                // now load up the node with lots of other stuff that we will test to see if it gets preserved during the
                // shuffle.
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP);
                assertNotNull("testContext.testNodeRef is null", testContext.testNodeRef);
                
                // test non CM namespace property
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
        
                // Check that the temporary aspect has been applied.
                assertTrue("temporary aspect not applied", nodeService.hasAspect(testContext.testNodeRef, ContentModel.ASPECT_TEMPORARY));
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        logger.debug("step b: write content to test file");
        
        /**
         * Write ContentDiskDriverTest1.docx to the test file,
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest1.docx");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest1.docx", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
                
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        logger.debug("Step b: rename the test file.");
                
        /**
         * Move the new file into place, stuff should get shuffled
         */
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
      logger.debug("Step c: validate metadata has been extracted.");  
      /**
      * c: check simple case of meta-data extraction has worked.
      */
     RetryingTransactionCallback<Void> validateFirstExtractionCB = new RetryingTransactionCallback<Void>() {

         @Override
         public Void execute() throws Throwable
         {
             Map<QName, Serializable> props = nodeService.getProperties(testContext.testNodeRef);
             
             assertTrue("Enabled property has been lost", props.containsKey(TransferModel.PROP_ENABLED));
             
             // Check that the temporary aspect has been applied.
             assertTrue("temporary aspect has not been removed", !nodeService.hasAspect(testContext.testNodeRef, ContentModel.ASPECT_TEMPORARY));
             assertTrue("hidden aspect has not been removed", !nodeService.hasAspect(testContext.testNodeRef, ContentModel.ASPECT_HIDDEN));

        
          
             // These metadata values should be extracted.
             assertEquals("description is not correct", "This is a test file", nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_DESCRIPTION));
             assertEquals("title is not correct", "ContentDiskDriverTest", nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_TITLE));
             assertEquals("author is not correct", "mrogers", nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_AUTHOR));
             
             ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
             assertEquals("mimeType is wrong", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", data.getMimetype());
             assertEquals("size is wrong", 11302, data.getSize());
                     
             return null;
         }
     };
     tran.doInTransaction(validateFirstExtractionCB, false, true);

        
    } // testScenarioMetadataExtractionForMac
    
    public void testDirListing()throws Exception
    {
        logger.debug("testDirListing");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        final String FOLDER_NAME = "parentFolder" + System.currentTimeMillis();
        final String HIDDEN_FOLDER_NAME = "hiddenFolder" + System.currentTimeMillis();
        RetryingTransactionCallback<NodeRef> createNodesCB = new RetryingTransactionCallback<NodeRef>() {

            @Override
            public NodeRef execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef parentNode = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDER_NAME), ContentModel.TYPE_FOLDER).getChildRef();
                nodeService.setProperty(parentNode, ContentModel.PROP_NAME, FOLDER_NAME);
                
                NodeRef hiddenNode = nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, HIDDEN_FOLDER_NAME), ForumModel.TYPE_FORUM).getChildRef();
                nodeService.setProperty(hiddenNode, ContentModel.PROP_NAME, HIDDEN_FOLDER_NAME);
                return parentNode;
            }
        };
        final NodeRef parentFolder = tran.doInTransaction(createNodesCB);
        
        List<String> excludedTypes = new ArrayList<String>();
        excludedTypes.add(ForumModel.TYPE_FORUM.toString());
        cifsHelper.setExcludedTypes(excludedTypes);
        SearchContext result = driver.startSearch(testSession, testConnection, "\\"+FOLDER_NAME + "\\*", 0);
        while(result.hasMoreFiles())
        {
            if (result.nextFileName().equals(HIDDEN_FOLDER_NAME))
            {
                fail("Exluded types mustn't be shown in cifs");    
            } 
        }

        RetryingTransactionCallback<Void> deleteNodeCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                nodeService.deleteNode(parentFolder);
                return null;
            }
        };
        tran.doInTransaction(deleteNodeCB, false, true);
    } //testDirListing


    public void testFileInformationUpdatingByEditorUserForAlf8808() throws Exception
    {
        final Holder<org.alfresco.service.cmr.model.FileInfo> editorFolder = new Holder<org.alfresco.service.cmr.model.FileInfo>();
        final Holder<org.alfresco.service.cmr.model.FileInfo> testFile = new Holder<org.alfresco.service.cmr.model.FileInfo>();

        // Configuring test server with test server configuration and getting test tree connection for test shared device
        ServerConfiguration config = new ServerConfiguration(ContentDiskDriverTest.TEST_SERVER_NAME);
        TestServer server = new TestServer(ContentDiskDriverTest.TEST_SERVER_NAME, config);
        DiskSharedDevice device = getDiskSharedDevice();
        final TreeConnection treeConnection = server.getTreeConnection(device);

        // Getting target entity for testing - ContentDiskDriver
        final ExtendedDiskInterface deviceInterface = (ExtendedDiskInterface) treeConnection.getInterface();
        // Creating mock-session
        final SrvSession session = new TestSrvSession(13, server, ContentDiskDriverTest.TEST_PROTOTYPE_NAME, ContentDiskDriverTest.TEST_REMOTE_NAME);

        transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                try
                {
                    NodeRef rootNode = repositoryHelper.getCompanyHome();
                    // Creating test user to invite him as Editor for test content. This user will be created correctly (with person and authentication options)
                    createUser(ContentDiskDriverTest.TEST_USER_AUTHORITY, ContentDiskDriverTest.TEST_USER_AUTHORITY, rootNode);
                    // Safely creating folder for test content
                    editorFolder.value = getOrCreateNode(rootNode, PermissionService.EDITOR, ContentModel.TYPE_FOLDER).getFirst();
                    // Creating test content which will be editable by user created above
                    testFile.value = getOrCreateNode(rootNode, "Test.txt", ContentModel.TYPE_CONTENT).getFirst();

                    // Applying 'Editor' role for test user to test file
                    permissionService.setPermission(testFile.value.getNodeRef(), ContentDiskDriverTest.TEST_USER_AUTHORITY, PermissionService.EDITOR, true);

                    try
                    {
                        // Creating data for target method invocation
                        final FileInfo updatedInfo = new FileInfo();
                        updatedInfo.setFileName(testFile.value.getName());
                        updatedInfo.setFileId(DefaultTypeConverter.INSTANCE.intValue(testFile.value.getProperties().get(ContentModel.PROP_NODE_DBID)));

                        // Testing ContentDiskDriver.setFileInformation() with test user authenticated who has 'Editor' role for test content.
                        // This method should fail if check on 'DELETE' permission was not moved to 'DeleteOnClose' context
                        AuthenticationUtil.runAs(new RunAsWork<Void>()
                        {
                            @Override
                            public Void doWork() throws Exception
                            {
                                deviceInterface.setFileInformation(session, treeConnection, testFile.value.getName(), updatedInfo);
                                return null;
                            }
                        }, ContentDiskDriverTest.TEST_USER_AUTHORITY);
                    }
                    catch (Exception e)
                    {
                        // Informing about test failure. Expected exception is 'org.alfresco.jlan.server.filesys.AccessDeniedException'
                        if (e.getCause() instanceof AccessDeniedException)
                        {
                            fail("For user='" + TEST_USER_AUTHORITY + "' " + e.getCause().toString());
                        }
                        else
                        {
                            fail("Unexpected exception was caught: " + e.toString());
                        }
                    }
                }
                finally
                {
                    // Cleaning all test data and rolling back transaction to revert all introduced changes during testing

                    if (authenticationService.authenticationExists(ContentDiskDriverTest.TEST_USER_AUTHORITY))
                    {
                        authenticationService.deleteAuthentication(ContentDiskDriverTest.TEST_USER_AUTHORITY);
                    }

                    if (personService.personExists(ContentDiskDriverTest.TEST_USER_AUTHORITY))
                    {
                        personService.deletePerson(ContentDiskDriverTest.TEST_USER_AUTHORITY);
                    }

                    try
                    {
                        if (null != testFile.value)
                        {
                            nodeService.deleteNode(testFile.value.getNodeRef());
                        }
                    }
                    catch (Exception e)
                    {
                        // Doing nothing
                    }

                    try
                    {
                        if (null != editorFolder.value)
                        {
                            nodeService.deleteNode(editorFolder.value.getNodeRef());
                        }
                    }
                    catch (Exception e)
                    {
                        // Doing nothing
                    }
                }

                return null;
            }
        }, false, true);
    }

    /**
     * Searching for file object with specified name or creating new one if such object is not exist
     * 
     * @param parentRef - {@link NodeRef} of desired parent object
     * @param name - {@link String} value for name of desired file object
     * @param type - {@link QName} instance which determines type of the object. It may be cm:content, cm:folder etc (see {@link ContentModel})
     * @return {@link Pair}&lt;{@link org.alfresco.service.cmr.model.FileInfo}, {@link Boolean}> instance which contains {@link NodeRef} of newly created object and
     *         <code>true</code> value if file object with specified name was not found or {@link NodeRef} of existent file object and <code>false</code> in other case
     */
    private Pair<org.alfresco.service.cmr.model.FileInfo, Boolean> getOrCreateNode(NodeRef parentRef, String name, QName type)
    {
        NodeRef result = nodeService.getChildByName(parentRef, ContentModel.ASSOC_CONTAINS, name);
        Boolean created = false;
        if (null == result)
        {
            result = nodeService.getChildByName(parentRef, ContentModel.ASSOC_CHILDREN, name);
        }
        if (created = (null == result))
        {
            result = fileFolderService.create(parentRef, name, type).getNodeRef();
        }
        return new Pair<org.alfresco.service.cmr.model.FileInfo, Boolean>(fileFolderService.getFileInfo(result), created);
    }

    /**
     * Creates correct user entity with correct user home space, person and authentication with password equal to '<code>password</code>' options if these options are not exist.
     * Method searches for space with name equal to '<code>name</code>' to make it user home space or creates new folder with name equal to '<code>name</code>'. All required
     * permissions and roles will be applied to user home space
     * 
     * @param name - {@link String} value which contains new user name
     * @param password - {@link String} value of text password for new user
     * @param parentNodeRef - {@link NodeRef} instance of parent folder where user home space should be found or created
     */
    private void createUser(String name, String password, NodeRef parentNodeRef)
    {
        Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
        properties.put(ContentModel.PROP_USERNAME, name);
        Pair<org.alfresco.service.cmr.model.FileInfo, Boolean> userHome = getOrCreateNode(parentNodeRef, name, ContentModel.TYPE_FOLDER);
        if (userHome.getSecond())
        {
            NodeRef nodeRef = userHome.getFirst().getNodeRef();
            permissionService.setPermission(nodeRef, name, permissionService.getAllPermission(), true);
            permissionService.setPermission(nodeRef, permissionService.getAllAuthorities(), PermissionService.CONSUMER, true);
            permissionService.setPermission(nodeRef, permissionService.getOwnerAuthority(), permissionService.getAllPermission(), true);
            ownableService.setOwner(nodeRef, name);
            permissionService.setInheritParentPermissions(nodeRef, false);

            properties.put(ContentModel.PROP_HOMEFOLDER, nodeRef);
            if (!personService.personExists(name))
            {
                personService.createPerson(properties);
            }
            if (!authenticationService.authenticationExists(name))
            {
                authenticationService.createAuthentication(name, password.toCharArray());
            }
        }
    }
    
    /**
     * Excel 2003 With Versionable file
     *
     * CreateFile 5EE27100
     * RenameFile oldPath:\Espaces Utilisateurs\System\Cherries.xls, 
     *          newPath:\Espaces Utilisateurs\System\Cherries.xls~RF172f241.TMP
     * RenameFile oldName=\Espaces Utilisateurs\System\5EE27100, 
     *          newName=\Espaces Utilisateurs\System\Cherries.xls, session:WNB0
     *
     * Set Delete On Close for Cherries.xls~RF172f241.TMP
     */
    public void testExcel2003SaveShuffle() throws Exception
    {
        //fail("not yet implemented");
        logger.debug("testScenarioExcel2003SaveShuffle");
        final String FILE_NAME = "Cherries.xls";
        final String FILE_TITLE = "Cherries";
        final String FILE_DESCRIPTION = "This is a test document to test CIFS shuffle";
        final String FILE_OLD_TEMP = "Cherries.xls~RF172f241.TMP";
        final String FILE_NEW_TEMP = "5EE27100";
        
        final QName RESIDUAL_MTTEXT = QName.createQName("{gsxhjsx}", "whatever");
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;
            NetworkFile oldFileHandle;
            
            NodeRef testNodeRef;   // node ref of test.doc
            
            Serializable testCreatedDate;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSExcel2003SaveShuffle";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
  
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // now load up the node with lots of other stuff that we will test to see if it gets preserved during the
                // shuffle.
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                // test non CM namespace property
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                // test CM property not related to an aspect
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_ADDRESSEE, "Fred");
                
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_TITLE, FILE_TITLE);
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_DESCRIPTION, FILE_DESCRIPTION);
                
                /**
                 * MLText value - also a residual value in a non cm namespace
                 */
                MLText mltext = new MLText();
                mltext.addValue(Locale.FRENCH, "Bonjour");
                mltext.addValue(Locale.ENGLISH, "Hello");
                mltext.addValue(Locale.ITALY, "Buongiorno");
                mlAwareNodeService.setProperty(testContext.testNodeRef, RESIDUAL_MTTEXT, mltext);

                // classifiable chosen since its not related to any properties.
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_CLASSIFIABLE, null);
                //nodeService.createAssociation(testContext.testNodeRef, targetRef, assocTypeQName);
        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        /**
         * Write some content to the test file
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "MS Excel 2003 shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();   
                
                testContext.testCreatedDate = nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_CREATED);
                
                MLText multi = (MLText)mlAwareNodeService.getProperty(testContext.testNodeRef, RESIDUAL_MTTEXT) ;
                multi.getValues();
     
     
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * b) Save the new file
         */
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "MS Word 2003 shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.newFileHandle.close();
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB, false, true);
        
        /**
         * rename the old file
         */
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
        

        RetryingTransactionCallback<Void> validateOldFileGoneCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                try
                {
                    driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                }
                catch (IOException e)
                { 
                    // expect to go here since previous step renamed the file.
                }
                
                return null;
            }
        };
        tran.doInTransaction(validateOldFileGoneCB, false, true);
        
        /**
         * Move the new file into place, stuff should get shuffled
         */
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
           
               // Check trx:enabled has been shuffled.
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               // check my residual MLText has been transferred
               assertTrue(props.containsKey(RESIDUAL_MTTEXT));
               
               // Check the titled aspect is correct
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );
               assertEquals("title wrong", FILE_TITLE, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_TITLE) );
               assertEquals("description wrong", FILE_DESCRIPTION, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_DESCRIPTION) );

               // commented out due to ALF-7641
               // CIFS shuffle, does not preseve MLText values.
               // Map<QName, Serializable> mlProps = mlAwareNodeService.getProperties(shuffledNodeRef);
               
               // MLText multi = (MLText)mlAwareNodeService.getProperty(shuffledNodeRef, RESIDUAL_MTTEXT) ;
               // multi.getValues();
               
               // check auditable properties 
               // commented out due to ALF-7635
               // assertEquals("creation date not preserved", ((Date)testContext.testCreatedDate).getTime(), ((Date)nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_CREATED)).getTime());
               
               // commented out due to ALF-7628 
               // assertEquals("ADDRESSEE PROPERTY Not copied", "Fred", nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_ADDRESSEE));
               // assertTrue("CLASSIFIABLE aspect not present", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_CLASSIFIABLE));
               
               // commented out due to ALF-7584.
               // assertEquals("noderef changed", testContext.testNodeRef, shuffledNodeRef);
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        
        tran.doInTransaction(deleteOldFileCB, false, true);
        
    }

    /**
     * Excel 2013 With Versionable file  (MNT-13078)
     *
     * CreateFile Cherries.xlsx
     * CreateFile ~herries.tmp
     * CreateFile Cherries.xlsx~RF172f241.TMP
     * DeleteFile Cherries.xlsx~RF172f241.TMP
     * RenameFile oldName: Cherries.xls,
     *            newName: Cherries.xlsx~RF172f241.TMP
     * Delete On Close for Cherries.xlsx~RF172f241.TMP
     * RenameFile oldName: ~herries.tmp,
     *            newName: Cherries.xlsx
     *
     */
    public void testExcel2013SaveShuffle() throws Exception
    {
        logger.debug("testScenarioExcel2013SaveShuffle");
        final String FILE_NAME = "Cherries.xlsx";
        final String FILE_ORIGINAL_TITLE = "Original";
        final String FILE_UNUSED_TEMP = "Cherries.xlsx~RF172f241.TMP";
        final String FILE_USED_TEMP = "~herries.tmp";
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSExcel2013SaveShuffle";

        class TestContext
        {
            NetworkFile firstFileHandle;
            NodeRef testNodeRef;   // node ref of test.doc
        };

        final TestContext testContext = new TestContext();

        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };

        /**
         * Delete a file in the test directory
         */

        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }

        /**
         * Create a file in the test directory
         */
        RetryingTransactionCallback<Void> createOriginalFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable {

               /**
                * Create the test directory we are going to use
                */
               FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
               FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
               driver.createDirectory(testSession, testConnection, createRootDirParams);
               driver.createDirectory(testSession, testConnection, createDirParams);

               /**
                * Create the file we are going to use
                */
               FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
               testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
               assertNotNull(testContext.firstFileHandle);
               String testContent = "MS Word 2013 shuffle test. This is first file content";
               byte[] testContentBytes = testContent.getBytes();
               testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
               testContext.firstFileHandle.close();

               // now load up the node with lots of other stuff that we will test to see if it gets preserved during the
               // shuffle.
               testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

               nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
               // need to remove. Otherwise file will be deleted (not placed into archive spaces store)
               nodeService.removeAspect(testContext.testNodeRef, ContentModel.ASPECT_NO_CONTENT);
               // test non CM namespace property
               nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);

               nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_TITLE, FILE_ORIGINAL_TITLE);

               return null;
            }
        };
        tran.doInTransaction(createOriginalFileCB, false, true);

        /**
         * Create a file in the test directory
         */
        RetryingTransactionCallback<Void> createUsedTempFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {

                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_USED_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                NetworkFile fileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(fileHandle);
                String testContent = "MS Word 2013 shuffle test. This is used file content";
                byte[] testContentBytes = testContent.getBytes();
                fileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                fileHandle.close();

                NodeRef usedRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_USED_TEMP);

                nodeService.addAspect(usedRef, ContentModel.ASPECT_VERSIONABLE, null);
                nodeService.removeAspect(usedRef, ContentModel.ASPECT_NO_CONTENT);
                nodeService.setProperty(usedRef, ContentModel.PROP_TITLE, "Used");

                return null;
            }
        };
        tran.doInTransaction(createUsedTempFileCB, false, true);

        /**
         * Create a file in the test directory
         */
        RetryingTransactionCallback<Void> createUnusedTempFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {

                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_UNUSED_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                NetworkFile unusedFile = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(unusedFile);

                NodeRef unusedNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_UNUSED_TEMP);
                nodeService.addAspect(unusedNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                nodeService.setProperty(unusedNodeRef, TransferModel.PROP_ENABLED, true);
                nodeService.setProperty(unusedNodeRef, ContentModel.PROP_TITLE, "Unused");

                return null;
            }
        };
        tran.doInTransaction(createUnusedTempFileCB, false, true);

        /**
         * Delete unused temporary file
         */
        RetryingTransactionCallback<Void> deleteUnusedFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                try
                {
                    driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_UNUSED_TEMP);
                }
                catch (IOException e)
                {
                    // expect to go here since previous step renamed the file.
                }

                return null;
            }
        };
        tran.doInTransaction(deleteUnusedFileCB, false, true);

        /**
         * Rename the original file to unused file
         */
        RetryingTransactionCallback<Void> renameToUnusedFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_UNUSED_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameToUnusedFileCB, false, true);

        /**
         * Delete unused temporary file
         */
        tran.doInTransaction(deleteUnusedFileCB, false, true);

        /**
         * Rename the used temporary file to original file
         */
        RetryingTransactionCallback<Void> renameToUsedFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_USED_TEMP, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(renameToUsedFileCB, false, true);



        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);

                // Check trx:enabled has been shuffled.
                assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
                assertTrue("node doesn't contain property 'TITLE'", props.containsKey(ContentModel.PROP_TITLE));
                assertEquals("propety 'TITLE' isn't correct", FILE_ORIGINAL_TITLE, props.get(ContentModel.PROP_TITLE));
                assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME));

                return null;
            }
        };

        tran.doInTransaction(validateCB, true, true);
    }

    /**
     * Excel 2003 CSV file with Versionable file 
     * 
     * CreateFile csv.csv and 5EE27101 
     * Add versionable aspect 
     * RenameFile oldPath:\Espaces Utilisateurs\System\csv.csv, newPath:\Espaces\Utilisateurs\System\5EE27101 
     * CreateFile name=\Espaces Utilisateurs\System\csv.csv
     * Add content
     */
    public void testCSVExcel2003SaveShuffle() throws Exception
    {
        logger.debug("testCSVExcel2003SaveShuffle");
        final String FILE_NAME = "csv.csv";
        final String FILE_TITLE = "csv";
        final String FILE_DESCRIPTION = "This is a test document to test CIFS shuffle";
        final String FILE_TEMP = "AAAA0000";

        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;

            NodeRef testNodeRef;

            Serializable testCreatedDate;
        }
        ;

        final TestContext testContext = new TestContext();

        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testMSExcel2003CSVShuffle";

        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Clean up from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };

        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }

        /**
         * Create a file in the test directory
         */
        RetryingTransactionCallback<Void> createTestFileFirstTime = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {

                /**
                 * Create the test directory we are going to use
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);

                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);

                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_TITLE, FILE_TITLE);
                nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_DESCRIPTION, FILE_DESCRIPTION);

                return null;
            }
        };
        tran.doInTransaction(createTestFileFirstTime, false, true);

        /**
         * Write some content to the test file. Add versionable aspect
         */
        RetryingTransactionCallback<Void> writeToTestFileAndAddVersionableAspect = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                String testContent = "MS Excel 2003 for CSV shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();

                testContext.testCreatedDate = nodeService.getProperty(testContext.testNodeRef, ContentModel.PROP_CREATED);

                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, Collections
                        .<QName, Serializable> singletonMap(ContentModel.PROP_VERSION_TYPE,
                                org.alfresco.service.cmr.version.VersionType.MINOR));

                return null;
            }
        };
        tran.doInTransaction(writeToTestFileAndAddVersionableAspect, false, true);

        /**
         * rename the test file to the temp
         */
        RetryingTransactionCallback<Void> renameTestFileToTemp = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameTestFileToTemp, false, true);

        /**
         * create the test file one more
         */
        RetryingTransactionCallback<Void> createTestFileOneMore = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {

                FileOpenParams params = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, FileAction.TruncateExisting, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                NetworkFile file = driver.createFile(testSession, testConnection, params);
                driver.closeFile(testSession, testConnection, file);

                return null;
            }
        };
        tran.doInTransaction(createTestFileOneMore, false, true);
        
      /**
      * Write the new content
      */
     RetryingTransactionCallback<Void> writeUpdate = new RetryingTransactionCallback<Void>()
     {

         @Override
         public Void execute() throws Throwable
         {
             FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
             testContext.newFileHandle = driver.openFile(testSession, testConnection, createFileParams);
             assertNotNull(testContext.newFileHandle);
             String testContent = "MS Word 2003 for CSV shuffle test This is new content";
             byte[] testContentBytes = testContent.getBytes();
             testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
             testContext.newFileHandle.close();

             return null;
         }
     };
     tran.doInTransaction(writeUpdate, false, true);

        // Check results
        RetryingTransactionCallback<Void> validate = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                // Check versionable aspect, version label and nodeRef
                assertTrue("VERSIONABLE aspect not present", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                assertEquals("nodeRef changed", testContext.testNodeRef, shuffledNodeRef);
    
                // Check the titled aspect is correct
                assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME));
                assertEquals("title wrong", FILE_TITLE, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_TITLE));
                assertEquals("description wrong", FILE_DESCRIPTION, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_DESCRIPTION));

                return null;
            }
        };

        tran.doInTransaction(validate, true, true);

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteTestFile = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };

        tran.doInTransaction(deleteTestFile, false, true);

    }

    /**
     * Simulates a SaveAs from Word2003
     * 1. Create new document SAVEAS.DOC, file did not exist
     * 2. Create -WRDnnnn.TMP file, where 'nnnn' is a 4 digit sequence to make the name unique
     * 3. Rename SAVEAS.DOC to Backup of SAVEAS.wbk
     * 4. Rename -WRDnnnn.TMP to SAVEAS.DOC 
     */
    public void testScenarioMSWord2003SaveAsShuffle() throws Exception
    {
        logger.debug("testScenarioMSWord2003SaveShuffle");
        final String FILE_NAME = "SAVEAS.DOC";
        final String FILE_OLD_TEMP = "SAVEAS.wbk";
        final String FILE_NEW_TEMP = "~WRD0002.TMP";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSWord2003SaveAsShuffle";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("a) create new file");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
  
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
             
        /**
         * b) Save the new file
         * Write ContentDiskDriverTest3.doc to the test file,
         */
        logger.debug("b) move new file into place");
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
         
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
            
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * c) rename the old file
         */
        logger.debug("c) rename old file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
           
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        logger.debug("d) move new file into place");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        logger.debug("e) validate results");
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertNotNull("data is null", data);
               assertEquals("size is wrong", 26112, data.getSize());
               assertEquals("mimeType is wrong", "application/msword",data.getMimetype());
           
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        
    }
    
    /**
     * Test Open Close File Scenario
     * 
     * 1) open(readOnly)
     * 2) open(readWrite)
     * 3) open(readWrite) - does nothing.
     * 4) close - does nothing
     * 5) close - does nothing
     * 6) close - updates the repo
     */
    public void testScenarioOpenCloseFile() throws Exception
    {    
        logger.debug("start of testScenarioOpenCloseFile");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        class TestContext
        {
            NodeRef testDirNodeRef;
            NodeRef targetNodeRef;
        };
        
        final TestContext testContext = new TestContext();
        
        final String FILE_NAME="testScenarioOpenFile.txt";
        final String FILE_PATH= TEST_ROOT_DOS_PATH + "\\" + FILE_NAME;
        
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);  
        
        testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_ROOT_DOS_PATH);
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, FILE_PATH);
                return null;
            }
        };
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
       
        /**
         * Step 1: Now create the file through the node service and open it.
         */
        logger.debug("Step 1) Create File and Open file created by node service");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                logger.debug("create file and close it immediatly");
                FileOpenParams createFileParams = new FileOpenParams(FILE_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                NetworkFile dummy = driver.createFile(testSession, testConnection, createFileParams);  
                assertFalse("file is closed after create", dummy.isClosed());
                driver.closeFile(testSession, testConnection, dummy);
                logger.debug("after create and close");
// TODO Bug in JavaNetworkFile                
//                assertTrue("file is not closed after close", dummy.isClosed());
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        testContext.targetNodeRef = getNodeForPath(testConnection, FILE_PATH);
       
        FileOpenParams openRO = new FileOpenParams(FILE_PATH, FileAction.CreateNotExist, AccessMode.ReadOnly, FileAttribute.NTNormal, 0);
        FileOpenParams openRW = new FileOpenParams(FILE_PATH, FileAction.CreateNotExist, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        
        /**
         * First open - read only
         */
        logger.debug("open file1 read only");
        NetworkFile file1 = driver.openFile(testSession, testConnection, openRO);
        assertNotNull(file1);
        assertFalse("file1 is closed", file1.isClosed());
        
        final String testString = "Yankee doodle went to town";
        byte[] stuff = testString.getBytes("UTF-8");
        
        /**
         * Negative test - file is open readOnly
         */
        try
        {
            driver.writeFile(testSession, testConnection, file1, stuff, 0, stuff.length, 0);
            fail("can write to a read only file!");
        }
        catch(Exception e)
        {
            // Expect to go here
        }
        
        logger.debug("open file 2 for read write");
        NetworkFile file2 = driver.openFile(testSession, testConnection, openRW);
        assertNotNull(file2);
        assertFalse("file is closed", file2.isClosed());

        /**
         * Write Some Content 
         */
        driver.writeFile(testSession, testConnection, file2, stuff, 0, stuff.length, 0);
            
        NetworkFile file3 = driver.openFile(testSession, testConnection, openRW);
        assertNotNull(file3);
       
        logger.debug("first close");
        driver.closeFile(testSession, testConnection, file2);
        // assertTrue("node does not have no content aspect", nodeService.hasAspect(testContext.targetNodeRef, ContentModel.ASPECT_NO_CONTENT));
        
        logger.debug("second close");
        driver.closeFile(testSession, testConnection, file3);
//        //assertTrue("node does not have no content aspect", nodeService.hasAspect(testContext.targetNodeRef, ContentModel.ASPECT_NO_CONTENT));
        
//        logger.debug("this should be the last close");
//        driver.closeFile(testSession, testConnection, file1);
//        assertFalse("node still has no content aspect", nodeService.hasAspect(testContext.targetNodeRef, ContentModel.ASPECT_NO_CONTENT));
        
        /**
         * Step 2: Negative test - Close the file again - should do nothing quietly!
         */
        logger.debug("this is a negative test - should do nothing");
        driver.closeFile(testSession, testConnection, file1);
        
        logger.debug("now validate");
         
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                Map<QName,Serializable> props = nodeService.getProperties(testContext.targetNodeRef);
                ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                assertNotNull("data is null", data);
                assertEquals("data wrong length", testString.length(), data.getSize());
           
                ContentReader reader = contentService.getReader(testContext.targetNodeRef, ContentModel.PROP_CONTENT);
                String s = reader.getContentString();
                assertEquals("content not written", testString, s);

                return null;
            }
        };
        
        tran.doInTransaction(validateCB, false, true);
                
    } // testOpenCloseFileScenario
    
    
    /**
     * Test Open Close File Scenario II  ALF-13401
     * Open Read Only of a file already open for read/write.
     * 
     * 1) open(readWrite)
     * 2) write some content.
     * 3) open(readOnly).
     * 4) read some content.
     * 5) close - updates the repo
     */
    public void testScenarioOpenCloseFileTwo() throws Exception
    {    
        logger.debug("start of testScenarioOpenCloseFileTwo");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        class TestContext
        {
            NodeRef testDirNodeRef;
            NodeRef targetNodeRef;
        };
        
        final TestContext testContext = new TestContext();
        
        final String FILE_NAME="testScenarioOpenFileTwo.txt";
        final String FILE_PATH= TEST_ROOT_DOS_PATH + "\\" + FILE_NAME;
        
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);  
        
        testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_ROOT_DOS_PATH);
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, FILE_PATH);
                return null;
            }
        };
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
       
        /**
         * Step 1: Now create the file through the node service and open it.
         */
        logger.debug("Step 1) Create File and Open file created by node service");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {   
                logger.debug("create file and close it immediatly");
                FileOpenParams createFileParams = new FileOpenParams(FILE_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                NetworkFile dummy = driver.createFile(testSession, testConnection, createFileParams);    
                driver.closeFile(testSession, testConnection, dummy);
                logger.debug("after create and close");
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        testContext.targetNodeRef = getNodeForPath(testConnection, FILE_PATH);
       
        FileOpenParams openRO = new FileOpenParams(FILE_PATH, FileAction.CreateNotExist, AccessMode.ReadOnly, FileAttribute.NTNormal, 0);
        FileOpenParams openRW = new FileOpenParams(FILE_PATH, FileAction.CreateNotExist, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        
        /**
         * First open - read write 
         */
        logger.debug("open file1 read only");
        NetworkFile file1 = driver.openFile(testSession, testConnection, openRW);
        assertNotNull(file1);
        
        final String testString = "Yankee doodle went to town, riding on a donkey.";
        byte[] stuff = testString.getBytes("UTF-8");
        
        driver.writeFile(testSession, testConnection, file1, stuff, 0, stuff.length, 0);
        
        logger.debug("open file 2 for read only");
        NetworkFile file2 = driver.openFile(testSession, testConnection, openRO);
        assertNotNull(file2);
        
        
        assertTrue("file size is 0", file2.getFileSize() > 0);
        
        
        /**
         * Write Some More Content 
         */
        driver.writeFile(testSession, testConnection, file1, stuff, 0, stuff.length, 0);
                 
        logger.debug("first close");
        driver.closeFile(testSession, testConnection, file2);
        
        logger.debug("second close");
        driver.closeFile(testSession, testConnection, file1);
       
        logger.debug("now validate");
         
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                Map<QName,Serializable> props = nodeService.getProperties(testContext.targetNodeRef);
                ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                assertNotNull("data is null", data);
                assertEquals("data wrong length", testString.length(), data.getSize());
           
                ContentReader reader = contentService.getReader(testContext.targetNodeRef, ContentModel.PROP_CONTENT);
                String s = reader.getContentString();
                assertEquals("content not written", testString, s);

                return null;
            }
        };
        
        tran.doInTransaction(validateCB, false, true);
                
    } // testOpenCloseFileScenarioTwo


    
    
    /**
     * Unit test of open read/write close versionable file - should not do anything.
     * <p>
     * This is done with a CIFS shuffle from word.  Basically Word holds the file open with a read/write lock while the 
     * shuffle is going on.
     * <p>
     * Create a file.
     * Apply versionable aspect
     * Open the file ReadWrite + OpLocks
     * Close the file
     * Check Version has not incremented.
     */
    public void testOpenCloseVersionableFile() throws Exception
    {  
        logger.debug("testOpenCloseVersionableFile");
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        final String FILE_PATH1=TEST_ROOT_DOS_PATH + "\\OpenCloseFile.new";
        
        class TestContext
        {
        };
        
        final TestContext testContext = new TestContext();
   
        FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
        driver.createDirectory(testSession, testConnection, dirParams);

        FileOpenParams params1 = new FileOpenParams(FILE_PATH1, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
        NetworkFile file1 = driver.createFile(testSession, testConnection, params1);
        driver.closeFile(testSession, testConnection, file1);
        
        /**
         * Make Node 1 versionable
         */   
        RetryingTransactionCallback<Void> makeVersionableCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef file1NodeRef = getNodeForPath(testConnection, FILE_PATH1);
                nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                ContentWriter contentWriter2 = contentService.getWriter(file1NodeRef, ContentModel.PROP_CONTENT, true);
                contentWriter2.putContent("test open close versionable node");
                
                return null;
            }
        };
        tran.doInTransaction(makeVersionableCB, false, true);
        
        
        RetryingTransactionCallback<String> readVersionCB = new RetryingTransactionCallback<String>() {

            @Override
            public String execute() throws Throwable
            {
                NodeRef shuffledNodeRef = getNodeForPath(testConnection, FILE_PATH1);
                
                Map<QName,Serializable> props = nodeService.getProperties(shuffledNodeRef);
                
                assertTrue("versionable aspect not present", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                props.get(ContentModel.PROP_VERSION_LABEL);


                return (String)props.get(ContentModel.PROP_VERSION_LABEL);
            }
        };
        
        String version = tran.doInTransaction(readVersionCB, false, true);
  
        /**
         * Step 1: Open The file Read/Write 
         * TODO Check primary assoc, peer assocs, child assocs, modified date, created date, nodeid, permissions.
         */
        NetworkFile file = driver.openFile(testSession, testConnection, params1);

        assertNotNull( "file is null", file);
        
        /**
         * Step 2: Close the file
         */
        driver.closeFile(testSession, testConnection, file);
        
        /**
         * Validate that there is no version increment.
         */
        String version2 = tran.doInTransaction(readVersionCB, false, true);
       
        assertEquals("version has incremented", version, version2);
        
        /**
         * Now do an update and check the version increments
         */
        file = driver.openFile(testSession, testConnection, params1);

        assertNotNull( "file is null", file);
        
        byte[] stuff = "Hello World".getBytes();
        driver.writeFile(testSession, testConnection, file, stuff, 0, stuff.length, 0);
        
        /**
         * Step 2: Close the file
         */
        driver.closeFile(testSession, testConnection, file);
        
        String version3 = tran.doInTransaction(readVersionCB, false, true);
        
        assertFalse("version not incremented", version.equals(version3));
         
    } // OpenCloseVersionableFile
    
    /**
    * Frame maker save
    * a) Lock File Created    (X.fm.lck)
    * b) Create new file (X.fm.C29)
    * c) Existing file rename out of the way.   (X.backup.fm)
    * d) New file rename into place. (X.fm.C29)
    * e) Old file deleted (open with delete on close)
    * f) Lock file deleted (open with delete on close)
    */
    public void testScenarioFrameMakerShuffle() throws Exception
    {  
        logger.debug("testScenarioFramemakerShuffle");
        
        final String LOCK_FILE = "X.fm.lck";
        final String FILE_NAME = "X.fm";
        final String FILE_OLD_TEMP = "X.backup.fm";
        final String FILE_NEW_TEMP = "X.fm.C29";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            String mimetype;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioFramemakerShuffle";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("a) create new file");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                ClassPathResource fileResource = new ClassPathResource("filesys/X1.fm");
                assertNotNull("unable to find test resource filesys/X1.fm", fileResource);
                writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);

                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
             
        /**
         * b) Save the new file
         * Write X2.fm to the test file,
         */
        logger.debug("b) move new file into place");
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
         
                ClassPathResource fileResource = new ClassPathResource("filesys/X2.fm");
                assertNotNull("unable to find test resource filesys/X2.fm", fileResource);
                writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                
                
                NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME);
                Map<QName, Serializable> props = nodeService.getProperties(file1NodeRef);
                ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                assertNotNull("data is null", data);
                assertEquals("size is wrong", 166912, data.getSize());
                testContext.mimetype = data.getMimetype();
                
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * c) rename the old file
         */
        logger.debug("c) rename old file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
           
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        logger.debug("d) move new file into place");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        /**
         * d) Delete the old file
         */
        logger.debug("d) move new file into place");
        RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        
        tran.doInTransaction(deleteOldFileCB, false, true);
        
        logger.debug("e) validate results");
        
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertNotNull("data is null", data);
               assertEquals("size is wrong", 123904, data.getSize());
               
               NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME); 
               assertTrue("file has lost versionable aspect", nodeService.hasAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE));

               assertEquals("mimeType is wrong", testContext.mimetype, data.getMimetype());
               
           
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
    }  // Scenario frame maker save
    
    /**
     * Test that rules fire on zero byte long files.
     * In this case check that a new file gets the versionable
     * aspect added.
     */
    public void testZeroByteRules() throws Exception
    {
        logger.debug("testZeroByteRules");
        final String FILE_NAME_ZERO = "Zero.docx";
        final String FILE_NAME_NON_ZERO = "NonZero.docx";
         
        class TestContext
        {
            NodeRef testDirNodeRef;
            NodeRef testZeroNodeRef;
            NodeRef testNonZeroNodeRef;
            NetworkFile firstFileHandle;
            NetworkFile secondFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testZeroByteRules";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteDirectory(testSession, testConnection, TEST_DIR);
                return null;
            }
        };
        
        try
        {
            tran.doInTransaction(deleteGarbageDirCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("create Test directory" + TEST_DIR);
        RetryingTransactionCallback<Void> createTestDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_DIR);
                assertNotNull("testDirNodeRef is null", testContext.testDirNodeRef);                 
                return null;
                
                
            }
        };                
        tran.doInTransaction(createTestDirCB);
        logger.debug("Create rule on test dir");
        
        RetryingTransactionCallback<Void> createRuleCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {                 
                Rule rule = new Rule();
                rule.setRuleType(RuleType.INBOUND);
                rule.applyToChildren(true);
                rule.setRuleDisabled(false);
                rule.setTitle("Make Versionable");
                rule.setDescription("ContentDiskDriverTest Test Zero Byte files");
                
                Map<String, Serializable> props = new HashMap<String, Serializable>(1);
                props.put("aspect-name", ContentModel.ASPECT_VERSIONABLE);
                Action addVersionable = actionService.createAction("add-features", props);
                
                ActionCondition noCondition1 = actionService.createActionCondition(NoConditionEvaluator.NAME);
                addVersionable.addActionCondition(noCondition1);
                
                ActionCondition noCondition2 = actionService.createActionCondition(NoConditionEvaluator.NAME);
                CompositeAction compAction = actionService.createCompositeAction();
                compAction.setTitle("Make Versionablea");
                compAction.setDescription("Add Aspect - Versionable");
                compAction.addAction(addVersionable);
                compAction.addActionCondition(noCondition2);

                rule.setAction(compAction);           
                         
                ruleService.saveRule(testContext.testDirNodeRef, rule);
                
                logger.debug("add aspect versionable rule created");
                     
                return null;
            }
        };
        tran.doInTransaction(createRuleCB, false, true);

        /**
         * Create a file in the test directory
         */  
        logger.debug("create test file in test directory");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {               
                /**
                 * Create the zero byte file we are going to use to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME_ZERO, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                testContext.testZeroNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME_ZERO);
                assertNotNull("testContext.testNodeRef is null", testContext.testZeroNodeRef);
                
                /**
                 * Create the non zero byte file we are going to use to test
                 */
                FileOpenParams createFileParams2 = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME_NON_ZERO, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.secondFileHandle = driver.createFile(testSession, testConnection, createFileParams2);
                assertNotNull(testContext.secondFileHandle);
                
                testContext.testNonZeroNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME_NON_ZERO);
                assertNotNull("testContext.testNodeRef is null", testContext.testNonZeroNodeRef);
        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        logger.debug("step b: close the file with zero byte content");
        
        /**
         * Write ContentDiskDriverTest1.docx to the test file,
         */
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
            
                logger.debug("close the file, firstFileHandle");
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                
                
                // Write hello world into the second file
                byte[] stuff = "Hello World".getBytes();
                driver.writeFile(testSession, testConnection, testContext.secondFileHandle, stuff, 0, stuff.length, 0);
                
                logger.debug("close the second non zero file, secondFileHandle");
                driver.closeFile(testSession, testConnection, testContext.secondFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        logger.debug("Step c: validate versioble aspect has been applied.");
        
        /**
         * c: check zero byte file has the versionable aspect.
         */
        RetryingTransactionCallback<Void> validateFirstExtractionCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                assertTrue("versionable aspect not applied to non zero file.", nodeService.hasAspect(testContext.testNonZeroNodeRef, ContentModel.ASPECT_VERSIONABLE));
                assertTrue("versionable aspect not applied to zero byte file.", nodeService.hasAspect(testContext.testZeroNodeRef, ContentModel.ASPECT_VERSIONABLE));
                return null;
            }
        };
        tran.doInTransaction(validateFirstExtractionCB, false, true);    
    } // testZeroByteRules
    
    /**
     * Test that files can be created with empty content and that
     * existing content can be over-wrriten by empty content.
     */
    public void testEmptyContent() throws Exception
    {
        logger.debug("testEmptyContent");
        final String FILE_NAME_ZERO = "Zero.docx";
        final String FILE_NAME_NON_ZERO = "NonZero.docx";
         
        class TestContext
        {
            NodeRef testDirNodeRef;
            NodeRef testZeroNodeRef;
            NodeRef testNonZeroNodeRef;
            NetworkFile firstFileHandle;
            NetworkFile secondFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testEmptyContent";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteDirectory(testSession, testConnection, TEST_DIR);
                return null;
            }
        };
        
        try
        {
            tran.doInTransaction(deleteGarbageDirCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("create Test directory" + TEST_DIR);
        RetryingTransactionCallback<Void> createTestDirCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                testContext.testDirNodeRef = getNodeForPath(testConnection, TEST_DIR);
                assertNotNull("testDirNodeRef is null", testContext.testDirNodeRef);                 
                return null;
                
                
            }
        };                
        tran.doInTransaction(createTestDirCB);

        /**
         * Create a file in the test directory
         */  
        logger.debug("create test file in test directory");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {               
                /**
                 * Create the zero byte file we are going to use to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME_ZERO, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                testContext.testZeroNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME_ZERO);
                assertNotNull("testContext.testNodeRef is null", testContext.testZeroNodeRef);
                
                logger.debug("close the file, firstFileHandle");
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                
                /**
                 * Create the non zero byte file we are going to use to test
                 */
                FileOpenParams createFileParams2 = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME_NON_ZERO, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.secondFileHandle = driver.createFile(testSession, testConnection, createFileParams2);
                assertNotNull(testContext.secondFileHandle);
                
                testContext.testNonZeroNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME_NON_ZERO);
                assertNotNull("testContext.testNodeRef is null", testContext.testNonZeroNodeRef);
                
                // Write hello world into the second file
                byte[] stuff = "Hello World".getBytes();
                driver.writeFile(testSession, testConnection, testContext.secondFileHandle, stuff, 0, stuff.length, 0);
                
                logger.debug("close the second non zero file, secondFileHandle");
                driver.closeFile(testSession, testConnection, testContext.secondFileHandle);   
   
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
            
        /**
         * d: check both files have content properties.
         */
        RetryingTransactionCallback<Void> checkContentPropsCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                assertNotNull("content missing create non zero file.", nodeService.getProperty(testContext.testNonZeroNodeRef, ContentModel.PROP_CONTENT));
                assertNotNull("content missing create zero byte file.", nodeService.getProperty(testContext.testZeroNodeRef, ContentModel.PROP_CONTENT));
                return null;
            }
        };
        tran.doInTransaction(checkContentPropsCB, false, true);  
        
        RetryingTransactionCallback<Void> truncateFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {                 
                /**
                 * Truncate the non zero byte file we are going to use to test
                 */
                FileOpenParams createFileParams2 = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME_NON_ZERO, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.secondFileHandle = driver.openFile(testSession, testConnection, createFileParams2);
                assertNotNull(testContext.secondFileHandle);
                
                testContext.testNonZeroNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME_NON_ZERO);
                assertNotNull("testContext.testNodeRef is null", testContext.testNonZeroNodeRef);

                driver.truncateFile(testSession, testConnection, testContext.secondFileHandle, 0);
                
                logger.debug("close the second non zero file, secondFileHandle");
                driver.closeFile(testSession, testConnection, testContext.secondFileHandle);   
   
                return null;
            }
        };
        tran.doInTransaction(truncateFileCB, false, true);
        
        /**
         * d: check both files have content properties.
         */
        RetryingTransactionCallback<Void> checkContentProps2CB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                ContentReader reader = contentService.getReader(testContext.testNonZeroNodeRef, ContentModel.PROP_CONTENT);
                String s = reader.getContentString();
                assertEquals("content not truncated", "", s);
                
                ContentReader reader2 = contentService.getReader(testContext.testZeroNodeRef, ContentModel.PROP_CONTENT);
                String s2 = reader2.getContentString();
                assertEquals("content not empty", "", s2);
                return null;
            }
        };
        tran.doInTransaction(checkContentProps2CB, false, true);    



    } // testEmptyFiles
    
    
    /**
     * Simulates a SaveAs from Word2003 for a checked out file
     * 
     * 1. Create new document TESTFILE.DOC, file did not exist
     * 2. CheckOut TESTFILE.DOC
     * 3. Create -WRDnnnn.TMP file, where 'nnnn' is a 4 digit sequence to make the name unique
     * 4. Rename TESTFILE(Working Copy).DOC to Backup of SAVEAS.wbk
     * 5. Rename -WRDnnnn.TMP to TESTFILE(Working Copy).DOC 
     * 6  CheckIn working copy.
     * 7. Validate TESTFILE.DOC
     */
    public void testScenarioMSWord2003SaveAsShuffleCheckedOutFile() throws Exception
    {
        logger.debug("testScenarioMSWord2003SaveShuffleLockedFile");
        final String FILE_NAME = "TESTFILE.DOC";
        final String FILE_OLD_TEMP = "SAVEAS.wbk";
        final String FILE_NEW_TEMP = "~WRD0002.TMP";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            String workingFileName;
            NodeRef workingCopy;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSWord2003ShuffleLockedFile";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("a) create new file and check out");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
  
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);
                
                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                
                /**
                 * CheckOut the test node
                 */
                NodeRef workingCopy = checkOutCheckInService.checkout(shuffledNodeRef);
                assertNotNull("Working copy is null", workingCopy);
                testContext.workingCopy = workingCopy;
                
                ChildAssociationRef ref = nodeService.getPrimaryParent(workingCopy);
                QName name = ref.getQName();
                testContext.workingFileName = ref.getQName().getLocalName();
                assertNotNull("working file name is null", testContext.workingFileName );
                
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
             
        /**
         * b) Save the new file
         * Write ContentDiskDriverTest3.doc to the test file,
         */
        logger.debug("b) move new file into place");
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
         
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
            
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * c) rename the old working file
         */
        logger.debug("c) rename old file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + testContext.workingFileName, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
           
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        logger.debug("d) move new file into place");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + testContext.workingFileName); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        logger.debug("e) now check in");
        
        /**
         * Now Check In
         */
        RetryingTransactionCallback<Void> checkInCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               
               checkOutCheckInService.checkin(testContext.workingCopy, null);         
               return null;
            }
        };
        
        tran.doInTransaction(checkInCB, false, true);
        
        
        logger.debug("e) validate results");
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                             
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertNotNull("data is null", data);
               assertEquals("size is wrong", 26112, data.getSize());
               assertEquals("mimeType is wrong", "application/msword",data.getMimetype());
           
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        
    } // Test Word Save Locked File
    
    /**
     * ALF-10686
     * This scenario is executed by windows explorer.
     * 
     * A file is created and the file handle kept open.
     * stuff is written
     * Then the modified date is set
     * Then the file is closed.
     * @throws Exception
     */
    public void testSetFileScenario() throws Exception
    {
        logger.debug("testSetFileInfo");
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        Date now = new Date();
        
        // CREATE 6 hours ago
        final Date CREATED = new Date(now.getTime() - 1000 * 60 * 60 * 6);
        // Modify one hour ago
        final Date MODIFIED = new Date(now.getTime() - 1000 * 60 * 60 * 1);
        
        class TestContext
        {     
            NodeRef testNodeRef;    
        };
        
        final TestContext testContext = new TestContext();
      
        /**
          * Step 1 : Create a new file in read/write mode and add some content.
          * Call SetInfo to set the creation date
          */
        int openAction = FileAction.CreateNotExist;
        
        final String FILE_NAME="testSetFileScenario.txt";
        final String FILE_PATH="\\"+FILE_NAME;
        
        // Clean up junk if it exists
        try
        {
            driver.deleteFile(testSession, testConnection, FILE_PATH);
        }
        catch (IOException ie)
        {
           // expect to go here
        }
                  
        final FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                
        final NetworkFile file = driver.createFile(testSession, testConnection, params);
        assertNotNull("file is null", file);
        assertFalse("file is read only, should be read-write", file.isReadOnly());
        
        RetryingTransactionCallback<Void> writeStuffCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                byte[] stuff = "Hello World".getBytes();
                
                driver.writeFile(testSession, testConnection, file, stuff, 0, stuff.length, 0);
                              
                FileInfo info = driver.getFileInformation(testSession, testConnection, FILE_PATH);
                info.setFileInformationFlags(FileInfo.SetModifyDate);
                info.setModifyDateTime(MODIFIED.getTime());
                info.setNetworkFile(file);
                driver.setFileInformation(testSession, testConnection, FILE_PATH, info);
                
                return null;
            }
        };
        tran.doInTransaction(writeStuffCB);
        
        RetryingTransactionCallback<Void> closeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                 // This close is in a different position to the simple setFileInformation scenarios above.
                driver.closeFile(testSession, testConnection, file);

                return null;
            }
        };
        tran.doInTransaction(closeFileCB);
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                NodeRef companyHome = repositoryHelper.getCompanyHome();
                NodeRef newNode = nodeService.getChildByName(companyHome, ContentModel.ASSOC_CONTAINS, FILE_NAME);
                testContext.testNodeRef = newNode;
                assertNotNull("can't find new node", newNode);
                Serializable content = nodeService.getProperty(newNode, ContentModel.PROP_CONTENT);
                assertNotNull("content is null", content);     
                Date modified = (Date)nodeService.getProperty(newNode, ContentModel.PROP_MODIFIED);
                assertEquals("modified time not set correctly", MODIFIED, modified);
                return null;
            }
        };
        tran.doInTransaction(validateCB);
        
         
        // clean up so we could run the test again
        RetryingTransactionCallback<Void> deleteFile = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, FILE_PATH);
                return null;
            }
        };
        tran.doInTransaction(deleteFile, false, true);
        
    } // test set modified scenario
    
    /**
     * This test tries to simulate the cifs shuffling that is done 
     * from Save from Mac Lion by TextEdit
     * 
     * a) Temp file created in temporary folder (test.txt)
     * b) Resource fork file created in temporary folder (._test.txt)
     * b) Target file deleted
     * c) Temp file moved to target file.
     */
    public void testScenarioMacLionTextEdit() throws Exception
    {
        logger.debug("testScenarioLionTextEdit");
        final String FILE_NAME = "test.txt";
        final String FORK_FILE_NAME = "._test.txt";
        final String TEMP_FILE_NAME = "test.txt";
        
        final String UPDATED_TEXT = "Mac Lion Text Updated Content";
        
        class TestContext
        {
            NetworkFile lockFileHandle;
            NetworkFile firstFileHandle;
            NetworkFile tempFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioLionTextEdit";
        final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioLionTextEdit\\.Temporary Items";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        /**
         * Create a file in the test directory
         */           
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                driver.createDirectory(testSession, testConnection, createTempDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                String testContent = "Mac Lion Text";
                byte[] testContentBytes = testContent.getBytes();
                 
                driver.writeFile(testSession, testConnection, testContext.firstFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                
                /**
                 * Create the temp file we are going to use
                 */
                FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                assertNotNull(testContext.tempFileHandle);
                               
                testContent = UPDATED_TEXT;
                testContentBytes = testContent.getBytes();
                driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                driver.closeFile(testSession, testConnection, testContext.tempFileHandle); 
                
                /**
                 * Create the temp resource fork file we are going to use
                 */
                createFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + FORK_FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.lockFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.lockFileHandle);
                testContext.lockFileHandle.closeFile();
                
                /**
                 * Also add versionable to target file
                 */
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
            
        /**
         * b) Delete the target file
         */
        RetryingTransactionCallback<Void> deleteTargetFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(deleteTargetFileCB, false, true);
        
        /**
         * c) Move the temp file into place
         */
        RetryingTransactionCallback<Void> moveTempFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, TEST_DIR + "\\" + FILE_NAME); 
                driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + FORK_FILE_NAME, TEST_DIR + "\\" + FORK_FILE_NAME); 
                return null;
            }
        };
        tran.doInTransaction(moveTempFileCB, false, true);
        
        /**
         * Validate results.
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {

                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
                assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                
                ContentReader reader = contentService.getReader(shuffledNodeRef, ContentModel.PROP_CONTENT);
                assertNotNull("Reader is null", reader);
                String s = reader.getContentString();
                assertEquals("content not written", UPDATED_TEXT, s);
                
                
                return null;
            }
        };
        
        tran.doInTransaction(validateCB, false, true);

    } // testScenarioLionTextEdit

    /**
     * Simulates a Save from Powerpoint 2011 Mac
     * 0. FileA.pptx already exists.
     * 1. Create new document FileA1.pptx
     * 2. Delete FileA.pptx
     * 3. Rename FileA1.pptx to FileA.pptx 
     */
    public void testScenarioMSPowerpoint2011MacSaveShuffle() throws Exception
    {
        logger.debug("testScenarioMSPowerpoint2011MacSaveShuffle(");
        
        final String FILE_NAME = "FileA.pptx";
        final String FILE_NEW_TEMP = "FileA1.pptx";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSPowerpoint2011MacSaveShuffle";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            logger.debug("expect to get exception - cleaning garbage");
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("0) create new file");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
  
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use (FileA.pptx)
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                
                NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
             
        /**
         * b) Save the new file
         * Write ContentDiskDriverTest3.doc to the test file,
         */
        logger.debug("b) write some content");
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
         
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
            
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * c) delete the old file
         */
        logger.debug("c) delete old file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
           
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        logger.debug("d) rename new file into place");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        logger.debug("e) validate results");
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertNotNull("data is null", data);
               assertEquals("size is wrong", 26112, data.getSize());
               assertEquals("mimeType is wrong", "application/msword",data.getMimetype());
               
               assertTrue("versionable aspect missing", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
               assertTrue("hidden aspect still applied", !nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_HIDDEN));
               assertTrue("temporary aspect still applied", !nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_TEMPORARY));
           
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        
    } // testScenarioMSPowerpoint2011MacSaveShuffle

    /**
     * Simulates a Save from Excel 2011 Mac
     * 0. FileA.xlsx already exists.
     * 1. Create new document ._A8A09200
     * 2. Delete FileA.xlsx
     * 3. Rename ._A8A09200 to FileA.xlsx 
     */
    public void testScenarioMSExcel2011MacSaveShuffle() throws Exception
    {
        logger.debug("testScenarioMSExcel2011MacSaveShuffle(");
        
        final String FILE_NAME = "FileA.xlsx";
        final String FILE_NEW_TEMP = "._A8A09200";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSExcel2011MacSaveShuffle";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            logger.debug("expect to get exception - cleaning garbage");
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("0) create new file");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
  
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use (FileA.xlsx)
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                
                NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);

                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
             
        /**
         * b) Save the new file
         * Write ContentDiskDriverTest3.doc to the test file,
         */
        logger.debug("b) write some content");
        RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
         
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
            
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(writeFileCB, false, true);
        
        /**
         * c) delete the old file
         */
        logger.debug("c) delete old file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
           
        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        logger.debug("d) rename new file into place");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        logger.debug("e) validate results");
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertNotNull("data is null", data);
               assertEquals("size is wrong", 26112, data.getSize());
               assertEquals("mimeType is wrong", "application/msword",data.getMimetype());
               
               assertTrue("versionable aspect missing", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
               assertTrue("hidden aspect still applied", !nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_HIDDEN));
               assertTrue("temporary aspect still applied", !nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_TEMPORARY));
           
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        
    } // testScenarioMSExcel2011MacSaveShuffle

    /**
     * This test tries to simulate the cifs shuffling that is done to
     * support MS Word 2011 on Mac with backup turned on. 
     * 
     * a) TEST.DOCX
     * b) Create new temp file in temp dir Word Work File D_.tmp
     * c) Delete backup file.
     * c) Rename TEST.DOCX to Backup of TEST.docx
     * d) Move temp file to target dir
     * d) Rename Word Work File D_.tmp to TEST.docx
     */
    public void testScenarioMSWord20011MacSaveWithBackup() throws Exception
    {
        logger.debug("testScenarioMSWord20011MacSaveWithBackup");
        final String FILE_NAME = "TEST.DOCX";
        final String FILE_BACKUP = "Backup of TEST.docx";
        final String FILE_NEW_TEMP = "Word Work File D_.tmp";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;            
            NodeRef testNodeRef;   // node ref of test.doc
        };
        
        final TestContext testContext = new TestContext();
        
        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMSWord20011MacSaveWithBackup";
        final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioMSWord20011MacSaveWithBackup\\.Temporary Items";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
        
        logger.debug("Step 0 - initialise");
        
        /**
         * Create a file in the test directory
         */           
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                driver.createDirectory(testSession, testConnection, createTempDirParams);
                
                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                // no need to test lots of different properties, that's already been tested above
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                String testContent = "MS Word 2011 shuffle test";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();  
                        
                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
               
        /**
         * a) Save the temp file in the temp dir
         */
        logger.debug("Step a - create a temp file in the temp dir");
        RetryingTransactionCallback<Void> saveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);
                String testContent = "MS Word 2011 shuffle test This is new content";
                byte[] testContentBytes = testContent.getBytes();
                testContext.newFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.newFileHandle.close();
              
                return null;
            }
        };
        tran.doInTransaction(saveNewFileCB, false, true);
        
        /*
         * Step b not used in test case
         */
        
        /**
         * c) rename the target file to a backup file
         */
        logger.debug("Step c - rename the target file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_BACKUP);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);
        
        
        /**
         * d) Move the new file into target dir
         */
        logger.debug("Step d - move new file into target dir");
        RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NEW_TEMP); 
                return null;
            }
        };
        
        tran.doInTransaction(moveNewFileCB, false, true);
        
        /**
         * e) Rename temp file into place.
         */
        logger.debug("Step e - rename temp file into place");
        RetryingTransactionCallback<Void> renameTempFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(renameTempFileCB, false, true);
        
        
        /**
         * Validate
         */
        
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
               assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME) );    
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, false, true);

    } // testScenarioMSMacWord20011SaveWithBackup save
    
    
    /**
     * Simulates a Mac Lion Drag and Drop 
     * 0. ALF-15158.diff  already exists and is versionable
     * 1. Delete ALF-15158.diff 
     * 2. Create new document ALF-15158.diff 
     */
    public void testMacDragAndDrop() throws Exception
    {
        logger.debug("testMacDragAndDrop()");
        
        final String FILE_NAME = "ALF-15158.diff";
        
        class TestContext
        {
            NetworkFile firstFileHandle;
            NodeRef file1NodeRef;
        };
        
        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\MacDragAndDrop";
        
        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
     
        /**
         * Create a file in the test directory
         */    
        
        try
        {
            logger.debug("expect to get exception - cleaning garbage");
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("0) create new file");
        RetryingTransactionCallback<TestContext> createFileCB = new RetryingTransactionCallback<TestContext>() {
            @Override
            public TestContext execute() throws Throwable
            {
  
                TestContext ctx = new TestContext();
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                
                /**
                 * Create the file we are going to use (FileA.pptx)
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                ctx.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(ctx.firstFileHandle);
                
                driver.closeFile(testSession, testConnection, ctx.firstFileHandle); 
                
                ctx.file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(ctx.file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                        
                return ctx;
            }
        };
        final TestContext testContext = tran.doInTransaction(createFileCB, false, true);
        
        /**
         * 1) delete the old file
         */
        logger.debug("1) delete old file");
        RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(renameOldFileCB, false, true);

             
        /**
         * 2) CreateNewFile and write some new content
         * 
         */
        logger.debug("2) write some content");
        RetryingTransactionCallback<Void> restoreFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
         
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);

                byte[] buffer= new byte[1000];
                InputStream is = fileResource.getInputStream();
                try
                {
                    long offset = 0;
                    int i = is.read(buffer, 0, buffer.length);
                    while(i > 0)
                    {
                        testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
                        offset += i;
                        i = is.read(buffer, 0, buffer.length);
                    }                 
                }
                finally
                {
                    is.close();
                }
            
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                    
                return null;
            }
        };
        tran.doInTransaction(restoreFileCB, false, true);
        
                   
        logger.debug("3) validate results");
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               assertNotNull("data is null", data);
               assertEquals("size is wrong", 26112, data.getSize());
               assertEquals("mimeType is wrong", "application/msword",data.getMimetype());
               
               assertTrue("versionable aspect missing", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
               assertTrue("hidden aspect still applied", !nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_HIDDEN));
               assertTrue("temporary aspect still applied", !nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_TEMPORARY));
           
               assertEquals("Node ref has changed", shuffledNodeRef, testContext.file1NodeRef);
               return null;
            }
        };
        
        tran.doInTransaction(validateCB, true, true);
        logger.debug("end testMacDragAndDrop");
        
    } // testMacDragAndDrop
    
    
    /**
     * Mountain Lion 2011 Word
     * a) Create new file (Word Work File D2.tmp)  
     * (Actually in real life its renamed from a temp directory.
     * c) Existing file rename out of the way.   (Word Work File L_5.tmp)
     * d) New file rename into place. (MacWord1.docx)
     * e) Old file deleted
     */
     public void testScenarioMountainLionWord2011() throws Exception
     {  
         logger.debug("testScenarioMountainLionWord2011");
         
         final String FILE_NAME = "MacWord1.docx";
         final String FILE_OLD_TEMP = "Word Work File L_5.tmp";
         final String FILE_NEW_TEMP = "Word Work File D_2.tmp";
         
         class TestContext
         {
             NetworkFile firstFileHandle;
             String mimetype;
         };
         
         final TestContext testContext = new TestContext();
         
         final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMountainLionWord2011";
         
         ServerConfiguration scfg = new ServerConfiguration("testServer");
         TestServer testServer = new TestServer("testServer", scfg);
         final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
         DiskSharedDevice share = getDiskSharedDevice();
         final TreeConnection testConnection = testServer.getTreeConnection(share);
         final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

         /**
          * Clean up just in case garbage is left from a previous run
          */
         RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };
         
         try
         {
             tran.doInTransaction(deleteGarbageFileCB);
         }
         catch (Exception e)
         {
             // expect to go here
         }
         
         logger.debug("a) create new file");
         RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 /**
                  * Create the test directory we are going to use 
                  */
                 FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 driver.createDirectory(testSession, testConnection, createRootDirParams);
                 driver.createDirectory(testSession, testConnection, createDirParams);
                 
                 /**
                  * Create the file we are going to test
                  */
                 FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                 assertNotNull(testContext.firstFileHandle);
                 
                 ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                 assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);
                 writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                 driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                 NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);

                 return null;
             }
         };
         tran.doInTransaction(createFileCB, false, true);
              
         /**
          * b) Save the new file
          * Write ContentDiskDriverTest3.doc,
          */
         logger.debug("b) move new file into place");
         RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
          
                 ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                 assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);
                 writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                 driver.closeFile(testSession, testConnection, testContext.firstFileHandle);   
                 
                 
                 NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME);
                 Map<QName, Serializable> props = nodeService.getProperties(file1NodeRef);
                 ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
//                 assertNotNull("data is null", data);
//                 assertEquals("size is wrong", 166912, data.getSize());
                 testContext.mimetype = data.getMimetype();
                 
                 return null;
             }
         };
         tran.doInTransaction(writeFileCB, false, true);
         
         /**
          * c) rename the old file
          */
         logger.debug("c) rename old file");
         RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                 return null;
             }
         };
         tran.doInTransaction(renameOldFileCB, false, true);
            
         /**
          * d) Move the new file into place, stuff should get shuffled
          */
         logger.debug("d) move new file into place");
         RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                 return null;
             }
         };
         
         tran.doInTransaction(moveNewFileCB, false, true);
         
         /**
          * d) Delete the old file
          */
         logger.debug("d) delete the old file");
         RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                 return null;
             }
         };
         
         tran.doInTransaction(deleteOldFileCB, false, true);
         
         logger.debug("e) validate results");
         
         /**
          * Now validate everything is correct
          */
         RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                
                Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
                
                ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                //assertNotNull("data is null", data);
                //assertEquals("size is wrong", 123904, data.getSize());
                
                NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME); 
                assertTrue("file has lost versionable aspect", nodeService.hasAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE));

                assertEquals("mimeType is wrong", testContext.mimetype, data.getMimetype());
                
            
                return null;
             }
         };
         
         tran.doInTransaction(validateCB, true, true);
     }  // Test Word 2011 Mountain Lion

     /**
      * This test tries to simulate the cifs shuffling that is done 
      * from Save from Mac Mountain Lion by Preview
      * 
      * a) Temp file created in temporary folder (Crysanthemum.jpg)
      * b) Target file deleted by open / delete on close flag / close
      * c) Temp file moved to target file.
      */
     public void testScenarioMacMountainLionPreview() throws Exception
     {
         logger.debug("testScenarioMountainLionPreview");
         final String FILE_NAME = "Crysanthemeum.jpg";
         final String TEMP_FILE_NAME = "Crysanthemeum.jpg";
         
         final String UPDATED_TEXT = "Mac Lion Preview Updated Content";
         
         class TestContext
         {
             NetworkFile firstFileHandle;
             NetworkFile tempFileHandle;            
             NodeRef testNodeRef;   // node ref Crysanthemenum.jpg
         };
         
         final TestContext testContext = new TestContext();
         
         final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
         final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview";
         final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview\\.Temporary Items";
         
         ServerConfiguration scfg = new ServerConfiguration("testServer");
         TestServer testServer = new TestServer("testServer", scfg);
         final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
         DiskSharedDevice share = getDiskSharedDevice();
         final TreeConnection testConnection = testServer.getTreeConnection(share);
         final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
         
         /**
          * Create a file in the test directory
          */           
         RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 /**
                  * Create the test directory we are going to use 
                  */
                 FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 driver.createDirectory(testSession, testConnection, createRootDirParams);
                 driver.createDirectory(testSession, testConnection, createDirParams);
                 driver.createDirectory(testSession, testConnection, createTempDirParams);
                 
                 /**
                  * Create the file we are going to use
                  */
                 FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                 assertNotNull(testContext.firstFileHandle);
                 
                 String testContent = "Mac Mountain Lion Text";
                 byte[] testContentBytes = testContent.getBytes();
                  
                 driver.writeFile(testSession, testConnection, testContext.firstFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                 
                 /**
                  * Create the temp file we are going to use
                  */
                 FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                 assertNotNull(testContext.tempFileHandle);
                                
                 testContent = UPDATED_TEXT;
                 testContentBytes = testContent.getBytes();
                 driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.tempFileHandle); 
                                  
                 /**
                  * Also add versionable to target file
                  */
                 testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                 
                 return null;
             }
         };
         tran.doInTransaction(createFileCB, false, true);
             
//         /**
//          * b) Delete the target file by opening it and set the delete on close bit
//          */
//         RetryingTransactionCallback<Void> deleteTargetFileCB = new RetryingTransactionCallback<Void>() {
//
//             @Override
//             public Void execute() throws Throwable
//             {
//                 FileOpenParams openFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
//                 testContext.tempFileHandle = driver.openFile(testSession, testConnection, openFileParams);
//                 FileInfo info = new FileInfo();
//                 info.setFileInformationFlags(FileInfo.SetDeleteOnClose);
//                 info.setDeleteOnClose(true);
//                 testContext.tempFileHandle.setDeleteOnClose(true);
//                 
//                 driver.setFileInformation(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, info);
//                 
//                 assertNotNull(testContext.tempFileHandle);
//                 logger.debug("this close should result in a file being deleted");
//                 driver.closeFile(testSession, testConnection,  testContext.tempFileHandle);
//                 return null;
//             }
//         };
//         tran.doInTransaction(deleteTargetFileCB, false, true);
         
       /**
       * b) Delete the target file by a simple delete
       */
      RetryingTransactionCallback<Void> deleteTargetFileCB = new RetryingTransactionCallback<Void>() {

          @Override
          public Void execute() throws Throwable
          {
                
              driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
              return null;
          }
      };
      tran.doInTransaction(deleteTargetFileCB, false, true);
         
         /**
          * c) Move the temp file into target directory
          */
         RetryingTransactionCallback<Void> moveTempFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, TEST_DIR + "\\" + FILE_NAME); 
                 return null;
             }
         };
         tran.doInTransaction(moveTempFileCB, false, true);
         
         /**
          * Validate results.
          */
         RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {

                 NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                 assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
                 return null;
             }
         };
         
         tran.doInTransaction(validateCB, false, true);

     } // testScenarioMountainLionPreview

     /**
      * This test tries to simulate the cifs shuffling that is done 
      * from Save from Mac Mountain Lion by Preview when document is saved first time
      * 
      * a) Temp file created in temporary folder (temp\image.jpg.sb-1e5e1543-ajn3cR)
      * b) Temp file renamed to original name (temp\image.jpg.sb-1e5e1543-ajn3cR -> temp\image.jpg)
      * c) Original document renamed to backup copy name (test\image.jpg -> test\image.jpg.sb-1e5e1543-ajn3cR)
      * d) Renamed temp file moved to original (temp\image.jpg -> test\image.jpg)
      */
     public void testScenarioMacMountainLionPreview_MNT_263() throws Exception
     {
         logger.debug("testScenarioMacMountainLionPreview_MNT_263");
         final String FILE_NAME = "image.jpg";
         final String TEMP_FILE_NAME = "image.jpg.sb-1e5e1543-ajn3cR";
         
         final String UPDATED_TEXT = "Mac Lion Preview Updated Content";
         
         class TestContext
         {
             NetworkFile firstFileHandle;
             NetworkFile tempFileHandle;            
             NodeRef testNodeRef;   // node ref image.jpg
         };
         
         final TestContext testContext = new TestContext();
         
         final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
         final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview";
         final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview\\.Temporary Items";
         
         ServerConfiguration scfg = new ServerConfiguration("testServer");
         TestServer testServer = new TestServer("testServer", scfg);
         final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
         DiskSharedDevice share = getDiskSharedDevice();
         final TreeConnection testConnection = testServer.getTreeConnection(share);
         final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
         
         /**
          * Create a file in the test directory
          */           
         RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 /**
                  * Create the test directory we are going to use 
                  */
                 FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 driver.createDirectory(testSession, testConnection, createRootDirParams);
                 driver.createDirectory(testSession, testConnection, createDirParams);
                 driver.createDirectory(testSession, testConnection, createTempDirParams);
                 
                 /**
                  * Create the file we are going to use
                  */
                 FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                 assertNotNull(testContext.firstFileHandle);
                 
                 String testContent = "Mac Lion Preview Content";
                 byte[] testContentBytes = testContent.getBytes();
                  
                 driver.writeFile(testSession, testConnection, testContext.firstFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                 
                 /**
                  * Create the temp file we are going to use
                  */
                 FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                 assertNotNull(testContext.tempFileHandle);
                                
                 testContent = UPDATED_TEXT;
                 testContentBytes = testContent.getBytes();
                 driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.tempFileHandle); 
                                  
                 /**
                  * Also add versionable to target file
                  */
                 testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                 
                 return null;
             }
         };
         tran.doInTransaction(createFileCB, false, true);
         
         RetryingTransactionCallback<Void> renameTempFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, TEST_TEMP_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };
         tran.doInTransaction(renameTempFileCB, false, true);
         
         RetryingTransactionCallback<Void> renameFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + TEMP_FILE_NAME);
                 return null;
             }
         };
         tran.doInTransaction(renameFileCB, false, true);
         
         RetryingTransactionCallback<Void> moveRenamedTempFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };
         tran.doInTransaction(moveRenamedTempFileCB, false, true);
         
         RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {

                 NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                 assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
                 assertEquals("Unexpected content size", contentService.getReader(shuffledNodeRef, ContentModel.PROP_CONTENT).getSize(), UPDATED_TEXT.length());
                 
                 return null;
             }
         };
         
         tran.doInTransaction(validateCB, false, true);

     } // testScenarioMacMountainLionPreview_MNT_263

     /**
      * This test tries to simulate the cifs shuffling that is done 
      * from Save from Mac Mountain Lion by Preview when document is opened/saved few time a row
      * 
      * a) Temp file created in temporary folder (temp\image.jpg)
      * b) Original file is renamed for deletion(test\image.jpg -> test\.smbdeleteAAA1b994.4)
      * c) Renamed file has got deleteOnClose flag
      * d) Renamed file is closed.
      * e) Temp file is moved into original file location(temp\image.jpg -> test\image.jgp) 
      */
     public void testScenarioMacMountainLionPreview_MNT_317() throws Exception
    {
        logger.debug("testScenarioMacMountainLionPreview_MNT_317");
        final String FILE_NAME = "image.jpg";
        final String TEMP_FILE_NAME = ".smbdeleteAAA1b994.4";

        final String UPDATED_TEXT = "Mac Lion Preview Updated Content";

        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile tempFileHandle;
            NodeRef testNodeRef; // node ref image.jpg
        }
        ;

        final TestContext testContext = new TestContext();

        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview";
        final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionPreview\\.Temporary Items";

        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Create a file in the test directory
         */
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                driver.createDirectory(testSession, testConnection, createTempDirParams);

                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);

                String testContent = "Mac Lion Preview Content";
                byte[] testContentBytes = testContent.getBytes();

                driver.writeFile(testSession, testConnection, testContext.firstFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);

                /**
                 * Create the temp file we are going to use
                 */
                FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                assertNotNull(testContext.tempFileHandle);

                testContent = UPDATED_TEXT;
                testContentBytes = testContent.getBytes();
                driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                driver.closeFile(testSession, testConnection, testContext.tempFileHandle);

                /**
                 * Also add versionable to target file
                 */
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);

                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);

        RetryingTransactionCallback<Void> renameFileCB = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                FileOpenParams openFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.tempFileHandle = driver.openFile(testSession, testConnection, openFileParams);
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + TEMP_FILE_NAME);
                
                return null;
            }
        };
        tran.doInTransaction(renameFileCB, false, true);

        /**
         * Delete file via deleteOnClose flag.
         */
        RetryingTransactionCallback<Void> deleteOnCloseCB = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                FileInfo info = new FileInfo();
                info.setFileInformationFlags(FileInfo.SetDeleteOnClose);
                info.setDeleteOnClose(true);
                testContext.tempFileHandle.setDeleteOnClose(true);

                driver.setFileInformation(testSession, testConnection, TEST_DIR + "\\" + TEMP_FILE_NAME, info);

                assertNotNull(testContext.tempFileHandle);
                logger.debug("this close should result in a file being deleted");
                driver.closeFile(testSession, testConnection, testContext.tempFileHandle);
                return null;
            }
        };
        tran.doInTransaction(deleteOnCloseCB, false, true);

//        /**
//         * Delete file directly.
//         */
//        RetryingTransactionCallback<Void> deleteTargetFileCB = new RetryingTransactionCallback<Void>()
//        {
//
//            @Override
//            public Void execute() throws Throwable
//            {
//
//                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + TEMP_FILE_NAME);
//                return null;
//            }
//        };
//        tran.doInTransaction(deleteTargetFileCB, false, true);

        RetryingTransactionCallback<Void> moveRenamedTempFileCB = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {
                driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        tran.doInTransaction(moveRenamedTempFileCB, false, true);

        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>()
        {

            @Override
            public Void execute() throws Throwable
            {

                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
                assertEquals("Unexpected content size", contentService.getReader(shuffledNodeRef, ContentModel.PROP_CONTENT).getSize(), UPDATED_TEXT.length());

                return null;
            }
        };

        tran.doInTransaction(validateCB, false, true);

    }     // testScenarioMacMountainLionPreview_MNT_317
     
    /**
      * This test tries to simulate the cifs shuffling that is done 
      * from Save from Mac Mountain Lion by Keynote when document is saved first time
      * 
      * a) Temp file created in temporary folder (temp\test.key)
      * b) Original document renamed to backup copy name (test\test.key -> test\test~.key)
      * c) Temp file moved to original name (temp\test.key -> test\test.key)
      */
     public void testScenarioMacMountainLionKeynote_MNT_8558() throws Exception
     {
         logger.debug("testScenarioMacMountainLionKeynote_MNT_8558");
         final String FILE_NAME = "test.key";
         final String BCKP_FILE_NAME = "test~.key";
         final String TEMP_FILE_NAME = "test.key";
         
         final String UPDATED_TEXT = "Mac Mountain Lion Keynote Updated Content";
         
         class TestContext
         {
             NetworkFile firstFileHandle;
             NetworkFile tempFileHandle;            
             NodeRef testNodeRef;   
         };
         
         final TestContext testContext = new TestContext();
         
         final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
         final String TEST_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionKeynote";
         final String TEST_TEMP_DIR = "\\ContentDiskDriverTest\\testScenarioMountainLionKeynote\\.Temporary Items";
         
         ServerConfiguration scfg = new ServerConfiguration("testServer");
         TestServer testServer = new TestServer("testServer", scfg);
         final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
         DiskSharedDevice share = getDiskSharedDevice();
         final TreeConnection testConnection = testServer.getTreeConnection(share);
         final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
         
         /**
          * Create a file in the test directory
          */           
         RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 /**
                  * Create the test directory we are going to use 
                  */
                 FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 driver.createDirectory(testSession, testConnection, createRootDirParams);
                 driver.createDirectory(testSession, testConnection, createDirParams);
                 driver.createDirectory(testSession, testConnection, createTempDirParams);
                 
                 /**
                  * Create the file we are going to use
                  */
                 FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                 assertNotNull(testContext.firstFileHandle);
                 
                 String testContent = "Mac Mountain Lion Keynote Content";
                 byte[] testContentBytes = testContent.getBytes();
                  
                 driver.writeFile(testSession, testConnection, testContext.firstFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                 
                 /**
                  * Create the temp file we are going to use
                  */
                 FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                 assertNotNull(testContext.tempFileHandle);
                                
                 testContent = UPDATED_TEXT;
                 testContentBytes = testContent.getBytes();
                 driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.tempFileHandle); 
                                  
                 /**
                  * Also add versionable to target file
                  */
                 testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                 
                 return null;
             }
         };
         tran.doInTransaction(createFileCB, false, true);
         
         RetryingTransactionCallback<Void> renameFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + BCKP_FILE_NAME);
                 return null;
             }
         };
         tran.doInTransaction(renameFileCB, false, true);
         
         RetryingTransactionCallback<Void> moveTempFileCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, TEST_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };
         tran.doInTransaction(moveTempFileCB, false, true);
         
         RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {

                 NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                 assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
                 assertEquals("Unexpected content size", contentService.getReader(shuffledNodeRef, ContentModel.PROP_CONTENT).getSize(), UPDATED_TEXT.length());
                 
                 return null;
             }
         };
         
         tran.doInTransaction(validateCB, false, true);
         
         //Make sure that during second rename test.key->test~.key deleted test~.key is not restored and version history doesn't lost. 
         RetryingTransactionCallback<Void> prepareForSecondRunCB  = new RetryingTransactionCallback<Void>() {

             @Override
             public Void execute() throws Throwable
             {

                 driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + BCKP_FILE_NAME);
                 FileOpenParams createTempFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + TEMP_FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                 
                 String testContent = UPDATED_TEXT;
                 byte[] testContentBytes = testContent.getBytes();
                 driver.writeFile(testSession, testConnection, testContext.tempFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                 driver.closeFile(testSession, testConnection, testContext.tempFileHandle); 
                 
                 return null;
             }
         };
         
         tran.doInTransaction(prepareForSecondRunCB, false, true);
         tran.doInTransaction(renameFileCB, false, true);
         tran.doInTransaction(moveTempFileCB, false, true);
         tran.doInTransaction(validateCB, false, true);

     } // testScenarioMacMountainLionKeynote_MNT_8558

     /**
      *  Gedit has the nasty behaviour of renaming an open file.
      *  1) create file (gedit12345678.txt)
      *  2) create temp file (.goutputStream-IRYDPW) write and flush
      *  3) rename (fails name collision)
      *  4) delete target
      *  5) rename this one succeeds
      *  6) close temp file
      *  
      */
     public void testGedit() throws Exception
     {
         logger.debug("testGEdit");
         
         final String FILE_NAME = "gedit12345678.txt";
         final String FILE_TITLE = "Gedit";
         final String FILE_DESCRIPTION = "This is a test document to test CIFS shuffle";
         final String TEMP_FILE_NAME = ".goutputStream-IRYDPW";
         final String UPDATE_TEXT = "Shuffle an open file";

         class TestContext
         {
             NetworkFile firstFileHandle;
             NetworkFile tempFileHandle;
             NodeRef testNodeRef;
         };

         final TestContext testContext = new TestContext();

         final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testGEdit";

         ServerConfiguration scfg = new ServerConfiguration("testServer");
         TestServer testServer = new TestServer("testServer", scfg);
         final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
         DiskSharedDevice share = getDiskSharedDevice();
         final TreeConnection testConnection = testServer.getTreeConnection(share);
         final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

         /**
          * Clean up from a previous run
          */
         RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {
                 driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };

         try
         {
             tran.doInTransaction(deleteGarbageFileCB);
         }
         catch (Exception e)
         {
             // expect to go here
         }

         /**
          * Create a file in the test directory
          */
         RetryingTransactionCallback<Void> createTestFileFirstTime = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {

                 /**
                  * Create the test directory we are going to use
                  */
                 FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 driver.createDirectory(testSession, testConnection, createRootDirParams);
                 driver.createDirectory(testSession, testConnection, createDirParams);

                 /**
                  * Create the file we are going to use
                  */
                 FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                 assertNotNull(testContext.firstFileHandle);

                 testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                 nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_TITLE, FILE_TITLE);
                 nodeService.setProperty(testContext.testNodeRef, ContentModel.PROP_DESCRIPTION, FILE_DESCRIPTION);

                 String testContent = "Gedit shuffle test";
                 byte[] testContentBytes = testContent.getBytes();
                 testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);

                 driver.closeFile(testSession, testConnection, testContext.firstFileHandle);
                 
                 nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                 
                 return null;
             }
         };
         tran.doInTransaction(createTestFileFirstTime, false, true);

        /**
          * Create the temp file
          * add content
          * leave open
          */
         RetryingTransactionCallback<Void> createTempFile = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {

                 FileOpenParams params = new FileOpenParams(TEST_DIR + "\\" + TEMP_FILE_NAME, FileAction.TruncateExisting, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                 NetworkFile file = driver.createFile(testSession, testConnection, params);
                 testContext.tempFileHandle = file;
                 String testContent = UPDATE_TEXT;
                 byte[] testContentBytes = testContent.getBytes();
                 testContext.tempFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                  /**     driver.closeFile(testSession, testConnection, file);   **/

                 return null;
             }
         };
         tran.doInTransaction(createTempFile, false, true);

         /**
          * rename the test file to the temp
          */
         RetryingTransactionCallback<Void> renameTestFileToTemp = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {
                 driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + TEMP_FILE_NAME, TEST_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };
         
         // expect this one to fail
         try
         {
             tran.doInTransaction(renameTestFileToTemp, false, true);
             fail("should have failed");
         }
         catch (Exception e)
         {
             // expect to go here
         }
         
         /**
          * delete the target file
          */
         RetryingTransactionCallback<Void> deleteTargetFile = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {
                 driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                 return null;
             }
         };
         
         tran.doInTransaction(deleteTargetFile, false, true);
         
         // This one should succeed
         tran.doInTransaction(renameTestFileToTemp, false, true);
         
         RetryingTransactionCallback<Void> closeTempFile = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {
                 driver.closeFile(testSession, testConnection, testContext.tempFileHandle);
                 return null;
             }
         };
         
         tran.doInTransaction(closeTempFile, false, true);
         
         // Now validate
         RetryingTransactionCallback<Void> validate = new RetryingTransactionCallback<Void>()
         {

             @Override
             public Void execute() throws Throwable
             {
                 NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                  
                 ContentReader reader = contentService.getReader(shuffledNodeRef, ContentModel.PROP_CONTENT);
                 String s = reader.getContentString();
                 assertEquals("content not written", UPDATE_TEXT, s);
                 
                 assertTrue("node is not versionable", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                 assertEquals("shuffledNode ref is different", shuffledNodeRef, testContext.testNodeRef);
      
        
                 return null;
             }
         };
         
         tran.doInTransaction(validate, false, true);

         logger.debug("end testGedit");
     } // testGedit
     
     
     /**
      * Windows7 Explorer update
      * 0) Existing file mark.jpg 
      * a) Create new file (~ark.tmp)  
      * b) Existing file rename out of the way.   (mark.jpg~RF5bb356.TMP)
      * c) New file rename into place. (~ark.tmp - mark.jpg)
      * d) Old file opened attributes only
      * e) set delete on close
      * f) close
      */
      public void testWindows7Explorer() throws Exception
      {  
          logger.debug("testWindows7Explorer");
          
          final String FILE_NAME = "mark.jpg";
          final String FILE_OLD_TEMP = "mark.jpg~RF5bb356.TMP";
          final String FILE_NEW_TEMP = "~ark.tmp";
          
          class TestContext
          {
              NodeRef testNodeRef;
              NetworkFile firstFileHandle;
              NetworkFile secondFileHandle;
          };
          
          final TestContext testContext = new TestContext();
          
          final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testWindows7Explorer";
          
          ServerConfiguration scfg = new ServerConfiguration("testServer");
          TestServer testServer = new TestServer("testServer", scfg);
          final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
          DiskSharedDevice share = getDiskSharedDevice();
          final TreeConnection testConnection = testServer.getTreeConnection(share);
          final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

          /**
           * Clean up just in case garbage is left from a previous run
           */
          RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                  return null;
              }
          };
          
          try
          {
              tran.doInTransaction(deleteGarbageFileCB);
          }
          catch (Exception e)
          {
              // expect to go here
          }
          
          logger.debug("0) create new file");
          RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  /**
                   * Create the test directory we are going to use 
                   */
                  FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                  FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                  driver.createDirectory(testSession, testConnection, createRootDirParams);
                  driver.createDirectory(testSession, testConnection, createDirParams);
                  
                  /**
                   * Create the file we are going to test
                   */
                  FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                  testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                  assertNotNull(testContext.firstFileHandle);
                  
                  ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTestMark.jpg");
                  assertNotNull("unable to find test resource filesys/ContentDiskDriverTestMark.jpg", fileResource);
                  writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                  driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                  NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                  testContext.testNodeRef = file1NodeRef;
                  nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);

                  return null;
              }
          };
          tran.doInTransaction(createFileCB, false, true);
               
          /**
           * a) Save the new file
           */
          logger.debug("a) save new file");
          RetryingTransactionCallback<Void> writeFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                  testContext.secondFileHandle = driver.createFile(testSession, testConnection, createFileParams);    
           
                  ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTestMark2.jpg");
                  assertNotNull("unable to find test resource filesys/ContentDiskDriverTestMark2.jpg", fileResource);
                  writeResourceToNetworkFile(fileResource, testContext.secondFileHandle);
                  driver.closeFile(testSession, testConnection, testContext.secondFileHandle);   
                  
                  return null;
              }
          };
          tran.doInTransaction(writeFileCB, false, true);
          
          /**
           * b) rename the old file
           */
          logger.debug("c) rename old file");
          RetryingTransactionCallback<Void> renameOldFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                  return null;
              }
          };
          tran.doInTransaction(renameOldFileCB, false, true);
             
          /**
           * c) Move the new file into place, stuff should get shuffled
           */
          logger.debug("d) move new file into place");
          RetryingTransactionCallback<Void> moveNewFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME); 
                  return null;
              }
          };
          
          tran.doInTransaction(moveNewFileCB, false, true);
          
          /**
           * d) Delete the old file
           */
          logger.debug("d) delete on close the old file");
          RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  FileOpenParams openFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_OLD_TEMP, 0, AccessMode.NTReadAttributesOnly, FileAttribute.NTNormal, 0);
                  testContext.secondFileHandle = driver.openFile(testSession, testConnection, openFileParams);
                  assertNotNull(testContext.secondFileHandle);
                  
                  FileInfo info = new FileInfo();
                  info.setFileInformationFlags(FileInfo.SetDeleteOnClose);
                  driver.setFileInformation(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP, info);
                  testContext.secondFileHandle.setDeleteOnClose(true);
                  
                  driver.closeFile(testSession, testConnection, testContext.secondFileHandle);
                  return null;
              }
          };
          
          tran.doInTransaction(deleteOldFileCB, false, true);
          
          logger.debug("e) validate results");
          
          /**
           * Now validate everything is correct
           */
          RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                 NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 assertTrue("file has lost versionable aspect", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
                 assertEquals("node ref has changed", shuffledNodeRef, testContext.testNodeRef);
                 
                 
                 Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
                 ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                 assertNotNull("data is null", data);
                 assertEquals("size is wrong", 10407, data.getSize());
                 assertEquals("mimeType is wrong", "image/jpeg", data.getMimetype());
                 
                 // TODO - test metadata extraction
                 //assertEquals(false, props.get(QName.createQName(NamespaceService.EXIF_MODEL_1_0_URI, "flash")));

             
                 return null;
              }
          };
          
          tran.doInTransaction(validateCB, true, true);
      }  // Test Word 7 Explorer Update

      /**
       * 0. test.txt and ~test.txt exist. 
       * 1. Delete test.txt 
       * 2. Rename test.txt~ to test.txt 
       */
      public void testNFS() throws Exception
      {
          logger.debug("testNFS()");
          
          final String FILE_NAME = "test.txt";
          final String FILE_NAME_TEMP = "test.txt~";
          
          class TestContext
          {
              NetworkFile firstFileHandle;
              NetworkFile tempFileHandle;
              NodeRef file1NodeRef;
          };
          
          final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testNFS";
          
          ServerConfiguration scfg = new ServerConfiguration("testServer");
          TestServer testServer = new TestServer("testServer", scfg);
          final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
          DiskSharedDevice share = getDiskSharedDevice();
          final TreeConnection testConnection = testServer.getTreeConnection(share);
          final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();        

          /**
           * Clean up just in case garbage is left from a previous run
           */
          RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                  return null;
              }
          };
          RetryingTransactionCallback<Void> deleteGarbageFileCB2 = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME_TEMP);
                  return null;
              }
          };
       
          /**
           * Create a file in the test directory
           */    
          
          try
          {
              logger.debug("expect to get exception - cleaning garbage");
              tran.doInTransaction(deleteGarbageFileCB);
          }
          catch (Exception e)
          {
              // expect to go here
          }
          try
          {
              logger.debug("expect to get exception - cleaning garbage");
              tran.doInTransaction(deleteGarbageFileCB2);
          }
          catch (Exception e)
          {
              // expect to go here
          }
          
          logger.debug("0) create new file");
          RetryingTransactionCallback<TestContext> setupCB = new RetryingTransactionCallback<TestContext>() {
              @Override
              public TestContext execute() throws Throwable
              {
    
                  TestContext ctx = new TestContext();
                  /**
                   * Create the test directory we are going to use 
                   */
                  FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                  FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                  driver.createDirectory(testSession, testConnection, createRootDirParams);
                  driver.createDirectory(testSession, testConnection, createDirParams);
                  
                  /**
                   * Create the file we are going to use 
                   */
                  {
                      FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);  
                      ctx.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                      assertNotNull(ctx.firstFileHandle);              
                      driver.closeFile(testSession, testConnection, ctx.firstFileHandle); 
                      ctx.file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                  }
                  {
                      FileOpenParams createTempFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                      ctx.tempFileHandle = driver.createFile(testSession, testConnection, createTempFileParams);
                      assertNotNull(ctx.tempFileHandle);              
                      driver.closeFile(testSession, testConnection, ctx.tempFileHandle); 
                  }        
                  return ctx;
              }
          };
          final TestContext testContext = tran.doInTransaction(setupCB, false, true);
          
          /**
           * 1) delete the old file
           */
          logger.debug("1) delete old file");
          RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                  return null;
              }
          };
          tran.doInTransaction(deleteOldFileCB, false, true);
          
          logger.debug("2) remame temp file");
          RetryingTransactionCallback<Void> renameTempFileCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                  driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME_TEMP, TEST_DIR + "\\" + FILE_NAME);
                  return null;
              }
          };
          tran.doInTransaction(renameTempFileCB, false, true);

          logger.debug("3) validate results");
          /**
           * Now validate everything is correct
           */
          RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {

              @Override
              public Void execute() throws Throwable
              {
                 NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                 
                 Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
                                 
//                 assertTrue("versionable aspect missing", nodeService.hasAspect(shuffledNodeRef, ContentModel.ASPECT_VERSIONABLE));
             
                 assertEquals("Node ref has changed", shuffledNodeRef, testContext.file1NodeRef);
                 return null;
              }
          };
          
          tran.doInTransaction(validateCB, true, true);
          logger.debug("end testNFS");
          
      } // testNFS

    private void doTransactionWorkAsEditor(final RunAsWork<Void> work, RetryingTransactionHelper tran)
    {
        RetryingTransactionCallback<Void> transactionCallback = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                try
                {
                    AuthenticationUtil.runAs(work, ContentDiskDriverTest.TEST_USER_AUTHORITY);
                }
                catch (Exception e)
                {
                    // Informing about test failure. Expected exception is 'AccessDeniedException' or 'PermissionDeniedException'
                    if (e.getCause() instanceof AccessDeniedException || e.getCause() instanceof PermissionDeniedException)
                    {
                        fail("For user='" + TEST_USER_AUTHORITY + "' " + e.getCause().toString());
                    }
                    else
                    {
                        fail("Unexpected exception was caught: " + e.toString());
                    }
                }
                return null;
            }
        };
        tran.doInTransaction(transactionCallback, false, true);
    }

    /**
     * 0. test.txt exist in folder where user has Editor permissions
     * 1. as Editor create temporary file in temporary directory
     * 2. as Editor rename test.txt to test.txt.sb-1eefba7a-rkC6XE
     * 3. as Editor move temporary file to working directory
     */
    public void testScenarioMacLionTextEditByEditor_ALF_16257() throws Exception
    {
        logger.debug("test Collaborator/editor edit txt file on Mac Os Mountain Lion : Alf16257");
        final String FILE_NAME = "test.txt";
        final String FILE_BACKUP = "test.txt.sb-1eefba7a-rkC6XE";
        final String FILE_NEW_TEMP = FILE_NAME; // the same but in temp dir

        class TestContext
        {
            NetworkFile firstFileHandle;
            NetworkFile newFileHandle;
            NodeRef testNodeRef; // node ref of FILE_NAME
        };
        final TestContext testContext = new TestContext();

        final String TEST_ROOT_DIR = "\\ContentDiskDriverTest";
        final String TEST_DIR = TEST_ROOT_DIR + "\\testALF16257txt";
        final String TEST_TEMP_DIR = TEST_DIR + "\\.TemporaryItems";
        final String UPDATED_TEXT = "This is new content";

        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "cifs", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }

        logger.debug("Step 0 - initialise");
        /**
         * Create a file in the test directory
         */
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                driver.createDirectory(testSession, testConnection, createTempDirParams);

                /**
                 * Create the file we are going to use
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);

                // no need to test lots of different properties, that's already been tested above
                testContext.testNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.setProperty(testContext.testNodeRef, TransferModel.PROP_ENABLED, true);
                nodeService.addAspect(testContext.testNodeRef, ContentModel.ASPECT_VERSIONABLE, null);

                String testContent = "CIFS: Collaborator/editor could not edit file on Mac Os Mountain Lion";
                byte[] testContentBytes = testContent.getBytes();
                testContext.firstFileHandle.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                testContext.firstFileHandle.close();

                // Apply 'Editor' role for test user to test folder
                permissionService.setPermission(getNodeForPath(testConnection, TEST_DIR), ContentDiskDriverTest.TEST_USER_AUTHORITY, PermissionService.EDITOR, true);
                // Apply full control on temporary directory
                permissionService.setPermission(getNodeForPath(testConnection, TEST_TEMP_DIR), PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true);

                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);

        /**
         * a) Save the temp file in the temp dir
         */
        logger.debug("Step a - create a temp file in the temp dir");
        RunAsWork<Void> saveNewFileCB = new RunAsWork<Void>()
        {
            @Override
            public Void doWork() throws Exception
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.newFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.newFileHandle);

                byte[] testContentBytes = UPDATED_TEXT.getBytes();
                driver.writeFile(testSession, testConnection, testContext.newFileHandle, testContentBytes, 0, testContentBytes.length, 0);
                driver.closeFile(testSession, testConnection, testContext.newFileHandle);

                NodeRef tempNodeRef = getNodeForPath(testConnection, TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP);
                ContentReader reader = contentService.getReader(tempNodeRef, ContentModel.PROP_CONTENT);
                assertNotNull(reader);
                String actualContent = reader.getContentString();
                assertEquals("new contents were not written to temporary file", UPDATED_TEXT, actualContent);
                return null;
            }
        };
        doTransactionWorkAsEditor(saveNewFileCB, tran);

        /**
         * b) rename the target file to a backup file
         */
        logger.debug("Step b - rename the target file as Editor");
        RunAsWork<Void> renameOldFileCB = new RunAsWork<Void>()
        {
            @Override
            public Void doWork() throws Exception
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_BACKUP);
                return null;
            }
        };
        doTransactionWorkAsEditor(renameOldFileCB, tran);

        /**
         * c) Move the new file into target dir, stuff should get shuffled
         */
        logger.debug("Step c - move new file into target dir as Editor");
        RunAsWork<Void> moveNewFileCB = new RunAsWork<Void>()
        {
            @Override
            public Void doWork() throws Exception
            {
                driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        doTransactionWorkAsEditor(moveNewFileCB, tran);

        /**
         * Validate
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);

                Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
                assertTrue("node does not contain shuffled ENABLED property", props.containsKey(TransferModel.PROP_ENABLED));
                assertEquals("name wrong", FILE_NAME, nodeService.getProperty(shuffledNodeRef, ContentModel.PROP_NAME));
                ContentReader reader = contentService.getReader(testContext.testNodeRef, ContentModel.PROP_CONTENT);
                assertNotNull(reader);
                String actualContent = reader.getContentString();
                assertEquals("contents were not updated", UPDATED_TEXT, actualContent);
                return null;
            }
        };
        tran.doInTransaction(validateCB, false, true);

        logger.debug("end testScenarioMacLionTextEditByEditor For ALF-16257");
    } // testScenarioMacLionTextEditByEditorForAlf16257

    /**
     * 0. MacWord1.docx exist in folder where user has Editor permissions
     * 1. as Editor rename MacWord1.docx to backup Word Work File L_5.tmp
     * 2. as Editor create temporary file in temporary directory and move it to working dir
     * 3. as Editor rename Word Work File D_2.tmp to MacWord1.docx
     */
    public void testScenarioMountainLionWord2011EditByEditor_ALF_16257() throws Exception
    {
        logger.debug("testScenarioMountainLionWord2011 Edit By Editor ALF-16257");

        final String FILE_NAME = "MacWord1.docx";
        final String FILE_OLD_TEMP = "Word Work File L_5.tmp";
        final String FILE_NEW_TEMP = "Word Work File D_2.tmp";

        class TestContext
        {
            NetworkFile firstFileHandle;
            String mimetype;
        };
        final TestContext testContext = new TestContext();

        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testALF16257Word";
        final String TEST_TEMP_DIR = TEST_DIR + "\\.TemporaryItems"; // need to match with interimPattern

        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
        
        logger.debug("a) create new file");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createTempDirParams = new FileOpenParams(TEST_TEMP_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);
                driver.createDirectory(testSession, testConnection, createTempDirParams);

                /**
                 * Create the file we are going to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);
                writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                NodeRef file1NodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
                nodeService.addAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE, null);
                
                // Apply 'Editor' role for test user to test folder
                permissionService.setPermission(getNodeForPath(testConnection, TEST_DIR), ContentDiskDriverTest.TEST_USER_AUTHORITY, PermissionService.EDITOR, true);
                // Apply full control on temporary directory
                permissionService.setPermission(getNodeForPath(testConnection, TEST_TEMP_DIR), PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true);

                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        /**
         * b) rename the old file, should fire doubleRenameShuffle scenario
         */
        logger.debug("b) rename old file");
        RunAsWork<Void> renameOldFileCB = new RunAsWork<Void>()
        {
            @Override
            public Void doWork() throws Exception
            {
                NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME);
                Map<QName, Serializable> props = nodeService.getProperties(file1NodeRef);
                ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
                testContext.mimetype = data.getMimetype();
                
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        doTransactionWorkAsEditor(renameOldFileCB, tran);
        
        /**
         * c) as Editor Save the new file in .TemporaryItems
         * and move it to working directory (should be detected by scenario)
         * Write ContentDiskDriverTest3.doc,
         */
        logger.debug("c) create temp file in temp dir");
        RunAsWork<Void> writeFileCB = new RunAsWork<Void>()
        {
            @Override
            public Void doWork() throws Exception
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);

                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
                assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);
                writeResourceToNetworkFile(fileResource, testContext.firstFileHandle);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle);

                driver.renameFile(testSession, testConnection, TEST_TEMP_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NEW_TEMP);
                return null;
            }
        };
        doTransactionWorkAsEditor(writeFileCB, tran);

        /**
         * d) Move the new file into place, stuff should get shuffled
         */
        logger.debug("d) move new file into place");
        RunAsWork<Void> moveNewFileCB = new RunAsWork<Void>()
        {
            @Override
            public Void doWork() throws Exception
            {
                driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        doTransactionWorkAsEditor(moveNewFileCB, tran);

        /**
         * e) Delete the old file
         */
        logger.debug("e) delete the old file");
        RetryingTransactionCallback<Void> deleteOldFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_OLD_TEMP);
                return null;
            }
        };
        
        tran.doInTransaction(deleteOldFileCB, false, true);
        
        logger.debug("e) validate results");

        logger.debug("f) validate results");
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {
            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
               //assertNotNull("data is null", data);
               //assertEquals("size is wrong", 123904, data.getSize());
               
               NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME); 
               assertTrue("file has lost versionable aspect", nodeService.hasAspect(file1NodeRef, ContentModel.ASPECT_VERSIONABLE));

               assertEquals("mimeType is wrong", testContext.mimetype, data.getMimetype());
               
           
               return null;
            }
        };
        tran.doInTransaction(validateCB, true, true);
        logger.debug("end testScenarioMountainLionWord2011 Edit By Editor ALF-16257");
    } // testScenarioMountainLionWord2011EditByEditor_ALF_16257
    
    
    /**
     * Guess mimetype with sufficient data - originally related to ACE-4523
     * Simulate creating a plain text document via Alfresco Share
     * then updating it via CIFS/FTP
     * 
     * 1. create a document called "foo" with just a little data with an explicit (incorrect) mimetype set.
     * 2. update the document with different text
     * 3. check the mimetype of the test doc has changed (since it can be guessed)
     */
    public void testMimetypeWithSufficientData() throws Exception
    {
        logger.debug("testMimetypeWithInsufficiantData");

        // a file without a clue about mimetype
        final String FILE_NAME = "foo";

        class TestContext
        {
            NetworkFile firstFileHandle;
            String mimetype;
        };
        final TestContext testContext = new TestContext();

        final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testMimetypeWithSufficientData";
        
        // this is a made up mimetype - so there is no way that it could be guessed.
        final String TEST_MIMETYPE = "text\bar";

        ServerConfiguration scfg = new ServerConfiguration("testServer");
        TestServer testServer = new TestServer("testServer", scfg);
        final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
        DiskSharedDevice share = getDiskSharedDevice();
        final TreeConnection testConnection = testServer.getTreeConnection(share);
        final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();

        /**
         * Clean up just in case garbage is left from a previous run
         */
        RetryingTransactionCallback<Void> deleteGarbageFileCB = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Throwable
            {
                driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
                return null;
            }
        };
        try
        {
            tran.doInTransaction(deleteGarbageFileCB);
        }
        catch (Exception e)
        {
            // expect to go here
        }
         
        logger.debug("a) create new file");
        RetryingTransactionCallback<Void> createFileCB = new RetryingTransactionCallback<Void>() {

            @Override
            public Void execute() throws Throwable
            {
                /**
                 * Create the test directory we are going to use 
                 */
                FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                driver.createDirectory(testSession, testConnection, createRootDirParams);
                driver.createDirectory(testSession, testConnection, createDirParams);

                /**
                 * Create the file we are going to test
                 */
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
                assertNotNull(testContext.firstFileHandle);
                driver.closeFile(testSession, testConnection, testContext.firstFileHandle); 
                
                
                ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTestTxt1.txt");
                // Add the test content via the content writer to simulate being created via Share.
                NodeRef file1NodeRef = getNodeForPath(testConnection,  TEST_DIR + "\\" + FILE_NAME);
                ContentWriter contentWriter2 = contentService.getWriter(file1NodeRef, ContentModel.PROP_CONTENT, true);
                // this is a made up mimetype - so there is no way that it could be guessed.
                contentWriter2.setMimetype(TEST_MIMETYPE);
                contentWriter2.putContent(fileResource.getFile());

                return null;
            }
        };
        tran.doInTransaction(createFileCB, false, true);
        
        /**
         * b) Update the file via CIFS
         */
        logger.debug("b) update file via CIFS");
        RetryingTransactionCallback<Void> updateFileCB = new RetryingTransactionCallback<Void>()
        {
            @Override
            public Void execute() throws Exception
            {
                FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
                NetworkFile file = driver.openFile(testSession, testConnection, createFileParams);
                assertNotNull(file);
                String testContent = "Bar";
                byte[] testContentBytes = testContent.getBytes();
                file.writeFile(testContentBytes, testContentBytes.length, 0, 0);
                driver.closeFile(testSession, testConnection, file);
                return null;
            }
        };
        tran.doInTransaction(updateFileCB, false, true);
        
        logger.debug("c) validate results");
        
        /**
         * Now validate everything is correct
         */
        RetryingTransactionCallback<Void> validateCB = new RetryingTransactionCallback<Void>() {
            @Override
            public Void execute() throws Throwable
            {
               NodeRef shuffledNodeRef = getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
               Map<QName, Serializable> props = nodeService.getProperties(shuffledNodeRef);
               ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
              
               
               /**
                * Validate mimetype has changed - we can guess that it is text !
                */
               assertEquals("mimeType is wrong", MimetypeMap.MIMETYPE_TEXT_PLAIN, data.getMimetype());
    
           
               return null;
            }
        };
        tran.doInTransaction(validateCB, true, true);
        logger.debug("end testMimetypeWithSufficientData");
    } // testMimetypeWithSufficientData"
    
    
    
    /**
     * Test server
     */
    public class TestServer extends NetworkFileServer
    {
        
        public TestServer(String proto, ServerConfiguration config)
        {
            super(proto, config);
            // TODO Auto-generated constructor stub
        }

        @Override
        public void startServer()
        {
                       
        }

        @Override
        public void shutdownServer(boolean immediate)
        {
            
        }
        
        public TreeConnection getTreeConnection(SharedDevice share) 
        {
            return new TreeConnection(share);
        }
    }
    
    /**
     * TestSrvSession
     */
    private class TestSrvSession extends SrvSession
    {

        public TestSrvSession(int sessId, NetworkServer srv, String proto,
                String remName)
        {
            super(sessId, srv, proto, remName);
            
            // Set the client info to user "fred"
            ClientInfo cinfo = ClientInfo.createInfo("fred", null);
            setClientInformation(cinfo);
            setUniqueId("test:" + sessId);

        }

        @Override
        public InetAddress getRemoteAddress()
        {
            return null;
        }

        @Override
        public boolean useCaseSensitiveSearch()
        {
            return false;
        }
    }
    
    private NodeRef getNodeForPath(TreeConnection tree, String path)
    throws FileNotFoundException
    {
        if(logger.isDebugEnabled())
        {
            logger.debug("getNodeRefForPath:" + path);
        }
   
        ContentContext ctx = (ContentContext) tree.getContext();
    
        return cifsHelper.getNodeRef(ctx.getRootNode(), path);
    }

    /**
     * Write the resource to the specified NetworkFile
     * @param resource
     * @param file
     * @throws IOException
     */
    private void writeResourceToNetworkFile(ClassPathResource resource, NetworkFile file) throws IOException
    {
 
        byte[] buffer= new byte[1000];
        InputStream is = resource.getInputStream();
        try
        {
            long offset = 0;
            int i = is.read(buffer, 0, buffer.length);
            while(i > 0)
            {
                file.writeFile(buffer, i, 0, offset);
                offset += i;
                i = is.read(buffer, 0, buffer.length);
            }                 
        }
        finally
        {
            is.close();
        }
    }
}
