org.alfresco.filesys.repo.ContentDiskDriverTest.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.filesys.repo.ContentDiskDriverTest.java

Source

/*
 * #%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();
        }
    }
}