modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java | 72 ++++ modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java | 135 +++++++- modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java | 98 +++++- modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java | 49 +-- modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java | 77 ++++- modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java | 152 +++++++++- modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml | 16 + 7 files changed, 526 insertions(+), 73 deletions(-)
New commits: commit 9946f3e2b2b4b0a86ebe001594818f016a4c4130 Author: John Mazzitelli mazz@redhat.com Date: Thu Jan 26 17:19:43 2012 -0500
[BZ 784124] fix the issue where, on initial deployment of a bundle, we didn't clean out any files that happen to be in the deployment dir. we need to remove them, they are in the way. we do back them up so they can be manually retrieved if the user screwed up.
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java b/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java index 14ed3af..a78f6b2 100644 --- a/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java +++ b/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java @@ -33,6 +33,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -102,6 +103,77 @@ public class FileUtil { StreamUtil.copy(is, os); }
+ public static void copyDirectory(File inDir, File outDir) throws IOException { + if (inDir.exists()) { + if (!inDir.isDirectory()) { + throw new IOException("Source directory [" + inDir + "] is not a directory"); + } + } else { + throw new FileNotFoundException("Source directory [" + inDir + "] does not exist"); + } + + if (!outDir.mkdirs()) { + throw new IOException("Destination directory [" + outDir + "] failed to be created"); + } + + if (!canWrite(outDir)) { + throw new IOException("Cannot write to destination directory [" + outDir + "]"); + } + + // TODO do we care to restore the last mod time on the destination dir? + //outDir.setLastModified(inDir.lastModified()); + + File[] files = inDir.listFiles(); + if (files == null) { + throw new IOException("Failed to get the list of files in source directory [" + inDir + "]"); + } + for (File file : files) { + File copiedFile = new File(outDir, file.getName()); + if (file.isDirectory()) { + copyDirectory(file, copiedFile); + } else { + copyFile(file, copiedFile); + } + } + + files = null; // help GC + return; + } + + /** + * Obtains the list of all files in the given directory and, recursively, all its subdirectories. + * Note that the returns list is only regular files - directory names are NOT in the list. Also, + * the names in the list are relative to the given directory. + * @param directory the directory whose files are to be returned + * @return list of files in the directory, not sorted in any particular order + * @throws IOException if directory does not exist or is not a directory + */ + public static List<File> getDirectoryFiles(File directory) throws IOException { + ArrayList<File> files = new ArrayList<File>(); + if (!directory.isDirectory()) { + throw new IOException("[" + directory + "] is not an existing directory"); + } + getDirectoryFilesRecursive(directory, files, null); + return files; + } + + private static void getDirectoryFilesRecursive(File directory, List<File> files, String relativeTo) + throws IOException { + File[] children = directory.listFiles(); + if (children == null) { + throw new IOException("Cannot obtain files from directory [" + directory + "]"); + } + for (File child : children) { + if (child.isDirectory()) { + getDirectoryFilesRecursive(child, files, ((relativeTo == null) ? "" : relativeTo) + child.getName() + + File.separatorChar); + } else { + files.add(new File(relativeTo, child.getName())); + } + } + return; + } + /** * Copy a stream, using a buffer. * @deprecated use {@link StreamUtil} for more methods like this - those are unit tested and used more diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java index 652bcda..40ce727 100644 --- a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java +++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java @@ -28,6 +28,8 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -301,9 +303,9 @@ public class Deployer { return; }
- debug("Estimated disk usage for this deployment is [", usage.getDiskUsage(), "] bytes (file count=[", usage - .getFileCount(), "]). The maximum disk space currently usable is estimated to be [", usage - .getMaxDiskUsable(), "] bytes."); + debug("Estimated disk usage for this deployment is [", usage.getDiskUsage(), "] bytes (file count=[", + usage.getFileCount(), "]). The maximum disk space currently usable is estimated to be [", + usage.getMaxDiskUsable(), "] bytes.");
if (usage.getDiskUsage() > usage.getMaxDiskUsable()) { throw new Exception( @@ -316,6 +318,31 @@ public class Deployer { }
private FileHashcodeMap performInitialDeployment(DeployDifferences diff, boolean dryRun) throws Exception { + // If we are to fully manage the deployment dir, then we need to delete everything we find here. + // Any old files do not belong here - only our bundle files should live here now. + if (this.deploymentData.isManageRootDir()) { + File destDir = this.deploymentData.getDestinationDir(); + log.info(buildLogMessage("Will be managing the deploy dir[", destDir, + "]; backing up and purging any obsolete content existing in there")); + if (destDir.isDirectory()) { + int deploymentId = this.deploymentData.getDeploymentProps().getDeploymentId(); + backupFiles(diff, deploymentId, destDir, dryRun, null, true); + if (!dryRun) { + // we want to purge everything that is originally in here, but we backed up the files in here + // so make sure we don't delete our metadata directory, which is where the backed up files are + File[] doomedFiles = destDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return !DeploymentsMetadata.METADATA_DIR.equals(name); + } + }); + for (File doomedFile : doomedFiles) { + FileUtil.purge(doomedFile, true); + } + } + } + } + FileHashcodeMap newFileHashcodeMap = extractZipAndRawFiles(new HashMap<String, String>(0), diff, dryRun);
// this is an initial deployment, so we know every file is new - tell our diff about them all @@ -340,8 +367,8 @@ public class Deployer { // * if a current file is backed up
FileHashcodeMap original = this.deploymentsMetadata.getCurrentDeploymentFileHashcodes(); - ChangesFileHashcodeMap current = original.rescan(this.deploymentData.getDestinationDir(), this.deploymentData - .getIgnoreRegex(), this.deploymentData.isManageRootDir()); + ChangesFileHashcodeMap current = original.rescan(this.deploymentData.getDestinationDir(), + this.deploymentData.getIgnoreRegex(), this.deploymentData.isManageRootDir()); FileHashcodeMap newFiles = getNewDeploymentFileHashcodeMap();
if (current.getUnknownContent() != null) { @@ -457,7 +484,8 @@ public class Deployer { int backupDeploymentId = props.getDeploymentId(); debug("Backing up files as part of update deployment. dryRun=", dryRun); for (String fileToBackupPath : currentFilesToBackup) { - backupFile(diff, backupDeploymentId, fileToBackupPath, dryRun); + boolean toBeDeleted = currentFilesToDelete.remove(fileToBackupPath); + backupFile(diff, backupDeploymentId, fileToBackupPath, dryRun, toBeDeleted); } }
@@ -503,8 +531,8 @@ public class Deployer { return newFileHashCodeMap; }
- private void backupFile(DeployDifferences diff, int deploymentId, final String fileToBackupPath, boolean dryRun) - throws Exception { + private void backupFile(DeployDifferences diff, int deploymentId, final String fileToBackupPath, boolean dryRun, + boolean removeFileToBackup) throws Exception {
File bakFile;
@@ -536,8 +564,8 @@ public class Deployer { String destDirDriveLetter = FileUtil.stripDriveLetter(destDirAbsPathBuilder); if (destDirDriveLetter == null || driveLetter.equals(destDirDriveLetter)) { bakFile = new File(backupDir, fileToBackupPath); - fileToBackup = new File(this.deploymentData.getDestinationDir(), fileToBackupPathNoDriveLetter - .toString()); + fileToBackup = new File(this.deploymentData.getDestinationDir(), + fileToBackupPathNoDriveLetter.toString()); } else { throw new Exception("Cannot backup relative path [" + fileToBackupPath + "] whose drive letter is different than the destination directory [" @@ -549,20 +577,77 @@ public class Deployer { } }
+ boolean deleted = false; // will be true if we were told to delete the file and we actually did delete it + if (!dryRun) { bakFile.getParentFile().mkdirs(); - FileUtil.copyFile(fileToBackup, bakFile); + // try to do a rename first if we are to remove the file, since this is more likely + // much faster and more efficient. + // if it fails (perhaps because we are crossing file systems), try a true copy + if (removeFileToBackup) { + boolean movedSuccessfully = fileToBackup.renameTo(bakFile); + if (movedSuccessfully) { + deleted = true; + } else { + FileUtil.copyFile(fileToBackup, bakFile); + deleted = fileToBackup.delete(); + if (deleted == false) { + // TODO: what should we do? is it a major failure if we can't remove files here? + debug("Failed to delete file [", fileToBackup, "] but it is backed up"); + if (diff != null) { + diff.addError(fileToBackupPath, "File [" + fileToBackup.getAbsolutePath() + + "] did not delete"); + } + } + } + } else { + FileUtil.copyFile(fileToBackup, bakFile); + } + } else { + deleted = removeFileToBackup; // this is a dry run, pretend we deleted it if we were asked to }
debug("Backed up file [", fileToBackup, "] to [", bakFile, "]. dryRun=", dryRun); + if (deleted) { + debug("Deleted file [", fileToBackup, "] after backing it up. dryRun=", dryRun); + }
if (diff != null) { diff.addBackedUpFile(fileToBackupPath, bakFile.getAbsolutePath()); + if (deleted) { + diff.addDeletedFile(fileToBackupPath); + } }
return; }
+ private void backupFiles(DeployDifferences diff, int deploymentId, File dirToBackup, boolean dryRun, + String relativeTo, boolean removeSourceFiles) throws Exception { + File[] files = dirToBackup.listFiles(); + if (files == null) { + throw new IOException("Failed to get the list of files in source directory [" + dirToBackup + "]"); + } + if (files.length > 0) { + this.deploymentsMetadata.getMetadataDirectory().mkdirs(); // make sure we create this, might not be there yet + for (File file : files) { + if (file.isDirectory()) { + if (file.getName().equals(DeploymentsMetadata.METADATA_DIR)) { + continue; // skip the RHQ metadata directory, its where we are putting our backups! + } + backupFiles(diff, deploymentId, file, dryRun, + ((relativeTo == null) ? "" : relativeTo) + file.getName() + File.separatorChar, + removeSourceFiles); + } else { + backupFile(diff, deploymentId, ((relativeTo == null) ? "" : relativeTo) + file.getName(), dryRun, + removeSourceFiles); + } + } + + files = null; // help GC + } + } + private FileHashcodeMap extractZipAndRawFiles(Map<String, String> currentFilesToLeaveAlone, DeployDifferences diff, boolean dryRun) throws Exception {
@@ -615,8 +700,8 @@ public class Deployer { ZipUtil.walkZipFile(zipFile, visitor); // we have to compress the file again - our new compressed file will have the new realized files in them if (!dryRun) { - createZipFile(compressedFile, this.deploymentData.getDestinationDir(), visitor - .getFileHashcodeMap()); + createZipFile(compressedFile, this.deploymentData.getDestinationDir(), + visitor.getFileHashcodeMap()); } }
@@ -1040,16 +1125,20 @@ public class Deployer {
private void debug(Object... objs) { if (log.isDebugEnabled()) { - String bundleName = this.deploymentData.getDeploymentProps().getBundleName(); - String bundleVersion = this.deploymentData.getDeploymentProps().getBundleVersion(); - int deploymentId = this.deploymentData.getDeploymentProps().getDeploymentId(); - StringBuilder str = new StringBuilder(); - str.append("Bundle [").append(bundleName).append(" v").append(bundleVersion).append(']'); - str.append("; Deployment [").append(deploymentId).append("]: "); - for (Object o : objs) { - str.append(o); - } - log.debug(str.toString()); + log.debug(buildLogMessage(objs)); + } + } + + private String buildLogMessage(Object... objs) { + String bundleName = this.deploymentData.getDeploymentProps().getBundleName(); + String bundleVersion = this.deploymentData.getDeploymentProps().getBundleVersion(); + int deploymentId = this.deploymentData.getDeploymentProps().getDeploymentId(); + StringBuilder str = new StringBuilder(); + str.append("Bundle [").append(bundleName).append(" v").append(bundleVersion).append(']'); + str.append("; Deployment [").append(deploymentId).append("]: "); + for (Object o : objs) { + str.append(o); } + return str.toString(); } } diff --git a/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java b/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java index 31659bd..bb7ad34 100644 --- a/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java +++ b/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java @@ -22,21 +22,92 @@ */ package org.rhq.core.util.file;
+import static java.util.Arrays.asList; +import static org.apache.commons.io.FileUtils.deleteDirectory; +import static org.apache.commons.io.FileUtils.toFile; +import static org.apache.commons.io.FileUtils.touch; +import static org.rhq.test.AssertUtils.assertCollectionEqualsNoOrder; + +import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern;
import org.testng.annotations.Test;
-import static java.util.Arrays.asList; -import static org.apache.commons.io.FileUtils.deleteDirectory; -import static org.apache.commons.io.FileUtils.toFile; -import static org.apache.commons.io.FileUtils.touch; -import static org.rhq.test.AssertUtils.assertCollectionEqualsNoOrder; +import org.rhq.core.util.stream.StreamUtil;
@Test public class FileUtilTest { + public void testCopyDirectory() throws Exception { + try { + FileUtil.copyDirectory(new File("this.does.not.exist"), new File("dummy")); + assert false : "the source directory did not exist, this should have failed because of that"; + } catch (Exception ok) { + } + + // create a source directory and a destination directory. Make sure we start off + // with a non-existent destination directory - we want the copyDirectory to create it for us. + File outDir = FileUtil.createTempDirectory("fileUtilTestCopyDir", ".dest", null); + assert outDir.delete() : "failed to start out with a non-existent dest directory"; + assert !outDir.exists() : "dest directory should not exist"; // yes, I am paranoid + + File inDir = FileUtil.createTempDirectory("fileUtilTestCopyDir", ".src", null); + try { + // create some test files in our source directory + String testFilename0 = "file0.txt"; + String testFilename1 = "subdir" + File.separatorChar + "subfile1.txt"; + String testFilename2 = "subdir" + File.separatorChar + "subfile2.txt"; + + File testFile = new File(inDir, testFilename0); + StreamUtil.copy(new ByteArrayInputStream("0".getBytes()), new FileOutputStream(testFile)); + assert "0".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); // sanity check, make sure its there + + testFile = new File(inDir, testFilename1); + testFile.getParentFile().mkdirs(); + StreamUtil.copy(new ByteArrayInputStream("1".getBytes()), new FileOutputStream(testFile)); + assert "1".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); // sanity check, make sure its there + testFile = new File(inDir, testFilename2); + testFile.getParentFile().mkdirs(); + StreamUtil.copy(new ByteArrayInputStream("2".getBytes()), new FileOutputStream(testFile)); + assert "2".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); // sanity check, make sure its there + + // copy our source directory and confirm the copies are correct + FileUtil.copyDirectory(inDir, outDir); + + testFile = new File(outDir, testFilename0); + assert testFile.exists() : "file did not get created: " + testFile; + assert "0".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); + testFile = new File(outDir, testFilename1); + assert testFile.exists() : "file did not get created: " + testFile; + assert "1".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); + testFile = new File(outDir, testFilename2); + assert testFile.exists() : "file did not get created: " + testFile; + assert "2".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); + + // let's test getDirectoryFiles while we are here + List<File> outFiles = FileUtil.getDirectoryFiles(outDir); + assert outFiles != null : outFiles; + assert outFiles.size() == 3 : outFiles; + assert outFiles.contains(new File(testFilename0)) : outFiles; + assert outFiles.contains(new File(testFilename1)) : outFiles; + assert outFiles.contains(new File(testFilename2)) : outFiles; + } finally { + // clean up our test + try { + FileUtil.purge(inDir, true); + } catch (Exception ignore) { + } + try { + FileUtil.purge(outDir, true); + } catch (Exception ignore) { + } + } + } + public void testStripDriveLetter() { StringBuilder str;
@@ -142,8 +213,7 @@ public class FileUtilTest { } });
- assertCollectionEqualsNoOrder(expectedFiles, actualFiles, - "Expected to visit all files in directory"); + assertCollectionEqualsNoOrder(expectedFiles, actualFiles, "Expected to visit all files in directory"); }
@Test @@ -176,8 +246,7 @@ public class FileUtilTest { } });
- assertCollectionEqualsNoOrder(expectedFiles, actualFiles, - "Expected to visit files in sub directories"); + assertCollectionEqualsNoOrder(expectedFiles, actualFiles, "Expected to visit files in sub directories"); }
@Test @@ -210,8 +279,7 @@ public class FileUtilTest { } });
- assertCollectionEqualsNoOrder(expectedFiles, actualFiles, - "Expected to visit files in nested sub directories"); + assertCollectionEqualsNoOrder(expectedFiles, actualFiles, "Expected to visit files in nested sub directories"); }
public void testGetPattern() { @@ -222,8 +290,8 @@ public class FileUtilTest { assert regex.matcher("/basedir/test1.txt").matches(); assert !regex.matcher("/basedir/test2.txt").matches();
- regex = assertPatternsRegex("(/basedir/easy\.txt)|(/basedir/test\.txt)", - new PathFilter("/basedir/easy.txt", null), new PathFilter("/basedir/test.txt", null)); + regex = assertPatternsRegex("(/basedir/easy\.txt)|(/basedir/test\.txt)", new PathFilter("/basedir/easy.txt", + null), new PathFilter("/basedir/test.txt", null));
assert regex.matcher("/basedir/easy.txt").matches(); assert regex.matcher("/basedir/test.txt").matches(); @@ -244,8 +312,8 @@ public class FileUtilTest { assert !regex.matcher("/basedir/subdir/foo.txt").matches(); assert !regex.matcher("/basedir/foo.txt.swp").matches();
- regex = assertPatternsRegex("(/var/lib/([^/]*\.war))|(/var/lib/([^/]*\.ear))", - new PathFilter("/var/lib", "*.war"), new PathFilter("/var/lib", "*.ear")); + regex = assertPatternsRegex("(/var/lib/([^/]*\.war))|(/var/lib/([^/]*\.ear))", new PathFilter("/var/lib", + "*.war"), new PathFilter("/var/lib", "*.ear"));
assert regex.matcher("/var/lib/myapp.war").matches(); assert regex.matcher("/var/lib/myapp.ear").matches(); diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java index 69d6d53..a69931a 100644 --- a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java +++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java @@ -230,12 +230,13 @@ public class DeployerTest { final String file999 = "dir1" + fileSeparator + "file999";
try { - if (ignore) { - // create a file that will be retained because we will be ignoring it - File ignoreDir = FileUtil.createTempDirectory("ignoreme", ".dir", tmpDir); - fileToIgnore = new File(ignoreDir, "some-log.log"); - StreamUtil.copy(new ByteArrayInputStream("boo".getBytes()), new FileOutputStream(fileToIgnore)); - } + // this is a file that will be removed because our initial deployment is managing the root deploy dir + // later we will recreate it to see that we ignore it during the upgrade. + // note that during the initial deployment, we will still back it up. + File ignoreDir = FileUtil.createTempDirectory("ignoreme", ".dir", tmpDir); + fileToIgnore = new File(ignoreDir, "some-log.log"); + StreamUtil.copy(new ByteArrayInputStream("boo".getBytes()), new FileOutputStream(fileToIgnore)); + String fileToIgnorePath = ignoreDir.getName() + "/" + fileToIgnore.getName(); // yes, use /, even if we are on windows
File testZipFile1 = new File("target/test-classes/updater-test1.zip"); File testZipFile2 = new File("target/test-classes/updater-test2.zip"); @@ -267,15 +268,25 @@ public class DeployerTest {
deployer.deploy(diff);
- if (ignore) { - assert "boo".equals(new String(StreamUtil.slurp(new FileInputStream(fileToIgnore)))); - assert diff.getIgnoredFiles().size() == 0 : "this was an initial deploy - nothing to ignore (ignore is only for updates)"; - } + // our initial deploy should have deleted this because we are managing the root dir + assert !fileToIgnore.exists() : "should have removed this file since we are managing the root dir"; + assert !fileToIgnore.getParentFile().exists() : "should have removed this file since we are managing the root dir"; + assert diff.getIgnoredFiles().size() == 0 : "this was an initial deploy - nothing to ignore (ignore is only for updates)"; assert diff.getAddedFiles().size() == 6 : diff; - assert diff.getDeletedFiles().size() == 0 : diff; + assert diff.getDeletedFiles().size() == 1 : diff; + assert diff.getDeletedFiles().contains(fileToIgnorePath) : "should have deleted this unknown file" + diff; assert diff.getChangedFiles().size() == 0 : diff; assert diff.getRealizedFiles().size() == 0 : "No fileA to realize in this deployment: " + diff; - assert diff.getBackedUpFiles().size() == 0 : "No fileA to realize in this deployment: " + diff; + assert diff.getBackedUpFiles().size() == 1 : diff; + assert diff.getBackedUpFiles().get(fileToIgnorePath) != null : "should have backed up this file" + diff; + + if (ignore) { + // let's create this again to make sure we really do ignore it + ignoreDir = FileUtil.createTempDirectory("ignoreme", ".dir", tmpDir); + fileToIgnore = new File(ignoreDir, "some-log.log"); + StreamUtil.copy(new ByteArrayInputStream("boo".getBytes()), new FileOutputStream(fileToIgnore)); + fileToIgnorePath = ignoreDir.getName() + "/" + fileToIgnore.getName(); // yes, use /, even if we are on windows + }
StreamUtil.copy(new ByteArrayInputStream("X".getBytes()), new FileOutputStream(new File(tmpDir, file1))); StreamUtil.copy(new ByteArrayInputStream("X".getBytes()), new FileOutputStream(updaterAabsolute)); @@ -295,7 +306,7 @@ public class DeployerTest { templateEngine, ignoreRegex, true, null); deployer = new Deployer(dd); diff = new DeployDifferences(); - deployer.deploy(diff); + deployer.deploy(diff); // this is an upgrade
if (ignore) { assert "boo".equals(new String(StreamUtil.slurp(new FileInputStream(fileToIgnore)))); @@ -396,11 +407,11 @@ public class DeployerTest { assert diff.getChangedFiles().contains(fileB) : diff; assert diff.getBackedUpFiles().size() == 4 : diff; assert diff.getBackedUpFiles().containsKey(diff.convertPath(updaterAabsolute.getAbsolutePath())) : diff; - assert diff.getBackedUpFiles().get(diff.convertPath(updaterAabsolute.getAbsolutePath())).equals( - diff.convertPath(updaterAabsoluteBackupTo2)) : diff; + assert diff.getBackedUpFiles().get(diff.convertPath(updaterAabsolute.getAbsolutePath())) + .equals(diff.convertPath(updaterAabsoluteBackupTo2)) : diff; assert diff.getBackedUpFiles().containsKey(diff.convertPath(updaterBabsolute.getAbsolutePath())) : diff; - assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath())).equals( - diff.convertPath(updaterBabsoluteBackupTo2)) : diff; + assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath())) + .equals(diff.convertPath(updaterBabsoluteBackupTo2)) : diff; assert diff.getBackedUpFiles().containsKey(fileB) : diff; assert diff.getBackedUpFiles().get(fileB).equals(diff.convertPath(fileBbackupTo2.getAbsolutePath())) : diff; assert diff.getBackedUpFiles().containsKey(file999) : diff; @@ -442,8 +453,8 @@ public class DeployerTest { assert diff.getChangedFiles().contains(diff.convertPath(updaterBabsolute.getAbsolutePath())) : diff; assert diff.getBackedUpFiles().size() == 1 : diff; assert diff.getBackedUpFiles().containsKey(diff.convertPath(updaterBabsolute.getAbsolutePath())) : diff; - assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath())).equals( - diff.convertPath(updaterBabsoluteBackupTo3)) : diff; + assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath())) + .equals(diff.convertPath(updaterBabsoluteBackupTo3)) : diff; if (realize) { assert diff.getRealizedFiles().size() == 1 : diff; assert diff.getRealizedFiles().containsKey(fileA) : diff; diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java index f875576..2736f16 100644 --- a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java +++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java @@ -205,7 +205,15 @@ public class SimpleDeployerTest { baseNoNewWithCurrentDifferentThanOriginal(true); }
- public void testWithSubdirectories() throws Exception { + public void testWithSubdirectoriesManageRootDir() throws Exception { + testWithSubdirectories(true); + } + + public void testWithSubdirectoriesNoManageRootDir() throws Exception { + testWithSubdirectories(false); + } + + private void testWithSubdirectories(boolean manageRootDir) throws Exception { // this test is different than all the rest, start with clean tmp/dest dirs with no beforeMethod buildup FileUtil.purge(this.tmpDir, false); FileUtil.purge(this.deployDir, false); @@ -227,14 +235,40 @@ public class SimpleDeployerTest { this.originalZipFiles.add(originalZipFile); this.originalDeployProps = new DeploymentProperties(1, "simple", "1.0", "original test deployment"); DeploymentData dd = new DeploymentData(originalDeployProps, originalZipFiles, null, tmpDir, deployDir, null, - null, null, null, true, null); + null, null, null, manageRootDir, null); + this.diff = new DeployDifferences(); Deployer deployer = new Deployer(dd); - this.originalFileHashcodeMap = deployer.deploy(null); + this.originalFileHashcodeMap = deployer.deploy(this.diff); assert new File(this.deployDir, origFileName1).exists(); assert new File(this.deployDir, origFileName2).exists(); - assert unrelated1.exists() : "the deployment removed unrelated file1"; - assert unrelated2.getParentFile().isDirectory() : "the deployment removed an unrelated dir"; - assert unrelated2.exists() : "the deployment removed unrelated file2"; + if (manageRootDir) { + assert !unrelated1.exists() : "the deployment should have removed unrelated file1"; + assert !unrelated2.getParentFile().isDirectory() : "the deployment should have removed an unrelated dir"; + assert !unrelated2.exists() : "the deployment should have removed unrelated file2"; + + assert this.diff.getBackedUpFiles().size() == 2 : this.diff; + assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName1)).exists() : this.diff; + assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName2)).exists() : this.diff; + assert this.diff.getDeletedFiles().size() == 2 : this.diff; + assert this.diff.getDeletedFiles().contains(unrelatedFileName1) : this.diff; + assert this.diff.getDeletedFiles().contains(unrelatedFileName2) : this.diff; + } else { + assert this.diff.getBackedUpFiles().size() == 0 : this.diff; + assert this.diff.getDeletedFiles().size() == 0 : this.diff; + assert unrelated1.exists() : "the deployment removed unrelated file1"; + assert unrelated2.getParentFile().isDirectory() : "the deployment removed an unrelated dir"; + assert unrelated2.exists() : "the deployment removed unrelated file2"; + } + + assert this.diff.getAddedFiles().size() == 2 : this.diff; + assert this.diff.getAddedFiles().contains(origFileName1) : this.diff; + assert this.diff.getAddedFiles().contains(origFileName2) : this.diff; + assert this.diff.getChangedFiles().isEmpty() : this.diff; + assert this.diff.getIgnoredFiles().isEmpty() : this.diff; + assert this.diff.getRealizedFiles().isEmpty() : this.diff; + assert this.diff.getRestoredFiles().isEmpty() : this.diff; + assert !this.diff.wasCleaned() : this.diff; + assert this.diff.getErrors().isEmpty() : this.diff;
// deploy new content this.newDeployProps = new DeploymentProperties(2, "simple", "2.0", "new test deployment"); @@ -246,19 +280,36 @@ public class SimpleDeployerTest { new String[] { newFileName1, newFileName2 }); HashSet<File> newZipFiles = new HashSet<File>(1); newZipFiles.add(newZipFile); - dd = new DeploymentData(newDeployProps, newZipFiles, null, tmpDir, deployDir, null, null, null, null, true, - null); + dd = new DeploymentData(newDeployProps, newZipFiles, null, tmpDir, deployDir, null, null, null, null, + manageRootDir, null); deployer = new Deployer(dd); FileHashcodeMap newFileHashcodeMap = deployer.deploy(this.diff); + assert newFileHashcodeMap != null; assert new File(this.deployDir, newFileName1).exists(); assert new File(this.deployDir, newFileName2).exists(); assert !new File(this.deployDir, origFileName1).exists(); assert !new File(this.deployDir, origFileName2).exists(); - assert !unrelated1.exists() : "the deployment did not remove unrelated file1"; - assert !unrelated2.exists() : "the deployment did not remove unrelated file1"; - assert this.diff.getBackedUpFiles().size() == 2 : this.diff; - assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName1)).exists() : this.diff; - assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName2)).exists() : this.diff; + if (manageRootDir) { + assert !unrelated1.exists() : "the deployment did not remove unrelated file1"; + assert !unrelated2.exists() : "the deployment did not remove unrelated file1"; + } else { + assert unrelated1.exists() : "the deployment removed unrelated file1 but we aren't managing the root dir"; + assert unrelated2.exists() : "the deployment removed unrelated file1 but we aren't managing the root dir"; + } + + assert this.diff.getAddedFiles().size() == 2 : this.diff; + assert this.diff.getAddedFiles().contains(newFileName1) : this.diff; + assert this.diff.getAddedFiles().contains(newFileName2) : this.diff; + assert this.diff.getDeletedFiles().size() == 2 : this.diff; + assert this.diff.getDeletedFiles().contains(origFileName1) : this.diff; + assert this.diff.getDeletedFiles().contains(origFileName2) : this.diff; + assert this.diff.getChangedFiles().isEmpty() : this.diff; + assert this.diff.getBackedUpFiles().isEmpty() : this.diff; + assert this.diff.getIgnoredFiles().isEmpty() : this.diff; + assert this.diff.getRealizedFiles().isEmpty() : this.diff; + assert this.diff.getRestoredFiles().isEmpty() : this.diff; + assert !this.diff.wasCleaned() : this.diff; + assert this.diff.getErrors().isEmpty() : this.diff; }
private void baseX_X_X(boolean dryRun) throws Exception { diff --git a/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java b/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java index a772ef0..d712401 100644 --- a/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java +++ b/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java @@ -231,11 +231,17 @@ public class AntBundlePluginComponentTest { upgrade(true); }
+ @Test(enabled = true) + public void testAntBundleInitialInstall() throws Exception { + doAntBundleInitialInstall(true); + } + /** * Test deployment of an RHQ bundle recipe with archive file and raw file + * @param startClean if true, the destination directory will be non-existent and thus clean + * if false, this will put some junk files in the dest directory */ - @Test(enabled = true) - public void testAntBundleInitialInstall() throws Exception { + private void doAntBundleInitialInstall(boolean startClean) throws Exception { ResourceType resourceType = new ResourceType("testSimpleBundle2Type", "plugin", ResourceCategory.SERVER, null); BundleType bundleType = new BundleType("testSimpleBundle2BType", resourceType); Repo repo = new Repo("test-bundle-two"); @@ -273,6 +279,25 @@ public class AntBundlePluginComponentTest { props.store(outputStream, "test.properties comment"); outputStream.close();
+ // if we are not to start clean, create some junk files that will need to be backed up and moved away + if (startClean == false) { + this.destDir.mkdirs(); + File junk1 = new File(this.destDir, "junk1.properties"); + Properties junkProps = new Properties(); + junkProps.setProperty("junk1", "wot gorilla?"); + FileOutputStream os = new FileOutputStream(junk1); + junkProps.store(os, "junk1.properties comment"); + os.close(); + + File junk2 = new File(this.destDir, "junksubdir" + File.separatorChar + "junk2.properties"); + junk2.getParentFile().mkdirs(); + junkProps = new Properties(); + junkProps.setProperty("junk2", "more junk"); + os = new FileOutputStream(junk2); + junkProps.store(os, "junk2.properties comment"); + os.close(); + } + BundleDeployRequest request = new BundleDeployRequest(); request.setBundleFilesLocation(this.bundleFilesDir); request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); @@ -501,8 +526,129 @@ public class AntBundlePluginComponentTest { assert "2".equals(props.getProperty("external2")) : "bundle purge removed our unmanaged file 2"; }
+ /** + * Test deployment of an RHQ bundle recipe where the deploy directory is to be fully managed. + * This is the typical use-case and the default behavior. + */ + @Test(enabled = true) + public void testAntBundleManageRootDir() throws Exception { + ResourceType resourceType = new ResourceType("testManageRootDirBundle", "plugin", ResourceCategory.SERVER, null); + BundleType bundleType = new BundleType("testManageRootDirBundle", resourceType); + Repo repo = new Repo("testManageRootDirBundle"); + PackageType packageType = new PackageType("testManageRootDirBundle", resourceType); + Bundle bundle = new Bundle("testManageRootDirBundle", bundleType, repo, packageType); + BundleVersion bundleVersion = new BundleVersion("testManageRootDirBundle", "1.0", bundle, + getRecipeFromFile("test-bundle-manage-root-dir.xml")); + BundleDestination destination = new BundleDestination(bundle, "testManageRootDirBundle", new ResourceGroup( + "testManageRootDirBundle"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath()); + Configuration config = new Configuration(); + + BundleDeployment deployment = new BundleDeployment(); + deployment.setName("test bundle deployment name"); + deployment.setBundleVersion(bundleVersion); + deployment.setConfiguration(config); + deployment.setDestination(destination); + + // create bundle test files + File file0 = new File(this.bundleFilesDir, "zero.properties"); + Properties props = new Properties(); + props.setProperty("zero", "0"); + FileOutputStream outputStream = new FileOutputStream(file0); + props.store(outputStream, "zero file"); + outputStream.close(); + + File file1 = new File(this.bundleFilesDir, "one.properties"); + props.clear(); + props.setProperty("one", "1"); + outputStream = new FileOutputStream(file1); + props.store(outputStream, "one file"); + outputStream.close(); + + File file2 = new File(this.bundleFilesDir, "two.properties"); + props.clear(); + props.setProperty("two", "2"); + outputStream = new FileOutputStream(file2); + props.store(outputStream, "two file"); + outputStream.close(); + + // create some external test files that don't belong to the bundle but are in the dest dir (which is to be managed by the bundle) + this.destDir.mkdirs(); + File external1 = new File(this.destDir, "external1.properties"); + props.clear(); + props.setProperty("external1", "1"); + outputStream = new FileOutputStream(external1); + props.store(outputStream, "external1 file"); + outputStream.close(); + + File external2 = new File(this.destDir, "extdir/external2.properties"); + external2.getParentFile().mkdirs(); + props.clear(); + props.setProperty("external2", "2"); + outputStream = new FileOutputStream(external2); + props.store(outputStream, "external2 file"); + outputStream.close(); + + // deploy the bundle + BundleDeployRequest request = new BundleDeployRequest(); + request.setBundleFilesLocation(this.bundleFilesDir); + request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); + request.setBundleManagerProvider(new MockBundleManagerProvider()); + request.setAbsoluteDestinationDirectory(this.destDir); + + BundleDeployResult results = plugin.deployBundle(request); + + assertResultsSuccess(results); + + // test that files were deployed in the proper place + props.clear(); + loadProperties(props, new FileInputStream(new File(this.destDir, "zero.properties"))); + assert "0".equals(props.getProperty("zero")) : "did not deploy bundle correctly 0"; + loadProperties(props, new FileInputStream(new File(this.destDir, "subdir1/one.properties"))); + assert "1".equals(props.getProperty("one")) : "did not deploy bundle correctly 1"; + loadProperties(props, new FileInputStream(new File(this.destDir, "subdir2/two.properties"))); + assert "2".equals(props.getProperty("two")) : "did not deploy bundle correctly 2"; + + DeploymentsMetadata metadata = new DeploymentsMetadata(this.destDir); + assert metadata.isManaged() == true : "missing metadata directory"; + assert metadata.getCurrentDeploymentProperties().getManageRootDir() == true : "should be managing root dir"; + + // make sure our external files/directories were removed because + // they aren't part of the bundle and we are fully managing the dest dir + props.clear(); + try { + loadProperties(props, new FileInputStream(new File(this.destDir, "external1.properties"))); + assert false : "bundle deployment did not remove our managed file 1"; + } catch (Exception ok) { + } + try { + loadProperties(props, new FileInputStream(new File(this.destDir, "extdir/external2.properties"))); + assert false : "bundle deployment did not remove our managed file 2"; + } catch (Exception ok) { + } + + // now purge the bundle - this should purge everything in the deploy dir because we are fully managing it + BundlePurgeRequest purgeRequest = new BundlePurgeRequest(); + purgeRequest.setLiveResourceDeployment(new BundleResourceDeployment(deployment, null)); + purgeRequest.setBundleManagerProvider(new MockBundleManagerProvider()); + purgeRequest.setAbsoluteDestinationDirectory(this.destDir); + + BundlePurgeResult purgeResults = plugin.purgeBundle(purgeRequest); + assertResultsSuccess(purgeResults); + + // make sure our bundle files have been completely purged; the metadata directory should have been purged too + assert new File(this.destDir, "zero.properties").exists() == false; + assert new File(this.destDir, "subdir1/one.properties").exists() == false; + assert new File(this.destDir, "subdir2/two.properties").exists() == false; + assert new File(this.destDir, "subdir1").exists() == false; + assert new File(this.destDir, "subdir2").exists() == false; + assert this.destDir.exists() == false : "deploy dir should not exist, we were told to fully manage it"; + + metadata = new DeploymentsMetadata(this.destDir); + assert metadata.getMetadataDirectory().exists() == false : "metadata directory should not exist"; + } + private void upgrade(boolean clean) throws Exception { - testAntBundleInitialInstall(); // install a bundle first + doAntBundleInitialInstall(clean); // install a bundle first cleanPluginDirs(); // clean everything but the dest dir - we want to upgrade the destination prepareBeforeTestMethod(); // prepare for our new test
diff --git a/modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml b/modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml new file mode 100644 index 0000000..9b77dd8 --- /dev/null +++ b/modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> + +<project name="simple-build" default="main" + xmlns:rhq="antlib:org.rhq.bundle"> + + <rhq:bundle name="testManageRootDirBundle" version="1.0"> + <rhq:deployment-unit name="simulated-war" manageRootDir="true"> + <rhq:file name="zero.properties" destinationFile="zero.properties"/> + <rhq:file name="one.properties" destinationFile="subdir1/one.properties"/> + <rhq:file name="two.properties" destinationFile="subdir2/two.properties"/> + </rhq:deployment-unit> + </rhq:bundle> + + <target name="main"/> + +</project> \ No newline at end of file
rhq-commits@lists.fedorahosted.org