org.rhq.core.util.updater.DeployerCanonicalPathTest.java Source code

Java tutorial

Introduction

Here is the source code for org.rhq.core.util.updater.DeployerCanonicalPathTest.java

Source

/*
 * RHQ Management Platform
 * Copyright (C) 2005-2013 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation, and/or the GNU Lesser
 * General Public License, version 2.1, also as published by the Free
 * Software Foundation.
 *
 * This program 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 General Public License and the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License
 * and the GNU Lesser General Public License along with this program;
 * if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

package org.rhq.core.util.updater;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import org.rhq.core.template.TemplateEngine;
import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.stream.StreamUtil;

/**
 * Tests deploying raw files to deployment locations specified with ".." in the path. This will require the deployer
 * code to transform the paths to canonical paths.
 *
 * @author John Mazzitelli
 */
@Test
public class DeployerCanonicalPathTest {

    private static final Log LOG = LogFactory.getLog(DeployerCanonicalPathTest.class);

    private TemplateEngine templateEngine;

    @BeforeClass
    public void beforeClass() {
        Map<String, String> tokens = new HashMap<String, String>();
        tokens.put("rhq.system.hostname", "localhost");
        tokens.put("rhq.system.sysprop.java.version", System.getProperty("java.version"));

        templateEngine = new TemplateEngine(tokens);
    }

    @BeforeMethod
    public void beforeMethod() {
        System.out.println("\n\n=============== START OF NEW TEST ===============\n");
    }

