/**
* Copyright (c) 2009--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.frontend.xmlrpc.configchannel.test;
import com.redhat.rhn.common.db.datasource.DataResult;
import com.redhat.rhn.common.hibernate.LookupException;
import com.redhat.rhn.common.validator.ValidatorException;
import com.redhat.rhn.domain.action.ActionFactory;
import com.redhat.rhn.domain.action.config.ConfigAction;
import com.redhat.rhn.domain.action.config.ConfigRevisionAction;
import com.redhat.rhn.domain.config.ConfigChannel;
import com.redhat.rhn.domain.config.ConfigChannelType;
import com.redhat.rhn.domain.config.ConfigFile;
import com.redhat.rhn.domain.config.ConfigFileState;
import com.redhat.rhn.domain.config.ConfigFileType;
import com.redhat.rhn.domain.config.ConfigRevision;
import com.redhat.rhn.domain.config.ConfigurationFactory;
import com.redhat.rhn.domain.server.Server;
import com.redhat.rhn.domain.server.ServerFactory;
import com.redhat.rhn.domain.server.test.ServerFactoryTest;
import com.redhat.rhn.frontend.dto.ConfigChannelDto;
import com.redhat.rhn.frontend.dto.ConfigFileDto;
import com.redhat.rhn.frontend.dto.ScheduledAction;
import com.redhat.rhn.frontend.xmlrpc.configchannel.ConfigChannelHandler;
import com.redhat.rhn.frontend.xmlrpc.serializer.ConfigRevisionSerializer;
import com.redhat.rhn.frontend.xmlrpc.test.BaseHandlerTestCase;
import com.redhat.rhn.manager.action.ActionManager;
import com.redhat.rhn.manager.configuration.ConfigChannelCreationHelper;
import com.redhat.rhn.manager.system.SystemManager;
import com.redhat.rhn.manager.system.test.SystemManagerTest;
import com.redhat.rhn.testing.ConfigTestUtils;
import com.redhat.rhn.testing.TestUtils;
import org.apache.commons.lang.RandomStringUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* ConfigChannelHandlerTest
* @version $Rev$
*/
public class ConfigChannelHandlerTest extends BaseHandlerTestCase {
private ConfigChannelHandler handler = new ConfigChannelHandler();
private static final String LABEL = "LABEL" + TestUtils.randomString();
private static final String NAME = "NAME" + TestUtils.randomString();
private static final String DESCRIPTION = "DESCRIPTION" + TestUtils.randomString();
public void testCreate() {
try {
handler.create(regular, LABEL, NAME, DESCRIPTION);
String msg = "Needs to be a config admin.. perm error not detected.";
fail(msg);
}
catch (Exception e) {
//Cool perm error!
}
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
assertEquals(LABEL, cc.getLabel());
assertEquals(NAME, cc.getName());
assertEquals(DESCRIPTION, cc.getDescription());
assertEquals(admin.getOrg(), cc.getOrg());
try {
cc = handler.create(admin, LABEL + "/", NAME, DESCRIPTION);
String msg = "Invalid character / not detected:(";
fail(msg);
}
catch (Exception e) {
System.out.println(e.getMessage());
//Cool invalid check works!..
}
}
public void testUpdate() {
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
String newName = NAME + TestUtils.randomString();
String desc = DESCRIPTION + TestUtils.randomString();
try {
handler.update(regular, LABEL, newName, desc);
String msg = "Needs to be a config admin/have access.. " +
"perm error not detected.";
fail(msg);
}
catch (Exception e) {
//Cool perm error!
}
cc = handler.update(admin, LABEL, newName, desc);
assertEquals(LABEL, cc.getLabel());
assertEquals(newName, cc.getName());
assertEquals(desc, cc.getDescription());
assertEquals(admin.getOrg(), cc.getOrg());
try {
String name = RandomStringUtils.randomAlphanumeric(
ConfigChannelCreationHelper.MAX_NAME_LENGTH + 1);
cc = handler.update(admin, LABEL, name, DESCRIPTION);
String msg = "Max length reached for name- not detected :(";
fail(msg);
}
catch (Exception e) {
System.out.println(e.getMessage());
//Cool invalid check works!..
}
}
public void testListGlobal() throws Exception {
ConfigChannel cc = ConfigTestUtils.createConfigChannel(admin.getOrg());
ConfigTestUtils.giveUserChanAccess(regular, cc);
List<ConfigChannelDto> list = handler.listGlobals(regular);
assertTrue(contains(cc, list));
}
public void testLookupGlobal() throws Exception {
List<String> channelLabels = new LinkedList<String>();
List<ConfigChannel> channels = new LinkedList<ConfigChannel>();
for (int i = 0; i < 10; i++) {
ConfigChannel cc = ConfigTestUtils.createConfigChannel(admin.getOrg());
ConfigTestUtils.giveUserChanAccess(regular, cc);
channels.add(cc);
channelLabels.add(cc.getLabel());
}
List<ConfigChannel> list = handler.lookupChannelInfo(regular,
channelLabels);
assertEquals(channels, list);
}
public void testGetDetailsByLabel() throws Exception {
ConfigChannel cc = ConfigTestUtils.createConfigChannel(admin.getOrg());
ConfigTestUtils.giveUserChanAccess(regular, cc);
ConfigChannel channel = handler.getDetails(regular, cc.getLabel());
assertEquals(channel, cc);
}
public void testGetDetailsById() throws Exception {
ConfigChannel cc = ConfigTestUtils.createConfigChannel(admin.getOrg());
ConfigTestUtils.giveUserChanAccess(regular, cc);
ConfigChannel channel = handler.getDetails(regular, cc.getId().intValue());
assertEquals(channel, cc);
}
public void testDelete() {
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
List<String> labels = new LinkedList<String>();
labels.add(cc.getLabel());
List <ConfigChannel> channels = handler.lookupChannelInfo(admin, labels);
assertEquals(1, channels.size());
handler.deleteChannels(admin, labels);
try {
handler.lookupChannelInfo(admin, labels);
fail("Lookup exception not raised!");
}
catch (LookupException e) {
// Cool could not find the item!..
}
}
/**
* Checks if a given config channel is present in a list.
* @param cc Config channel
* @param list list of type COnfigChannelDto
* @return true if the List contains it , false other wise
*/
private boolean contains(ConfigChannel cc, List<ConfigChannelDto> list) {
for (ConfigChannelDto dto : list) {
if (dto.getLabel().equals(cc.getLabel())) {
return true;
}
}
return false;
}
private ConfigRevision createRevision(String path, String contents,
String group, String owner,
String perms, boolean isDir,
ConfigChannel cc, String selinuxCtx)
throws ValidatorException {
Map <String, Object> data = new HashMap<String, Object>();
data.put(ConfigRevisionSerializer.GROUP, group);
data.put(ConfigRevisionSerializer.OWNER, owner);
data.put(ConfigRevisionSerializer.PERMISSIONS, perms);
data.put(ConfigRevisionSerializer.SELINUX_CTX, selinuxCtx);
String start = "#@";
String end = "@#";
if (!isDir) {
data.put(ConfigRevisionSerializer.CONTENTS, contents);
data.put(ConfigRevisionSerializer.MACRO_START, start);
data.put(ConfigRevisionSerializer.MACRO_END, end);
}
ConfigRevision rev = handler.createOrUpdatePath(
admin, cc.getLabel(), path, isDir, data);
assertEquals(path, rev.getConfigFile().getConfigFileName().getPath());
assertEquals(group, rev.getConfigInfo().getGroupname());
assertEquals(owner, rev.getConfigInfo().getUsername());
assertEquals(perms, String.valueOf(rev.getConfigInfo().getFilemode()));
assertEquals(selinuxCtx, rev.getConfigInfo().getSelinuxCtx());
if (isDir) {
assertEquals(ConfigFileType.dir(), rev.getConfigFileType());
}
else if (ConfigFileType.file().equals(rev.getConfigFileType())) {
assertEquals(contents, rev.getConfigContent().getContentsString());
assertEquals(start, rev.getConfigContent().getDelimStart());
assertEquals(end, rev.getConfigContent().getDelimEnd());
}
assertEquals(cc, rev.getConfigFile().getConfigChannel());
assertRevNotChanged(rev, cc);
return rev;
}
private ConfigRevision createSymlinkRevision(String path, String targetPath,
ConfigChannel cc, String selinuxCtx)
throws ValidatorException {
Map <String, Object> data = new HashMap<String, Object>();
data.put(ConfigRevisionSerializer.TARGET_PATH, targetPath);
data.put(ConfigRevisionSerializer.SELINUX_CTX, selinuxCtx);
ConfigRevision rev = handler.createOrUpdateSymlink(admin,
cc.getLabel(), path, data);
assertEquals(path, rev.getConfigFile().getConfigFileName().getPath());
assertEquals(ConfigFileType.symlink(), rev.getConfigFileType());
assertEquals(targetPath, rev.getConfigInfo().getTargetFileName().getPath());
assertEquals(selinuxCtx, rev.getConfigInfo().getSelinuxCtx());
assertEquals(cc, rev.getConfigFile().getConfigChannel());
assertRevNotChanged(rev, cc);
return rev;
}
private void assertRev(ConfigRevision rev, String path, ConfigChannel cc) {
List<String> paths = new ArrayList<String>(1);
paths.add(path);
assertTrue(rev.matches(handler.lookupFileInfo(admin, cc.getLabel(), paths)
.get(0)));
}
private void assertRevNotChanged(ConfigRevision rev, ConfigChannel cc) {
assertRev(rev, rev.getConfigFile().getConfigFileName().getPath(), cc);
}
public void testAddPath() throws Exception {
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
String path = "/tmp/foo/path" + TestUtils.randomString();
String contents = "HAHAHAHA";
ConfigRevision rev = createRevision(path, contents,
"group" + TestUtils.randomString(),
"owner" + TestUtils.randomString(),
"777",
false, cc, "unconfined_u:object_r:tmp_t");
try {
createRevision(path, contents,
"group" + TestUtils.randomString(),
"owner" + TestUtils.randomString(),
"744",
true, cc, "unconfined_u:object_r:tmp_t");
fail("Can't change the path from file to directory.");
}
catch (Exception e) {
// Can;t change.. Won't allow...
assertRevNotChanged(rev, cc);
}
try {
createRevision(path + TestUtils.randomString() + "/" , contents,
"group" + TestUtils.randomString(),
"owner" + TestUtils.randomString(),
"744",
true, cc, "unconfined_u:object_r:tmp_t");
fail("Validation error on the path.");
}
catch (Exception e) {
// Can;t change.. Won't allow...
assertRevNotChanged(rev, cc);
}
createRevision(path + TestUtils.randomString(), "",
"group" + TestUtils.randomString(),
"owner" + TestUtils.randomString(),
"744",
true, cc, "unconfined_u:object_r:tmp_t");
createSymlinkRevision(path + TestUtils.randomString(),
path + TestUtils.randomString(), cc, "root:root");
}
public void testListFiles() {
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
List<String> paths = new LinkedList<String>();
Map<String, ConfigRevision> revisions = new HashMap<String, ConfigRevision>();
setupPathsAndRevisions(cc, paths, revisions);
List<ConfigFileDto> files = handler.listFiles(admin, LABEL);
for (ConfigFileDto dto : files) {
assertTrue(revisions.containsKey(dto.getPath()));
ConfigRevision rev = revisions.get(dto.getPath());
assertEquals(rev.getConfigFileType().getLabel(), dto.getType());
assertNotNull(dto.getModified());
}
}
/**
* @param cc the channel
* @param paths a list holder for paths
* @param revisions a holder of revisions
*/
private void setupPathsAndRevisions(ConfigChannel cc, List<String> paths,
Map<String, ConfigRevision> revisions) {
String path = "/tmp/foo/path/";
for (int i = 0; i < 10; i++) {
boolean isDir = i % 2 == 0;
String newPath = path + TestUtils.randomString();
String contents = isDir ? "" : TestUtils.randomString();
paths.add(newPath);
revisions.put(newPath, createRevision(newPath,
contents,
"group" + TestUtils.randomString(),
"owner" + TestUtils.randomString(),
"744",
isDir, cc,
"unconfined_u:object_r:tmp_t"));
}
}
public void testRemovePaths() throws Exception {
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
List<String> paths = new LinkedList<String>();
Map<String, ConfigRevision> revisions = new HashMap<String, ConfigRevision>();
setupPathsAndRevisions(cc, paths, revisions);
paths.remove(paths.size() - 1);
handler.deleteFiles(admin, LABEL, paths);
List<ConfigFileDto> files = handler.listFiles(admin, LABEL);
assertEquals(1, files.size());
}
public void testScheduleFileComparisons() throws Exception {
Server server = ServerFactoryTest.createTestServer(admin, true);
ConfigChannel cc = handler.create(admin, LABEL, NAME, DESCRIPTION);
// create a config file
String path = "/tmp/foo/path" + TestUtils.randomString();
String contents = "HAHAHAHA";
ConfigRevision rev = createRevision(path, contents,
"group" + TestUtils.randomString(),
"owner" + TestUtils.randomString(),
"777",
false, cc, "unconfined_u:object_r:tmp_t");
DataResult dr = ActionManager.recentlyScheduledActions(admin, null, 30);
int preScheduleSize = dr.size();
// schedule file comparison action
List<Integer> serverIds = new ArrayList<Integer>();
serverIds.add(server.getId().intValue());
Integer actionId = handler.scheduleFileComparisons(admin, LABEL, path,
serverIds);
// was the action scheduled?
dr = ActionManager.recentlyScheduledActions(admin, null, 30);
assertEquals(1, dr.size() - preScheduleSize);
assertEquals(
"Show differences between profiled config files and deployed config files",
((ScheduledAction)dr.get(0)).getTypeName());
assertEquals(actionId, new Integer(
((ScheduledAction)dr.get(0)).getId().intValue()));
}
public void testChannelExists() {
handler.create(admin, LABEL, NAME, DESCRIPTION);
int validChannel = handler.channelExists(admin, LABEL);
int invalidChannel = handler.channelExists(admin, "dummy");
assertEquals(validChannel, 1);
assertEquals(invalidChannel, 0);
}
public void testDeployAllSystems() throws Exception {
// Create global config channels
ConfigChannel gcc1 = ConfigTestUtils.createConfigChannel(admin.getOrg(),
ConfigChannelType.global());
ConfigChannel gcc2 = ConfigTestUtils.createConfigChannel(admin.getOrg(),
ConfigChannelType.global());
Long ver = new Long(2);
// gcc1 only
Server srv1 = ServerFactoryTest.createTestServer(regular, true);
srv1.subscribe(gcc1);
srv1.subscribe(gcc2);
ServerFactory.save(srv1);
Map <Long, Set<ConfigRevision>> revisions =
new HashMap<Long, Set<ConfigRevision>>();
ConfigFile g1f1 = gcc1.createConfigFile(
ConfigFileState.normal(), "/etc/foo1");
store(revisions, gcc1.getId(), ConfigTestUtils.createConfigRevision(g1f1));
ConfigurationFactory.commit(gcc1);
ConfigFile g1f2 = gcc1.createConfigFile(
ConfigFileState.normal(), "/etc/foo2");
store(revisions, gcc1.getId(), ConfigTestUtils.createConfigRevision(g1f2));
ConfigurationFactory.commit(gcc2);
ConfigFile g2f2 = gcc2.createConfigFile(
ConfigFileState.normal(), "/etc/foo4");
store(revisions, gcc2.getId(), ConfigTestUtils.createConfigRevision(g2f2));
ConfigurationFactory.commit(gcc2);
ConfigFile g2f3 = gcc2.createConfigFile(
ConfigFileState.normal(), "/etc/foo3");
store(revisions, gcc2.getId(), ConfigTestUtils.createConfigRevision(g2f3));
ConfigurationFactory.commit(gcc2);
// System 1 - both g1f1 and g1f2 should deploy here
List<Number> systems = new ArrayList<Number>();
systems.add(srv1.getId());
Date date = new Date();
try {
// validate that system must have config deployment capability
// in order to deploy config files... (e.g. rhncfg* pkgs installed)
handler.deployAllSystems(regular, gcc1.getLabel(), date);
fail("Shouldn't be permitted to deploy without config deploy capability.");
}
catch (Exception e) {
// Success
}
SystemManagerTest.giveCapability(srv1.getId(),
SystemManager.CAP_CONFIGFILES_DEPLOY, ver);
handler.deployAllSystems(regular, gcc1.getLabel(), date);
DataResult<ScheduledAction> actions = ActionManager.
recentlyScheduledActions(regular, null, 1);
ConfigAction ca = null;
for (ScheduledAction action : actions) {
if (ActionFactory.TYPE_CONFIGFILES_DEPLOY.getName().
equals(action.getTypeName())) {
ca = (ConfigAction)ActionManager.lookupAction(regular,
action.getId().longValue());
}
}
assertNotNull(ca);
assertEquals(revisions.get(gcc1.getId()).size(),
ca.getConfigRevisionActions().size());
for (ConfigRevisionAction cra : ca.getConfigRevisionActions()) {
assertTrue(revisions.get(gcc1.getId()).contains(cra.getConfigRevision()));
}
}
private void store(Map<Long, Set<ConfigRevision>> revisions, Long ccid,
ConfigRevision crev) {
if (!revisions.containsKey(ccid)) {
revisions.put(ccid, new HashSet<ConfigRevision>());
}
revisions.get(ccid).add(crev);
}
}