/*
* JBoss, Home of Professional Open Source.
* Copyright ${year}, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.domain.controller.operations;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEFAULT_INTERFACE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INCLUDES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jboss.as.controller.Cancellable;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.client.Operation;
import org.jboss.as.controller.client.OperationMessageHandler;
import org.jboss.as.controller.client.OperationResponse;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.registry.Resource;
import org.jboss.as.domain.controller.resources.ProfileResourceDefinition;
import org.jboss.as.host.controller.MasterDomainControllerClient;
import org.jboss.as.repository.HostFileRepository;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceContainer;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceListener;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceNotFoundException;
import org.jboss.msc.service.ServiceRegistry;
import org.jboss.msc.service.StartException;
import org.jboss.threads.AsyncFuture;
import org.junit.Assert;
import org.junit.Test;
/**
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
*/
public class SocketBindingGroupIncludesHandlerTestCase extends AbstractOperationTestCase {
@Test
public void testGoodSocketBindingGroupIncludesAdd() throws Exception {
PathAddress addr = getSocketBindingGroupAddress("test");
ModelNode op = Util.createAddOperation(addr);
op.get(DEFAULT_INTERFACE).set("public");
op.get(INCLUDES).add("binding-one").add("binding-two");
MockOperationContext operationContext = getOperationContext(addr);
SocketBindingGroupAddHandler.INSTANCE.execute(operationContext, op);
operationContext.executeNextStep();
}
// // WFCORE-833 replaced by DomainSocketBindingGroupTestCase.testBadSocketBindingGroupIncludesAdd()
// @Test(expected=OperationFailedException.class)
// public void testBadSocketBindingGroupIncludesAdd() throws Exception {
// PathAddress addr = getSocketBindingGroupAddress("test");
// ModelNode op = Util.createAddOperation(addr);
// op.get(DEFAULT_INTERFACE).set("public");
// op.get(INCLUDES).add("binding-one").add("NOT_THERE");
// MockOperationContext operationContext = getOperationContext(addr);
// SocketBindingGroupAddHandler.INSTANCE.execute(operationContext, op);
// operationContext.executeNextStep();
// }
@Test
public void testGoodSocketBindingGroupIncludesWrite() throws Exception {
PathAddress addr = getSocketBindingGroupAddress("binding-one");
ModelNode list = new ModelNode().add("binding-two");
ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
MockOperationContext operationContext = getOperationContext(addr);
SocketBindingGroupResourceDefinition.createIncludesValidationHandler().execute(operationContext, op);
operationContext.executeNextStep();
}
// // WFCORE-833 replaced by DomainSocketBindingGroupTestCase.testBadSocketBindingGroupIncludesWrite()
// @Test(expected=OperationFailedException.class)
// public void testBadSocketBindingGroupIncludesWrite() throws Exception {
// PathAddress addr = getSocketBindingGroupAddress("binding-one");
// ModelNode list = new ModelNode().add("bad-SocketBindingGroup");
// ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
// MockOperationContext operationContext = getOperationContext(addr);
// SocketBindingGroupResourceDefinition.createRestartRequiredHandler().execute(operationContext, op);
// operationContext.executeNextStep();
// }
@Test(expected=OperationFailedException.class)
public void testCyclicSocketBindingGroupIncludesWrite() throws Exception {
PathAddress addr = getSocketBindingGroupAddress("binding-three");
ModelNode list = new ModelNode().add("binding-four");
ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
MockOperationContext operationContext = getOperationContextWithIncludes(addr);
SocketBindingGroupResourceDefinition.createIncludesValidationHandler().execute(operationContext, op);
operationContext.executeNextStep();
}
@Test
public void testGoodSocketBindingGroupIncludesRemove() throws Exception {
PathAddress addr = getSocketBindingGroupAddress("binding-four");
ModelNode op = Util.createRemoveOperation(addr);
MockOperationContext operationContext = getOperationContextWithIncludes(addr);
DomainSocketBindingGroupRemoveHandler.INSTANCE.execute(operationContext, op);
// WFCORE-833 no next validation step any more
//operationContext.executeNextStep();
}
// // WFCORE-833 replaced by DomainSocketBindingGroupTestCase.testBadSocketBindingGroupIncludesRemove()
// @Test(expected=OperationFailedException.class)
// public void testBadSocketBindingGroupIncludesRemove() throws Exception {
// PathAddress addr = getSocketBindingGroupAddress("binding-three");
// ModelNode op = Util.createRemoveOperation(addr);
// MockOperationContext operationContext = getOperationContextWithIncludes(addr);
// DomainSocketBindingGroupRemoveHandler.INSTANCE.execute(operationContext, op);
// operationContext.executeNextStep();
// }
@Test
public void testIncludesWithNoOverriddenSubsystems() throws Exception {
//Here we test changing the includes attribute value
//Testing what happens when adding subsystems at runtime becomes a bit too hard to mock up
//so we test that in ServerManagementTestCase
PathAddress addr = getSocketBindingGroupAddress("binding-four");
ModelNode list = new ModelNode().add("binding-three");
ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
MockOperationContext operationContext = getOperationContextForSocketBindingIncludes(addr, new RootResourceInitializer() {
@Override
public void addAdditionalResources(Resource root) {
Resource subsystemA = Resource.Factory.create();
root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-three"))
.registerChild(PathElement.pathElement(SUBSYSTEM, "a"), subsystemA);
Resource subsystemB = Resource.Factory.create();
Resource SocketBindingGroup4 = root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-four"));
SocketBindingGroup4.registerChild(PathElement.pathElement(SUBSYSTEM, "b"), subsystemB);
}
});
SocketBindingGroupResourceDefinition.createIncludesValidationHandler().execute(operationContext, op);
operationContext.executeNextStep();
}
@Test
public void testIncludesWithOverriddenSocketBindings() throws Exception {
try {
//Here we test changing the includes attribute value
//Testing what happens when adding subsystems at runtime becomes a bit too hard to mock up
//so we test that in ServerManagementTestCase
PathAddress addr = getSocketBindingGroupAddress("binding-four");
ModelNode list = new ModelNode().add("binding-three");
ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
MockOperationContext operationContext = getOperationContextForSocketBindingIncludes(addr, new RootResourceInitializer() {
@Override
public void addAdditionalResources(Resource root) {
Resource subsystemA = Resource.Factory.create();
root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-three"))
.registerChild(PathElement.pathElement(SOCKET_BINDING, "a"), subsystemA);
Resource subsystemB = Resource.Factory.create();
Resource SocketBindingGroup4 = root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-four"));
SocketBindingGroup4.registerChild(PathElement.pathElement(SOCKET_BINDING, "a"), subsystemB);
}
});
SocketBindingGroupResourceDefinition.createIncludesValidationHandler().execute(operationContext, op);
operationContext.executeNextStep();
Assert.fail("Expected error");
} catch (OperationFailedException expected) {
Assert.assertTrue(expected.getMessage().contains("166"));
Assert.assertTrue(expected.getMessage().contains("'binding-four'"));
Assert.assertTrue(expected.getMessage().contains("'binding-three'"));
Assert.assertTrue(expected.getMessage().contains("'a'"));
}
}
@Test
public void testGroupWithBindingsIncludesSameBindings() throws Exception {
try {
//Here we test changing the includes attribute value
//Testing what happens when adding subsystems at runtime becomes a bit too hard to mock up
//so we test that in ServerManagementTestCase
PathAddress addr = getSocketBindingGroupAddress("binding-five");
ModelNode list = new ModelNode().add("binding-three").add("binding-four");
ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
MockOperationContext operationContext = getOperationContextForSocketBindingIncludes(addr, new RootResourceInitializer() {
@Override
public void addAdditionalResources(Resource root) {
Resource bindingA = Resource.Factory.create();
root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-three"))
.registerChild(PathElement.pathElement(SOCKET_BINDING, "a"), bindingA);
Resource bindingB = Resource.Factory.create();
Resource group4 = root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-four"));
group4.registerChild(PathElement.pathElement(SOCKET_BINDING, "a"), bindingB);
Resource bindingC = Resource.Factory.create();
Resource group5 = root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-five"));
group5.registerChild(PathElement.pathElement(SOCKET_BINDING, "x"), bindingC);
}
});
ProfileResourceDefinition.createIncludesValidationHandler().execute(operationContext, op);
operationContext.executeNextStep();
Assert.fail("Expected error");
} catch (OperationFailedException expected) {
Assert.assertTrue(expected.getMessage().contains("168"));
Assert.assertTrue(expected.getMessage().contains("'binding-five'"));
Assert.assertTrue(expected.getMessage().contains("'binding-four'"));
Assert.assertTrue(expected.getMessage().contains("'binding-three'"));
Assert.assertTrue(expected.getMessage().contains("'a'"));
}
}
@Test
public void testEmptyGroupIncludesSameBindings() throws Exception {
try {
//Here we test changing the includes attribute value
//Testing what happens when adding subsystems at runtime becomes a bit too hard to mock up
//so we test that in ServerManagementTestCase
PathAddress addr = getSocketBindingGroupAddress("binding-five");
ModelNode list = new ModelNode().add("binding-three").add("binding-four");
ModelNode op = Util.getWriteAttributeOperation(addr, INCLUDES, list);
MockOperationContext operationContext = getOperationContextForSocketBindingIncludes(addr, new RootResourceInitializer() {
@Override
public void addAdditionalResources(Resource root) {
Resource bindingA = Resource.Factory.create();
root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-three"))
.registerChild(PathElement.pathElement(SOCKET_BINDING, "a"), bindingA);
Resource bindingB = Resource.Factory.create();
Resource group4 = root.getChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-four"));
group4.registerChild(PathElement.pathElement(SOCKET_BINDING, "a"), bindingB);
//binding-five is empty
}
});
ProfileResourceDefinition.createIncludesValidationHandler().execute(operationContext, op);
operationContext.executeNextStep();
Assert.fail("Expected error");
} catch (OperationFailedException expected) {
Assert.assertTrue(expected.getMessage().contains("168"));
Assert.assertTrue(expected.getMessage().contains("'binding-five'"));
Assert.assertTrue(expected.getMessage().contains("'binding-four'"));
Assert.assertTrue(expected.getMessage().contains("'binding-three'"));
Assert.assertTrue(expected.getMessage().contains("'a'"));
}
}
private PathAddress getSocketBindingGroupAddress(String SocketBindingGroupName) {
return PathAddress.pathAddress(SOCKET_BINDING_GROUP, SocketBindingGroupName);
}
MockOperationContext getOperationContext(final PathAddress operationAddress) {
final Resource root = createRootResource();
return new MockOperationContext(root, false, operationAddress, false);
}
MockOperationContext getOperationContextWithIncludes(final PathAddress operationAddress) {
final Resource root = createRootResource();
Resource socketBindingGroupThree = Resource.Factory.create();
root.registerChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-three"), socketBindingGroupThree);
Resource socketBindingGroupFour = Resource.Factory.create();
socketBindingGroupFour.getModel().get(INCLUDES).add("binding-three");
root.registerChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-four"), socketBindingGroupFour);
return new MockOperationContext(root, false, operationAddress, false);
}
MockOperationContext getOperationContextForSocketBindingIncludes(final PathAddress operationAddress, RootResourceInitializer initializer) {
final Resource root = createRootResource();
Resource socketBindingGroupThree = Resource.Factory.create();
root.registerChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-three"), socketBindingGroupThree);
Resource socketBindingGroupFour = Resource.Factory.create();
root.registerChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-four"), socketBindingGroupFour);
Resource socketBindingGroupFive = Resource.Factory.create();
root.registerChild(PathElement.pathElement(SOCKET_BINDING_GROUP, "binding-five"), socketBindingGroupFive);
initializer.addAdditionalResources(root);
return new MockOperationContext(root, false, operationAddress, false);
}
private class MockOperationContext extends AbstractOperationTestCase.MockOperationContext {
private boolean reloadRequired;
private boolean rollback;
private OperationStepHandler nextStep;
protected MockOperationContext(final Resource root, final boolean booting, final PathAddress operationAddress, final boolean rollback) {
super(root, booting, operationAddress);
this.rollback = rollback;
}
public void completeStep(ResultHandler resultHandler) {
if (nextStep != null) {
stepCompleted();
} else if (rollback) {
resultHandler.handleResult(ResultAction.ROLLBACK, this, null);
}
}
public void stepCompleted() {
if (nextStep != null) {
try {
OperationStepHandler step = nextStep;
nextStep = null;
step.execute(this, null);
} catch (OperationFailedException e) {
throw new OperationFailedRuntimeException(e);
}
}
}
public void reloadRequired() {
reloadRequired = true;
}
public boolean isReloadRequired() {
return reloadRequired;
}
public void revertReloadRequired() {
reloadRequired = false;
}
public void addStep(OperationStepHandler step, Stage stage) throws IllegalArgumentException {
if (step instanceof DomainModelIncludesValidator) {
nextStep = step;
}
}
public void addStep(ModelNode operation, OperationStepHandler step, Stage stage) throws IllegalArgumentException {
if (operation.get(OP).asString().equals("verify-running-server")) {
return;
}
super.addStep(operation, step, stage);
}
@Override
public boolean isBooting() {
return false;
}
public Resource removeResource(PathAddress address) throws UnsupportedOperationException {
PathElement element = operationAddress.getLastElement();
PathAddress parentAddress = operationAddress.size() > 1 ? operationAddress.subAddress(0, operationAddress.size() - 1) : PathAddress.EMPTY_ADDRESS;
Resource parent = root.navigate(parentAddress);
return parent.removeChild(element);
}
public void executeNextStep() throws OperationFailedException {
nextStep.execute(this, new ModelNode());
}
@Override
public ServiceRegistry getServiceRegistry(boolean modify) throws UnsupportedOperationException {
return new ServiceRegistry() {
@Override
public List<ServiceName> getServiceNames() {
return null;
}
@Override
public ServiceController<?> getService(ServiceName name) {
return null;
}
@Override
public ServiceController<?> getRequiredService(ServiceName name) throws ServiceNotFoundException {
if (name.equals(MasterDomainControllerClient.SERVICE_NAME)) {
return new ServiceController<MasterDomainControllerClient>() {
@Override
public void addListener(ServiceListener<? super MasterDomainControllerClient> arg0) {
}
@Override
public MasterDomainControllerClient awaitValue() throws IllegalStateException, InterruptedException {
return null;
}
@Override
public MasterDomainControllerClient awaitValue(long arg0, TimeUnit arg1)
throws IllegalStateException, InterruptedException, TimeoutException {
return null;
}
@Override
public boolean compareAndSetMode(Mode arg0,
Mode arg1) {
return false;
}
@Override
public ServiceName[] getAliases() {
return null;
}
@Override
public Set<ServiceName> getImmediateUnavailableDependencies() {
return null;
}
@Override
public Mode getMode() {
return null;
}
@Override
public ServiceName getName() {
return null;
}
@Override
public ServiceController<?> getParent() {
return null;
}
@Override
public Service<MasterDomainControllerClient> getService() throws IllegalStateException {
return null;
}
@Override
public ServiceContainer getServiceContainer() {
return null;
}
@Override
public StartException getStartException() {
return null;
}
@Override
public State getState() {
return null;
}
@Override
public Substate getSubstate() {
return null;
}
@Override
public MasterDomainControllerClient getValue() throws IllegalStateException {
return new MasterDomainControllerClient() {
@Override
public void close() throws IOException {
}
@Override
public AsyncFuture<ModelNode> executeAsync(Operation operation, OperationMessageHandler messageHandler) {
return null;
}
@Override
public AsyncFuture<ModelNode> executeAsync(ModelNode operation, OperationMessageHandler messageHandler) {
return null;
}
@Override
public ModelNode execute(Operation operation, OperationMessageHandler messageHandler) throws IOException {
return null;
}
@Override
public ModelNode execute(ModelNode operation, OperationMessageHandler messageHandler) throws IOException {
return null;
}
@Override
public ModelNode execute(Operation operation) throws IOException {
return null;
}
@Override
public ModelNode execute(ModelNode operation) throws IOException {
return null;
}
@Override
public void unregister() {
}
@Override
public void register() throws IOException {
}
@Override
public Cancellable pollForConnect() {
return null;
}
@Override
public HostFileRepository getRemoteFileRepository() {
return null;
}
@Override
public void fetchAndSyncMissingConfiguration(OperationContext context, Resource resource)
throws OperationFailedException {
//
}
@Override
public OperationResponse executeOperation(Operation operation,
OperationMessageHandler messageHandler) throws IOException {
return null;
}
@Override
public AsyncFuture<OperationResponse> executeOperationAsync(Operation operation,
OperationMessageHandler messageHandler) {
return null;
}
};
}
@Override
public void removeListener(ServiceListener<? super MasterDomainControllerClient> arg0) {
}
@Override
public void retry() {
}
@Override
public void setMode(Mode arg0) {
}
};
}
throw new ServiceNotFoundException();
}
};
}
}
private static class OperationFailedRuntimeException extends RuntimeException {
public OperationFailedRuntimeException(OperationFailedException e) {
super(e.getMessage());
}
}
/**
* Allows tests to add more resources to the model
*/
private interface RootResourceInitializer {
void addAdditionalResources(Resource root);
}
}