    // any raw file path (absolute or relative) that contains ".." will be converted to an absolute, canonical path - this is what we test
    public void testInitialDeployRawFilesWithCanonicalPaths() throws Exception {
        File tmpDirDest = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".dest", null);
        File tmpDirSrc = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".src", null);
        File rawFileRelativeDest = new File("dir-does-not-existA/../rawA.txt"); // relative to "tmpDirDest" that we just created above
        File rawFileRelativeDest2 = new File("dir-does-not-existA/../../rawA.txt"); // relative to "tmpDirDest" but it takes us above it
        File rawFileAbsoluteDest = new File(System.getProperty("java.io.tmpdir"),
                "dir-does-not-existB/../rawB.txt");

        try {
            // put some source files in our tmpDirSrc location
            File testRawFileA = new File(tmpDirSrc, "updater-testA.txt");
            File testRawFileA2 = new File(tmpDirSrc, "updater-testA2.txt");
            File testRawFileB = new File(tmpDirSrc, "updater-testB.txt");
            FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA);
            FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA2);
            FileUtil.copyFile(new File("target/test-classes/updater-testB.txt"), testRawFileB);

            DeploymentProperties deploymentProps = new DeploymentProperties(0, "testbundle", "1.0.test", null,
                    DestinationComplianceMode.full);
            HashMap<File, File> zipFiles = null;
            Map<File, File> rawFiles = new HashMap<File, File>(3);
            rawFiles.put(testRawFileA, rawFileRelativeDest); // we will realize this one ...
            rawFiles.put(testRawFileA2, rawFileRelativeDest2); // and this one ...
            rawFiles.put(testRawFileB, rawFileAbsoluteDest); // and we will realize this one, too
            File destDir = tmpDirDest;
            Pattern ignoreRegex = null;
            Set<File> realizeRawFiles = new HashSet<File>(3);
            realizeRawFiles.add(testRawFileA);
            realizeRawFiles.add(testRawFileA2);
            realizeRawFiles.add(testRawFileB);
            DeploymentData dd = new DeploymentData(deploymentProps, tmpDirSrc, destDir, rawFiles, realizeRawFiles,
                    zipFiles, null, templateEngine, ignoreRegex, null);
            Deployer deployer = new Deployer(dd);
            DeployDifferences diff = new DeployDifferences();
            FileHashcodeMap map = deployer.deploy(diff);
            System.out.println("map-->\n" + map);
            System.out.println("diff->\n" + diff);

            String rawFileRelativeDestAbsolute = FileUtil
                    .normalizePath(new File(tmpDirDest, rawFileRelativeDest.getPath())).getAbsolutePath();
            String rawFileRelativeDestAbsolute2 = FileUtil
                    .normalizePath(new File(tmpDirDest, rawFileRelativeDest2.getPath())).getAbsolutePath();
            String rawFileAbsoluteDestAbsolute = FileUtil.normalizePath(rawFileAbsoluteDest).getAbsolutePath();

            assert map.size() == 3 : map;

            assert map.containsKey("rawA.txt") : map;
            assert new File(rawFileRelativeDestAbsolute).exists();
            assert new File(rawFileRelativeDestAbsolute2).exists();
            assert MessageDigestGenerator.getDigestString(new File(rawFileRelativeDestAbsolute))
                    .equals(map.get("rawA.txt"));

            // rawFileRelativeDestAbsolute2 should be treated just like an absolute, external file
            assert MessageDigestGenerator.getDigestString(new File(rawFileRelativeDestAbsolute2))
                    .equals(map.get(rawFileRelativeDestAbsolute2));
            assert !MessageDigestGenerator.getDigestString(testRawFileA)
                    .equals(map.get("rawA.txt")) : "should have different hash, we realize this one!";

            assert map.containsKey(rawFileAbsoluteDestAbsolute) : map;
            assert new File(rawFileAbsoluteDestAbsolute).exists();
            assert MessageDigestGenerator.getDigestString(new File(rawFileAbsoluteDestAbsolute))
                    .equals(map.get(rawFileAbsoluteDestAbsolute));
            assert !MessageDigestGenerator.getDigestString(testRawFileB).equals(
                    map.get(rawFileAbsoluteDestAbsolute)) : "should have different hash, we realized this one";

            assert diff.getAddedFiles().size() == 3 : diff;
            assert diff.getAddedFiles().contains(diff.convertPath("rawA.txt")) : diff;
            assert diff.getAddedFiles().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
            assert diff.getAddedFiles().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
            assert diff.getRealizedFiles().size() == 3 : diff;
            assert diff.getRealizedFiles().keySet().contains(diff.convertPath("rawA.txt")) : diff;
            assert diff.getRealizedFiles().keySet().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
            assert diff.getRealizedFiles().keySet().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
        } finally {
            FileUtil.purge(tmpDirDest, true);
            FileUtil.purge(tmpDirSrc, true);
            rawFileAbsoluteDest.getCanonicalFile().delete();
        }
    }

    public void testUpdateDeployRawFileWithRelativePath() throws Exception {
        File tmpDirDest = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".dest", null);
        File tmpDirSrc = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".src", null);
        File rawFileRelativeDest = new File("dir-does-not-existA/../rawA.txt"); // relative to "tmpDirDest" that we just created above
        File rawFileRelativeDest2 = new File("dir-does-not-existA/../../rawA.txt"); // relative to "tmpDirDest" but it takes us above it
        File rawFileAbsoluteDest = new File(System.getProperty("java.io.tmpdir"),
                "dir-does-not-existB/../rawB.txt");

        try {
            // put some source files in our tmpDirSrc location
            File testRawFileA = new File(tmpDirSrc, "updater-testA.txt");
            File testRawFileA2 = new File(tmpDirSrc, "updater-testA2.txt");
            File testRawFileB = new File(tmpDirSrc, "updater-testB.txt");
            FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA);
            FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA2);
            FileUtil.copyFile(new File("target/test-classes/updater-testB.txt"), testRawFileB);

            DeploymentProperties deploymentProps = new DeploymentProperties(0, "testbundle", "1.0.test", null,
                    DestinationComplianceMode.full);
            HashMap<File, File> zipFiles = null;
            Map<File, File> rawFiles = new HashMap<File, File>(3);
            rawFiles.put(testRawFileA, rawFileRelativeDest);
            rawFiles.put(testRawFileA2, rawFileRelativeDest2);
            rawFiles.put(testRawFileB, rawFileAbsoluteDest);
            File destDir = tmpDirDest;
            Pattern ignoreRegex = null;
            DeploymentData dd = new DeploymentData(deploymentProps, tmpDirSrc, destDir, rawFiles, null, zipFiles,
                    null, templateEngine, ignoreRegex, null);
            Deployer deployer = new Deployer(dd);
            DeployDifferences diff = new DeployDifferences();
            FileHashcodeMap map = deployer.deploy(diff);
            System.out.println("map-->\n" + map);
            System.out.println("diff->\n" + diff);
            assert map.size() == 3 : map;

            // make sure the first raw file is in the dest dir
            String f = rawFileRelativeDest.getPath();
            File destFile = new File(tmpDirDest, f).getCanonicalFile(); // notice f is assumed relative to tmpDirDest, must convert to canonical path
            assert destFile.exists() : destFile;
            FileUtil.writeFile(new ByteArrayInputStream("modifiedR".getBytes()), destFile); // change the file so we back it up during update

            // make sure the second raw file, though specified originally as a relative file, is in the external location
            f = rawFileRelativeDest2.getPath();
            destFile = new File(tmpDirDest, f).getCanonicalFile(); // must convert to canonical path
            assert destFile.exists() : destFile;
            FileUtil.writeFile(new ByteArrayInputStream("modifiedR2".getBytes()), destFile); // change the file so we back it up during update

            // make sure the third raw file is in the external location
            destFile = rawFileAbsoluteDest.getCanonicalFile(); // must convert to canonical path
            assert destFile.exists() : destFile;
            FileUtil.writeFile(new ByteArrayInputStream("modifiedA".getBytes()), destFile); // change the file so we back it up during update

            // UPDATE
            // alter the src files so we backup our changed files
            FileUtil.writeFile(new ByteArrayInputStream("src.modifiedR".getBytes()), testRawFileA);
            FileUtil.writeFile(new ByteArrayInputStream("src.modifiedR2".getBytes()), testRawFileA2);
            FileUtil.writeFile(new ByteArrayInputStream("src.modifiedA".getBytes()), testRawFileB);

            deploymentProps = new DeploymentProperties(1, "testbundle", "2.0.test", null,
                    DestinationComplianceMode.full);
            dd = new DeploymentData(deploymentProps, tmpDirSrc, destDir, rawFiles, null, zipFiles, null,
                    templateEngine, ignoreRegex, null);
            deployer = new Deployer(dd);
            diff = new DeployDifferences();
            map = deployer.deploy(diff);
            System.out.println("map-->\n" + map);
            System.out.println("diff->\n" + diff);

            String rawFileRelativeDestAbsolute = FileUtil
                    .normalizePath(new File(tmpDirDest, rawFileRelativeDest.getPath())).getAbsolutePath();
            String rawFileRelativeDestAbsolute2 = FileUtil
                    .normalizePath(new File(tmpDirDest, rawFileRelativeDest2.getPath())).getAbsolutePath();
            String rawFileAbsoluteDestAbsolute = FileUtil.normalizePath(rawFileAbsoluteDest).getAbsolutePath();

            assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileRelativeDestAbsolute))))
                    .equals("src.modifiedR");
            assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileRelativeDestAbsolute2))))
                    .equals("src.modifiedR2");
            assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileAbsoluteDestAbsolute))))
                    .equals("src.modifiedA");

            boolean isWindows = File.separatorChar == '\\';
            final File metadir = new File(tmpDirDest, ".rhqdeployments");
            File backupRel = new File(metadir, "1/backup/rawA.txt");
            File backupRel2;
            // test the second raw file, the one that was specified originally as a relative file but took us out of the dest dir
            if (!isWindows) {
                backupRel2 = new File(metadir, "1/ext-backup/" + rawFileRelativeDestAbsolute2);
            } else {
                StringBuilder str = new StringBuilder(rawFileRelativeDestAbsolute2);
                String driveLetter = FileUtil.stripDriveLetter(str);
                if (driveLetter != null) {
                    driveLetter = "_" + driveLetter + '/';
                } else {
                    driveLetter = "";
                }
                backupRel2 = new File(metadir, "1/ext-backup/" + driveLetter + str.toString());
            }
            // test the third raw file, the one that was specified originally as an absolute, external file
            File backupAbs;
            if (!isWindows) {
                backupAbs = new File(metadir, "1/ext-backup/" + rawFileAbsoluteDestAbsolute);
            } else {
                StringBuilder str = new StringBuilder(rawFileAbsoluteDestAbsolute);
                String driveLetter = FileUtil.stripDriveLetter(str);
                if (driveLetter != null) {
                    driveLetter = "_" + driveLetter + '/';
                } else {
                    driveLetter = "";
                }
                backupAbs = new File(metadir, "1/ext-backup/" + driveLetter + str.toString());
            }

            // the backup files should exist
            assert backupRel.exists() : backupRel;
            assert backupRel2.exists() : backupRel2;
            assert backupAbs.exists() : backupAbs;

            assert map.size() == 3 : map;
            assert diff.getChangedFiles().size() == 3 : diff;
            assert diff.getChangedFiles().contains(diff.convertPath("rawA.txt")) : diff;
            assert diff.getChangedFiles().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
            assert diff.getChangedFiles().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
            assert diff.getDeletedFiles().isEmpty() : diff;
            assert diff.getBackedUpFiles().size() == 3 : diff;
            assert diff.getBackedUpFiles().keySet().contains(diff.convertPath("rawA.txt")) : diff;
            assert diff.getBackedUpFiles().keySet().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
            assert diff.getBackedUpFiles().keySet().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
        } finally {
            FileUtil.purge(tmpDirDest, true);
            FileUtil.purge(tmpDirSrc, true);
            rawFileAbsoluteDest.getCanonicalFile().delete();
        }
    }

    public void testInitialDeploymentGlossesOverSymlinksInParents() throws Exception {
        //java7 API, but we're in tests, and require java7 to build anyway
        Path root = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".symlink-root", null).toPath();
        Path symlinkTarget = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".symlink-target", null)
                .toPath();

        File src = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".src", null);

        Path parent = root.resolve("parent");
        parent.toFile().mkdirs();

        try {
            File destination = null;

            try {
                destination = Files.createSymbolicLink(parent.resolve("destination"), symlinkTarget).toFile();
            } catch (UnsupportedOperationException e) {
                LOG.info(
                        "Skipping testInitialDeploymentGlossesOverSymlinksInParents. The current filesystem doesn't support symlinks");
                return;
            }

            // put some source files in our tmpDirSrc location
            File testRawFileA = new File(src, "updater-testA.txt");
            File testRawFileA2 = new File(src, "updater-testA2.txt");
            File testRawFileB = new File(src, "updater-testB.txt");
            File testRawFileADest = new File(destination, "../realDest/rawA.txt");
            File testRawFileA2Dest = new File(destination, "../realDest/rawA2.txt");
            File testRawFileBDest = new File(destination, "../../realDest/rawB.txt");
            FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA);
            FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA2);
            FileUtil.copyFile(new File("target/test-classes/updater-testB.txt"), testRawFileB);

            DeploymentProperties deploymentProps = new DeploymentProperties(0, "testbundle", "1.0.test", null,
                    DestinationComplianceMode.full);
            HashMap<File, File> zipFiles = null;
            Map<File, File> rawFiles = new HashMap<File, File>(3);
            rawFiles.put(testRawFileA, testRawFileADest);
            rawFiles.put(testRawFileA2, testRawFileA2Dest);
            rawFiles.put(testRawFileB, testRawFileBDest);

            DeploymentData dd = new DeploymentData(deploymentProps, src, destination, rawFiles, null, zipFiles,
                    null, templateEngine, null, null);
            Deployer deployer = new Deployer(dd);
            DeployDifferences diff = new DeployDifferences();
            FileHashcodeMap map = deployer.deploy(diff);
            System.out.println("map-->\n" + map);
            System.out.println("diff->\n" + diff);

            assert map.size() == 3 : map;

            assert parent.resolve("realDest/rawA.txt").toFile().exists() : "rawA.txt not deployed correctly";
            assert parent.resolve("realDest/rawA2.txt").toFile().exists() : "rawA2.txt not deployed correctly";
            assert root.resolve("realDest/rawB.txt").toFile().exists() : "rawB.txt not deployed correctly";

            //the symlink target, being the destination of the deployment should have the .rhqdeployments directory
            //specified. No other files should exist there though.
            assert symlinkTarget.resolve(".rhqdeployments").toFile()
                    .exists() : "Could not find .rhqdeployments on the expected location";
            assert symlinkTarget.toFile()
                    .listFiles().length == 1 : "The target of the symlink should have no other files than .rhqdeployments";
        } finally {
            FileUtil.purge(root.toFile(), true);
            FileUtil.purge(symlinkTarget.toFile(), true);
            FileUtil.purge(src, true);
        }
    }
}