@@ -0,0 +1,170 @@
/*
Copyright 2019 Red Hat, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.wildfly.core.test.standalone.mgmt;

import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.test.integration.management.extension.EmptySubsystemParser;
import org.jboss.as.test.integration.management.extension.ExtensionUtils;
import org.jboss.as.test.integration.management.extension.optypes.OpTypesExtension;
import org.jboss.dmr.ModelNode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.core.testrunner.ManagementClient;
import org.wildfly.core.testrunner.WildflyTestRunner;

import javax.inject.Inject;
import java.io.IOException;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
* Tests adding and removing extensions and subsystems in a composite op.
*
* @author Brian Stansberry
*/
@RunWith(WildflyTestRunner.class)
public class ExtensionSubsystemCompositeTestCase {

private static final PathAddress EXT = PathAddress.pathAddress("extension", OpTypesExtension.EXTENSION_NAME);
private static final PathAddress SUBSYSTEM = PathAddress.pathAddress("subsystem", OpTypesExtension.SUBSYSTEM_NAME);

@Inject
private static ManagementClient managementClient;

@Before
public void installExtensionModule() throws IOException {
// We use OpTypesExtension for this test because it's convenient. Doesn't do anything crazy
// and exposes an op ('public') that we can call to check the subsystem is added and functions
ExtensionUtils.createExtensionModule(OpTypesExtension.EXTENSION_NAME, OpTypesExtension.class,
EmptySubsystemParser.class.getPackage());
}

@After
public void removeExtensionModule() {

try {
executeOp(Util.createRemoveOperation(SUBSYSTEM), SUCCESS);
} catch (Throwable ignored) {
// assume subsystem wasn't there
} finally {
try {
executeOp(Util.createRemoveOperation(EXT), SUCCESS);
} catch (Throwable t) {
// assume extension wasn't there
} finally {
ExtensionUtils.deleteExtensionModule(OpTypesExtension.EXTENSION_NAME);
}
}
}

@Test
public void test() throws IOException {

// 1) Sanity check -- subsystem not there
ModelNode invokePublic = Util.createEmptyOperation("public", SUBSYSTEM);
testBadOp(invokePublic);

// 2) sanity check -- subsystem add w/o extension -- fail
ModelNode subAdd = Util.createAddOperation(SUBSYSTEM);
testBadOp(subAdd);

// 3) ext add + sub add + sub other in composite
ModelNode extAdd = Util.createAddOperation(EXT);
ModelNode goodAdd = buildComposite(extAdd, subAdd, invokePublic);
testGoodComposite(goodAdd);

// 4) Sanity check -- try invokePublic again outside the composite
ModelNode response = executeOp(invokePublic, "success");
assertTrue(response.toString(), response.has("result"));
assertTrue(response.toString(), response.get("result").asBoolean());

// 5) sub remove + ext remove + sub add in composite -- fail
ModelNode subRemove = Util.createRemoveOperation(SUBSYSTEM);
ModelNode extRemove = Util.createRemoveOperation(EXT);
ModelNode badRemove = buildComposite(invokePublic, subRemove, extRemove, subAdd);
response = testBadOp(badRemove);
// But the 'public' op should have worked
validateInvokePublicStep(response, 1, true);

// 6) sub remove + ext remove in composite
ModelNode goodRemove = buildComposite(invokePublic, subRemove, extRemove);
response = executeOp(goodRemove, "success");
validateInvokePublicStep(response, 1, false);

// 7) confirm ext add + sub add + sub other still works
testGoodComposite(goodAdd);

// 8) Sanity check -- try invokePublic again outside the composite
response = executeOp(invokePublic, "success");
assertTrue(response.toString(), response.has("result"));
assertTrue(response.toString(), response.get("result").asBoolean());
}

private ModelNode executeOp(ModelNode op, String outcome) throws IOException {
ModelNode response = managementClient.getControllerClient().execute(op);
assertTrue(response.toString(), response.hasDefined(OUTCOME));
assertEquals(response.toString(), outcome, response.get(OUTCOME).asString());
return response;
}

private void testGoodComposite(ModelNode composite) throws IOException {
ModelNode result = executeOp(composite, "success");
validateInvokePublicStep(result, 3, false);
}

private ModelNode testBadOp(ModelNode badOp) throws IOException {
ModelNode response = executeOp(badOp, "failed");
String msg = response.toString();
assertTrue(msg, response.has("failure-description"));
ModelNode failure = response.get("failure-description");
assertTrue(msg, failure.asString().contains("WFLYCTL0030"));
return response;
}

private static ModelNode buildComposite(ModelNode... steps) {
ModelNode result = Util.createEmptyOperation("composite", PathAddress.EMPTY_ADDRESS);
ModelNode stepsParam = result.get("steps");
for (ModelNode step : steps) {
stepsParam.add(step);
}
return result;
}

private static void validateInvokePublicStep(ModelNode response, int step, boolean expectRollback) {
String msg = response.toString();
assertTrue(msg, response.has("result"));
ModelNode result = response.get("result");
assertTrue(msg, result.isDefined());
String stepKey = "step-"+step;
assertEquals(msg, expectRollback ? "failed" : "success", result.get(stepKey, "outcome").asString());
assertTrue(msg, result.has(stepKey, "result"));
assertTrue(msg, result.get(stepKey, "result").asBoolean());
if (expectRollback) {
assertTrue(msg, result.has(stepKey, "rolled-back"));
assertTrue(msg, result.get(stepKey, "rolled-back").asBoolean());
} else {
assertFalse(msg, result.has(stepKey, "rolled-back"));
}
}

}
@@ -29,7 +29,7 @@
<parent>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-core-parent</artifactId>
<version>9.0.0.Beta7-SNAPSHOT</version>
<version>9.0.0.Beta8-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@@ -30,7 +30,7 @@
<parent>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-core-parent</artifactId>
<version>9.0.0.Beta7-SNAPSHOT</version>
<version>9.0.0.Beta8-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

@@ -29,7 +29,7 @@
<parent>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-core-parent</artifactId>
<version>9.0.0.Beta7-SNAPSHOT</version>
<version>9.0.0.Beta8-SNAPSHOT</version>
</parent>

<artifactId>wildfly-threads</artifactId>
@@ -29,7 +29,7 @@
<parent>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-core-parent</artifactId>
<version>9.0.0.Beta7-SNAPSHOT</version>
<version>9.0.0.Beta8-SNAPSHOT</version>
</parent>

<artifactId>wildfly-version</artifactId>