/*
* RHQ Management Platform
* Copyright (C) 2011 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 as published by
* the Free Software Foundation version 2 of the License.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.core.pc.drift;
import static org.rhq.common.drift.FileEntry.addedFileEntry;
import static org.rhq.core.domain.drift.DriftChangeSetCategory.COVERAGE;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.common.drift.ChangeSetWriter;
import org.rhq.common.drift.Headers;
import org.rhq.core.domain.drift.DriftChangeSetCategory;
import org.rhq.core.domain.drift.DriftFile;
import org.rhq.core.domain.drift.JPADriftFile;
import org.rhq.core.util.ZipUtil;
import org.rhq.test.AssertUtils;
public class DriftFilesSenderTest extends DriftTest {
DriftClientTestStub driftClient;
DriftFilesSender sender;
@BeforeMethod
public void initSender() {
driftClient = new DriftClientTestStub();
sender = new DriftFilesSender();
sender.setDriftClient(driftClient);
sender.setChangeSetManager(changeSetMgr);
sender.setResourceId(resourceId());
}
@Test
public void sendOneFile() throws Exception {
String driftDefName = "send-one-file-test";
File serverConf = createRandomFile(resourceDir, "server.conf");
String serverConfHash = sha256(serverConf);
File changeSetDir = changeSetDir(driftDefName);
Headers headers = createHeaders(driftDefName, COVERAGE);
ChangeSetWriter writer = changeSetMgr.getChangeSetWriter(resourceId(), headers);
writer.write(addedFileEntry("server.conf", serverConfHash, serverConf.lastModified(), serverConf.length()));
writer.close();
sender.setDriftFiles(driftFiles(serverConfHash));
sender.setHeaders(headers);
sender.run();
assertContentFileExists(changeSetDir);
assertContentFileMatches(changeSetDir, serverConfHash);
}
@Test
public void sendFilesInOneDirectory() throws Exception {
String driftDefName = "single-directory-test";
File confDir = mkdir(resourceDir, "conf");
File server1Conf = createRandomFile(confDir, "server-1.conf");
File server2Conf = createRandomFile(confDir, "server-2.conf");
String server1ConfHash = sha256(server1Conf);
String server2ConfHash = sha256(server2Conf);
File changeSetDir = changeSetDir(driftDefName);
Headers headers = createHeaders(driftDefName, COVERAGE);
ChangeSetWriter writer = changeSetMgr.getChangeSetWriter(resourceId(), headers);
writer.write(addedFileEntry("conf/server-1.conf", server1ConfHash, server1Conf.lastModified(), server1Conf
.length()));
writer.write(addedFileEntry("conf/server-2.conf", server2ConfHash, server2Conf.lastModified(), server2Conf
.length()));
writer.close();
sender.setDriftFiles(driftFiles(server1ConfHash, server2ConfHash));
sender.setHeaders(headers);
sender.run();
assertContentFileExists(changeSetDir);
assertContentFileMatches(changeSetDir, server1ConfHash, server2ConfHash);
}
@Test
public void sendFilesInMultipleDirectories() throws Exception {
String driftDefName = "multiple-directories-test";
File confDir = mkdir(resourceDir, "conf");
File libDir = mkdir(resourceDir, "lib");
File server1Conf = createRandomFile(confDir, "server-1.conf");
File server2Conf = createRandomFile(confDir, "server-2.conf");
File server1Jar = createRandomFile(libDir, "server-1.jar");
File server2Jar = createRandomFile(libDir, "server-2.jar");
String server1ConfHash = sha256(server1Conf);
String server2ConfHash = sha256(server2Conf);
String server1JarHash = sha256(server1Jar);
String server2JarHash = sha256(server2Jar);
File changeSetDir = changeSetDir(driftDefName);
Headers headers = createHeaders(driftDefName, COVERAGE);
ChangeSetWriter writer = changeSetMgr.getChangeSetWriter(resourceId(), headers);
writer.write(addedFileEntry("conf/server-1.conf", server1ConfHash, server1Conf.lastModified(), server1Conf
.length()));
writer.write(addedFileEntry("conf/server-2.conf", server2ConfHash, server2Conf.lastModified(), server2Conf
.length()));
writer
.write(addedFileEntry("lib/server-1.jar", server1JarHash, server1Jar.lastModified(), server1Jar.length()));
writer
.write(addedFileEntry("lib/server-2.jar", server2JarHash, server2Jar.lastModified(), server2Jar.length()));
writer.close();
// Note that the order of the drift files is random. When the server sends a request
// for files we cannot assume that the files will be in any particular order.
sender.setDriftFiles(driftFiles(server1JarHash, server2ConfHash, server2JarHash, server1ConfHash));
sender.setHeaders(headers);
sender.run();
assertContentFileExists(changeSetDir);
assertContentFileMatches(changeSetDir, server1ConfHash, server2ConfHash, server1JarHash, server2JarHash);
}
@Test
public void checkForFilesThatHaveBeenRemoved() throws Exception {
String driftDefName = "file-exists-test";
File confDir = mkdir(resourceDir, "conf");
File server1Conf = createRandomFile(confDir, "server-1.conf");
File server2Conf = createRandomFile(confDir, "server-2.conf");
String server1ConfHash = sha256(server1Conf);
String server2ConfHash = sha256(server2Conf);
File changeSetDir = changeSetDir(driftDefName);
Headers headers = createHeaders(driftDefName, COVERAGE);
ChangeSetWriter writer = changeSetMgr.getChangeSetWriter(resourceId(), headers);
writer.write(addedFileEntry("conf/server-1.conf", server1ConfHash, server1Conf.lastModified(), server1Conf
.length()));
writer.write(addedFileEntry("conf/server-2.conf", server2ConfHash, server2Conf.lastModified(), server2Conf
.length()));
writer.close();
// It is possible that the server can request a file that has been deleted since it
// it was initially detected during drift detection.
server1Conf.delete();
sender.setDriftFiles(driftFiles(server1ConfHash, server2ConfHash));
sender.setHeaders(headers);
sender.run();
assertContentFileExists(changeSetDir);
assertContentFileMatches(changeSetDir, server2ConfHash);
}
@Test
public void doNotSendEmptyZipFileToServer() throws Exception {
String driftDefName = "empty_content_test";
File confDir = mkdir(resourceDir, "conf");
File serverConf = createRandomFile(confDir, "server.conf");
String serverConfHash = sha256(serverConf);
Headers headers = createHeaders(driftDefName, COVERAGE);
ChangeSetWriter writer = changeSetMgr.getChangeSetWriter(resourceId(), headers);
writer
.write(addedFileEntry("conf/server.conf", serverConfHash, serverConf.lastModified(), serverConf.length()));
writer.close();
serverConf.delete();
sender.setDriftFiles(driftFiles(serverConfHash));
sender.setHeaders(headers);
sender.run();
assertEquals(driftClient.getSendChangeSetContentInvocationCount(), 0,
"Do not call DriftClient to send content to server when there is no content to send.");
assertContentFileExists(changeSetDir(driftDefName));
}
void assertContentFileExists(File changeSetDir) {
File[] files = getContentFiles(changeSetDir);
assertEquals(files.length, 1, "Expected to find a single content zip file but found " + Arrays.toString(files));
}
void assertContentFileMatches(File changeSetDir, String... expectedFileNames) throws Exception {
File contentFile = getContentFiles(changeSetDir)[0];
final List<String> actualFileNames = new LinkedList<String>();
ZipUtil.walkZipFile(contentFile, new ZipUtil.ZipEntryVisitor() {
@Override
public boolean visit(ZipEntry entry, ZipInputStream stream) throws Exception {
actualFileNames.add(entry.getName());
return true;
}
});
AssertUtils.assertCollectionEqualsNoOrder(Arrays.asList(expectedFileNames), actualFileNames,
"The content file " + contentFile.getPath() + " does not contain the correct entries");
}
private File[] getContentFiles(File changeSetDir) {
return changeSetDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith("content_") && name.endsWith(".zip");
}
});
}
/**
* This method only verifies that a file having a particular hash or SHA-256 has been
* copied to the specified content directory.
*
* @param contentDir The directory to which the file should have been copied
*
* @param fileHash The file hash which is expected to be the name of the file in the
* content directory.
*/
void assertFileCopiedToContentDir(File contentDir, String fileHash) {
File file = new File(contentDir, fileHash);
assertTrue(file.exists(), "Expected to find file named " + file.getName() + " in content directory "
+ contentDir.getPath() + ". The SHA-256 hash should be used as the file name.");
}
Headers createHeaders(String configName, DriftChangeSetCategory type) {
Headers headers = new Headers();
headers.setResourceId(resourceId());
headers.setDriftDefinitionId(0);
headers.setDriftDefinitionName(configName);
headers.setBasedir(resourceDir.getAbsolutePath());
headers.setType(type);
return headers;
}
List<DriftFile> driftFiles(String... hashes) {
List<DriftFile> files = new ArrayList<DriftFile>();
for (String hash : hashes) {
files.add(new JPADriftFile(hash));
}
return files;
}
}