/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt 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.test.manualmode.transaction; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PROCESS_STATE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESPONSE_HEADERS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.Map; import org.jboss.arquillian.container.test.api.ContainerController; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.as.test.integration.management.base.AbstractCliTestBase; import org.jboss.as.test.integration.management.util.CLIOpResult; import org.jboss.as.test.integration.management.util.MgmtOperationException; import org.jboss.as.test.shared.TimeoutUtil; import org.jboss.dmr.ModelNode; import org.jboss.logging.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * @author Ivo Studensky - <istudensky@redhat.com>, initial test case * @author Romain Pelisse - <belaran@redhat.com>, rework testcase for work on JBEAP-6449 * */ @RunWith(Arquillian.class) @RunAsClient public class ObjectStoreTypeTestCase extends AbstractCliTestBase { @SuppressWarnings("unused") private static Logger log = Logger.getLogger(ObjectStoreTypeTestCase.class); private static final String CONTAINER = "default-jbossas"; private static final String JDBC_STORE_DS_NAME = "ObjectStoreTestDS"; @ArquillianResource private static ContainerController container; @Before public void before() throws Exception { container.start(CONTAINER); initCLI(TimeoutUtil.adjust(20 * 1000)); String objectStoreType = readObjectStoreType(); assertTrue("Invalid store type: " + objectStoreType, objectStoreType.equals("journal") || objectStoreType.equals("default")); setDefaultObjectStore(); } @After public void after() throws Exception { closeCLI(); container.stop(CONTAINER); } @SuppressWarnings("rawtypes") private void check(String objectStoreTypeExpected) throws IOException, MgmtOperationException { final CLIOpResult ret = cli.readAllAsOpResult(); if (ret != null && ret.getFromResponse(RESPONSE_HEADERS) != null) { assertEquals("restart-required", (String) ((Map) ret.getFromResponse(RESPONSE_HEADERS)).get(PROCESS_STATE)); cli.sendLine("reload"); } String objectStoreType = readObjectStoreType(); assertEquals(objectStoreTypeExpected, objectStoreType); } @Test public void testHornetQObjectStore() throws IOException, MgmtOperationException { try { useJournalStore(); } finally { setDefaultObjectStore(); } } @Test public void testJournalObjectStore() throws IOException, MgmtOperationException { try { cli.sendLine("/subsystem=transactions:write-attribute(name=use-journal-store, value=true)"); check("journal"); } finally { setDefaultObjectStore(); } } @Test public void testJdbcObjectStore() throws IOException, MgmtOperationException { try { useJdbcStore(); check("jdbc"); } finally { cleanJdbcSettingsAndResetToObjectStore(); } } @Test public void ifJournalIsTrueThenHornetQToo() throws IOException, MgmtOperationException { useJournalStore(); checkThatAllUseAttributesAreConsistent("true", "false", "true"); } private void useJdbcStore() throws IOException, MgmtOperationException { useJdbcStore(true); } private void useJdbcStore(boolean expectedResults) throws IOException, MgmtOperationException { setDefaultObjectStore(); // 1 - Create DS - required for the JDBC store createDataSource(); // 2 - Set the value for 'jdbc-store-datasource' cli.sendLine("/subsystem=transactions:write-attribute(name=jdbc-store-datasource, value=java:jboss/datasources/" + JDBC_STORE_DS_NAME + ")"); CLIOpResult result = cli.readAllAsOpResult(); assertTrue("Failed to set jdbc-store-datasource.", result.isIsOutcomeSuccess()); // 3 - set 'use-jdbc-store' to true cli.sendLine("/subsystem=transactions:write-attribute(name=use-jdbc-store, value=true)"); result = cli.readAllAsOpResult(); assertEquals("Failed to set use-jdbc-store to expected value", expectedResults, result.isIsOutcomeSuccess()); } @Test public void testUseJdbcStoreWithoutDatasource() throws Exception { try { // try to set use-jdbc-store to true without defining datasource cli.sendLine("/subsystem=transactions:write-attribute(name=use-jdbc-store, value=true)", true); CLIOpResult result = cli.readAllAsOpResult(); assertFalse("Expected failure when jdbc-store-datasource is not set.", result.isIsOutcomeSuccess()); } finally { setDefaultObjectStore(); } } @Test public void testUndefinedJdbcStoreDSWhenJDBCisUsed() throws Exception { try { // Use JDBC store useJdbcStore(); // try, and fail, to undefine jdbc-store-datasource when use-jdbc-store is set to true cli.sendLine("/subsystem=transactions:undefine-attribute(name=jdbc-store-datasource", true); CLIOpResult result = cli.readAllAsOpResult(); if (result.isIsOutcomeSuccess()) fail("The jdbc-store-datasource attribute has been undefined, while JDBC store is in use."); } finally { cleanJdbcSettingsAndResetToObjectStore(); } } private void checkAttributeIsAsExpected(String attributeName, String expectedValue) { try { cli.sendLine("/subsystem=transactions:read-attribute(name=" + attributeName + ")"); CLIOpResult result = cli.readAllAsOpResult(); assertEquals(attributeName + " has not the expected value", expectedValue, result.getResult()); } catch (Exception e) { throw new IllegalStateException(e); } } private void checkThatAllUseAttributesAreConsistent(String useJournalStore, String useJdbcStore, String useHornetQStore) { checkAttributeIsAsExpected("use-jdbc-store", useJdbcStore); checkAttributeIsAsExpected("use-journal-store", useJournalStore); checkAttributeIsAsExpected("use-hornetq-store", useHornetQStore); } @Test public void testEitherJdbcOrJournalStore() throws Exception { try { // Set journal store useJournalStore(); // Check that attributes are consistent with setting checkThatAllUseAttributesAreConsistent("true", "false", "true"); // Use jdbcStore useJdbcStore(); // Check that attributes are consistent with setting checkThatAllUseAttributesAreConsistent("false", "true", "false"); } finally { cleanJdbcSettingsAndResetToObjectStore(); } } enum StorageMode { USE_JDBC_STORE("use-jdbc-store"), USE_JOURNAL_STORE("use-journal-store"), USE_HORNETQ_STORE("use-hornetq-store"); StorageMode(String attributeName) { this.attributeName = attributeName; } String attributeName; public static StorageMode buildFromAttributeName(String attributeName) { for ( StorageMode mode : StorageMode.values() ) { if ( mode.attributeName.equals(attributeName) ) return mode; } throw new IllegalArgumentException("No such storage mode available:" + attributeName); } } /* * Checks that using two different storage mechanisms, within a * batch, make the batch fails. * * See https://issues.jboss.org/browse/WFLY-8335 for more information */ @Test(expected=java.lang.AssertionError.class) public void testBatchCliFailsIfNoDSisDefined() throws IOException { createDataSource(); cli.sendLine("batch"); cli.sendLine("/subsystem=transactions:write-attribute(name=use-journal-store,value=true)"); cli.sendLine("/subsystem=transactions:write-attribute(name=jdbc-store-datasource, value=java:jboss/datasources/" + JDBC_STORE_DS_NAME + ")"); cli.sendLine("/subsystem=transactions:write-attribute(name=use-jdbc-store,value=true)"); cli.sendLine("run-batch"); } @Test public void testThatAlternatesAreProperlyDefined() throws IOException { cli.sendLine("/subsystem=transactions:read-resource-description"); CLIOpResult result = cli.readAllAsOpResult(); if ( result != null && result.getResultAsMap() != null ) { ModelNode atts = (ModelNode)result.getResponseNode().get("result").get("attributes"); for ( StorageMode mode : StorageMode.values() ) checkStorageMode(atts, mode); } else fail("Read resource description operation did provide any result"); } private void checkStorageMode(ModelNode atts, StorageMode mode) { ModelNode modeNode = atts.get(mode.attributeName); assertTrue(modeNode != null); ModelNode alternatives = modeNode.get("alternatives"); assertTrue(alternatives != null); assertEquals(2, alternatives.asList().size()); for ( int nbAlternative = 0; nbAlternative < 2 ; nbAlternative++ ) checkAlternative(alternatives.get(nbAlternative).asString(), mode); } private void checkAlternative(String alternative, StorageMode mode) { StorageMode alternativeStorageMode = StorageMode.buildFromAttributeName(alternative); assertTrue(alternativeStorageMode != mode ); } private void useJournalStore() throws IOException, MgmtOperationException { cli.sendLine("/subsystem=transactions:write-attribute(name=use-journal-store, value=true)"); check("journal"); } private void createDataSource() { cli.sendLine("data-source add --name=" + JDBC_STORE_DS_NAME + " --jndi-name=java:jboss/datasources/" + JDBC_STORE_DS_NAME + " --driver-name=h2 --connection-url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 --jta=false"); } private void undefinedAttributeIfDefined(String attributeName) { try { cli.sendLine("/subsystem=transactions:read-attribute(name=" + attributeName + ")"); CLIOpResult result = cli.readAllAsOpResult(); if (result.getResponseNode().isDefined()) cli.sendLine("/subsystem=transactions:undefine-attribute(name=" + attributeName + ")"); } catch (IOException e) { throw new IllegalStateException(e); } } private void cleanJdbcSettingsAndResetToObjectStore() throws IOException, MgmtOperationException { try { cleanupSettingsUsedForJDBCStore(); } finally { setDefaultObjectStore(); } } private void removeDatasource() { try { cli.sendLine("data-source remove --name=" + JDBC_STORE_DS_NAME); } catch (Exception e) { // if the DS does not exist, not need to delete it... } } private void cleanupSettingsUsedForJDBCStore() { try { // Undefine 'use-jdbc-store' first, if defined undefinedAttributeIfDefined("use-jdbc-store"); // then undefine 'jdbc-store' undefinedAttributeIfDefined("jdbc-store-datasource"); // finally delete Datasource if exists removeDatasource(); // Reload configuration cli.sendLine("reload"); } catch (Exception e) { throw new IllegalStateException(e); } } private String readObjectStoreType() throws IOException, MgmtOperationException { cli.sendLine("/subsystem=transactions/log-store=log-store:read-attribute(name=type)"); final CLIOpResult res = cli.readAllAsOpResult(); return (String) res.getResult(); } private void setDefaultObjectStore() throws IOException, MgmtOperationException { final String objectStoreType = readObjectStoreType(); if ("default".equals(objectStoreType)) { return; } try { cli.sendLine("/subsystem=transactions:write-attribute(name=use-journal-store, value=false)"); } finally { cli.sendLine("reload"); } } }