.gitignore | 3 modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java | 4 modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/Address.java | 2 modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/DatasourceJBossASClient.java | 12 modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java | 25 modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/WebJBossASClient.java | 377 +++++++- modules/core/arquillian-integration/pom.xml | 1 modules/core/arquillian-integration/suite-extension/pom.xml | 29 modules/core/arquillian-integration/suite-extension/src/main/java/org/rhq/arquillian/extension/suite/SuiteDeploymentArquillianExtension.java | 176 +++ modules/core/arquillian-integration/suite-extension/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension | 1 modules/core/dbutils/pom.xml | 5 modules/core/domain/pom.xml | 45 modules/core/domain/src/main/java/org/rhq/core/domain/alert/AlertCondition.java | 1 modules/core/domain/src/main/java/org/rhq/core/domain/alert/composite/AlertConditionAvailabilityCategoryComposite.java | 9 modules/core/domain/src/test/java/org/rhq/core/domain/shared/StartStopContainerArquillianExtension.java | 3 modules/core/domain/src/test/java/org/rhq/core/domain/shared/SuiteDeploymentArquillianExtension.java | 176 --- modules/core/domain/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension | 1 modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java | 30 modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml | 11 modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java | 6 modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerInstallUtil.java | 159 +++ modules/enterprise/server/itests-2/pom.xml | 81 + modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/alert/test/AlertConditionTest.java | 14 modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBeanTest.java | 10 modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/test/AvailabilityManagerTest.java | 229 ++++ modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java | 5 modules/enterprise/server/itests-2/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension | 1 modules/enterprise/server/jar/pom.xml | 13 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/internal/GlobalConditionCache.java | 4 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/model/AvailabilityDurationCacheElement.java | 14 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java | 62 + modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/naming/AccessCheckingInitialContextFactoryBuilder.java | 5 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java | 26 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java | 5 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/EventHandlerBean.java | 42 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/GroupHandlerBean.java | 64 - modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java | 18 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java | 101 +- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/RootHandlerBean.java | 3 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/UserHandlerBean.java | 159 +++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java | 24 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/EventDefinitionRest.java | 74 + modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Link.java | 7 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/OperationDefinitionRest.java | 4 modules/integration-tests/jndi-access/jndi-access-test/pom.xml | 307 ++---- modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java | 242 +++-- modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/arquillian.xml | 5 modules/integration-tests/jndi-access/remote-server/pom.xml | 2 modules/integration-tests/pom.xml | 11 modules/integration-tests/rest-api/pom.xml | 28 modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AbstractBase.java | 48 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/EventTest.java | 223 ++++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java | 78 - modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java | 469 ++++++++++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/MetricsTest.java | 361 +++++++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/OperationsTest.java | 248 +++++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java | 276 ++++- modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/RootURITest.java | 112 ++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/StatusTest.java | 93 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/UserTest.java | 158 +++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Baseline.java | 107 ++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Event.java | 85 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/EventSource.java | 116 ++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Group.java | 65 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/GroupDef.java | 76 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/MDataPoint.java | 91 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Operation.java | 129 ++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/OperationHistory.java | 108 ++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Schedule.java | 61 + modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java | 3 modules/test-utils/src/main/java/org/rhq/test/AssertUtils.java | 41 modules/test-utils/src/main/java/org/rhq/test/PropertyMatcher.java | 22 73 files changed, 4711 insertions(+), 897 deletions(-)
New commits: commit 8aa16ccbb947f95aee01f25a1c4d8c800c133a8c Merge: 764fb31 17d9ac9 Author: Jirka Kremser jkremser@redhat.com Date: Wed Dec 19 23:50:44 2012 +0100
Merge branch 'master' into jkremser/ha-jsf-to-gwt-rewrite
commit 17d9ac9e8b5a926b468da48eb4cde5c8765453c3 Author: Jay Shaughnessy jshaughn@redhat.com Date: Wed Dec 19 16:57:06 2012 -0500
[Bug 888927 -Availability duration conditions limited to one alert definition per resource] Add the hooks to further qualify AvailDuration checkCondition quartz job trigger names with the alertDefId. This will allow avail duration conditions on any number of alert defs for the same resource.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/alert/AlertCondition.java b/modules/core/domain/src/main/java/org/rhq/core/domain/alert/AlertCondition.java index 386cef9..a43816f 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/alert/AlertCondition.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/alert/AlertCondition.java @@ -150,6 +150,7 @@ import org.rhq.core.domain.operation.OperationRequestStatus; + " SELECT new org.rhq.core.domain.alert.composite.AlertConditionAvailabilityCategoryComposite " // + " ( " // + " ac, " // + + " ad.id, " // needed for avail duration + " res.id, " // + " (" // + " SELECT a.availabilityType " // diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/alert/composite/AlertConditionAvailabilityCategoryComposite.java b/modules/core/domain/src/main/java/org/rhq/core/domain/alert/composite/AlertConditionAvailabilityCategoryComposite.java index 4798f41..870dbd2 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/alert/composite/AlertConditionAvailabilityCategoryComposite.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/alert/composite/AlertConditionAvailabilityCategoryComposite.java @@ -33,19 +33,26 @@ import org.rhq.core.domain.measurement.AvailabilityType; */ public class AlertConditionAvailabilityCategoryComposite extends AbstractAlertConditionCategoryComposite {
+ private final Integer alertDefinitionId; private final Integer resourceId; private final AvailabilityType availabilityType;
- public AlertConditionAvailabilityCategoryComposite(AlertCondition condition, Integer resourceId, + public AlertConditionAvailabilityCategoryComposite(AlertCondition condition, Integer alertDefinitionId, + Integer resourceId, AvailabilityType availabilityType) {
super(condition);
+ this.alertDefinitionId = alertDefinitionId; this.resourceId = resourceId; // For a resource with no Availability records we initialize to UNKNOWN this.availabilityType = (null != availabilityType) ? availabilityType : AvailabilityType.UNKNOWN; }
+ public Integer getAlertDefinitionId() { + return alertDefinitionId; + } + public Integer getResourceId() { return resourceId; } diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/alert/test/AlertConditionTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/alert/test/AlertConditionTest.java index a74550d..657ec05 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/alert/test/AlertConditionTest.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/alert/test/AlertConditionTest.java @@ -285,12 +285,14 @@ public class AlertConditionTest extends UpdatePluginMetadataTestBase { SchedulerLocal scheduler = LookupUtil.getSchedulerBean(); scheduler.scheduleTriggeredJob(AlertAvailabilityDurationJob.class, false, null);
- // create our resource with alert definition + // create our resource with two alert definitions (we use 2 to test BZ888927) @SuppressWarnings("unused") MeasurementDefinition metricDef = createResourceWithMetricSchedule(); // use a 10s duration, this is not allowed in general, the gui forces 1 minute minimum - createAlertDefinitionWithAvailDurationCondition(resource.getId(), AlertConditionOperator.AVAIL_DURATION_DOWN, - 10); + createAlertDefinitionWithAvailDurationCondition(resource.getId(), "testAvailDurationAlertDef_1", + AlertConditionOperator.AVAIL_DURATION_DOWN, 10); + createAlertDefinitionWithAvailDurationCondition(resource.getId(), "testAvailDurationAlertDef_2", + AlertConditionOperator.AVAIL_DURATION_DOWN, 10);
// resource has initial UNKNOWN ResourceAvailability and no Availability records. simulate an avail report // coming from the agent and setting the initial avail to UP. @@ -321,7 +323,7 @@ public class AlertConditionTest extends UpdatePluginMetadataTestBase { Thread.sleep(6000);
alerts = getAlerts(resource.getId()); - assert alerts.size() == 1 : "One alert should have fired on the avail duration: " + alerts; + assert alerts.size() == 2 : "Two alerts should have fired on the avail duration: " + alerts;
// purge the resource fully, which should remove all alert defs and alert conditions and condition logs int resourceId = resource.getId(); @@ -546,7 +548,7 @@ public class AlertConditionTest extends UpdatePluginMetadataTestBase { return alertDefinition; }
- private AlertDefinition createAlertDefinitionWithAvailDurationCondition(int resourceId, + private AlertDefinition createAlertDefinitionWithAvailDurationCondition(int resourceId, String alertDefName, AlertConditionOperator condition, int duration) { HashSet<AlertCondition> conditions = new HashSet<AlertCondition>(1); AlertCondition cond1 = new AlertCondition(); @@ -559,7 +561,7 @@ public class AlertConditionTest extends UpdatePluginMetadataTestBase { conditions.add(cond1);
AlertDefinition alertDefinition = new AlertDefinition(); - alertDefinition.setName("avail duration: " + condition.name()); + alertDefinition.setName(alertDefName); alertDefinition.setEnabled(true); alertDefinition.setPriority(AlertPriority.HIGH); alertDefinition.setAlertDampening(new AlertDampening(Category.NONE)); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/internal/GlobalConditionCache.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/internal/GlobalConditionCache.java index a787557..e5c6572 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/internal/GlobalConditionCache.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/internal/GlobalConditionCache.java @@ -164,8 +164,8 @@ class GlobalConditionCache extends AbstractConditionCache {
try { AvailabilityDurationCacheElement cacheElement = new AvailabilityDurationCacheElement( - alertConditionOperator, alertCondition.getOption(), availabilityComposite.getAvailabilityType(), - alertConditionId); + availabilityComposite.getAlertDefinitionId(), alertConditionOperator, alertCondition.getOption(), + availabilityComposite.getAvailabilityType(), alertConditionId); addTo("availabilityDurationCache", availabilityDurationCache, availabilityComposite.getResourceId(), cacheElement, alertConditionId, stats); } catch (InvalidCacheElementException icee) { diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/model/AvailabilityDurationCacheElement.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/model/AvailabilityDurationCacheElement.java index ea608f5..8b3ff23 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/model/AvailabilityDurationCacheElement.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/alert/engine/model/AvailabilityDurationCacheElement.java @@ -41,16 +41,21 @@ import org.rhq.enterprise.server.util.LookupUtil;
public final class AvailabilityDurationCacheElement extends AbstractEnumCacheElement<AvailabilityType> {
+ private int alertDefinitionId; + /** * @param operator * @param operatorOption the duration, in seconds (as String) * @param value * @param conditionTriggerId this is actually the alertConditionId, renamed here. */ - public AvailabilityDurationCacheElement(AlertConditionOperator operator, String operatorOption, + public AvailabilityDurationCacheElement(int alertDefinitionId, AlertConditionOperator operator, + String operatorOption, AvailabilityType value, int conditionTriggerId) {
super(operator, operatorOption, value, conditionTriggerId); + + this.alertDefinitionId = alertDefinitionId; }
/** @@ -62,6 +67,7 @@ public final class AvailabilityDurationCacheElement extends AbstractEnumCacheEle * @param resource * @param providedValue */ + @SuppressWarnings("incomplete-switch") public static void checkCacheElements(List<AvailabilityDurationCacheElement> cacheElements, Resource resource, AvailabilityType providedValue) { if (null == cacheElements) { @@ -90,6 +96,10 @@ public final class AvailabilityDurationCacheElement extends AbstractEnumCacheEle } }
+ public int getAlertDefinitionId() { + return alertDefinitionId; + } + /** * Each avail duration check is performed by triggering an execution of {@link AlertAvailabilityDurationJob}. * Note that each of the scheduled jobs is relevant to only 1 condition evaluation. @@ -104,7 +114,7 @@ public final class AvailabilityDurationCacheElement extends AbstractEnumCacheEle String jobName = AlertAvailabilityDurationJob.class.getName(); String jobGroupName = AlertAvailabilityDurationJob.class.getName(); String operator = cacheElement.getAlertConditionOperator().name(); - String triggerName = operator + "-" + resource.getId(); + String triggerName = operator + "-" + resource.getId() + cacheElement.getAlertDefinitionId(); String duration = (String) cacheElement.getAlertConditionOperatorOption(); // convert from seconds to milliseconds Date jobTime = new Date(System.currentTimeMillis() + (Long.valueOf(duration).longValue() * 1000));
commit d5564f3562ee960115cc533f029521000c870f45 Author: John Mazzitelli mazz@redhat.com Date: Wed Dec 19 12:39:24 2012 -0500
[BZ 887411] don't uninventory everything just because we commited some top level server
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java index 473b0d0..eaca661 100644 --- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java +++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java @@ -1087,7 +1087,24 @@ public class InventoryManager extends AgentService implements ContainerService, return true; }
+ /** + * Performs a sync so that resources passed in are reflected in the agent's inventory. + * This assumes the resource sync infos passed in represent the full inventory tree. + * + * @param syncInfo information on all resources in the entire inventory tree + */ private void synchInventory(ResourceSyncInfo syncInfo) { + synchInventory(syncInfo, false); + } + + /** + * Performs a sync so that resources passed in are reflected in the agent's inventory. + * + * @param syncInfo the resources' sync data + * @param partialInventory if true, syncInfo represents only a partial inventory. + * if false, syncInfo represents the full inventory tree of all resources + */ + private void synchInventory(ResourceSyncInfo syncInfo, boolean partialInventory) { log.info("Syncing local inventory with Server inventory..."); long startTime = System.currentTimeMillis(); Set<Resource> syncedResources = new LinkedHashSet<Resource>(); @@ -1099,7 +1116,12 @@ public class InventoryManager extends AgentService implements ContainerService,
// rhq-980 Adding agent-side logging to report any unexpected synch failure. try { - getAllUuids(syncInfo, allServerSideUuids); + // don't bother doing this if we are processing a partial inventory. + // allServerSideUuids is only ever used to purge obsolete resources, but we don't + // do that for partial inventories, so we don't need to prepare that collection for partials. + if (!partialInventory) { + getAllUuids(syncInfo, allServerSideUuids); + }
log.debug("Processing Server sync info..."); processSyncInfo(syncInfo, syncedResources, unknownResourceIds, modifiedResourceIds, deletedResourceIds, @@ -1113,7 +1135,9 @@ public class InventoryManager extends AgentService implements ContainerService,
mergeUnknownResources(unknownResourceIds); mergeModifiedResources(modifiedResourceIds); - purgeObsoleteResources(allServerSideUuids); + if (!partialInventory) { + purgeObsoleteResources(allServerSideUuids); + } postProcessNewlyCommittedResources(newlyCommittedResources); if (log.isDebugEnabled()) { if (!deletedResourceIds.isEmpty()) { @@ -2188,7 +2212,7 @@ public class InventoryManager extends AgentService implements ContainerService, + "] and its descendants...");
// Get the latest resource data rooted at the given id. - synchInventory(syncInfo); + synchInventory(syncInfo, true); // this method assumes we only get a single resource and its children (BZ 887411) performServiceScan(syncInfo.getId()); // NOTE: This will block (the initial scan blocks). }
commit a06a6ff899355823a42c3e79ac70a82510fddbe2 Author: Jay Shaughnessy jshaughn@redhat.com Date: Wed Dec 19 10:45:43 2012 -0500
Try forcing ojdbc driver resolution usinbg the local repo since it can't always be found in profile-defined repositories.
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java index dd46a29..e038fe0 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java @@ -341,6 +341,11 @@ public abstract class AbstractEJB3Test extends Arquillian { // If we're running oracle we need to include the OJDBC driver because dbunit needs it. Note that we need // add it explicitly even though it is a provided module used by the datasource. if (!Boolean.valueOf(System.getProperty("rhq.skip.oracle"))) { + // in proxy situations (like Jenkins) shrinkwrap won't be able to find repositories defined in + // settings.xml profiles. We know at this point the driver is in the local repo, try going offline + // at this point to force local repo resolution since the oracle driver is not in public repos. + // see http://stackoverflow.com/questions/6291146/arquillian-shrinkwrap-mavendepend... + resolver.goOffline(); dependencies.addAll(resolver.artifact("com.oracle:ojdbc6:jar:" + System.getProperty("rhq.ojdbc.version")) .resolveAs(JavaArchive.class)); }
commit becf9e4f40c63b8c3a6b1d6aea7122fa9eab67ab Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Dec 18 14:28:03 2012 -0500
Avoid the unzipping if it is already unzipped. It takes time for unzip to actually do all of the file compares just to know it doesn't need to add anything.
diff --git a/modules/enterprise/server/itests-2/pom.xml b/modules/enterprise/server/itests-2/pom.xml index 5811fef..db60c86 100644 --- a/modules/enterprise/server/itests-2/pom.xml +++ b/modules/enterprise/server/itests-2/pom.xml @@ -26,8 +26,8 @@ <jboss.vm.args>-Xmx700m -XX:MaxPermSize=200m -Djava.security.manager -Djava.security.policy==${jboss.unzip.location}/security.policy</jboss.vm.args> <jboss.vm.args.debug></jboss.vm.args.debug> <!-- -Ditest.debug can override this, see below --> - <!-- These properties guide which datasources are used for integration tests. Only one should be true. - The default is Postgres, specify -Pitest.oracle to use Oracle --> + <!-- These properties guide which datasources are used for integration tests. Only one should be true. The default is + Postgres, specify -Pitest.oracle to use Oracle --> <skip.postgres>false</skip.postgres> <skip.oracle>true</skip.oracle> </properties> @@ -96,12 +96,12 @@ </dependency>
<dependency> - <groupId>org.rhq</groupId> - <artifactId>rhq-arquillian-suite-extension</artifactId> - <version>${project.version}</version> - <scope>test</scope> + <groupId>org.rhq</groupId> + <artifactId>rhq-arquillian-suite-extension</artifactId> + <version>${project.version}</version> + <scope>test</scope> </dependency> - + <dependency> <groupId>org.rhq</groupId> <artifactId>rhq-core-domain</artifactId> @@ -231,15 +231,30 @@ <id>prepare Standalone XML</id> <phase>process-test-resources</phase> <configuration> - <target> - <echo>Unzipping JBossAS ${jboss.version} found at ${jboss.zip}</echo> - <unzip src="${jboss.zip}" dest="${jboss.unzip.location}/.." /> - <echo>JBossAS ${jboss.version} should now be at: ${jboss.unzip.location}</echo> - - <echo>Copying security policy to JBossAS</echo> - <copy file="${project.build.directory}/test-classes/security.policy" tofile="${jboss.unzip.location}/security.policy" /> - + <tasks> + <taskdef resource="net/sf/antcontrib/antcontrib.properties" /> <property name="jboss.conf" location="${jboss.unzip.location}/standalone/configuration/standalone.xml" /> + <property name="jboss.conf.safe" location="${jboss.conf}.safe" /> + <if> + <available file="${jboss.unzip.location}" /> + <then> + <echo>Skipping unzipping JBossAS ${jboss.version}, it is already unzipped</echo> + <echo>Restoring safe copy of standalone.xml for pending test additions</echo> + <copy file="${jboss.conf.safe}" tofile="${jboss.conf}" overwrite="true" /> + </then> + <else> + <echo>Unzipping JBossAS ${jboss.version} found at ${jboss.zip}</echo> + <unzip src="${jboss.zip}" dest="${jboss.unzip.location}/.." /> + <echo>JBossAS ${jboss.version} should now be at: ${jboss.unzip.location}</echo> + + <echo>Copying security policy to JBossAS</echo> + <copy file="${project.build.directory}/test-classes/security.policy" tofile="${jboss.unzip.location}/security.policy" /> + + <echo>Saving copy of standalone.xml</echo> + <copy file="${jboss.conf}" tofile="${jboss.conf.safe}" /> + </else> + </if> + <echo>Will now add test configuration to JBossAS config file: ${jboss.conf}</echo> <replace file="${jboss.conf}">
@@ -460,8 +475,7 @@ </dependencies> </module> ]]></echo> - - </target> + </tasks> </configuration> <goals> <goal>run</goal> @@ -703,8 +717,8 @@ </properties>
<dependencies> - <!-- The provided scope in the root pom is not sufficient, we need this fo shrinkwrap to resolve - dependency and add the jar to the deployment. --> + <!-- The provided scope in the root pom is not sufficient, we need this fo shrinkwrap to resolve dependency and add + the jar to the deployment. --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId>
commit 245fb391a81fe6a3c5c7331bb6c683fce63a7530 Author: Heiko W. Rupp hwr@redhat.com Date: Tue Dec 18 17:10:41 2012 +0100
Add tests for the operations part of the rest-api
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/OperationDefinitionRest.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/OperationDefinitionRest.java index 2f5055c..f84149e 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/OperationDefinitionRest.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/OperationDefinitionRest.java @@ -1,9 +1,7 @@ package org.rhq.enterprise.server.rest.domain;
import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map;
import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlRootElement; @@ -15,7 +13,7 @@ import com.wordnik.swagger.annotations.ApiProperty; * @author Heiko W. Rupp */ @ApiClass(value = "The template from which operations are created") -@XmlRootElement +@XmlRootElement(name = "operationDefinition") public class OperationDefinitionRest {
public OperationDefinitionRest() { diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/OperationsTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/OperationsTest.java new file mode 100644 index 0000000..72d40c9 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/OperationsTest.java @@ -0,0 +1,248 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +package org.rhq.modules.integrationTests.restApi; + +import java.util.List; +import java.util.Map; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.response.Response; + +import org.junit.Before; +import org.junit.Test; + +import org.rhq.modules.integrationTests.restApi.d.Operation; + +import static com.jayway.restassured.RestAssured.expect; +import static com.jayway.restassured.RestAssured.get; +import static com.jayway.restassured.RestAssured.given; +import static org.hamcrest.core.Is.is; + +/** + * Test the operations part of the rest api + * @author Heiko W. Rupp + */ +public class OperationsTest extends AbstractBase { + + private int definitionId; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); // Junit does not call that for us + Response r = + given() + .header(acceptJson) + .queryParam("resourceId",10001) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/operation/definitions"); + + definitionId = -1; + List<Map<String,Object>> list = r.as(List.class); + for (Map<String,Object> map : list) { + if (map.get("name").equals("discovery")) + definitionId = (Integer) map.get("id"); + } + + assert definitionId !=-1 : "No discovery operation found"; + } + + @Test + public void testGetDefinitionById() throws Exception { + + // Now retrieve that definition by id + + given() + .header(acceptJson) + .pathParam("did",definitionId) + .expect() + .statusCode(200) + .body("name",is("discovery")) + .when() + .get("/operation/definition/{did}"); + + } + + @Test + public void testCreateDraftOperation() throws Exception { + + Operation draft = + given() + .header(acceptJson) + .pathParam("definitionId",definitionId) + .queryParam("resourceId",10001) + .expect() + .statusCode(200) + .log().ifError() + .when() + .post("/operation/definition/{definitionId}") + .as(Operation.class); + + assert draft != null; + assert draft.getDefinitionId() == definitionId; + + int draftId = draft.getId(); + + // check if we can retrieve one single draft + + Operation op = get("/operation/" + draftId).as(Operation.class); + assert op !=null; + assert op.equals(draft); + + } + + @Test + public void testCreateAndUpdateDraftOperation() throws Exception { + + Operation draft = + given() + .header(acceptJson) + .pathParam("definitionId",definitionId) + .queryParam("resourceId",10001) + .expect() + .statusCode(200) + .log().ifError() + .when() + .post("/operation/definition/{definitionId}") + .as(Operation.class); + + assert draft != null; + assert draft.getDefinitionId() == definitionId; + + int draftId = draft.getId(); + draft.getParams().put("detailed",true); + + try { + given() + .contentType(ContentType.JSON) + .pathParam("id", draftId) + .body(draft) + .expect() + .statusCode(200) + .log().ifError() + .when() + .put("/operation/{id}"); + } finally { + // delete the draft again + expect() + .statusCode(204) + .when() + .delete("/operation/" + draftId); + } + + + } + + @Test + public void testCreateDraftOperationAndScheduleExecution() throws Exception { + + Operation draft = + given() + .header(acceptJson) + .pathParam("definitionId",definitionId) + .queryParam("resourceId",10001) + .expect() + .statusCode(200) + .log().ifError() + .when() + .post("/operation/definition/{definitionId}") + .as(Operation.class); + + assert draft != null; + assert draft.getDefinitionId() == definitionId; + + int draftId = draft.getId(); + + draft.setReadyToSubmit(true); + draft.getParams().put("detailed", true); + + // update to schedule + Operation scheduled = + given() + .contentType(ContentType.JSON) + .pathParam("id",draftId) + .body(draft) + .expect() + .statusCode(200) + .log().ifError() + .when() + .put("/operation/{id}") + .as(Operation.class); + + System.out.println(scheduled); + String history = null; + List<Map<String,Object>> links = scheduled.getLinks(); + for (Map<String,Object> link : links) { + if (link.get("rel").equals("history")) + history = (String) link.get("href"); + } + assert history != null; + + String historyId = history.substring(history.lastIndexOf("/")+1); + try { + Thread.sleep(5000); // we need to wait a little as the execution may take time + + given() + .pathParam("hid",historyId) + .expect() + .statusCode(200) + .log().everything() + .when() + .get("/operation/history/{hid}"); + + // See if we also find it when we are looking for histories on the resource + Response response = + given() + .queryParam("resourceId",10001) + .header(acceptJson) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/operation/history"); + + // compare + List<Map<String,Object>> list = response.as(List.class); + boolean found = false; + for (Map<String,Object> map : list) { + if (map.get("jobId").equals(historyId)) { + found = true; + } + } + assert found; + + } finally { + + // Delete the history item + given() + .pathParam("hid",historyId) + .expect() + .statusCode(204) + .log().ifError() + .when() + .delete("/operation/history/{hid}"); + + } + + } + +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Operation.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Operation.java new file mode 100644 index 0000000..54a1505 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Operation.java @@ -0,0 +1,129 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.rhq.modules.integrationTests.restApi.d; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An operation for testing + * @author Heiko W. Rupp + */ +public class Operation { + + int id; + String name; + boolean readyToSubmit; + int resourceId; + int definitionId; + Map<String,Object> params = new HashMap<String, Object>(); + List<Map<String,Object>> links; + + public Operation() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isReadyToSubmit() { + return readyToSubmit; + } + + public void setReadyToSubmit(boolean readyToSubmit) { + this.readyToSubmit = readyToSubmit; + } + + public int getResourceId() { + return resourceId; + } + + public void setResourceId(int resourceId) { + this.resourceId = resourceId; + } + + public int getDefinitionId() { + return definitionId; + } + + public void setDefinitionId(int definitionId) { + this.definitionId = definitionId; + } + + public Map<String, Object> getParams() { + return params; + } + + public void setParams(Map<String, Object> params) { + this.params = params; + } + + public List<Map<String, Object>> getLinks() { + return links; + } + + public void setLinks(List<Map<String, Object>> links) { + this.links = links; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Operation operation = (Operation) o; + + if (definitionId != operation.definitionId) return false; + if (id != operation.id) return false; + if (readyToSubmit != operation.readyToSubmit) return false; + if (resourceId != operation.resourceId) return false; + if (links != null ? !links.equals(operation.links) : operation.links != null) return false; + if (!name.equals(operation.name)) return false; + if (params != null ? !params.equals(operation.params) : operation.params != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + name.hashCode(); + result = 31 * result + (readyToSubmit ? 1 : 0); + result = 31 * result + resourceId; + result = 31 * result + definitionId; + result = 31 * result + (params != null ? params.hashCode() : 0); + result = 31 * result + (links != null ? links.hashCode() : 0); + return result; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/OperationHistory.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/OperationHistory.java new file mode 100644 index 0000000..fa0af5c --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/OperationHistory.java @@ -0,0 +1,108 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.rhq.modules.integrationTests.restApi.d; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An operationhistory item for testing + * @author Heiko W. Rupp + */ +public class OperationHistory { + + String operationName; + String resourceName; + long lastModified; + String status; + String errorMessage; + String jobId; + + Map<String,Object> result = new HashMap<String, Object>(); + List<Object> links; + + public OperationHistory() { + } + + public String getOperationName() { + return operationName; + } + + public void setOperationName(String operationName) { + this.operationName = operationName; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public long getLastModified() { + return lastModified; + } + + public void setLastModified(long lastModified) { + this.lastModified = lastModified; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getJobId() { + return jobId; + } + + public void setJobId(String jobId) { + this.jobId = jobId; + } + + public Map<String, Object> getResult() { + return result; + } + + public void setResult(Map<String, Object> result) { + this.result = result; + } + + public List<Object> getLinks() { + return links; + } + + public void setLinks(List<Object> links) { + this.links = links; + } +}
commit 3605ce3398557277d8ddf4deb3ffaa83337b7c58 Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Dec 18 10:06:59 2012 -0500
[Bug 884338 (not a fix) - Agent's availability report is ignored due to bogus stale resource error] I failed to reproduce this issue but: - Add some better logging and some attempted repair code for this situation - Add a couple more tests
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/test/AvailabilityManagerTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/test/AvailabilityManagerTest.java index f180036..ff1193d 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/test/AvailabilityManagerTest.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/test/AvailabilityManagerTest.java @@ -24,7 +24,6 @@ import java.util.Date; import java.util.List; import java.util.Random;
-import javax.persistence.EntityManager; import javax.persistence.Query; import javax.transaction.Status;
@@ -37,6 +36,7 @@ import org.rhq.core.domain.measurement.Availability; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.ResourceAvailability; import org.rhq.core.domain.resource.Agent; +import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceType; @@ -117,7 +117,6 @@ public class AvailabilityManagerTest extends AbstractEJB3Test {
if (additionalResources != null) { getTransactionManager().begin(); - EntityManager em = getEntityManager();
for (Resource res : additionalResources) { Resource res2 = em.find(Resource.class, res.getId()); @@ -130,7 +129,6 @@ public class AvailabilityManagerTest extends AbstractEJB3Test {
if (theResourceType != null) { getTransactionManager().begin(); - EntityManager em = getEntityManager();
em.remove(em.find(ResourceType.class, theResourceType.getId())); theResourceType = null; @@ -159,7 +157,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { beginTx();
try { - setupResource(em); + setupResource(); commitAndClose();
Availability aThen = new Availability(theResource, then, UP); @@ -211,7 +209,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { beginTx();
try { - setupResource(em); + setupResource(); commitAndClose();
Availability aThen = new Availability(theResource, then, UP); @@ -278,7 +276,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { List<AvailabilityPoint> availPoints; Availability avail;
- setupResource(em); + setupResource(); // platform: UNKNOWN(0) --> commitAndClose();
@@ -430,7 +428,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { beginTx();
try { - setupResource(em); + setupResource(); commitAndClose();
@@ -460,7 +458,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { beginTx();
try { - setupResource(em); + setupResource(); commitAndClose();
@@ -490,7 +488,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { try { prepareForTestAgents();
- setupResource(em); + setupResource(); commitAndClose();
@@ -561,13 +559,13 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { try { prepareForTestAgents();
- setupResource(em); // setup theResource + setupResource(); // setup theResource
allResources.add(theResource);
// now create a bunch more resources for (int i = 0; i < 99; i++) { - allResources.add(setupAnotherResource(em, i, theResource)); + allResources.add(setupAnotherResource(i, theResource)); } em.flush();
@@ -736,7 +734,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { beginTx();
try { - setupResource(em); // inserts initial UNKNOWN Availability at epoch + setupResource(); // inserts initial UNKNOWN Availability at epoch commitAndClose();
@@ -823,7 +821,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { beginTx();
try { - setupResource(em); + setupResource(); commitAndClose();
@@ -884,7 +882,7 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { try { Availability avail;
- setupResource(em); + setupResource(); commitAndClose();
@@ -972,11 +970,11 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { Availability avail; AvailabilityReport report;
- setupResource(em); + setupResource(); commitAndClose();
- long allAvailCount = setUpAvailabilities(em); + long allAvailCount = setUpAvailabilities();
// we now have 1:00 UP, 1:20 DOWN, 1:40 UP Subject overlord = LookupUtil.getSubjectManager().getOverlord(); @@ -1050,11 +1048,10 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { Availability avail; AvailabilityReport report;
- setupResource(em); + setupResource(); commitAndClose();
- - long allAvailCount = setUpAvailabilities(em); + long allAvailCount = setUpAvailabilities();
// we now have 1:00 UP, 1:20 DOWN, 1:40 UP Subject overlord = LookupUtil.getSubjectManager().getOverlord(); @@ -1121,19 +1118,174 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { } }
+ /** + * This was an attempt to get the behavior of this bug but it didn't. This inserts duplicate avail records, which + * should be discarded. + */ + @Test(enabled = ENABLE_TESTS) + public void testBZ884338_1() throws Exception { + beginTx(); + + try { + Availability avail; + AvailabilityReport report; + + setupResource(); + commitAndClose(); + + long allAvailCount = setUpAvailabilities(); + assertTrue("should have >= 3 avail records", 3 <= allAvailCount); + List<Availability> avails = getResourceAvailabilities(theResource); + // there is always the UNKNOWN period starting at epoch, plus the three created in setup + assertEquals(avails.toString(), 4, avails.size()); + + // we now have 1:00 UP, 1:20 DOWN, 1:40 UP + avail = availabilityManager.getCurrentAvailabilityForResource(overlord, theResource.getId()); + assert avail.getAvailabilityType() == UP; + + // insert a duplicate current 1:40 UP and an out-of-order 1:20 DOWN, these should be ignored + Long currentStartTime = avail.getStartTime(); + long newStartTime = currentStartTime; + avail = new Availability(theResource, newStartTime, UP); + report = new AvailabilityReport(false, theAgent.getName()); + report.addAvailability(avail); + + newStartTime = (currentStartTime - (20 * 60 * 1000L)); + avail = new Availability(theResource, newStartTime, DOWN); + report = new AvailabilityReport(false, theAgent.getName()); + report.addAvailability(avail); + + Thread.sleep(1000); + availabilityManager.mergeAvailabilityReport(report); + + // the agent should have been updated, but no new rows in availability were added + Agent agent = LookupUtil.getAgentManager().getAgentByName(theAgent.getName()); + Date lastReport = new Date(agent.getLastAvailabilityReport()); + assert lastReport != null; + assertEquals(allAvailCount, countAvailabilitiesInDB().longValue()); + avails = getResourceAvailabilities(theResource); + assertEquals(avails.toString(), 4, avails.size()); + + // avail start times should be unchanged 0, 1:00 (UP), 1:20(DOWN), 1:40(UP) + avail = avails.get(0); // 0..1:00 + assertTrue(avail.toString(), Math.abs(avail.getStartTime() - 0L) < 1000L); + assertEquals(avail.toString(), AvailabilityType.UNKNOWN, avail.getAvailabilityType()); + assertTrue(avail.toString(), Math.abs(avail.getEndTime() - avails.get(1).getStartTime()) < 1000L); + avail = avails.get(1); // 1:00..1:20 + assertTrue(avail.toString(), Math.abs(currentStartTime - (avail.getStartTime() + (40 * 60 * 1000))) < 1000L); + assertEquals(avail.toString(), AvailabilityType.UP, avail.getAvailabilityType()); + assertTrue(avail.toString(), Math.abs(avail.getEndTime() - avails.get(2).getStartTime()) < 1000L); + avail = avails.get(2); // 1:20..1:40 + assertTrue(avail.toString(), Math.abs(currentStartTime - (avail.getStartTime() + (20 * 60 * 1000))) < 1000L); + assertEquals(avail.toString(), AvailabilityType.DOWN, avail.getAvailabilityType()); + assertTrue(avail.toString(), Math.abs(avail.getEndTime() - avails.get(3).getStartTime()) < 1000L); + avail = avails.get(3); // 1:40 + assertTrue(avail.toString(), Math.abs(currentStartTime - avail.getStartTime()) < 1000L); + assertEquals(avail.toString(), AvailabilityType.UP, avail.getAvailabilityType()); + assertEquals(avail.toString(), avail.getEndTime(), null); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + if (Status.STATUS_ACTIVE == getTransactionManager().getStatus()) { + getTransactionManager().rollback(); + } + } + } + + /** + * Still can't reproduce the bug but this test tries to validate the repair code we have in case we detect + * the problem. + */ + @Test(enabled = ENABLE_TESTS) + public void testBZ884338_2() throws Exception { + beginTx(); + + try { + Availability avail; + AvailabilityReport report; + + setupResource(); + + commitAndClose(); + + long allAvailCount = setUpAvailabilities(); + assertTrue("should have >= 3 avail records", 3 <= allAvailCount); + List<Availability> avails = getResourceAvailabilities(theResource); + // there is always the UNKNOWN period starting at epoch, plus the three created in setup + assertEquals(avails.toString(), 4, avails.size()); + + // we now have 1:00 UP, 1:20 DOWN, 1:40 UP + avail = availabilityManager.getCurrentAvailabilityForResource(overlord, theResource.getId()); + + beginTx(); + + avail = em.find(Availability.class, avail.getId()); + assert avail.getAvailabilityType() == UP; + + // mess things up by assigning an end time to the latest avail record. + Long currentStartTime = avail.getStartTime(); + + Long nonNullEndTime = currentStartTime + 1000L; + avail.setEndTime(nonNullEndTime); + avail = em.merge(avail); + + commitAndClose(); + + // try to insert new avail, this should trigger the repair code + long newStartTime = (currentStartTime + (5 * 60 * 1000L)); + avail = new Availability(theResource, newStartTime, DOWN); + report = new AvailabilityReport(false, theAgent.getName()); + report.addAvailability(avail); + + Thread.sleep(1000); + availabilityManager.mergeAvailabilityReport(report); + + avails = getResourceAvailabilities(theResource); + assertEquals(avails.toString(), 4, avails.size()); + + // avail start times should now be 0, 1:00 (UP), 1:10(DOWN), 1:40(UP) + avail = avails.get(0); // 0..1:00 + assertTrue(avail.toString(), Math.abs(avail.getStartTime() - 0L) < 1000L); + assertEquals(avail.toString(), AvailabilityType.UNKNOWN, avail.getAvailabilityType()); + assertTrue(avail.toString(), Math.abs(avail.getEndTime() - avails.get(1).getStartTime()) < 1000L); + avail = avails.get(1); // 1:00..1:20 + assertTrue(avail.toString(), Math.abs(currentStartTime - (avail.getStartTime() + (40 * 60 * 1000))) < 1000L); + assertEquals(avail.toString(), AvailabilityType.UP, avail.getAvailabilityType()); + assertTrue(avail.toString(), Math.abs(avail.getEndTime() - avails.get(2).getStartTime()) < 1000L); + avail = avails.get(2); // 1:20..1:40 + assertTrue(avail.toString(), Math.abs(currentStartTime - (avail.getStartTime() + (20 * 60 * 1000))) < 1000L); + assertEquals(avail.toString(), AvailabilityType.DOWN, avail.getAvailabilityType()); + assertTrue(avail.toString(), Math.abs(avail.getEndTime() - avails.get(3).getStartTime()) < 1000L); + avail = avails.get(3); // 1:40 + assertTrue(avail.toString(), Math.abs(currentStartTime - avail.getStartTime()) < 1000L); + assertEquals(avail.toString(), AvailabilityType.UP, avail.getAvailabilityType()); + assertEquals(avail.toString(), null, avail.getEndTime()); // THIS IS THE CHANGE + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + if (Status.STATUS_ACTIVE == getTransactionManager().getStatus()) { + getTransactionManager().rollback(); + } + } + } + @Test(enabled = ENABLE_TESTS) public void testMergeReportPerformance() throws Exception { beginTx(); List<Resource> allResources = new ArrayList<Resource>();
try { - setupResource(em); // setup theResource + setupResource(); // setup theResource
allResources.add(theResource);
// now create a bunch more resources for (int i = 0; i < 100; i++) { - allResources.add(setupAnotherResource(em, i, theResource)); + allResources.add(setupAnotherResource(i, theResource)); } em.flush();
@@ -1260,8 +1412,6 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { /** * See how many rows we have in the availability table * - * @param em EntityManager to use - * * @return the rowcount * * @throws Exception @@ -1277,22 +1427,36 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { }
/** - * Just set up a resource where we can attach the availabilities to + * See how many rows we have in the availability table * - * @param em The EntityManager to use + * @return the rowcount + * + * @throws Exception + */ + private List<Availability> getResourceAvailabilities(Resource r) throws Exception { + AvailabilityCriteria c = new AvailabilityCriteria(); + c.addFilterResourceId(r.getId()); + c.addSortStartTime(PageOrdering.ASC); + return availabilityManager.findAvailabilityByCriteria(overlord, c); + } + + /** + * Just set up a resource where we can attach the availabilities to * * @return A Resource ready to use */ - private Resource setupResource(EntityManager em) { - theAgent = new Agent("testagent", "localhost", 1234, "", "randomToken"); + private Resource setupResource() { + String prefix = this.getClass().getSimpleName() + "_"; + theAgent = new Agent(prefix + "agent", "localhost", 1234, "", "randomToken"); em.persist(theAgent);
- theResourceType = new ResourceType("test-plat", "test-plugin", ResourceCategory.PLATFORM, null); + theResourceType = new ResourceType(prefix + "type", prefix + "plugin", ResourceCategory.PLATFORM, null); em.persist(theResourceType);
- theResource = new Resource("test-platform-key", "test-platform-name", theResourceType); + theResource = new Resource(prefix + "resourceKey", prefix + "resourceName", theResourceType); theResource.setUuid("" + new Random().nextInt()); theResource.setAgent(theAgent); + theResource.setInventoryStatus(InventoryStatus.COMMITTED); em.persist(theResource);
em.flush(); @@ -1303,12 +1467,11 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { * Set up another unique resource that will be related to <code>theAgent</code>. The resource will be of type <code> * theResourceType</code>. * - * @param em The EntityManager to use * @param uniqueNumber used to define a unique key for the resource * * @return A Resource ready to use */ - private Resource setupAnotherResource(EntityManager em, int uniqueNumber, Resource parentResource) { + private Resource setupAnotherResource(int uniqueNumber, Resource parentResource) { Resource newResource;
newResource = new Resource("test-platform-key-" + uniqueNumber, "test-platform-name-" + uniqueNumber, @@ -1326,13 +1489,11 @@ public class AvailabilityManagerTest extends AbstractEJB3Test { * Set up an availability scenario where we set up availability for one hour, split it in the middle and have 20min * up, 20min down, 20min up starting at 1:00am. * - * @param em An EntityManager to use - * * @return total number of availability records in the DB after we've added ours * * @throws Exception */ - private long setUpAvailabilities(EntityManager em) throws Exception { + private long setUpAvailabilities() throws Exception { Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); cal.set(Calendar.HOUR, 1); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java index 05dd802..31f1040 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/AvailabilityManagerBean.java @@ -46,6 +46,7 @@ import org.rhq.core.domain.discovery.AvailabilityReport; import org.rhq.core.domain.measurement.Availability; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.ResourceAvailability; +import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.composite.ResourceIdWithAvailabilityComposite; import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite; @@ -556,9 +557,41 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa } catch (NoResultException nre) { // This should not happen unless the Resource in the report is stale, which can happen in certain // sync scenarios. A Resource is given its initial Availability/ResourceAvailability when it is - // persisted so it is guaranteed to have Availability, so, the Resource must not exist. - log.info("Skipping mergeAvailabilityReport() for stale resource [" + reported.getResource() - + "]. These messages should go away after the next agent synchronization with the server."); + // persisted so it is guaranteed to have Availability, so, the Resource must not exist. At least + // it must not exist in my utopian view of the world. Let's just make sure... + Resource attachedResource = (Resource) entityManager.find(Resource.class, reported.getResource() + .getId()); + if (null == attachedResource) { + // expected case + log.info("Skipping mergeAvailabilityReport() for stale resource [" + reported.getResource() + + "]. These messages should go away after the next agent synchronization with the server."); + + } else if (InventoryStatus.COMMITTED == attachedResource.getInventoryStatus()) { + // this should not happen, it means the resource exists but has no latest Availability + // record (i.e. sendTime == null). Try to correct the situation. + log.warn("Resource [" + reported.getResource() + + "] has no latest availability record (i.e. no endtime) - will attempt to repair.\n" + + report.toString(false)); + try { + List<Availability> attachedAvails = attachedResource.getAvailability(); + if (attachedAvails.isEmpty()) { + attachedResource.initCurrentAvailability(); + entityManager.merge(attachedResource); + + } else { + Availability attachedLastAvail = attachedAvails.get(attachedAvails.size() - 1); + attachedLastAvail.setEndTime(null); + entityManager.merge(attachedLastAvail); + } + + // ask the agent for a full report so as to ensure we are in sync with agent + askForFullReport = true; + + } catch (Throwable t) { + log.warn("Unable to repair latest availablity for Resource [" + reported.getResource() + + "]", t); + } + }
} catch (NonUniqueResultException nure) { // This condition should never happen. In my world of la-la land, I've done everything @@ -661,7 +694,7 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa public void updateAgentResourceAvailabilities(int agentId, AvailabilityType platformAvailType, AvailabilityType childAvailType) {
- platformAvailType = (null == platformAvailType) ? AvailabilityType.UNKNOWN : platformAvailType; + platformAvailType = (null == platformAvailType) ? AvailabilityType.DOWN : platformAvailType; childAvailType = (null == childAvailType) ? AvailabilityType.UNKNOWN : childAvailType;
// get the platform resource if not already at platformAvailType (since this is the one @@ -681,17 +714,8 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa query.setParameter("disabled", AvailabilityType.DISABLED); List<ResourceIdWithAvailabilityComposite> resourcesWithStatus = query.getResultList();
- // The above queries only return resources if they have at least one row in Availability. - // This may be a problem in the future, and may need to be fixed. - // If a resource has 0 rows of availability, then it is by definition "unknown". If, - // availabilityType is null, we don't have to do anything since the unknown state hasn't changed. - // If this method is told to set all agent resources to something of other than unknown (null) - // availability, then we may need to completely rethink the query we do above so it returns composite - // objects for all resources, even those that have 0 rows of availability. Remember though, that once - // we get an availability report from an agent, a resource will have at least 1 availability row. So, - // a resource should rarely have 0 avail rows; if it does, it normally gets one within a minute - // (since the agent sends avail reports every 60 seconds or so by default). So this problem might not - // be as bad as first thought. + // The above queries only return resources if they have at least one row in Availability. This should + // not be a problem since a new Resource gets an initial UNKNOWN Availability record at persist-time.
if (log.isDebugEnabled()) { log.debug("Agent #[" + agentId + "] is going to have [" + resourcesWithStatus.size() @@ -815,6 +839,14 @@ public class AvailabilityManagerBean implements AvailabilityManagerLocal, Availa }
return; + + } catch (NonUniqueResultException nure) { + // This should not happen but can happen if the startTime exactly matches an existing start time. In + // this case assume we have somehow been passed a duplicate report, and ignore the entry. + log.warn("Resource [" + toInsert.getResource() + + "] received a duplicate Availability. It is being ignored: " + toInsert); + + return; }
// If we are inserting the same availability type, the first one can just continue
commit f908a455b968de7826667f5b1a0628290dcda537 Author: Heiko W. Rupp hwr@redhat.com Date: Tue Dec 18 10:23:53 2012 +0100
Add tests for the REST-Api endpoints and fix some issues in the API.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java index 1e8b99f..6e7f1de 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AbstractRestBean.java @@ -57,6 +57,7 @@ import org.rhq.core.domain.resource.group.GroupCategory; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal; +import org.rhq.enterprise.server.rest.domain.GroupRest; import org.rhq.enterprise.server.rest.domain.Link; import org.rhq.enterprise.server.rest.domain.ResourceWithType;
@@ -426,6 +427,31 @@ public class AbstractRestBean { return resourceGroup; }
+ protected GroupRest fillGroup(ResourceGroup group, UriInfo uriInfo) { + + GroupRest gr = new GroupRest(group.getName()); + gr.setId(group.getId()); + gr.setCategory(group.getGroupCategory()); + gr.setRecursive(group.isRecursive()); + if (group.getGroupDefinition()!=null) + gr.setDynaGroupDefinitionId(group.getGroupDefinition().getId()); + gr.setExplicitCount(group.getExplicitResources().size()); + gr.setImplicitCount(group.getImplicitResources().size()); + UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); + uriBuilder.path("/group/{id}"); + URI uri = uriBuilder.build(group.getId()); + Link link = new Link("edit",uri.toASCIIString()); + gr.getLinks().add(link); + + uriBuilder = uriInfo.getBaseUriBuilder(); + uriBuilder.path("/group/{id}/metricDefinitions"); + uri = uriBuilder.build(group.getId()); + link = new Link("metricDefinitions",uri.toASCIIString()); + gr.getLinks().add(link); + + return gr; + } + private static class CacheKey { private String namespace; private int id; diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java index 9e3b41a..9835b58 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java @@ -93,7 +93,7 @@ public class AlertHandlerBean extends AbstractRestBean { @Path("/") @ApiOperation(value = "List all alerts", multiValueResponse = true, responseClass = "List<AlertRest>") public Response listAlerts( - @ApiParam(value = "Page number", defaultValue = "0") @QueryParam("page") int page, + @ApiParam(value = "Page number", defaultValue = "1") @QueryParam("page") int page, @ApiParam(value = "Limit to priority", allowableValues = "High, Medium, Low, All") @DefaultValue("All") @QueryParam("prio") String prio, @ApiParam(value = "Should full resources and definitions be sent") @QueryParam("slim") @DefaultValue( "false") boolean slim, diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java index 5d5671f..f0ffdb4 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java @@ -30,6 +30,7 @@ import org.apache.commons.logging.LogFactory;
import org.rhq.enterprise.server.authz.PermissionException; import org.rhq.enterprise.server.resource.ResourceNotFoundException; +import org.rhq.enterprise.server.resource.group.ResourceGroupNotFoundException; import org.rhq.enterprise.server.rest.domain.RHQErrorWrapper;
/** @@ -57,8 +58,12 @@ public class CustomExceptionMapper implements ExceptionMapper<Exception> { status =Response.Status.NOT_FOUND; else if (cause instanceof ResourceNotFoundException) status = Response.Status.NOT_FOUND; + else if (cause instanceof ResourceGroupNotFoundException) + status = Response.Status.NOT_FOUND; else if (cause instanceof ParameterMissingException) status = Response.Status.NOT_ACCEPTABLE; + else if (cause instanceof IllegalArgumentException) + status = Response.Status.NOT_ACCEPTABLE; else if (cause instanceof PermissionException) status = Response.Status.FORBIDDEN; else diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/EventHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/EventHandlerBean.java index ad1b7b0..3d7abe0 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/EventHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/EventHandlerBean.java @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - package org.rhq.enterprise.server.rest;
import java.util.ArrayList; @@ -62,6 +61,7 @@ import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.util.PageControl; import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.event.EventManagerLocal; +import org.rhq.enterprise.server.rest.domain.EventDefinitionRest; import org.rhq.enterprise.server.rest.domain.EventRest; import org.rhq.enterprise.server.rest.domain.EventSourceRest;
@@ -112,6 +112,40 @@ public class EventHandlerBean extends AbstractRestBean { }
@GET + @Path("/{id}/definitions") + @ApiOperation(value = "List the defined event source definitions for the resource", responseClass = "EventDefintionRest", multiValueResponse = true) + public Response listEventDefinitionsForResource(@ApiParam("id of the resource") @PathParam("id") int resourceId, + @Context Request request, + @Context HttpHeaders headers) { + + Resource res = fetchResource(resourceId); + ResourceType resourceType = res.getResourceType(); + em.refresh(resourceType); + Set<EventDefinition> eventDefinitions = resourceType.getEventDefinitions(); + + List<EventDefinitionRest> definitionsRest = new ArrayList<EventDefinitionRest>(eventDefinitions.size()); + for (EventDefinition source : eventDefinitions) { + EventDefinitionRest esr = new EventDefinitionRest(); + esr.setDescription(source.getDescription()); + esr.setId(source.getId()); + esr.setDisplayName(source.getDisplayName()); + esr.setName(source.getName()); + definitionsRest.add(esr); + } + + Response.ResponseBuilder builder; + MediaType mediaType = headers.getAcceptableMediaTypes().get(0); + if (mediaType.equals(MediaType.APPLICATION_XML_TYPE)) { + GenericEntity<List<EventDefinitionRest>> list = new GenericEntity<List<EventDefinitionRest>>(definitionsRest) {}; + builder = Response.ok(list, mediaType); + } + else { + builder = Response.ok(definitionsRest, mediaType); + } + return builder.build(); + } + + @GET @Path("/source/{id}") @ApiOperation(value = "Retrieve the event source with the passed id", responseClass = "EventSourceRest") public EventSourceRest getEventSource(@ApiParam("Id of the source to retrieve") @PathParam("id") int sourceId) { @@ -127,7 +161,7 @@ public class EventHandlerBean extends AbstractRestBean { @ApiOperation("Add a new event source for a resource. This can e.g. be a different logfile. " + "The source.name must match an existing definition fo this resource. " + "If an event source for the definition name and resource with the same location already exists, no new source is created. " + - "NOTE: An Event source added this way will not sow up in the connection properties.") + "NOTE: An Event source added this way will not show up in the connection properties.") public EventSourceRest addEventSource(@ApiParam("id of the resource") @PathParam("id") int resourceId, EventSourceRest esr) {
@@ -177,8 +211,8 @@ public class EventHandlerBean extends AbstractRestBean { }
@GET @GZIP - @Path("/source/{id}/events") - @ApiOperation(value = "List the events for the event source with the passed id. If no time range is given, the last 200 entries will be displayed", + @Path("/source/{id}/events") + @ApiOperation(value = "List the events for the event source with the passed id. If no time range is given, the last 200 entries will be displayed", responseClass = "EventRest", multiValueResponse = true) public Response getEventsForSource(@PathParam("id") int sourceId, @QueryParam("startTime") long startTime, diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/GroupHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/GroupHandlerBean.java index 9f0ed9f..59739b1 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/GroupHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/GroupHandlerBean.java @@ -54,6 +54,7 @@ import com.wordnik.swagger.annotations.ApiParam; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
+import org.jboss.resteasy.annotations.Form; import org.jboss.resteasy.annotations.GZIP; import org.jboss.resteasy.annotations.cache.Cache;
@@ -114,7 +115,7 @@ public class GroupHandlerBean extends AbstractRestBean { if (q!=null) { criteria.addFilterName(q); } - List<ResourceGroup> groups = resourceGroupManager.findResourceGroupsByCriteria(caller,criteria); + List<ResourceGroup> groups = resourceGroupManager.findResourceGroupsByCriteria(caller, criteria);
List<GroupRest> list = new ArrayList<GroupRest>(groups.size()); for (ResourceGroup group : groups) { @@ -177,14 +178,13 @@ public class GroupHandlerBean extends AbstractRestBean { resourceType = resourceTypeManager.getResourceTypeById(caller,group.getResourceTypeId()); newGroup.setResourceType(resourceType); } catch (ResourceTypeNotFoundException e) { - e.printStackTrace(); // TODO: Customise this generated block throw new StuffNotFoundException("ResourceType with id " + group.getResourceTypeId()); } }
Response.ResponseBuilder builder; try { - newGroup = resourceGroupManager.createResourceGroup(caller,newGroup); + newGroup = resourceGroupManager.createResourceGroup(caller, newGroup); UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); uriBuilder.path("/group/{id}"); URI uri = uriBuilder.build(newGroup.getId()); @@ -200,7 +200,7 @@ public class GroupHandlerBean extends AbstractRestBean {
@PUT @Path("{id}") - @ApiOperation(value = "Update the passed group") + @ApiOperation(value = "Update the passed group. Currently only name change is supported") public Response updateGroup(@ApiParam(value = "Id of the group to update") @PathParam("id") int id, @ApiParam(value = "New version of the group") GroupRest in, @Context HttpHeaders headers, @@ -304,7 +304,7 @@ public class GroupHandlerBean extends AbstractRestBean { @Context HttpHeaders headers, @Context UriInfo uriInfo) {
ResourceGroup resourceGroup = fetchGroup(id, false); - Resource res = resourceManager.getResource(caller,resourceId); + Resource res = resourceManager.getResource(caller, resourceId); if (res==null) throw new StuffNotFoundException("Resource with id " + resourceId);
@@ -351,31 +351,6 @@ public class GroupHandlerBean extends AbstractRestBean { return builder.build(); }
- private GroupRest fillGroup(ResourceGroup group, UriInfo uriInfo) { - - GroupRest gr = new GroupRest(group.getName()); - gr.setId(group.getId()); - gr.setCategory(group.getGroupCategory()); - gr.setRecursive(group.isRecursive()); - if (group.getGroupDefinition()!=null) - gr.setDynaGroupDefinitionId(group.getGroupDefinition().getId()); - gr.setExplicitCount(group.getExplicitResources().size()); - gr.setImplicitCount(group.getImplicitResources().size()); - UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); - uriBuilder.path("/group/{id}"); - URI uri = uriBuilder.build(group.getId()); - Link link = new Link("edit",uri.toASCIIString()); - gr.getLinks().add(link); - - uriBuilder = uriInfo.getBaseUriBuilder(); - uriBuilder.path("/group/{id}/metricDefinitions"); - uri = uriBuilder.build(group.getId()); - link = new Link("metricDefinitions",uri.toASCIIString()); - gr.getLinks().add(link); - - return gr; - } - @GZIP @GET @Path("/definitions") @@ -523,9 +498,11 @@ public class GroupHandlerBean extends AbstractRestBean {
} catch (GroupDefinitionAlreadyExistsException e) { builder =Response.status(Response.Status.CONFLICT); + builder.entity(e.getMessage()); } catch (GroupDefinitionCreateException e) { e.printStackTrace(); // TODO: Customise this generated block - builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR); + builder = Response.status(Response.Status.NOT_ACCEPTABLE); + builder.entity(e.getMessage()); } return builder.build(); } @@ -533,10 +510,11 @@ public class GroupHandlerBean extends AbstractRestBean { @PUT @Path("/definition/{id}") @Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML}) - @ApiOperation("Update an existing GroupDefinition") + @ApiOperation("Update an existing GroupDefinition or recalculate it if the query param 'recalculate' is set to true") public Response updateGroupDefinition(@ApiParam("Id fo the definition to update") @PathParam("id") int definitionId, @ApiParam("If true, trigger a re-calculation") @QueryParam( "recalculate") - @DefaultValue("false") boolean recalculate, GroupDefinitionRest definition, + @DefaultValue("false") boolean recalculate, + GroupDefinitionRest definition, // TODO mark as optional? @Context HttpHeaders headers, @Context UriInfo uriInfo) {
@@ -549,6 +527,19 @@ public class GroupHandlerBean extends AbstractRestBean {
Response.ResponseBuilder builder = null;
+ if (recalculate) { + try { + definitionManager.calculateGroupMembership(caller,gd.getId()); + builder = Response.noContent(); + } catch (Exception e) { + builder = Response.status(Response.Status.NOT_ACCEPTABLE); + builder.entity(e.getLocalizedMessage()); + } + return builder.build(); + } + + // Not recalculation, but an update + if (!definition.getName().isEmpty()) gd.setName(definition.getName()); gd.setDescription(definition.getDescription()); @@ -566,18 +557,11 @@ public class GroupHandlerBean extends AbstractRestBean { try { definitionManager.updateGroupDefinition(caller,gd); } catch (Exception e) { - e.printStackTrace(); // TODO: Customise this generated block builder = Response.status(Response.Status.NOT_ACCEPTABLE); builder.entity(e.getLocalizedMessage()); return builder.build(); }
- if (recalculate) { - try { - definitionManager.calculateGroupMembership(caller,gd.getId()); - } catch (Exception e) { - } - }
try { // Re-fetch, as groups may have changed diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java index b927acf..115452d 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java @@ -747,14 +747,20 @@ public class MetricHandlerBean extends AbstractRestBean { @Path("data/{scheduleId}/baseline") @Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML}) @ApiOperation(value = "Set a new baseline for the schedule") - @ApiError(code = 404, reason = NO_SCHEDULE_FOR_ID) - public void setBaseline(@ApiParam("Id of the schedule") @PathParam("scheduleId") int scheduleId, - Baseline baseline, HttpHeaders headers, @Context UriInfo uriInfo) { + @ApiErrors({ + @ApiError(code = 404, reason = NO_SCHEDULE_FOR_ID), + @ApiError(code = 406 ,reason = "Baseline data is incorrect") + }) + public Response setBaseline(@ApiParam("Id of the schedule") @PathParam("scheduleId") int scheduleId, + Baseline baseline, @Context HttpHeaders headers, @Context UriInfo uriInfo) { MeasurementSchedule schedule = obtainSchedule(scheduleId, false, DataType.MEASUREMENT);
// little bit of sanity checking - if (baseline.getMin()>baseline.getMean() || baseline.getMean()>baseline.getMax() || baseline.getMin()>baseline.getMax()) - throw new IllegalArgumentException("Baseline not correct. it should be min<=mean<=max"); + if (baseline.getMin()>baseline.getMean() || baseline.getMean()>baseline.getMax() || baseline.getMin()>baseline.getMax()) { + Response.ResponseBuilder builder = Response.status(Response.Status.NOT_ACCEPTABLE); + builder.entity("Baseline not correct. it should be min<=mean<=max"); + return builder.build(); + }
MeasurementBaseline mBase = schedule.getBaseline(); if (mBase == null) { @@ -770,6 +776,8 @@ public class MetricHandlerBean extends AbstractRestBean {
scheduleManager.updateSchedule(caller,schedule);
+ return Response.created(uriInfo.getRequestUriBuilder().build()).build(); + }
/** diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java index 98b2e6e..22d8111 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java @@ -33,6 +33,7 @@ import javax.ejb.Stateless; import javax.interceptor.Interceptors; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -51,6 +52,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo;
+import com.arjuna.ats.internal.jdbc.drivers.modifiers.list; import com.wordnik.swagger.annotations.Api; import com.wordnik.swagger.annotations.ApiError; import com.wordnik.swagger.annotations.ApiOperation; @@ -77,6 +79,7 @@ import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.util.PageControl; +import org.rhq.core.domain.util.PageList; import org.rhq.core.domain.util.PageOrdering; import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.alert.AlertManagerLocal; @@ -115,11 +118,10 @@ public class ResourceHandlerBean extends AbstractRestBean { private EntityManager entityManager;
@GET - @Path("/{id}") + @Path("/{id:\d+}") @Cache(isPrivate = true,maxAge = 120) @ApiOperation(value = "Retrieve a single resource", responseClass = "ResourceWithType") @ApiError(code = 404, reason = NO_RESOURCE_FOR_ID) - public Response getResource(@ApiParam("Id of the resource to retrieve") @PathParam("id") int id, @Context Request request, @Context HttpHeaders headers, @Context UriInfo uriInfo) { @@ -151,15 +153,27 @@ public class ResourceHandlerBean extends AbstractRestBean {
@GET @GZIP @Path("/") - @ApiOperation(value = "Search for resources by the given search string", responseClass = "ResourceWithType") + @ApiOperation(value = "Search for resources by the given search string, possibly limited by category and paged", responseClass = "ResourceWithType") public Response getResourcesByQuery(@ApiParam("String to search in the resource name") @QueryParam("q") String q, + @ApiParam("Limit to category (PLATFORM, SERVER, SERVICE") @QueryParam("category") String category, + @ApiParam("Page size for paging") @QueryParam("ps") @DefaultValue("20") int pageSize, + @ApiParam("Page for paging") @QueryParam("page") Integer page, @Context HttpHeaders headers, @Context UriInfo uriInfo) { ResourceCriteria criteria = new ResourceCriteria(); - criteria.addFilterName(q); - List<Resource> ret = resMgr.findResourcesByCriteria(caller,criteria); + if (q!=null) { + criteria.addFilterName(q); + } + if (category!=null) { + criteria.addFilterResourceCategories(ResourceCategory.valueOf(category.toUpperCase())); + } + if (page!=null) { + criteria.setPaging(page,pageSize); + criteria.addSortName(PageOrdering.ASC); + } + PageList<Resource> ret = resMgr.findResourcesByCriteria(caller,criteria);
- Response.ResponseBuilder builder = getResponseBuilderForResourceList(headers,uriInfo,ret); + Response.ResponseBuilder builder = getResponseBuilderForResourceList(headers,uriInfo,ret, page, pageSize);
return builder.build(); } @@ -173,22 +187,27 @@ public class ResourceHandlerBean extends AbstractRestBean { @Context UriInfo uriInfo) {
PageControl pc = new PageControl(); - List<Resource> ret = resMgr.findResourcesByCategory(caller, ResourceCategory.PLATFORM, + PageList<Resource> ret = resMgr.findResourcesByCategory(caller, ResourceCategory.PLATFORM, InventoryStatus.COMMITTED, pc); - Response.ResponseBuilder builder = getResponseBuilderForResourceList(headers, uriInfo, ret); + Response.ResponseBuilder builder = getResponseBuilderForResourceList(headers, uriInfo, ret, null, 20);
return builder.build(); }
/** * Translate the passed list of resources into a response according to the acceptable mime types etc. + * + * * @param headers HttpHeaders from the request * @param uriInfo Uri from the request * @param resources List of resources + * @param page Page of pageSize. If null, paging is ignored + * @param pageSize numer of elements on a page * @return An initialized ResponseBuilder */ private Response.ResponseBuilder getResponseBuilderForResourceList(HttpHeaders headers, UriInfo uriInfo, - List<Resource> resources) { + PageList<Resource> resources, Integer page, + int pageSize) { List<ResourceWithType> rwtList = new ArrayList<ResourceWithType>(resources.size()); for (Resource r : resources) { putToCache(r.getId(), Resource.class, r); @@ -197,14 +216,35 @@ public class ResourceHandlerBean extends AbstractRestBean { } // What media type does the user request? MediaType mediaType = headers.getAcceptableMediaTypes().get(0); - Response.ResponseBuilder builder; + Response.ResponseBuilder builder = Response.ok(); + builder.type(mediaType); + UriBuilder uriBuilder; + if (page!=null) { + + // TODO look a the page control and check if there is a next page at all + if (resources.getTotalSize()> page*pageSize) { + int nextPage = page+1; + uriBuilder = uriInfo.getRequestUriBuilder(); // adds ?q, ?ps and ?category if needed + uriBuilder.replaceQueryParam("page",nextPage); + + builder.header("Link",new Link("next",uriBuilder.build().toString())); + } + + if (page>1) { + int prevPage = page -1; + uriBuilder = uriInfo.getRequestUriBuilder(); // adds ?q, ?ps and ?category if needed + uriBuilder.replaceQueryParam("page",prevPage); + builder.header("prev",uriBuilder.build().toString()); + } + }
if (mediaType.equals(MediaType.TEXT_HTML_TYPE)) { - builder = Response.ok(renderTemplate("listResourceWithType", rwtList), mediaType); + builder.entity(renderTemplate("listResourceWithType", rwtList)); + } else { GenericEntity<List<ResourceWithType>> list = new GenericEntity<List<ResourceWithType>>(rwtList) { }; - builder = Response.ok(list); + builder.entity(list); } return builder; } @@ -453,7 +493,7 @@ public class ResourceHandlerBean extends AbstractRestBean { }
private Resource obtainResource(int resourceId) { - Resource resource = getFromCache(resourceId, Resource.class); + Resource resource = resMgr.getResource(caller,resourceId); if (resource == null) { resource = resMgr.getResource(caller, resourceId); if (resource != null) @@ -487,7 +527,6 @@ public class ResourceHandlerBean extends AbstractRestBean { "via a normal RHQ agent") @POST @Path("platform/{name}") - public Response createPlatform( @ApiParam(value = "Name of the platform") @PathParam("name") String name, @ApiParam(value = "Type of the platform", allowableValues = "Linux,Windows,... TODO") StringValue typeValue, @@ -510,8 +549,8 @@ public class ResourceHandlerBean extends AbstractRestBean { URI uri = uriBuilder.build(r.getId());
- javax.ws.rs.core.Response.ResponseBuilder builder = Response.ok(rwt); - builder.location(uri); + Response.ResponseBuilder builder = Response.created(uri); + builder.entity(rwt); return builder.build();
} @@ -541,7 +580,7 @@ public class ResourceHandlerBean extends AbstractRestBean { uriBuilder.path("/resource/{id}"); URI uri = uriBuilder.build(platform.getId());
- javax.ws.rs.core.Response.ResponseBuilder builder = Response.created(uri); + Response.ResponseBuilder builder = Response.created(uri); builder.entity(rwt); return builder.build();
@@ -587,21 +626,18 @@ public class ResourceHandlerBean extends AbstractRestBean {
Resource r = resMgr.getResourceByParentAndKey(caller,null,resourceKey,plugin,typeName); if (r!=null) { - // platform exists - return it + // resource exists - return it ResourceWithType rwt = fillRWT(r,uriInfo);
UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); uriBuilder.path("/resource/{id}"); URI uri = uriBuilder.build(r.getId());
- - javax.ws.rs.core.Response.ResponseBuilder builder = Response.ok(rwt); - builder.location(uri); + Response.ResponseBuilder builder = Response.created(uri); + builder.entity(rwt); return builder.build(); - }
- Resource res = new Resource(resourceKey,name,resType); res.setUuid(resourceKey); res.setAgent(parent.getAgent()); @@ -616,15 +652,30 @@ public class ResourceHandlerBean extends AbstractRestBean {
ResourceWithType rwt = fillRWT(res,uriInfo);
- javax.ws.rs.core.Response.ResponseBuilder builder = Response.ok(rwt); + UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); + uriBuilder.path("/resource/{id}"); + URI uri = uriBuilder.build(res.getId()); + + Response.ResponseBuilder builder = Response.created(uri); + builder.entity(rwt); return builder.build();
} catch (ResourceAlreadyExistsException e) { throw new IllegalArgumentException(e); } + }
+ @DELETE + @Path("/{id}") + @ApiOperation("Remove a resource from inventory") + public Response uninventoryOrDeleteResource( + @PathParam("id") int resourceId + /*,@DefaultValue("false") @QueryParam("physical") boolean delete*/) {
- } + resMgr.uninventoryResource(caller,resourceId); + + return Response.status(Response.Status.NO_CONTENT).build();
+ } } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/RootHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/RootHandlerBean.java index 8d2f130..7998294 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/RootHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/RootHandlerBean.java @@ -53,7 +53,7 @@ public class RootHandlerBean extends AbstractRestBean { "dynaGroups","group/definitions", "alerts","alert", "status","status", - "favoriteResource","user/favorites/resource", + "favoriteResources","user/favorites/resource", "operationHistory","operation/history", "self","" }; @@ -87,6 +87,7 @@ public class RootHandlerBean extends AbstractRestBean { } else if (mediaType.equals(MediaType.APPLICATION_XML_TYPE)) { target += ".xml"; } else { + log.error("Unknown media type " + mediaType); throw new WebApplicationException(Response.Status.NOT_ACCEPTABLE); } Link link = new Link(rel,target); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/UserHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/UserHandlerBean.java index bdd613e..a0f1177 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/UserHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/UserHandlerBean.java @@ -27,6 +27,8 @@ import java.util.TreeSet; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.interceptor.Interceptors; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; @@ -53,9 +55,13 @@ import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.resource.Resource; +import org.rhq.core.domain.resource.group.ResourceGroup; +import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.auth.SubjectManagerLocal; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.resource.ResourceNotFoundException; +import org.rhq.enterprise.server.resource.group.ResourceGroupNotFoundException; +import org.rhq.enterprise.server.rest.domain.GroupRest; import org.rhq.enterprise.server.rest.domain.ResourceWithType; import org.rhq.enterprise.server.rest.domain.UserRest;
@@ -90,6 +96,10 @@ public class UserHandlerBean extends AbstractRestBean { @EJB ResourceManagerLocal resourceManager;
+ @PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME) + private EntityManager entityManager; + + @GZIP @GET @Path("favorites/resource") @@ -102,10 +112,19 @@ public class UserHandlerBean extends AbstractRestBean { MediaType mediaType = httpHeaders.getAcceptableMediaTypes().get(0); for (Integer id : favIds) { try { - Resource res = resourceManager.getResource(caller,id); + /* + * In theory we should not have any bad resource ids in favorites, but ... + * First check if the resource exists, as otherwise resourceManager.getResource() + * throws an exception that seems to kill the transaction and backend connection + * See https://bugzilla.redhat.com/show_bug.cgi?id=886850 + */ + Resource res = entityManager.find(Resource.class,id); + if (res!=null) { + res = resourceManager.getResource(caller,id);
- ResourceWithType rwt = fillRWT(res,uriInfo); - ret.add(rwt); + ResourceWithType rwt = fillRWT(res,uriInfo); + ret.add(rwt); + } } catch (Exception e) { if (e.getCause()!=null && e.getCause() instanceof ResourceNotFoundException) @@ -127,16 +146,82 @@ public class UserHandlerBean extends AbstractRestBean {
}
+ @GZIP + @GET + @Path("favorites/group") + @ApiOperation(value = "Return a list of favorite groups of the caller", multiValueResponse = true, responseClass = "GroupRest") + public Response getGroupFavorites(@Context UriInfo uriInfo, @Context HttpHeaders httpHeaders) { + + Set<Integer> favIds = getGroupIdsForFavorites(); + List<GroupRest> ret = new ArrayList<GroupRest>(); + + MediaType mediaType = httpHeaders.getAcceptableMediaTypes().get(0); + for (Integer id : favIds) { + try { + /* + * In theory we should not have any bad group ids in favorites, but ... + * First check if the group exists, as otherwise resourceGroupManager.getResourceGroup() + * throws an exception that seems to kill the transaction and backend connection + * See https://bugzilla.redhat.com/show_bug.cgi?id=886850 + */ + ResourceGroup res = entityManager.find(ResourceGroup.class,id); + if (res!=null) { + res = resourceGroupManager.getResourceGroup(caller, id); + + GroupRest rwt = fillGroup(res, uriInfo); + ret.add(rwt); + } + } + catch (Exception e) { + if (e.getCause()!=null && e.getCause() instanceof ResourceGroupNotFoundException) + log.debug("Favorite group with id "+ id + " not found - not returning to the user"); + else + log.warn("Retrieving group with id " + id + " failed: " + e.getLocalizedMessage()); + } + } + Response.ResponseBuilder builder; + if (mediaType.equals(MediaType.TEXT_HTML_TYPE)) { + builder = Response.ok(renderTemplate("listGroup", ret), mediaType); + } else { + GenericEntity<List<GroupRest>> list = new GenericEntity<List<GroupRest>>(ret) { + }; + builder = Response.ok(list); + } + + return builder.build(); + + } +
@PUT @Path("favorites/resource/{id}") @ApiOperation(value = "Add a resource as favorite for the caller") public void addFavoriteResource(@ApiParam(name = "id", value = "Id of the resource") - @PathParam("id") int id) { + @PathParam("id") int resourceId) { + + // Check if the resource exists and throw an error if not + fetchResource(resourceId); + Set<Integer> favIds = getResourceIdsForFavorites(); - if (!favIds.contains(id)) { - favIds.add(id); - updateFavorites(favIds); + if (!favIds.contains(resourceId)) { + favIds.add(resourceId); + updateResourceFavorites(favIds); + } + } + + @PUT + @Path("favorites/group/{id}") + @ApiOperation(value = "Add a group as favorite for the caller") + public void addFavoriteResourceGroup(@ApiParam(name = "id", value = "Id of the group") + @PathParam("id") int groupId) { + + // Check if the resource exists and throw an error if not + fetchGroup(groupId, false); + + Set<Integer> favIds = getGroupIdsForFavorites(); + if (!favIds.contains(groupId)) { + favIds.add(groupId); + updateGroupFavorites(favIds); } }
@@ -148,9 +233,20 @@ public class UserHandlerBean extends AbstractRestBean { Set<Integer> favIds = getResourceIdsForFavorites(); if (favIds.contains(id)) { favIds.remove(id); - updateFavorites(favIds); + updateResourceFavorites(favIds); } + }
+ @DELETE + @Path("favorites/group/{id}") + @ApiOperation(value="Remove a group from favorites") + public void removeResourceGroupFromFavorites(@ApiParam(name="id", value = "Id of the group") + @PathParam("id") int id) { + Set<Integer> favIds = getGroupIdsForFavorites(); + if (favIds.contains(id)) { + favIds.remove(id); + updateGroupFavorites(favIds); + } }
@GET @@ -182,15 +278,9 @@ public class UserHandlerBean extends AbstractRestBean { return builder.build(); }
- private void updateFavorites(Set<Integer> favIds) { + private void updateResourceFavorites(Set<Integer> favIds) { Configuration conf = caller.getUserConfiguration(); - StringBuilder builder = new StringBuilder(); - Iterator<Integer> iter = favIds.iterator(); - while (iter.hasNext()) { - builder.append(iter.next()); - if (iter.hasNext()) - builder.append('|'); - } + StringBuilder builder = buildFavStringFromSet(favIds); PropertySimple prop = conf.getSimple(RESOURCE_HEALTH_RESOURCES); if (prop==null) { conf.put(new PropertySimple(RESOURCE_HEALTH_RESOURCES,builder.toString())); @@ -201,9 +291,35 @@ public class UserHandlerBean extends AbstractRestBean { subjectManager.updateSubject(caller,caller); }
+ + private void updateGroupFavorites(Set<Integer> favIds) { + Configuration conf = caller.getUserConfiguration(); + StringBuilder builder = buildFavStringFromSet(favIds); + PropertySimple prop = conf.getSimple(GROUP_HEALTH_GROUPS); + if (prop==null) { + conf.put(new PropertySimple(GROUP_HEALTH_GROUPS,builder.toString())); + } else { + prop.setStringValue(builder.toString()); + } + caller.setUserConfiguration(conf); + subjectManager.updateSubject(caller,caller); + } + private Set<Integer> getResourceIdsForFavorites() { Configuration conf = caller.getUserConfiguration(); String favsString = conf.getSimpleValue(RESOURCE_HEALTH_RESOURCES,""); + Set<Integer> favIds = getIdsFromFavString(favsString); + return favIds; + } + + private Set<Integer> getGroupIdsForFavorites() { + Configuration conf = caller.getUserConfiguration(); + String favsString = conf.getSimpleValue(GROUP_HEALTH_GROUPS,""); + Set<Integer> favIds = getIdsFromFavString(favsString); + return favIds; + } + + private Set<Integer> getIdsFromFavString(String favsString) { Set<Integer> favIds = new TreeSet<Integer>(); if (!favsString.isEmpty()) { String[] favStringArray = favsString.split("\|"); @@ -214,4 +330,15 @@ public class UserHandlerBean extends AbstractRestBean { return favIds; }
+ private StringBuilder buildFavStringFromSet(Set<Integer> favIds) { + StringBuilder builder = new StringBuilder(); + Iterator<Integer> iter = favIds.iterator(); + while (iter.hasNext()) { + builder.append(iter.next()); + if (iter.hasNext()) + builder.append('|'); + } + return builder; + } + } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java index 69623fb..ad5e43c 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java @@ -1,3 +1,25 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ package org.rhq.enterprise.server.rest.domain;
import javax.xml.bind.annotation.XmlRootElement; @@ -9,7 +31,7 @@ import com.wordnik.swagger.annotations.ApiProperty; * A baseline * @author Heiko W. Rupp */ -@ApiClass("Representation of a metic baseline/-band") +@ApiClass("Representation of a metric baseline/-band") @XmlRootElement public class Baseline {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/EventDefinitionRest.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/EventDefinitionRest.java new file mode 100644 index 0000000..3154042 --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/EventDefinitionRest.java @@ -0,0 +1,74 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.enterprise.server.rest.domain; + +import javax.xml.bind.annotation.XmlRootElement; + +import com.wordnik.swagger.annotations.ApiClass; +import com.wordnik.swagger.annotations.ApiProperty; + +/** + * An Event definition + * @author Heiko W. Rupp + */ +@ApiClass(value = "An Event definition", description = "You can retrieve an EventDefinition and with its name create new EventSources for that resource") +@XmlRootElement +public class EventDefinitionRest { + + int id; + String name; + String displayName; + String description; + + public EventDefinitionRest() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @ApiProperty("The name of the definition, used to create EventSources") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Link.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Link.java index 3287750..a00e270 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Link.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Link.java @@ -48,9 +48,8 @@ public class Link {
@Override public String toString() { - return "Link{" + - "rel='" + rel + ''' + - ", href='" + href + ''' + - '}'; + return + href + "; " + + "rel='" + rel + ''' ; } } diff --git a/modules/integration-tests/pom.xml b/modules/integration-tests/pom.xml index 95d947a..4c31380 100644 --- a/modules/integration-tests/pom.xml +++ b/modules/integration-tests/pom.xml @@ -40,15 +40,15 @@ <name>integration.tests</name> </property> </activation> - + <modules> <module>apache-plugin-test</module> <module>jndi-access</module> <!--<module>mod_cluster-plugin-test</module>--> - <!--<module>rest-api</module>--> + <module>rest-api</module> </modules> </profile> - + <profile> <id>code-coverage</id> <activation> @@ -62,7 +62,7 @@ <!--<module>mod_cluster-plugin-test</module>--> <!--<module>rest-api</module>--> </modules> - </profile> + </profile> </profiles>
diff --git a/modules/integration-tests/rest-api/pom.xml b/modules/integration-tests/rest-api/pom.xml index a2e25f5..3ba07c4 100644 --- a/modules/integration-tests/rest-api/pom.xml +++ b/modules/integration-tests/rest-api/pom.xml @@ -18,6 +18,8 @@
<properties> <surefire-plugin.version>2.10</surefire-plugin.version> + <jackson.version>1.9.5</jackson.version> + <rest-assured.version>1.7.2</rest-assured.version> </properties>
<build> @@ -39,18 +41,32 @@ </build>
<dependencies> - <dependency> - <groupId>com.restfuse</groupId> - <artifactId>com.eclipsesource.restfuse</artifactId> - <version>1.0.0</version> + <dependency> + <groupId>com.jayway.restassured</groupId> + <artifactId>rest-assured</artifactId> + <version>${rest-assured.version}</version> <scope>test</scope> - </dependency> - <dependency> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-core-asl</artifactId> + <version>${jackson.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-mapper-asl</artifactId> + <version>${jackson.version}</version> + <scope>test</scope> + </dependency> + </dependencies>
</project> diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AbstractBase.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AbstractBase.java new file mode 100644 index 0000000..3dd20e2 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AbstractBase.java @@ -0,0 +1,48 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.modules.integrationTests.restApi; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.response.Header; + +import org.junit.Before; + +import static com.jayway.restassured.RestAssured.basic; + +/** + * Common setup for the tests + * @author Heiko W. Rupp + */ +public abstract class AbstractBase { + + static final String APPLICATION_JSON = "application/json"; + private static final String APPLICATION_XML = "application/xml"; + static Header acceptJson = new Header("Accept", APPLICATION_JSON); + static Header acceptXml = new Header("Accept", APPLICATION_XML); + + @Before + public void setUp() throws Exception { + + RestAssured.baseURI = "http://" + System.getProperty("rest.server","localhost") ; + RestAssured.port = 7080; + RestAssured.basePath = "/rest/"; + RestAssured.authentication = basic("rhqadmin","rhqadmin"); + + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/EventTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/EventTest.java new file mode 100644 index 0000000..697d6f0 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/EventTest.java @@ -0,0 +1,223 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.modules.integrationTests.restApi; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.response.Response; + +import org.junit.Test; + +import org.rhq.modules.integrationTests.restApi.d.Event; +import org.rhq.modules.integrationTests.restApi.d.EventSource; + +import static com.jayway.restassured.RestAssured.given; + +/** + * Test the event endpoints of the REST api + * @author Heiko W. Rupp + */ +public class EventTest extends AbstractBase { + + @Test + public void testGetSourcesForResource() throws Exception { + + given() + .header(acceptJson) + .pathParam("id",10001) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/event/{id}/sources"); + + } + + @Test + public void testGetDefinitionsForResource() throws Exception { + + given() + .header(acceptJson) + .pathParam("id",10001) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/event/{id}/definitions"); + + } + + @Test + public void testAddGetDeleteEventSource() throws Exception { + + EventSource es = new EventSource(); + es.setResourceId(10001); + es.setName("Event Log"); // Name of the event definition + es.setLocation("-x-test-location"); + + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id",10001) + .body(es) + .expect() + .statusCode(200) + .log().ifError() + .when() + .post("/event/{id}/sources"); + + EventSource result = response.as(EventSource.class); + + try { + + // Directly find our generated source + + response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id",result.getId()) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/event/source/{id}"); + + EventSource ev2 = response.as(EventSource.class); + assert result.equals(ev2); + + // Search in the list for the resource + response = + given() + .header(acceptJson) + .pathParam("id",10001) + .expect() + .statusCode(200) + .when() + .get("/event/{id}/sources"); + + List<Map<String,Object>> listOfMaps = response.as(List.class); + boolean found = false; + for (Map<String,Object> map: listOfMaps) { + if (map.get("id").equals(result.getId()) && map.get("name").equals(result.getName())) + found=true; + } + assert found; + } + finally { + + // Delete the source again + given() + .pathParam("id", result.getId()) + .expect() + .statusCode(200) + .when() + .delete("/event/source/{id}"); + } + } + @Test + public void testAddGetEventOnSource() throws Exception { + + EventSource es = new EventSource(); + es.setResourceId(10001); + es.setName("Event Log"); // Name of the event definition + es.setLocation("-x-test-location"); + + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id",10001) + .body(es) + .expect() + .statusCode(200) + .log().ifError() + .when() + .post("/event/{id}/sources"); + + EventSource eventSource = response.as(EventSource.class); + + long now = System.currentTimeMillis(); + try { + + // Add an event + Event event = new Event(eventSource.getId(),now,"Li la lu :->"); + List<Event> events = new ArrayList<Event>(1); + events.add(event); + + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id",eventSource.getId()) + .body(events) + .expect() + .statusCode(204) // no content returned + .log().ifError() + .when() + .post("/event/source/{id}/events"); + + + // and retrieve it again from the event source + response = + given() + .header(acceptJson) + .pathParam("id", eventSource.getId()) + .queryParam("startTime",now - 10) + .queryParam("endTime",now + 10) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/event/source/{id}/events"); + List list = response.as(List.class); + assert list.size()>0; + + // Get the list of events from the resource + response = + given() + .header(acceptJson) + .pathParam("id", 10001) + .queryParam("startTime",now - 10) + .queryParam("endTime",now + 10) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/event/{id}/events"); + list = response.as(List.class); + assert list.size()>0; + + + } + finally { + + // Delete the source again + given() + .pathParam("id", eventSource.getId()) + .expect() + .statusCode(200) + .when() + .delete("/event/source/{id}"); + } + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java deleted file mode 100644 index 570e2bf..0000000 --- a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2012 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, version 2, as - * published by the Free Software Foundation, and/or the GNU Lesser - * General Public License, version 2.1, also as published by the Free - * Software Foundation. - * - * 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 and the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.rhq.modules.integrationTests.restApi; - - -import com.eclipsesource.restfuse.AuthenticationType; -import com.eclipsesource.restfuse.Destination; -import com.eclipsesource.restfuse.HttpJUnitRunner; -import com.eclipsesource.restfuse.Method; -import com.eclipsesource.restfuse.Response; -import com.eclipsesource.restfuse.annotation.Authentication; -import com.eclipsesource.restfuse.annotation.Context; -import com.eclipsesource.restfuse.annotation.HttpTest; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test the status part of the API - */ -@RunWith(HttpJUnitRunner.class) -public class GetStatusTest { - - - - @Rule - public Destination destination = new Destination("http://" + System.getProperty("rest.server","localhost") + ":7080/rest"); - - @Context - private Response response; - - - @Test - @HttpTest( method = Method.GET, path = "/status" ) - public void testAuthRequired() { - com.eclipsesource.restfuse.Assert.assertUnauthorized(response); - } - - - @Test - @HttpTest( method = Method.GET, path = "/status" ,authentications = - @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin", password = "rhqadmin") - ) - public void testAuthRhqadmin() { - com.eclipsesource.restfuse.Assert.assertOk(response); - } - - @Test - @HttpTest( method = Method.GET, path = "/status" ,authentications = - @Authentication(type = AuthenticationType.BASIC, user = "user", password = "name23") - ) - public void testAuthRestricted() { - com.eclipsesource.restfuse.Assert.assertUnauthorized(response); - } - - -} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java new file mode 100644 index 0000000..2194281 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java @@ -0,0 +1,469 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.modules.integrationTests.restApi; + +import java.util.ArrayList; +import java.util.List; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.path.json.JsonPath; +import com.jayway.restassured.response.Response; + +import org.apache.http.HttpStatus; +import org.junit.Test; + +import org.rhq.modules.integrationTests.restApi.d.Group; +import org.rhq.modules.integrationTests.restApi.d.GroupDef; + +import static com.jayway.restassured.RestAssured.expect; +import static com.jayway.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; + +/** + * Test group related stuff + * @author Heiko W. Rupp + */ +public class GroupTest extends AbstractBase { + + @Test + public void testGetGroups() throws Exception { + expect().statusCode(200) + .when().get("/group"); + } + + @Test + public void testGetGroupsQuery() throws Exception { + given() + .queryParam("q","lala") + .expect() + .statusCode(200) + .when().get("/group"); + } + + @Test + public void testCreateGroupAndRemove() throws Exception { + Group group = new Group("-x-test-group"); + + // create the group + Response created = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + // Determine location from response + // and compare id with the found group below + String location = created.header("Location"); + int createdId = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + // Search for it + Response response = + given() + .queryParam("q", "-x-test-group") + .expect() + .statusCode(200) + .when() + .get("/group"); + + JsonPath jsonPath = response.jsonPath(); + assert jsonPath.get("[0].name").equals("-x-test-group"); // [0] as the query returns a list + int groupId = jsonPath.get("[0].id"); + assert groupId == createdId; + + // delete the group again + given() + .pathParam("id",groupId) + .expect() + .statusCode(200) + .log().ifError() + .when() + .delete("/group/{id}"); + + } + + @Test + public void testUpdateGroup() throws Exception { + Group group = new Group("-x-test-group"); + + // Generate the group + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + String location = response.header("Location"); + int id = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + group.setName("-x-test-2"); + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .pathParam("id",id) + .expect() + .statusCode(HttpStatus.SC_OK) + .log().ifError() + .when() + .put("/group/{id}"); + } + finally { + // delete the group + given() + .pathParam("id", id) + .expect() + .statusCode(200) + .log().ifError() + .when() + .delete("/group/{id}"); + } + } + + @Test + public void testAddResourceToGroup() throws Exception { + Group group = new Group("-x-test-group"); + + // Generate the group + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + String location = response.header("Location"); + int id = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .pathParam("id",id) + .pathParam("resourceId",10001) + .expect() + .statusCode(HttpStatus.SC_OK) + .log().ifError() + .when() + .put("/group/{id}/resource/{resourceId}"); + } + finally { + // delete the group + given() + .pathParam("id",id) + .expect() + .statusCode(200) + .log().ifError() + .when() + .delete("/group/{id}"); + } + } + + @Test + public void testAddNonExistingResourceToGroup() throws Exception { + Group group = new Group("-x-test-group"); + + // Generate the group + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + String location = response.header("Location"); + int id = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .pathParam("id",id) + .pathParam("resourceId",1) + .expect() + .statusCode(HttpStatus.SC_NOT_FOUND) + .log().ifError() + .when() + .put("/group/{id}/resource/{resourceId}"); + } + finally { + // delete the group + given() + .pathParam("id",id) + .expect() + .statusCode(200) + .log().ifError() + .when() + .delete("/group/{id}"); + } + } + + @Test + public void testRemoveResourceFromGroup() throws Exception { + Group group = new Group("-x-test-group"); + + // Generate the group + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + String location = response.header("Location"); + int id = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + // Add a resource to the group + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .pathParam("id",id) + .pathParam("resourceId",10001) + .expect() + .statusCode(HttpStatus.SC_OK) + .log().ifError() + .when() + .put("/group/{id}/resource/{resourceId}"); + + // and remove it again + given() + .header(acceptJson) + .pathParam("id",id) + .pathParam("resourceId",10001) + .expect() + .statusCode(HttpStatus.SC_OK) + .log().ifError() + .when() + .delete("/group/{id}/resource/{resourceId}"); + + } + finally { + // delete the group + given() + .pathParam("id",id) + .expect() + .statusCode(200) + .log().ifError() + .when() + .delete("/group/{id}"); + } + } + + @Test + public void testGetMetricDefinitionsForGroup() throws Exception { + Group group = new Group("-x-test-group"); + group.setCategory("COMPATIBLE"); + group.setResourceTypeId(10001); + + // Generate the group + Response response = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .log().everything() + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + String location = response.header("Location"); + int id = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + response = + given() + .header(acceptJson) + .pathParam("id",id) + .expect() + .statusCode(HttpStatus.SC_OK) + .log().ifError() + .when() + .get("/group/{id}/metricDefinitions"); + + } + finally { + // delete the group + given() + .pathParam("id",id) + .expect() + .statusCode(200) + .log().ifError() + .when() + .delete("/group/{id}"); + } + } + + @Test + public void testGetGroupDefinitions() throws Exception { + + expect() + .statusCode(200) + .log().ifError() + .when() + .get("/group/definitions"); + } + + @Test + public void testCreateRetrieveDeleteDefinition() throws Exception { + + GroupDef gd = new GroupDef("-x-test-def"); + gd.setDescription("Just testing"); + List<String> list = new ArrayList<String>(); + list.add("groupby resource"); + list.add("resource.name"); + gd.setExpression(list); + + Response response = + given() + .contentType(ContentType.JSON) + .header("Accept","application/json") + .body(gd) + .expect() + .statusCode(201) + .log().ifError() + .when() + .post("/group/definitions"); + + + String location = response.getHeader("Location"); + int defintionId = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + // retrieve by id + given() + .pathParam("id", defintionId) + .expect() + .statusCode(200) + .when() + .get("/group/definition/{id}"); + + // retrieve by query + Response resp = + given() + .queryParam("q", "-x-test-def") + .expect() + .statusCode(200) + .body("name", hasItem("-x-test-def")) + .log().ifError() + .when() + .get("/group/definitions"); + } finally { + + // remove the definition again + expect() + .statusCode(204) + .when() + .delete("/group/definition/" + defintionId); + } + + } + + @Test + public void testCreateUpdateRecalcDeleteDefinition() throws Exception { + + GroupDef gd = new GroupDef("-x-test-def2"); + gd.setDescription("Just testing"); + List<String> list = new ArrayList<String>(); + list.add("groupby resource.trait[partitionName]"); + list.add("resource.type.plugin = JBossAS"); + list.add("resource.type.name = JBossAS Server"); + gd.setExpression(list); + + Response response = + given() + .contentType(ContentType.JSON) + .header("Accept","application/json") + .body(gd) + .expect() + .statusCode(201) + .log().ifError() + .when() + .post("/group/definitions"); + + + String location = response.getHeader("Location"); + int defintionId = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + gd.setDescription("Hulla"); + list = new ArrayList<String>(1); + list.add("groupby resource.pluginConfiguration[productType]"); + gd.setExpression(list); + + given() + .contentType(ContentType.JSON) + .header("Accept", "application/json") + .body(gd) + .pathParam("id", defintionId) + .expect() + .statusCode(200) + .log().ifError() + .when() + .put("/group/definition/{id}"); + + given() + .contentType(ContentType.JSON) + .header("Accept","application/json") + .body(gd) // needs to be supplied as dummy + .pathParam("id", defintionId) + .queryParam("recalculate",true) + .expect() + .statusCode(204) + .log().ifError() + .when() + .put("/group/definition/{id}"); + } + finally { + + expect() + .statusCode(204) + .when() + .delete("/group/definition/" + defintionId); + } + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/MetricsTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/MetricsTest.java new file mode 100644 index 0000000..28fa806 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/MetricsTest.java @@ -0,0 +1,361 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.modules.integrationTests.restApi; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.path.json.JsonPath; +import com.jayway.restassured.response.Response; + +import org.junit.Before; +import org.junit.Test; + +import org.rhq.modules.integrationTests.restApi.d.Baseline; +import org.rhq.modules.integrationTests.restApi.d.MDataPoint; +import org.rhq.modules.integrationTests.restApi.d.Schedule; + +import static com.jayway.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; + +/** + * Test stuff related to metrics + * @author Heiko W. Rupp + */ +public class MetricsTest extends AbstractBase { + + private int numericScheduleId; + private long defaultInterval; + + @Override + @Before + public void setUp() throws Exception { + super.setUp();// is not called by junit before this one + + // Determine a schedule id for the common cases + Response r = + given() + .header(acceptJson) + .queryParam("type", "metric") + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/resource/10001/schedules"); + + JsonPath jp = r.jsonPath(); + numericScheduleId = jp.getInt("[0].scheduleId"); + defaultInterval = jp.getLong("[0].collectionInterval"); + } + + @Test + public void testGetScheduleById() throws Exception { + + given() + .header(acceptJson) + .pathParam("id", numericScheduleId) + .expect() + .statusCode(200) + .body("scheduleId", containsString("" + numericScheduleId)) + .log().ifError() + .when() + .get("/metric/schedule/{id}"); + + } + + @Test + public void testPutGetRawData() throws Exception { + + long now = System.currentTimeMillis(); + + MDataPoint dataPoint = new MDataPoint(); + dataPoint.setScheduleId(numericScheduleId); + dataPoint.setTimeStamp(now); + dataPoint.setValue(1.5); + + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id", numericScheduleId) + .pathParam("timestamp",now) + .body(dataPoint) + .expect() + .statusCode(201) + .log().ifError() + .when() + .put("/metric/data/{id}/raw/{timestamp}"); + + Response response = + given() + .header(acceptJson) + .pathParam("id", numericScheduleId) + .queryParam("startTime",now - 10) + .queryParam("endTime",now + 10) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/metric/data/{id}/raw"); + + List<Map<String,Object>> list = response.as(List.class); + assert list.size()>0; + + boolean found = false; + for (Map<String, Object> map : list) { + MDataPoint mp = new MDataPoint(map); + if (mp.equals(dataPoint)) + found = true; + } + assert found; + + } + + @Test + public void testPostGetRawData() throws Exception { + + long now = System.currentTimeMillis(); + + MDataPoint dataPoint = new MDataPoint(); + dataPoint.setScheduleId(numericScheduleId); + dataPoint.setTimeStamp(now); + dataPoint.setValue(1.5); + List<MDataPoint> points = new ArrayList<MDataPoint>(1); + points.add(dataPoint); + + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(points) + .expect() + .statusCode(204) + .log().ifError() + .when() + .post("/metric/data/raw"); + + Response response = + given() + .header(acceptJson) + .pathParam("id", numericScheduleId) + // no start and end time -> last 8h of data + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/metric/data/{id}/raw"); + + List<Map<String,Object>> list = response.as(List.class); + assert list.size()>0 : "No data retrieved"; + + boolean found = false; + for (Map<String, Object> map : list) { + MDataPoint mp = new MDataPoint(map); + if (mp.equals(dataPoint)) + found = true; + } + assert found; + + } + + @Test + public void testUpdateSchedule() throws Exception { + + Schedule schedule = new Schedule(); + schedule.setCollectionInterval(1234567); + schedule.setEnabled(true); + + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id", numericScheduleId) + .body(schedule) + .expect() + .statusCode(200) + .log().ifError() + .when() + .put("/metric/schedule/{id}"); + + // reset to original interval + + schedule.setCollectionInterval(defaultInterval); + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .pathParam("id", numericScheduleId) + .body(schedule) + .expect() + .statusCode(200) + .log().ifError() + .when() + .put("/metric/schedule/{id}"); + + } + + @Test + public void testAddGetTrait() throws Exception { + // Determine a trait schedule + Response r = + given() + .header(acceptJson) + .queryParam("type", "trait") + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/resource/10001/schedules"); + + JsonPath jp = r.jsonPath(); + int tsId = jp.getInt("[0].scheduleId"); + + String trait = "{"value":"Hello World!" }"; + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(trait) + .pathParam("id",tsId) + .expect() + .statusCode(200) // TODO 201 ? + .log().ifError() + .when() + .put("/metric/data/{id}/trait"); + + given() + .header(acceptJson) + .pathParam("id",tsId) + .expect() + .statusCode(200) + .log().ifError() + .body("value",is("Hello World!")) + .when() + .get("/metric/data/{id}/trait"); + + } + + @Test + public void testSetGetBaseline() throws Exception { + + long now = System.currentTimeMillis(); + + Baseline baseline = new Baseline(0.0,2.0,1.0,now); + + given() + .contentType(ContentType.XML) + .header(acceptJson) + .body(baseline) + .pathParam("sid", numericScheduleId) + .expect() + .statusCode(201) + .log().ifError() + .when() + .put("/metric/data/{sid}/baseline"); + + Baseline result = + given() + .header(acceptJson) + .pathParam("sid",numericScheduleId) + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/metric/data/{sid}/baseline") + .as(Baseline.class); + + assert result.equals(baseline); + } + + @Test + public void testSetBadBaseline() throws Exception { + + long now = System.currentTimeMillis(); + + Baseline baseline = new Baseline(10.0,1.0,2.0,now); + + given() + .contentType(ContentType.JSON) + .header(acceptJson) + .body(baseline) + .pathParam("sid", numericScheduleId) + .expect() + .statusCode(406) + .log().ifError() + .when() + .put("/metric/data/{sid}/baseline"); + } + + @Test + public void testGetAggregate() throws Exception { + + long now = System.currentTimeMillis(); + + Response r = + given() + .header(acceptJson) + .pathParam("scheduleId", numericScheduleId) + .expect() + .statusCode(200) + .body("scheduleId", is(numericScheduleId)) + .body("numDataPoints", is(60)) + .log().ifError() + .when() + .get("/metric/data/{scheduleId}"); + + Map map = r.as(Map.class); + List<MDataPoint> points = (List<MDataPoint>) map.get("dataPoints"); + assert points.size()==60; + + } + +// @Test Not yet - see https://bugzilla.redhat.com/show_bug.cgi?id=835647 TODO + public void testGetAggregate120Points() throws Exception { + + long now = System.currentTimeMillis(); + + Response r = + given() + .header(acceptJson) + .pathParam("scheduleId", numericScheduleId) + .queryParam("dataPoints",120) + .expect() + .statusCode(200) + .body("scheduleId", is(numericScheduleId)) + .body("numDataPoints", is(120)) + .log().ifError() + .when() + .get("/metric/data/{scheduleId}"); + + Map map = r.as(Map.class); + List<MDataPoint> points = (List<MDataPoint>) map.get("dataPoints"); + assert points.size()==120; + + } + @Test + public void testGetAggregateMinusOnePoints() throws Exception { + + given() + .header(acceptJson) + .pathParam("scheduleId", numericScheduleId) + .queryParam("dataPoints",-1) + .expect() + .statusCode(406) + .when() + .get("/metric/data/{scheduleId}"); + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java index ca63c32..f6164ba 100644 --- a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java @@ -22,83 +22,253 @@ */ package org.rhq.modules.integrationTests.restApi;
-import com.eclipsesource.restfuse.AuthenticationType; -import com.eclipsesource.restfuse.Destination; -import com.eclipsesource.restfuse.HttpJUnitRunner; -import com.eclipsesource.restfuse.Method; -import com.eclipsesource.restfuse.Response; -import com.eclipsesource.restfuse.annotation.Authentication; -import com.eclipsesource.restfuse.annotation.Context; -import com.eclipsesource.restfuse.annotation.Header; -import com.eclipsesource.restfuse.annotation.HttpTest; - -import org.junit.Rule; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.path.json.JsonPath; +import com.jayway.restassured.response.Response; + +import org.apache.http.HttpStatus; +import org.hamcrest.CoreMatchers; import org.junit.Test; -import org.junit.runner.RunWith;
-import static junit.framework.Assert.assertTrue; +import static com.jayway.restassured.RestAssured.expect; +import static com.jayway.restassured.RestAssured.get; +import static com.jayway.restassured.RestAssured.given; +import static com.jayway.restassured.RestAssured.with; +import static org.hamcrest.CoreMatchers.containsString;
/** * Test the resources part * @author Heiko W. Rupp */ -@RunWith(HttpJUnitRunner.class) -public class ResourcesTest { +public class ResourcesTest extends AbstractBase {
- @Rule - public Destination destination = new Destination("http://" + System.getProperty("rest.server","localhost") + ":7080/rest"); + @Test + public void testPlatformsPresent() { + expect() + .statusCode(200) + .body("links[0].rel", CoreMatchers.hasItem("self")) + .when() + .get("/resource/platforms.json"); + }
- @Context - private Response response; + @Test + public void testGetPlatformJson() {
+ given() + .header("Accept","application/json") + .expect() + .statusCode(200) + .contentType(ContentType.JSON) + .body("links.rel", CoreMatchers.hasItem("self")) + .when() + .get("/resource/10001");
- @HttpTest( method = Method.GET, path = "/resource/platforms" ) - public void testAuthRequired() { - com.eclipsesource.restfuse.Assert.assertUnauthorized(response); }
- @HttpTest( method = Method.GET, path = "/resource/platforms",authentications = - @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin", password = "rhqadmin") - ) - public void testPlatformsPresent() { - com.eclipsesource.restfuse.Assert.assertOk(response); - assertTrue(response.hasBody()); + @Test + public void testResourceQuery() throws Exception { + String json = get("/resource/platforms.json").asString(); + String platformName = JsonPath.with(json).get("[0].resourceName"); + + given() + .header("Accept","application/json") + .with() + .queryParam("q",platformName) + .queryParam("category","platform") + .expect() + .statusCode(200) + .body("links[0].rel", CoreMatchers.hasItem("self")) + .when() + .get("/resource"); }
- @HttpTest( method = Method.GET, path = "/resource/10001",authentications = - @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin", password = "rhqadmin"), - headers = {@Header(name = "Accept",value ="application/json")} - ) - public void testGetPlatformJson() { - com.eclipsesource.restfuse.Assert.assertOk(response); - assertTrue(response.hasBody()); + @Test + public void testResourceQueryCategory() throws Exception { + + with() + .queryParam("category","PlAtForM") + .expect() + .statusCode(200) + .when() + .get("/resource"); + + + with() + .queryParam("category","SeRvEr") + .expect() + .statusCode(200) + .when() + .get("/resource"); + + + with() + .queryParam("category", "seRVice") + .expect() + .statusCode(200) + .when() + .get("/resource"); + } + + @Test + public void testPaging() throws Exception { + + given() + .header("Accept", "application/json") + .with() + .queryParam("page", 1) + .queryParam("ps", 2) // Unusually small to provoke having more than 1 page + .queryParam("category", "service") + .expect() + .statusCode(200) + .header("Link", containsString("page=2")) + .body("links[0].rel", CoreMatchers.hasItem("self")) + .when().get("/resource"); }
- @HttpTest( method = Method.GET, path = "/resource/10001",authentications = - @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin", password = "rhqadmin"), - headers = {@Header(name = "Accept",value ="application/xml")} - ) + @Test public void testGetPlatformXml() { - com.eclipsesource.restfuse.Assert.assertOk(response); - assertTrue(response.hasBody()); + given() + .header("Accept","application/xml") + .expect() + .statusCode(200) + .contentType(ContentType.XML) + .when() + .get("/resource/10001"); }
- @HttpTest( method = Method.GET, path = "/resource/10001/schedules",authentications = - @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin", password = "rhqadmin"), - headers = {@Header(name = "Accept",value ="application/json")} - ) + @Test public void testGetPlatformSchedules() { - com.eclipsesource.restfuse.Assert.assertOk(response); - assertTrue(response.hasBody()); + given() + .header("Accept","application/json") + .expect() + .statusCode(200) + .when() + .get("/resource/10001/schedules"); }
- @HttpTest( method = Method.GET, path = "/resource/10001/children",authentications = - @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin", password = "rhqadmin"), - headers = {@Header(name = "Accept",value ="application/json")} - ) + @Test public void testGetPlatformChildren() { - com.eclipsesource.restfuse.Assert.assertOk(response); - assertTrue(response.hasBody()); + given() + .header("Accept","application/json") + .expect() + .statusCode(200) + .when() + .get("/resource/10001/children"); }
+ @Test + public void testCreatePlatform() throws Exception { + + given().body("{"value":"Linux"}") + .header("Content-Type","application/json") + .header("Accept","application/json") + .expect().statusCode(201) + .when().post("/resource/platform/api-test-dummy"); + } + + @Test + public void testCreatePlatformAndRemove() throws Exception { + + Response response = + with().body("{"value":"Linux"}") + .header("Content-Type","application/json") + .header("Accept","application/json") + .expect().statusCode(201) + .when().post("/resource/platform/api-test-dummy").andReturn(); + + String platformId = response.jsonPath().getString("resourceId"); + + given().pathParam("id",platformId) + .expect().statusCode(HttpStatus.SC_NO_CONTENT) + .when().delete("/resource/{id}"); + } + + @Test + public void testCreatePlatformWithChildAndRemove() throws Exception { + + Response response = + with().body("{"value":"Linux"}") + .header("Content-Type","application/json") + .header("Accept","application/json") + .expect() + .statusCode(201) + .when() + .post("/resource/platform/api-test-dummy"); + + String platformId = response.jsonPath().getString("resourceId"); + + try { + Response child = + with().body("{"value":"CPU"}") // Type of new resource + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .pathParam("name", "test") + .queryParam("plugin", "Platforms") + .queryParam("parentId", platformId) + .expect() + .statusCode(201) + .log().ifError() + .when().post("/resource/{name}").andReturn(); + } + finally { + given().pathParam("id",platformId) + .expect().statusCode(HttpStatus.SC_NO_CONTENT) + .when().delete("/resource/{id}"); + } + } + + @Test + public void testAlertsForResource() throws Exception { + given() + .header("Accept","application/json") + .expect().statusCode(200) + .when().get("/resource/10001/alerts"); + } + + @Test + public void testSchedulesForResource() throws Exception { + given() + .header("Accept","application/json") + .expect().statusCode(200) + .when().get("/resource/10001/schedules"); + } + + @Test + public void testAvailabilityForResource() throws Exception { + given() + .header("Accept", "application/json") + .expect().statusCode(200) + .when().get("/resource/10001/availability"); + } + + @Test + public void testAvailabilityHistoryForResource() throws Exception { + given() + .header("Accept", "application/json") + .expect().statusCode(200) + .when().get("/resource/10001/availability/history"); + } + + @Test + public void testUpdateAvailablity() throws Exception { + long now = System.currentTimeMillis()-100; + given().body("{"since":" + now + ","type":"DISABLED","resourceId":10001}") + .header("Content-Type","application/json") + .header("Accept","application/json") + .pathParam("id",10001) + .expect() + .statusCode(HttpStatus.SC_NO_CONTENT) + .log().ifError() + .when().put("/resource/{id}/availability"); + + Response response = given() + .header("Accept", "application/json") + .expect().statusCode(200) + .when().get("/resource/10001/availability"); + + String currentType = response.jsonPath().get("type"); + assert currentType.equals("DISABLED"); // TODO small window where an agent may have sent an update + + } } diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/RootURITest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/RootURITest.java new file mode 100644 index 0000000..35111f0 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/RootURITest.java @@ -0,0 +1,112 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.modules.integrationTests.restApi; + +import java.util.List; +import java.util.Map; + +import com.jayway.restassured.path.json.JsonPath; + +import org.junit.Test; + +import static com.jayway.restassured.RestAssured.expect; +import static com.jayway.restassured.RestAssured.get; +import static com.jayway.restassured.RestAssured.given; + +/** + * Test the / resource (http://localhost:7080/rest/ ) + * @author Heiko W. Rupp + */ +public class RootURITest extends AbstractBase { + + @Test + public void testRootPresent() throws Exception { + + given().header("Accept","text/html") + .expect().statusCode(200) + .when().get("/"); + + given().header("Accept","text/html") + .expect().statusCode(200) + .when().get("/index"); + + given().header("Accept","application/json") + .expect().statusCode(200) + .when().get("/"); + + given().header("Accept","application/json") + .expect().statusCode(200) + .when().get("/index"); + + expect().statusCode(200) + .when().get("/.json"); + + expect().statusCode(200) + .when().get("/.xml"); + + expect().statusCode(200) + .when().get("/.html"); + + expect().statusCode(200) + .when().get("/index.json"); + + expect().statusCode(200) + .when().get("/index.xml"); + + expect().statusCode(200) + .when().get("/index.html"); + + } + + @Test + public void testLinksInRoot() throws Exception { + + String json = get("/index.json").asString(); + List<Map<String,String>> links = JsonPath.with(json).getList(""); // with() already returns the list + + assert links != null; + assert links.size()>0; + + String[] mediaTypes = {"text/html","application/xml","application/json"}; + + for (Map<String,String> link : links) { + String href= link.get("href"); + + for (String mediaType : mediaTypes) { + given().header("Accept",mediaType) + .expect().statusCode(200) + .log().ifError() + .when().get(href); + } + } + } + + @Test + public void testJsonPWrapping() throws Exception { + + String json = get("/index.json").asString(); + assert !json.startsWith("foo("); + + String jsonp = get("/index.json?jsonp=foo").asString(); + assert jsonp.startsWith("foo("); + String jp2 = "foo(" + json+ ");"; + assert jsonp.equals(jp2); + + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/StatusTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/StatusTest.java new file mode 100644 index 0000000..073a56a --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/StatusTest.java @@ -0,0 +1,93 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi; + + +import static com.jayway.restassured.RestAssured.*; + +import org.junit.Test; + +/** + * Test the status part of the API + */ +public class StatusTest extends AbstractBase{ + + + @Test + public void testAuthRequired() { + given() + .auth().none() + .expect() + .statusCode(401) + .when() + .get("/status"); + } + + + @Test + public void testAuthRhqadmin() { + expect() + .statusCode(200) + .log().ifError() + .when() + .get("/status"); + + given() + .header("Accept","text/html") + .expect() + .statusCode(200) + .log().ifError() + .when() + .get("/status"); + + given().header("Accept","application/json") + .expect().statusCode(200) + .when().get("/status"); + + given().header("Accept","application/xml") + .expect().statusCode(200) + .when().get("/status"); + + } + + @Test + public void testAuthRestricted() { + given() + .auth().basic("user","name23") + .expect() + .statusCode(401) + .when() + .get("/rest/status"); // Wrong url does not matter, as the access is checked before hitting the rest api + } + + @Test + public void testServerOpMode() throws Exception { + + expect() + .statusCode(200) + .log().ifError() + .when() + .get("/status/server"); + + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/UserTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/UserTest.java new file mode 100644 index 0000000..07e2f29 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/UserTest.java @@ -0,0 +1,158 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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.modules.integrationTests.restApi; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.path.json.JsonPath; +import com.jayway.restassured.response.Response; + +import org.apache.http.HttpStatus; +import org.junit.Test; + +import org.rhq.modules.integrationTests.restApi.d.Group; + +import static com.jayway.restassured.RestAssured.delete; +import static com.jayway.restassured.RestAssured.expect; +import static com.jayway.restassured.RestAssured.given; + +/** + * Test user related functionality of the rest api + * @author Heiko W. Rupp + */ +public class UserTest extends AbstractBase { + + @Test + public void testGetFavoritesResources() throws Exception { + + expect().statusCode(200) + .log().ifError() + .when().get("/user/favorites/resource"); + } + + @Test + public void testGetFavoriteGroups() throws Exception { + + expect().statusCode(200) + .log().ifError() + .when().get("/user/favorites/group"); + } + + @Test + public void testAddRemoveFavoriteResources() throws Exception { + + expect().statusCode(204) + .when().put("/user/favorites/resource/10001"); + + try { + Response r = + expect() + .statusCode(200) + .when() + .get("/user/favorites/resource"); + JsonPath jp = r.jsonPath(); + assert jp.getList("resourceId").contains("10001"); + } + finally { + expect() + .statusCode(204) + .when().delete("/user/favorites/resource/10001"); + } + } + + @Test + public void testAddRemoveFavoriteGroup() throws Exception { + Group group = new Group("-x-test-group-user"); + + // create a group + Response created = + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(group) + .expect() + .statusCode(HttpStatus.SC_CREATED) + .log().ifError() + .when() + .post("/group"); + + String location = created.header("Location"); + int groupId = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + + try { + given() + .header("Accept", "application/json") + .contentType(ContentType.XML) + .pathParam("id", groupId) + .expect() + .statusCode(204) + .when() + .put("/user/favorites/group/{id}"); + + Response r = + given() + .header("Accept", "application/json") + .expect() + .statusCode(200) + .when() + .get("/user/favorites/group"); +// JsonPath jp = r.jsonPath(); // TODO enable as soon as JsonPath syntax is known +// assert jp.getList("$[].id").contains(""+groupId); + } + finally { + given() + .pathParam("id",groupId) + .expect() + .statusCode(204) + .when() + .delete("/user/favorites/group/{id}"); + + delete("/group/" + groupId); + } + } + + @Test + public void testAddNonExistingResource() throws Exception { + + expect() + .statusCode(404) + .when() + .put("/user/favorites/resource/1"); // RHQ resource ids are > 10k + } + + @Test + public void testAddNonExistingGroup() throws Exception { + + expect() + .statusCode(404) + .log().everything() + .when() + .put("/user/favorites/group/1"); // RHQ group ids are > 10k + } + + @Test + public void testGetUserInfo() throws Exception { + given() + .pathParam("id","rhqadmin") + .expect() + .statusCode(200) + .when() + .get("/user/{id}"); + + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Baseline.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Baseline.java new file mode 100644 index 0000000..f596e96 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Baseline.java @@ -0,0 +1,107 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +import javax.xml.bind.annotation.XmlRootElement; + +/** + * A metric baseline + * @author Heiko W. Rupp + */ +@XmlRootElement +public class Baseline { + + double min; + double max; + double mean; + long computeTime; + + public Baseline() { + } + + public Baseline(double min, double max, double mean, long computeTime) { + this.min = min; + this.max = max; + this.mean = mean; + this.computeTime = computeTime; + } + + public double getMin() { + return min; + } + + public void setMin(double min) { + this.min = min; + } + + public double getMax() { + return max; + } + + public void setMax(double max) { + this.max = max; + } + + public double getMean() { + return mean; + } + + public void setMean(double mean) { + this.mean = mean; + } + + public long getComputeTime() { + return computeTime; + } + + public void setComputeTime(long computeTime) { + this.computeTime = computeTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Baseline baseline = (Baseline) o; + + if (Double.compare(baseline.max, max) != 0) return false; + if (Double.compare(baseline.mean, mean) != 0) return false; + if (Double.compare(baseline.min, min) != 0) return false; + + return true; + } + + @Override + public int hashCode() { + int result; + long temp; + temp = min != +0.0d ? Double.doubleToLongBits(min) : 0L; + result = (int) (temp ^ (temp >>> 32)); + temp = max != +0.0d ? Double.doubleToLongBits(max) : 0L; + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = mean != +0.0d ? Double.doubleToLongBits(mean) : 0L; + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Event.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Event.java new file mode 100644 index 0000000..89adef2 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Event.java @@ -0,0 +1,85 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +/** + * An Event for testing + * @author Heiko W. Rupp + */ +public class Event { + + int id; + String detail; + int sourceId; + long timestamp; + String severity = "INFO"; + + public Event() { + } + + public Event(int sourceId, long timestamp, String detail) { + this.detail = detail; + this.sourceId = sourceId; + this.timestamp = timestamp; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public int getSourceId() { + return sourceId; + } + + public void setSourceId(int sourceId) { + this.sourceId = sourceId; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public String getSeverity() { + return severity; + } + + public void setSeverity(String severity) { + this.severity = severity; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/EventSource.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/EventSource.java new file mode 100644 index 0000000..9ba191d --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/EventSource.java @@ -0,0 +1,116 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +/** + * EventSource for testing + * @author Heiko W. Rupp + */ +public class EventSource { + + int id; + String name; + String location; + int resourceId; + String displayName; + String description; + + public EventSource() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public int getResourceId() { + return resourceId; + } + + public void setResourceId(int resourceId) { + this.resourceId = resourceId; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EventSource that = (EventSource) o; + + if (id != that.id) return false; + if (resourceId != that.resourceId) return false; + if (description != null ? !description.equals(that.description) : that.description != null) return false; + if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) return false; + if (!location.equals(that.location)) return false; + if (!name.equals(that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + name.hashCode(); + result = 31 * result + location.hashCode(); + result = 31 * result + resourceId; + result = 31 * result + (displayName != null ? displayName.hashCode() : 0); + result = 31 * result + (description != null ? description.hashCode() : 0); + return result; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Group.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Group.java new file mode 100644 index 0000000..d576f4e --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Group.java @@ -0,0 +1,65 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +/** + * A group for testing + * @author Heiko W. Rupp + */ +public class Group { + + String name; + String category = "MIXED"; + Integer resourceTypeId; + + public Group() { + } + + public Group(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public Integer getResourceTypeId() { + return resourceTypeId; + } + + public void setResourceTypeId(Integer resourceTypeId) { + this.resourceTypeId = resourceTypeId; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/GroupDef.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/GroupDef.java new file mode 100644 index 0000000..16bfda3 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/GroupDef.java @@ -0,0 +1,76 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +import java.util.List; + +/** + * A Group definition for testing + * @author Heiko W. Rupp + */ +public class GroupDef { + + private int id; + private String name; + private String description; + private List<String> expression; + + public GroupDef() { + } + + public GroupDef(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List<String> getExpression() { + return expression; + } + + public void setExpression(List<String> expression) { + this.expression = expression; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/MDataPoint.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/MDataPoint.java new file mode 100644 index 0000000..f42155d --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/MDataPoint.java @@ -0,0 +1,91 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +import java.util.Map; + +/** + * A numeric data point for testing + * @author Heiko W. Rupp + */ +public class MDataPoint { + + long timeStamp; + Double value; + private int scheduleId; + + public MDataPoint() { + } + + public MDataPoint(Map<String,Object> in) { + timeStamp = (Long) in.get("timeStamp"); + value = (Double) in.get("value"); + scheduleId = (Integer)in.get("scheduleId"); + } + + public long getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } + + public int getScheduleId() { + return scheduleId; + } + + public void setScheduleId(int scheduleId) { + this.scheduleId = scheduleId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MDataPoint that = (MDataPoint) o; + + if (scheduleId != that.scheduleId) return false; + if (timeStamp != that.timeStamp) return false; + if (value != null ? !value.equals(that.value) : that.value != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (timeStamp ^ (timeStamp >>> 32)); + result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + scheduleId; + return result; + } +} diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Schedule.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Schedule.java new file mode 100644 index 0000000..be7344d --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Schedule.java @@ -0,0 +1,61 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.rhq.modules.integrationTests.restApi.d; + +/** + * A metric schedule for testing + * @author Heiko W. Rupp + */ +public class Schedule { + + private int scheduleId; + private boolean enabled; + private long collectionInterval; + + public Schedule() { + } + + public int getScheduleId() { + return scheduleId; + } + + public void setScheduleId(int scheduleId) { + this.scheduleId = scheduleId; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public long getCollectionInterval() { + return collectionInterval; + } + + public void setCollectionInterval(long collectionInterval) { + this.collectionInterval = collectionInterval; + } +}
commit f414d81fc9e0ce155982f25c4afcba615ec936d2 Author: Thomas SEGISMONT tsegismo@redhat.com Date: Mon Dec 17 23:30:19 2012 +0100
Revert "Bug 887320 - Agent raise OutOfMemoryError when adding new Deployment child resource on AS7"
This reverts commit 52bdd6fa4f1fa658abd0a190282ea2f8f3b10b4d.
Fix will not work (HttpRetryException): streaming mode does not support authentication
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java index e1c50cb..a7fe82d 100644 --- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java +++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java @@ -97,7 +97,6 @@ public class ASUploadConnection { connection.setReadTimeout(timeout * 1000); // default 60s connection.setDoInput(true); connection.setDoOutput(true); - connection.setChunkedStreamingMode(1024 * 64); // 64k chunks connection.setRequestMethod(POST_REQUEST_METHOD); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY_PARAM);
commit d937bc35698d34ca39aa99f885b82656762269ee Author: John Mazzitelli mazz@redhat.com Date: Mon Dec 17 16:57:58 2012 -0500
add a comment to the props file
diff --git a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml index 9b2742e..4e27030 100644 --- a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml +++ b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml @@ -401,6 +401,8 @@ rhq.server.email.from-address=rhqadmin@localhost # the RHQ Server will bind to (jboss.bind.address) and the ports # browsers will use to access the RHQ web application # (rhq.server.socket.binding.port.http, rhq.server.socket.binding.port.https) +# If you change the binding address, you might also want to change +# "rhq.autoinstall.public-endpoint-address" as well. #############################################################################
jboss.bind.address=0.0.0.0
commit 52bdd6fa4f1fa658abd0a190282ea2f8f3b10b4d Author: Thomas SEGISMONT tsegismo@redhat.com Date: Mon Dec 17 15:01:42 2012 +0100
Bug 887320 - Agent raise OutOfMemoryError when adding new Deployment child resource on AS7
HttpUrlConnection keeps data in memory until output stream is closed if content length is unknown. Setting transfer mechanism to chunks solves the problem.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java index a7fe82d..e1c50cb 100644 --- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java +++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java @@ -97,6 +97,7 @@ public class ASUploadConnection { connection.setReadTimeout(timeout * 1000); // default 60s connection.setDoInput(true); connection.setDoOutput(true); + connection.setChunkedStreamingMode(1024 * 64); // 64k chunks connection.setRequestMethod(POST_REQUEST_METHOD); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY_PARAM);
commit 35000db271b01396052737dbda03551802277c3b Author: Lukas Krejci lkrejci@redhat.com Date: Sat Dec 15 00:44:26 2012 +0100
Ooops, forgot to implement the exception check in the JndiAccessTest.
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java index d330ba1..2e088f8 100644 --- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java +++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java @@ -35,6 +35,7 @@ import javax.script.ScriptException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.testng.Assert; import org.testng.annotations.Parameters; import org.testng.annotations.Test;
@@ -253,7 +254,14 @@ public class JndiAccessTest extends Arquillian { }
private void checkIsDesiredSecurityException(Throwable t) { - //TODO implement - System.out.println(t); + String message = t.getMessage(); + String permissionTrace = "org.rhq.allow.server.internals.access"; + + if (!message.contains(permissionTrace)) { + Assert + .fail( + "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. ", + t); + } } }
commit c195ba605e0c7816db5bfe212e9265268d6c5030 Author: John Mazzitelli mazz@redhat.com Date: Fri Dec 14 18:33:53 2012 -0500
add https connector - use self-signed cert by default
diff --git a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/Address.java b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/Address.java index c35bbda..d07f469 100644 --- a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/Address.java +++ b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/Address.java @@ -69,7 +69,7 @@ public class Address implements Cloneable { }
@Override - public Address clone() throws CloneNotSupportedException { + public Address clone() { Address clone = new Address(); clone.addressNode = addressNode.clone(); return clone; diff --git a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/DatasourceJBossASClient.java b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/DatasourceJBossASClient.java index c3ceec2..fc7ae88 100644 --- a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/DatasourceJBossASClient.java +++ b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/DatasourceJBossASClient.java @@ -238,11 +238,7 @@ public class DatasourceJBossASClient extends JBossASClient { final ModelNode requestN = new ModelNode(); requestN.get(OPERATION).set(ADD); requestN.get(ADDRESS).set(addr.getAddressNode()); - if (entry.getValue().indexOf("${") > -1) { - requestN.get(VALUE).setExpression(entry.getValue()); - } else { - requestN.get(VALUE).set(entry.getValue()); - } + setPossibleExpression(requestN, VALUE, entry.getValue()); batch[n++] = requestN; }
@@ -327,11 +323,7 @@ public class DatasourceJBossASClient extends JBossASClient { final ModelNode requestN = new ModelNode(); requestN.get(OPERATION).set(ADD); requestN.get(ADDRESS).set(addr.getAddressNode()); - if (entry.getValue().indexOf("${") > -1) { - requestN.get(VALUE).setExpression(entry.getValue()); - } else { - requestN.get(VALUE).set(entry.getValue()); - } + setPossibleExpression(requestN, VALUE, entry.getValue()); batch[n++] = requestN; }
diff --git a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java index 9ceb300..fa4a5b9 100644 --- a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java +++ b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/JBossASClient.java @@ -107,7 +107,7 @@ public class JBossASClient { public static ModelNode createWriteAttributeRequest(String attributeName, String attributeValue, Address address) { final ModelNode op = createRequest(WRITE_ATTRIBUTE, address); op.get(NAME).set(attributeName); - op.get(VALUE).set(attributeValue); + setPossibleExpression(op, VALUE, attributeValue); return op; }
@@ -220,6 +220,29 @@ public class JBossASClient { return "Unknown failure"; }
+ /** + * This sets the given node's named attribute to the given value. If the value + * appears to be an expression (that is, contains "${" somewhere in it), this will + * set the value as an expression on the node. + * + * @param node the node whose attribute is to be set + * @param name the name of the attribute whose value is to be set + * @param value the value, possibly an expression + * + * @return returns the node + */ + public static ModelNode setPossibleExpression(ModelNode node, String name, String value) { + if (value != null) { + if (value.contains("${")) { + return node.get(name).setExpression(value); + } else { + return node.get(name).set(value); + } + } else { + return node.get(name).clear(); + } + } + ///////////////////////////////////////////////////////////////// // Non-static methods that need the client
diff --git a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/WebJBossASClient.java b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/WebJBossASClient.java index 59ab471..f1d030d 100644 --- a/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/WebJBossASClient.java +++ b/modules/common/jboss-as-dmr-client/src/main/java/org/rhq/common/jbossas/client/controller/WebJBossASClient.java @@ -31,6 +31,8 @@ public class WebJBossASClient extends JBossASClient { public static final String SUBSYSTEM_WEB = "web"; public static final String VIRTUAL_SERVER = "virtual-server"; public static final String DEFAULT_HOST = "default-host"; + public static final String CONNECTOR = "connector"; + public static final String SSL = "ssl";
public WebJBossASClient(ModelControllerClient client) { super(client); @@ -45,12 +47,381 @@ public class WebJBossASClient extends JBossASClient { * @throws Exception */ public void setEnableWelcomeRoot(boolean enableFlag) throws Exception { - Address address = Address.root().add(SUBSYSTEM, SUBSYSTEM_WEB, VIRTUAL_SERVER, DEFAULT_HOST); - ModelNode req = createWriteAttributeRequest("enable-welcome-root", Boolean.toString(enableFlag), address); - ModelNode response = execute(req); + final Address address = Address.root().add(SUBSYSTEM, SUBSYSTEM_WEB, VIRTUAL_SERVER, DEFAULT_HOST); + final ModelNode req = createWriteAttributeRequest("enable-welcome-root", Boolean.toString(enableFlag), address); + final ModelNode response = execute(req); if (!isSuccess(response)) { throw new FailureException(response); } return; } + + /** + * Checks to see if there is already a connector with the given name. + * + * @param name the name to check + * @return true if there is a connector with the given name already in existence + */ + public boolean isConnector(String name) throws Exception { + final Address address = Address.root().add(SUBSYSTEM, SUBSYSTEM_WEB, CONNECTOR, name); + return null != readResource(address); + } + + /** + * Use this to modify an attribute for an existing connector. + * @param connectorName the existing connector whose attribute is to be changed + * @param attribName the attribute to get a new value + * @param attribValue the new value of the attribute + * @throws Exception if failed to change the attribute on the named connector + */ + public void changeConnector(String connectorName, String attribName, String attribValue) throws Exception { + final Address address = Address.root().add(SUBSYSTEM, SUBSYSTEM_WEB, CONNECTOR, connectorName); + final ModelNode op = createWriteAttributeRequest(attribName, attribValue, address); + final ModelNode response = execute(op); + if (!isSuccess(response)) { + throw new FailureException(response); + } + return; + } + + /** + * Add a new web connector, which may be a secure SSL connector (HTTPS) or not (HTTP). + * + * @param name + * @param connectorConfig + * @throws Exception + */ + public void addConnector(String name, ConnectorConfiguration connectorConfig) throws Exception { + ModelNode fullRequest; + + final Address connectorAddress = Address.root().add(SUBSYSTEM, SUBSYSTEM_WEB, CONNECTOR, name); + final ModelNode connectorRequest = createRequest(ADD, connectorAddress); + setPossibleExpression(connectorRequest, "executor", connectorConfig.getExecutor()); + setPossibleExpression(connectorRequest, "max-connections", connectorConfig.getMaxConnections()); + setPossibleExpression(connectorRequest, "max-post-size", connectorConfig.getMaxPostSize()); + setPossibleExpression(connectorRequest, "max-save-post-size", connectorConfig.getMaxSavePostSize()); + setPossibleExpression(connectorRequest, "protocol", connectorConfig.getProtocol()); + setPossibleExpression(connectorRequest, "proxy-name", connectorConfig.getProxyName()); + setPossibleExpression(connectorRequest, "proxy-port", connectorConfig.getProxyPort()); + setPossibleExpression(connectorRequest, "scheme", connectorConfig.getScheme()); + setPossibleExpression(connectorRequest, "socket-binding", connectorConfig.getSocketBinding()); + setPossibleExpression(connectorRequest, "redirect-port", connectorConfig.getRedirectPort()); + setPossibleExpression(connectorRequest, "enabled", String.valueOf(connectorConfig.isEnabled())); + setPossibleExpression(connectorRequest, "enable-lookups", String.valueOf(connectorConfig.isEnableLookups())); + setPossibleExpression(connectorRequest, "secure", String.valueOf(connectorConfig.isSecure())); + + SSLConfiguration sslConfig = connectorConfig.getSslConfiguration(); + if (sslConfig != null) { + final Address sslAddress = connectorAddress.clone().add(SSL, "configuration"); // name MUST be "configuration" here + final ModelNode sslRequest = createRequest(ADD, sslAddress); + setPossibleExpression(sslRequest, "ca-certificate-file", sslConfig.getCaCertificateFile()); + setPossibleExpression(sslRequest, "ca-certificate-password", sslConfig.getCaCertificatePassword()); + setPossibleExpression(sslRequest, "ca-revocation-url", sslConfig.getCaRevocationUrl()); + setPossibleExpression(sslRequest, "certificate-file", sslConfig.getCertificateFile()); + setPossibleExpression(sslRequest, "certificate-key-file", sslConfig.getCertificateKeyFile()); + setPossibleExpression(sslRequest, "cipher-suite", sslConfig.getCipherSuite()); + setPossibleExpression(sslRequest, "key-alias", sslConfig.getKeyAlias()); + setPossibleExpression(sslRequest, "keystore-type", sslConfig.getKeystoreType()); + setPossibleExpression(sslRequest, "name", sslConfig.getName()); + setPossibleExpression(sslRequest, "password", sslConfig.getPassword()); + setPossibleExpression(sslRequest, "protocol", sslConfig.getProtocol()); + setPossibleExpression(sslRequest, "session-cache-size", sslConfig.getSessionCacheSize()); + setPossibleExpression(sslRequest, "session-timeout", sslConfig.getSessionTimeout()); + setPossibleExpression(sslRequest, "truststore-type", sslConfig.getTruststoreType()); + setPossibleExpression(sslRequest, "verify-client", sslConfig.getVerifyClient()); + setPossibleExpression(sslRequest, "verify-depth", sslConfig.getVerifyDepth()); + fullRequest = createBatchRequest(connectorRequest, sslRequest); + } else { + fullRequest = connectorRequest; + } + + final ModelNode response = execute(fullRequest); + if (!isSuccess(response)) { + throw new FailureException(response, "Failed to add new connector [" + name + "]"); + } + return; + } + + public static class ConnectorConfiguration { + private boolean enabled = true; + private boolean enableLookups = false; + private String executor; + private String maxConnections; + private String maxSavePostSize; + private String maxPostSize; + private String protocol = "HTTP/1.1"; + private String proxyPort; + private String proxyName; + private String scheme; + private boolean secure = false; + private String socketBinding; + private String redirectPort; + private SSLConfiguration sslConfiguration; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnableLookups() { + return enableLookups; + } + + public void setEnableLookups(boolean enableLookups) { + this.enableLookups = enableLookups; + } + + public String getExecutor() { + return executor; + } + + public void setExecutor(String executor) { + this.executor = executor; + } + + public String getMaxConnections() { + return maxConnections; + } + + public void setMaxConnections(String maxConnections) { + this.maxConnections = maxConnections; + } + + public String getMaxSavePostSize() { + return maxSavePostSize; + } + + public void setMaxSavePostSize(String maxSavePostSize) { + this.maxSavePostSize = maxSavePostSize; + } + + public String getMaxPostSize() { + return maxPostSize; + } + + public void setMaxPostSize(String maxPostSize) { + this.maxPostSize = maxPostSize; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getProxyPort() { + return proxyPort; + } + + public void setProxyPort(String proxyPort) { + this.proxyPort = proxyPort; + } + + public String getProxyName() { + return proxyName; + } + + public void setProxyName(String proxyName) { + this.proxyName = proxyName; + } + + public String getScheme() { + return scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public String getSocketBinding() { + return socketBinding; + } + + public void setSocketBinding(String socketBinding) { + this.socketBinding = socketBinding; + } + + public String getRedirectPort() { + return redirectPort; + } + + public void setRedirectPort(String redirectPort) { + this.redirectPort = redirectPort; + } + + public SSLConfiguration getSslConfiguration() { + return sslConfiguration; + } + + public void setSslConfiguration(SSLConfiguration sslConfiguration) { + this.sslConfiguration = sslConfiguration; + // if we are given an SSL config, we must be secure, so set that now, too + if (sslConfiguration != null) { + this.secure = true; + } + } + } + + public static class SSLConfiguration { + private String caCertificateFile; + private String caCertificatePassword; + private String caRevocationUrl; + private String certificateKeyFile; + private String certificateFile; + private String cipherSuite; + private String keyAlias; + private String keystoreType; + private String name; + private String password; + private String protocol = "HTTP/1.1"; + private String sessionCacheSize; + private String sessionTimeout; + private String truststoreType; + private String verifyClient; + private String verifyDepth; + + public String getCaCertificateFile() { + return caCertificateFile; + } + + public void setCaCertificateFile(String caCertificateFile) { + this.caCertificateFile = caCertificateFile; + } + + public String getCaCertificatePassword() { + return caCertificatePassword; + } + + public void setCaCertificationPassword(String caCertificatePassword) { + this.caCertificatePassword = caCertificatePassword; + } + + public String getCaRevocationUrl() { + return caRevocationUrl; + } + + public void setCaRevocationUrl(String caRevocationUrl) { + this.caRevocationUrl = caRevocationUrl; + } + + public String getCertificateKeyFile() { + return certificateKeyFile; + } + + public void setCertificateKeyFile(String certificateKeyFile) { + this.certificateKeyFile = certificateKeyFile; + } + + public String getCertificateFile() { + return certificateFile; + } + + public void setCertificateFile(String certificateFile) { + this.certificateFile = certificateFile; + } + + public String getCipherSuite() { + return cipherSuite; + } + + public void setCipherSuite(String cipherSuite) { + this.cipherSuite = cipherSuite; + } + + public String getKeyAlias() { + return keyAlias; + } + + public void setKeyAlias(String keyAlias) { + this.keyAlias = keyAlias; + } + + public String getKeystoreType() { + return keystoreType; + } + + public void setKeystoreType(String keystoreType) { + this.keystoreType = keystoreType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getSessionCacheSize() { + return sessionCacheSize; + } + + public void setSessionCacheSize(String sessionCacheSize) { + this.sessionCacheSize = sessionCacheSize; + } + + public String getSessionTimeout() { + return sessionTimeout; + } + + public void setSessionTimeout(String sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + public String getTruststoreType() { + return truststoreType; + } + + public void setTruststoreType(String truststoreType) { + this.truststoreType = truststoreType; + } + + public String getVerifyClient() { + return verifyClient; + } + + /** + * @param verifyClient can be "true" or "want" (and preassumably "need") + */ + public void setVerifyClient(String verifyClient) { + this.verifyClient = verifyClient; + } + + public String getVerifyDepth() { + return verifyDepth; + } + + public void setVerifyDepth(String verifyDepth) { + this.verifyDepth = verifyDepth; + } + } } diff --git a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml index d84f8c4..9b2742e 100644 --- a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml +++ b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml @@ -484,16 +484,17 @@ rhq.communications.multicast-detector.port=16162
# Server-side SSL Security Configuration for HTTPS thru Tomcat # These are used for browser https access and -# for incoming messages from agents over sslservlet transport -# [you cannot use ${x} variables - see https://jira.jboss.org/jira/browse/JBWEB-74] +# for incoming messages from agents over sslservlet transport. +# Relative filenames are relative to jboss.server.config.dir. +# [you cannot use ${x} variables in these rhq.server.tomcat settings] rhq.server.tomcat.security.client-auth-mode=want rhq.server.tomcat.security.secure-socket-protocol=TLS rhq.server.tomcat.security.algorithm=SunX509 rhq.server.tomcat.security.keystore.alias=RHQ -rhq.server.tomcat.security.keystore.file=conf/rhq.keystore +rhq.server.tomcat.security.keystore.file=rhq.keystore rhq.server.tomcat.security.keystore.password=RHQManagement rhq.server.tomcat.security.keystore.type=JKS -rhq.server.tomcat.security.truststore.file=conf/rhq.truststore +rhq.server.tomcat.security.truststore.file=rhq.truststore rhq.server.tomcat.security.truststore.password=RHQManagement rhq.server.tomcat.security.truststore.type=JKS
diff --git a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java index 589efca..81dcdd0 100644 --- a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java +++ b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java @@ -384,9 +384,6 @@ public class InstallerServiceImpl implements InstallerService {
String appServerConfigDir = getAppServerConfigDir();
- // create a keystore whose cert has a CN of this server's public endpoint address - ServerInstallUtil.createKeystore(serverDetails, appServerConfigDir); - // create an rhqadmin/rhqadmin management user so when discovered, the AS7 plugin can immediately // connect to the RHQ Server. ServerInstallUtil.createDefaultManagementUser(serverDetails, appServerConfigDir); @@ -401,6 +398,9 @@ public class InstallerServiceImpl implements InstallerService {
// Make sure our deployment scanner is configured as we need it ServerInstallUtil.configureDeploymentScanner(mcc); + + // create a keystore whose cert has a CN of this server's public endpoint address + ServerInstallUtil.prepareWebConnectors(mcc, serverDetails, appServerConfigDir, serverProperties); } finally { safeClose(mcc); } diff --git a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerInstallUtil.java b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerInstallUtil.java index 5c0316d..85dedf9 100644 --- a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerInstallUtil.java +++ b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerInstallUtil.java @@ -55,6 +55,9 @@ import org.rhq.common.jbossas.client.controller.JBossASClient; import org.rhq.common.jbossas.client.controller.MessagingJBossASClient; import org.rhq.common.jbossas.client.controller.SecurityDomainJBossASClient; import org.rhq.common.jbossas.client.controller.SocketBindingJBossASClient; +import org.rhq.common.jbossas.client.controller.WebJBossASClient; +import org.rhq.common.jbossas.client.controller.WebJBossASClient.ConnectorConfiguration; +import org.rhq.common.jbossas.client.controller.WebJBossASClient.SSLConfiguration; import org.rhq.core.db.DatabaseType; import org.rhq.core.db.DatabaseTypeFactory; import org.rhq.core.db.DbUtil; @@ -162,9 +165,9 @@ public class ServerInstallUtil { public static void setupMailService(ModelControllerClient mcc, HashMap<String, String> serverProperties) throws Exception {
- String fromAddressExpr = "${" + ServerProperties.PROP_EMAIL_FROM_ADDRESS + ":rhqadmin@localhost.com}"; - //String smtpHostExpr = "${" + ServerProperties.PROP_EMAIL_SMTP_HOST + ":localhost}"; - String smtpPortExpr = "${" + ServerProperties.PROP_EMAIL_SMTP_PORT + ":25}"; + String fromAddressExpr = buildExpression(ServerProperties.PROP_EMAIL_FROM_ADDRESS, serverProperties, true); + String smtpHostExpr = buildExpression(ServerProperties.PROP_EMAIL_SMTP_HOST, serverProperties, false); // enable when AS7-5321 is fixed + String smtpPortExpr = buildExpression(ServerProperties.PROP_EMAIL_SMTP_PORT, serverProperties, true);
// Tweek the mail configuration that comes out of box. Setup a batch request to write the proper attributes.
@@ -179,16 +182,14 @@ public class ServerInstallUtil { "remote-destination-outbound-socket-binding", "mail-smtp"); ModelNode writeHost = JBossASClient.createRequest(JBossASClient.WRITE_ATTRIBUTE, addr); writeHost.get(JBossASClient.NAME).set("host"); - // TODO: see https://issues.jboss.org/browse/AS7-5321 - that must be fixed before supporting expressions - //writeHost.get(JBossASClient.VALUE).setExpression(smtpHostExpr); - writeHost.get(JBossASClient.VALUE).set(serverProperties.get(ServerProperties.PROP_EMAIL_SMTP_HOST)); // remove when AS7-5321 is fixed + JBossASClient.setPossibleExpression(writeHost, JBossASClient.VALUE, smtpHostExpr);
// now the SMTP port addr = Address.root().add("socket-binding-group", "standard-sockets", "remote-destination-outbound-socket-binding", "mail-smtp"); ModelNode writePort = JBossASClient.createRequest(JBossASClient.WRITE_ATTRIBUTE, addr); writePort.get(JBossASClient.NAME).set("port"); - writePort.get(JBossASClient.VALUE).setExpression(smtpPortExpr); + JBossASClient.setPossibleExpression(writePort, JBossASClient.VALUE, smtpPortExpr);
ModelNode batch = JBossASClient.createBatchRequest(writeFromAddr, writeHost, writePort); JBossASClient client = new JBossASClient(mcc); @@ -1166,12 +1167,150 @@ public class ServerInstallUtil { }
/** + * Ensures our web connectors are configured properly. + * + * @param mcc the AS client + * @param serverDetails details of the server being installed + * @param configDirStr location of a configuration directory where the keystore is to be stored + * @param serverProperties the full set of server properties + * @throws Exception + */ + public static void prepareWebConnectors(ModelControllerClient mcc, ServerDetails serverDetails, String configDirStr, + HashMap<String, String> serverProperties) throws Exception { + + // first create our keystore + File keystoreFile = createKeystore(serverDetails, configDirStr); + + // out of box, we always get a non-secure connector (called "http")... + final String connectorName = "http"; + + // ...but we want a secure SSL connector, too. + // This is the name of the secure connector we want to create. + final String sslConnectorName = "https"; + + WebJBossASClient client = new WebJBossASClient(mcc); + + if (!client.isConnector(sslConnectorName)) { + LOG.info("Creating https connector..."); + + SSLConfiguration ssl = new SSLConfiguration(); + + // truststore + ssl.setCaCertificateFile(getAbsoluteFileLocation("rhq.server.tomcat.security.truststore.file", + serverProperties, configDirStr)); // this cannot be an expression - AS7 doesn't support that now + ssl.setCaCertificationPassword(buildExpression("rhq.server.tomcat.security.truststore.password", + serverProperties, false)); + ssl.setTruststoreType(buildExpression("rhq.server.tomcat.security.truststore.type", serverProperties, false)); + + // keystore + ssl.setCertificateKeyFile(getAbsoluteFileLocation("rhq.server.tomcat.security.keystore.file", + serverProperties, configDirStr)); // this cannot be an expression - AS7 doesn't support that now + ssl.setPassword(buildExpression("rhq.server.tomcat.security.keystore.password", serverProperties, false)); + ssl.setKeyAlias(buildExpression("rhq.server.tomcat.security.keystore.alias", serverProperties, false)); + ssl.setKeystoreType(buildExpression("rhq.server.tomcat.security.keystore.type", serverProperties, false)); + + // SSL protocol config + ssl.setProtocol(buildExpression("rhq.server.tomcat.security.secure-socket-protocol", serverProperties, + false)); + ssl.setVerifyClient(buildExpression("rhq.server.tomcat.security.client-auth-mode", serverProperties, + false)); + + // note: there doesn't appear to be a way for AS7 to support algorithm, like SunX509 or IbmX509 + // so I think it just uses the JVM's default. This means "rhq.server.tomcat.security.algorithm" is unused + + ConnectorConfiguration connector = new ConnectorConfiguration(); + connector.setMaxConnections(buildExpression("rhq.server.startup.web.max-connections", serverProperties, + false)); + connector.setScheme("https"); + connector.setSocketBinding("https"); + connector.setSslConfiguration(ssl); + + // create it now + client.addConnector("https", connector); + + LOG.info("https connector created."); + } + + if (client.isConnector(connectorName)) { + client.changeConnector(connectorName, "redirect-port", + buildExpression("rhq.server.socket.binding.port.https", serverProperties, false)); + } else { + LOG.warn("There doesn't appear to be a http connector configured already - this is strange."); + } + } + + /** + * For a property whose value might be a file, return that file's absolute path. If the property + * has a value whose pathname is already absolute, return it. If the property has a value whose path + * is relative, it is considered relative to defaultRootDir and its absolute path based on that root dir + * is returned. + * + * @param propertyName the property whose value in properties is considered a pathname (which may + * relative or it may be absolute). + * @param properties where to find the named property + * @param defaultRootDir if the property value is a relative file path, this is what it is relative to + * @return the absolute path of the file + */ + private static String getAbsoluteFileLocation(String propertyName, HashMap<String, String> properties, + String defaultRootDir) { + + if (properties == null || !properties.containsKey(propertyName)) { + return null; + } + + String propertyValue = properties.get(propertyName); + File path = new File(propertyValue); + if (path.isAbsolute()) { + return path.getAbsolutePath(); + } else { + return new File(defaultRootDir, propertyValue).getAbsolutePath(); + } + } + + /** + * You would think this would be simple - just set a value to ${propName:defaultVal} but some + * JBossAS attributes don't support expressions when you think they could or should. In this + * case, we'll pass in supportsExpression=false until we support AS versions that support + * expressions (at which time we'll change to code to pass in true for those attributes). + * If supportsExpression is true, the returned string will be ${propName} if defaultProperties is + * null or doesn't have that property defined; ${propName:defaultVal} if the default property + * is found. + * If supportsExpression is false, this will take the actual property value for + * propName found in the givem default properties and return that string. + * If there is no sysprop of that name, this method returns an empty string. + * + * @param propName + * @param defaultProperties + * @param supportsExpression + * @return the attribute expression value (or real value if supportsExpression is false). + */ + private static String buildExpression(String propName, HashMap<String, String> defaultProperties, + boolean supportsExpression) { + + if (supportsExpression) { + if ((defaultProperties != null) && (defaultProperties.containsKey(propName))) { + return "${" + propName + ":" + defaultProperties.get(propName) + "}"; + } else { + return "${" + propName + "}"; + } + } else { + if ((defaultProperties != null) && (defaultProperties.containsKey(propName))) { + return defaultProperties.get(propName); + } else { + LOG.warn("There is no known value for property [" + propName + "]"); + return ""; + } + } + } + + /** * Creates a keystore whose cert has a CN of this server's public endpoint address. * * @param serverDetails details of the server being installed * @param configDirStr location of a configuration directory where the keystore is to be stored + * @return where the keystore file should be created (if an error occurs, this file won't exist) */ - public static void createKeystore(ServerDetails serverDetails, String configDirStr) { + private static File createKeystore(ServerDetails serverDetails, String configDirStr) { File confDir = new File(configDirStr); File keystore = new File(confDir, "rhq.keystore"); File keystoreBackup = new File(confDir, "rhq.keystore.backup"); @@ -1182,7 +1321,7 @@ public class ServerInstallUtil { if (!keystore.renameTo(keystoreBackup)) { LOG.warn("Cannot backup existing keystore - cannot generate a new cert with a proper domain name. [" + keystore + "] will be the keystore used by this server"); - return; + return keystore; } }
@@ -1205,6 +1344,8 @@ public class ServerInstallUtil { + "] to [" + keystore + "]"); } } + + return keystore; }
/**
commit f834d9e091c2598f51cc620f3a9e27ae39252d76 Author: Lukas Krejci lkrejci@redhat.com Date: Sat Dec 15 00:25:50 2012 +0100
added a .gitignore entry for cachedir of the python script engine generated during some tests.
diff --git a/.gitignore b/.gitignore index 07d07ab..32f606a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ modules/enterprise/gui/content_http-war/build/classes/ .*.jsfdia .wtpmodules *~ + +#these are created by the python script engine during the tests +cachedir/ \ No newline at end of file
commit e00d4e22f5e32593b366a23f908fc521be1a8f44 Author: Lukas Krejci lkrejci@redhat.com Date: Sat Dec 15 00:23:02 2012 +0100
Made the JndiAccessTest remote integration test work again. For that (among other things) the suite extension previously defined in the core/domain test-jar was moved into a standalone module core/arquillian-integration/suite-extension.
Also fixed a problem in the AccessCheckingInitialContextFactoryBuilder that would create incorrect InitialContextFactory in the pass-through mode when constructing context factories for remote connections, which is exactly what this integration test is for.
diff --git a/modules/core/arquillian-integration/pom.xml b/modules/core/arquillian-integration/pom.xml index a6a9cab..cbdc2a9 100644 --- a/modules/core/arquillian-integration/pom.xml +++ b/modules/core/arquillian-integration/pom.xml @@ -22,6 +22,7 @@ <modules> <module>container</module> <module>archive</module> + <module>suite-extension</module> </modules>
</project> diff --git a/modules/core/arquillian-integration/suite-extension/pom.xml b/modules/core/arquillian-integration/suite-extension/pom.xml new file mode 100644 index 0000000..3ccb886 --- /dev/null +++ b/modules/core/arquillian-integration/suite-extension/pom.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd%22%3E + + <!-- Parent --> + <parent> + <groupId>org.rhq</groupId> + <artifactId>rhq-arquillian-parent</artifactId> + <version>4.6.0-SNAPSHOT</version> + </parent> + + <!-- Model Version --> + <modelVersion>4.0.0</modelVersion> + + <!-- Artifact Configuration --> + + <artifactId>rhq-arquillian-suite-extension</artifactId> + <name>RHQ Arquillian Suite Extension</name> + <description>RHQ Suite Extension for Arquillian - enabling a single deployment per test-suite</description> + + <!-- Dependencies --> + <dependencies> + <dependency> + <groupId>org.jboss.arquillian.container</groupId> + <artifactId>arquillian-container-test-impl-base</artifactId> + </dependency> + </dependencies> +</project> diff --git a/modules/core/arquillian-integration/suite-extension/src/main/java/org/rhq/arquillian/extension/suite/SuiteDeploymentArquillianExtension.java b/modules/core/arquillian-integration/suite-extension/src/main/java/org/rhq/arquillian/extension/suite/SuiteDeploymentArquillianExtension.java new file mode 100644 index 0000000..0b3ea6e --- /dev/null +++ b/modules/core/arquillian-integration/suite-extension/src/main/java/org/rhq/arquillian/extension/suite/SuiteDeploymentArquillianExtension.java @@ -0,0 +1,176 @@ +/* + * RHQ Management Platform + * Copyright 2012, Red Hat Middleware LLC, 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 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.arquillian.extension.suite; + +import java.util.concurrent.Callable; + +import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor; +import org.jboss.arquillian.container.spi.Container; +import org.jboss.arquillian.container.spi.ContainerRegistry; +import org.jboss.arquillian.container.spi.client.container.DeployableContainer; +import org.jboss.arquillian.container.spi.client.deployment.Deployment; +import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario; +import org.jboss.arquillian.container.spi.event.DeployDeployment; +import org.jboss.arquillian.container.spi.event.DeploymentEvent; +import org.jboss.arquillian.container.spi.event.UnDeployDeployment; +import org.jboss.arquillian.container.spi.event.container.AfterStart; +import org.jboss.arquillian.container.spi.event.container.BeforeStop; +import org.jboss.arquillian.container.test.impl.client.deployment.event.GenerateDeployment; +import org.jboss.arquillian.core.api.Event; +import org.jboss.arquillian.core.api.Instance; +import org.jboss.arquillian.core.api.InstanceProducer; +import org.jboss.arquillian.core.api.annotation.Inject; +import org.jboss.arquillian.core.api.annotation.Observes; +import org.jboss.arquillian.core.api.event.ManagerStarted; +import org.jboss.arquillian.core.spi.EventContext; +import org.jboss.arquillian.core.spi.LoadableExtension; +import org.jboss.arquillian.test.spi.TestClass; +import org.jboss.arquillian.test.spi.annotation.ClassScoped; +import org.jboss.arquillian.test.spi.context.ClassContext; +import org.jboss.arquillian.test.spi.event.suite.AfterClass; +import org.jboss.arquillian.test.spi.event.suite.BeforeClass; + +/** + * This the extension Aslak did to provide some ability for Arquillian (1.0.2) to run multiple + * test classes against a single Deployment. I've only changed the class name and package. + * See https://gist.github.com/3975179. + * + * The Deployment is declared in the arquillian.launch file. The extension is declared in + * resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension . + * + * @author Aslak Knutsen + * @author Jay Shaughnessy + */ +public class SuiteDeploymentArquillianExtension implements LoadableExtension { + + public void register(ExtensionBuilder builder) { + builder.observer(SuiteDeployer.class); + } + + public static class SuiteDeployer { + + private Class<?> deploymentClass; + private DeploymentScenario suiteDeploymentScenario; + + @Inject + @ClassScoped + private InstanceProducer<DeploymentScenario> classDeploymentScenario; + + @Inject + private Event<DeploymentEvent> deploymentEvent; + + @Inject + private Event<GenerateDeployment> generateDeploymentEvent; + + @Inject + // Active some form of ClassContext around our deployments due to assumption bug in AS7 extension. + private Instance<ClassContext> classContext; + + public void startup(@Observes(precedence = -100) + ManagerStarted event, ArquillianDescriptor descriptor) { + deploymentClass = getDeploymentClass(descriptor); + + executeInClassScope(new Callable<Void>() { + public Void call() throws Exception { + generateDeploymentEvent.fire(new GenerateDeployment(new TestClass(deploymentClass))); + suiteDeploymentScenario = classDeploymentScenario.get(); + return null; + } + }); + } + + public void deploy(@Observes + final AfterStart event, final ContainerRegistry registry) { + executeInClassScope(new Callable<Void>() { + public Void call() throws Exception { + for (Deployment d : suiteDeploymentScenario.deployments()) { + deploymentEvent.fire(new DeployDeployment(findContainer(registry, + event.getDeployableContainer()), d)); + } + return null; + } + }); + } + + public void undeploy(@Observes + final BeforeStop event, final ContainerRegistry registry) { + executeInClassScope(new Callable<Void>() { + public Void call() throws Exception { + for (Deployment d : suiteDeploymentScenario.deployments()) { + deploymentEvent.fire(new UnDeployDeployment(findContainer(registry, + event.getDeployableContainer()), d)); + } + return null; + } + }); + } + + public void overrideBefore(@Observes + EventContext<BeforeClass> event) { + // Don't continue TestClass's BeforeClass context as normal. + // No DeploymentGeneration or Deploy will take place. + + classDeploymentScenario.set(suiteDeploymentScenario); + } + + public void overrideAfter(@Observes + EventContext<AfterClass> event) { + // Don't continue TestClass's AfterClass context as normal. + // No UnDeploy will take place. + } + + private void executeInClassScope(Callable<Void> call) { + try { + classContext.get().activate(deploymentClass); + call.call(); + } catch (Exception e) { + throw new RuntimeException("Could not invoke operation", e); + } finally { + classContext.get().deactivate(); + } + } + + private Container findContainer(ContainerRegistry registry, DeployableContainer<?> deployable) { + for (Container container : registry.getContainers()) { + if (container.getDeployableContainer() == deployable) { + return container; + } + } + return null; + } + + private Class<?> getDeploymentClass(ArquillianDescriptor descriptor) { + if (descriptor == null) { + throw new IllegalArgumentException("Descriptor must be specified"); + } + String className = descriptor.extension("suite").getExtensionProperties().get("deploymentClass"); + if (className == null) { + throw new IllegalArgumentException( + "A extension element with property deploymentClass must be specified in arquillian.xml"); + } + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Could not load defined deploymentClass: " + className, e); + } + } + } +} diff --git a/modules/core/arquillian-integration/suite-extension/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/modules/core/arquillian-integration/suite-extension/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension new file mode 100644 index 0000000..c058acc --- /dev/null +++ b/modules/core/arquillian-integration/suite-extension/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension @@ -0,0 +1 @@ +org.rhq.arquillian.extension.suite.SuiteDeploymentArquillianExtension diff --git a/modules/core/domain/src/test/java/org/rhq/core/domain/shared/StartStopContainerArquillianExtension.java b/modules/core/domain/src/test/java/org/rhq/core/domain/shared/StartStopContainerArquillianExtension.java index da01d45..f3842d3 100644 --- a/modules/core/domain/src/test/java/org/rhq/core/domain/shared/StartStopContainerArquillianExtension.java +++ b/modules/core/domain/src/test/java/org/rhq/core/domain/shared/StartStopContainerArquillianExtension.java @@ -32,6 +32,9 @@ import org.jboss.arquillian.test.spi.event.enrichment.BeforeEnrichment; import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
/** + * TODO if we ever decide to use this class, please move it into its standalone module so that it can be used + * independently of domain jar. + * * @author Jay Shaughnessy */ public class StartStopContainerArquillianExtension implements LoadableExtension { diff --git a/modules/core/domain/src/test/java/org/rhq/core/domain/shared/SuiteDeploymentArquillianExtension.java b/modules/core/domain/src/test/java/org/rhq/core/domain/shared/SuiteDeploymentArquillianExtension.java deleted file mode 100644 index 677df75..0000000 --- a/modules/core/domain/src/test/java/org/rhq/core/domain/shared/SuiteDeploymentArquillianExtension.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * RHQ Management Platform - * Copyright 2012, Red Hat Middleware LLC, 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 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.domain.shared; - -import java.util.concurrent.Callable; - -import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor; -import org.jboss.arquillian.container.spi.Container; -import org.jboss.arquillian.container.spi.ContainerRegistry; -import org.jboss.arquillian.container.spi.client.container.DeployableContainer; -import org.jboss.arquillian.container.spi.client.deployment.Deployment; -import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario; -import org.jboss.arquillian.container.spi.event.DeployDeployment; -import org.jboss.arquillian.container.spi.event.DeploymentEvent; -import org.jboss.arquillian.container.spi.event.UnDeployDeployment; -import org.jboss.arquillian.container.spi.event.container.AfterStart; -import org.jboss.arquillian.container.spi.event.container.BeforeStop; -import org.jboss.arquillian.container.test.impl.client.deployment.event.GenerateDeployment; -import org.jboss.arquillian.core.api.Event; -import org.jboss.arquillian.core.api.Instance; -import org.jboss.arquillian.core.api.InstanceProducer; -import org.jboss.arquillian.core.api.annotation.Inject; -import org.jboss.arquillian.core.api.annotation.Observes; -import org.jboss.arquillian.core.api.event.ManagerStarted; -import org.jboss.arquillian.core.spi.EventContext; -import org.jboss.arquillian.core.spi.LoadableExtension; -import org.jboss.arquillian.test.spi.TestClass; -import org.jboss.arquillian.test.spi.annotation.ClassScoped; -import org.jboss.arquillian.test.spi.context.ClassContext; -import org.jboss.arquillian.test.spi.event.suite.AfterClass; -import org.jboss.arquillian.test.spi.event.suite.BeforeClass; - -/** - * This the extension Aslak did to provide some ability for Arquillian (1.0.2) to run multiple - * test classes against a single Deployment. I've only changed the class name and package. - * See https://gist.github.com/3975179. - * - * The Deployment is declared in the arquillian.launch file. The extension is declared in - * resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension . - * - * @author Aslak Knutsen - * @author Jay Shaughnessy - */ -public class SuiteDeploymentArquillianExtension implements LoadableExtension { - - public void register(ExtensionBuilder builder) { - builder.observer(SuiteDeployer.class); - } - - public static class SuiteDeployer { - - private Class<?> deploymentClass; - private DeploymentScenario suiteDeploymentScenario; - - @Inject - @ClassScoped - private InstanceProducer<DeploymentScenario> classDeploymentScenario; - - @Inject - private Event<DeploymentEvent> deploymentEvent; - - @Inject - private Event<GenerateDeployment> generateDeploymentEvent; - - @Inject - // Active some form of ClassContext around our deployments due to assumption bug in AS7 extension. - private Instance<ClassContext> classContext; - - public void startup(@Observes(precedence = -100) - ManagerStarted event, ArquillianDescriptor descriptor) { - deploymentClass = getDeploymentClass(descriptor); - - executeInClassScope(new Callable<Void>() { - public Void call() throws Exception { - generateDeploymentEvent.fire(new GenerateDeployment(new TestClass(deploymentClass))); - suiteDeploymentScenario = classDeploymentScenario.get(); - return null; - } - }); - } - - public void deploy(@Observes - final AfterStart event, final ContainerRegistry registry) { - executeInClassScope(new Callable<Void>() { - public Void call() throws Exception { - for (Deployment d : suiteDeploymentScenario.deployments()) { - deploymentEvent.fire(new DeployDeployment(findContainer(registry, - event.getDeployableContainer()), d)); - } - return null; - } - }); - } - - public void undeploy(@Observes - final BeforeStop event, final ContainerRegistry registry) { - executeInClassScope(new Callable<Void>() { - public Void call() throws Exception { - for (Deployment d : suiteDeploymentScenario.deployments()) { - deploymentEvent.fire(new UnDeployDeployment(findContainer(registry, - event.getDeployableContainer()), d)); - } - return null; - } - }); - } - - public void overrideBefore(@Observes - EventContext<BeforeClass> event) { - // Don't continue TestClass's BeforeClass context as normal. - // No DeploymentGeneration or Deploy will take place. - - classDeploymentScenario.set(suiteDeploymentScenario); - } - - public void overrideAfter(@Observes - EventContext<AfterClass> event) { - // Don't continue TestClass's AfterClass context as normal. - // No UnDeploy will take place. - } - - private void executeInClassScope(Callable<Void> call) { - try { - classContext.get().activate(deploymentClass); - call.call(); - } catch (Exception e) { - throw new RuntimeException("Could not invoke operation", e); - } finally { - classContext.get().deactivate(); - } - } - - private Container findContainer(ContainerRegistry registry, DeployableContainer<?> deployable) { - for (Container container : registry.getContainers()) { - if (container.getDeployableContainer() == deployable) { - return container; - } - } - return null; - } - - private Class<?> getDeploymentClass(ArquillianDescriptor descriptor) { - if (descriptor == null) { - throw new IllegalArgumentException("Descriptor must be specified"); - } - String className = descriptor.extension("suite").getExtensionProperties().get("deploymentClass"); - if (className == null) { - throw new IllegalArgumentException( - "A extension element with property deploymentClass must be specified in arquillian.xml"); - } - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Could not load defined deploymentClass: " + className, e); - } - } - } -} diff --git a/modules/core/domain/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/modules/core/domain/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension deleted file mode 100644 index cd4854a..0000000 --- a/modules/core/domain/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension +++ /dev/null @@ -1 +0,0 @@ -org.rhq.core.domain.shared.SuiteDeploymentArquillianExtension diff --git a/modules/enterprise/server/itests-2/pom.xml b/modules/enterprise/server/itests-2/pom.xml index 407dc0b..5811fef 100644 --- a/modules/enterprise/server/itests-2/pom.xml +++ b/modules/enterprise/server/itests-2/pom.xml @@ -96,6 +96,13 @@ </dependency>
<dependency> + <groupId>org.rhq</groupId> + <artifactId>rhq-arquillian-suite-extension</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + + <dependency> <groupId>org.rhq</groupId> <artifactId>rhq-core-domain</artifactId> <version>${project.version}</version> @@ -672,6 +679,17 @@
</executions> </plugin> + + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + </plugin> </plugins> </build>
diff --git a/modules/enterprise/server/itests-2/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/modules/enterprise/server/itests-2/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension deleted file mode 100644 index cd4854a..0000000 --- a/modules/enterprise/server/itests-2/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension +++ /dev/null @@ -1 +0,0 @@ -org.rhq.core.domain.shared.SuiteDeploymentArquillianExtension diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/naming/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/naming/AccessCheckingInitialContextFactoryBuilder.java index 52addaa..370fb10 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/naming/AccessCheckingInitialContextFactoryBuilder.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/naming/AccessCheckingInitialContextFactoryBuilder.java @@ -32,7 +32,6 @@ import java.util.EnumMap; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; -import java.util.List; import java.util.Set;
import javax.naming.Context; @@ -174,9 +173,7 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
@Override public InitialContextFactory wrap(InitialContextFactory factory) { - List<DecoratorPicker<Context, ContextDecorator>> pickers = Collections.emptyList(); - - return new DecoratingInitialContextFactory(factory, pickers); + return factory; } };
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml index 36da98a..a0cffa7 100644 --- a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml +++ b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml @@ -7,7 +7,6 @@ <version>4.6.0-SNAPSHOT</version> </parent>
- <groupId>org.rhq</groupId> <artifactId>jndi-access-test</artifactId> <packaging>jar</packaging>
@@ -15,9 +14,10 @@ <description>Tests for local and remote JNDI access from within serverside scripts.</description>
<properties> - <rhq.server.datasource>java:/RHQDS</rhq.server.datasource> - <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping> - <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version> + <jboss.zip>${settings.localRepository}/org/jboss/as/jboss-as-dist/${jboss.version}/jboss-as-dist-${jboss.version}.zip</jboss.zip> + <jboss.unzip.location>${basedir}/target/jboss-as-${jboss.version}</jboss.unzip.location> + <jnp.port>54987</jnp.port> + <jnp.rmiPort>54988</jnp.rmiPort> </properties>
<dependencies> @@ -28,247 +28,166 @@ <scope>runtime</scope> </dependency>
- <!--================ Test Deps ================ --> - - <!-- Note, the test deps are intentionally placed above the other - scoped deps because of classpath reasons. Maven orders the [test] classpath - in the order listed in the pom. We specifically need the embeddable-ejb3 - jar above the standard ejb3 jars because we need the embeddble packages loaded - when testing. --> - <dependency> - <groupId>org.rhq</groupId> - <artifactId>test-utils</artifactId> - <version>${project.version}</version> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - </exclusion> - </exclusions> + <groupId>org.jboss.as</groupId> + <artifactId>jboss-as-dist</artifactId> + <type>zip</type> + <scope>provided</scope> </dependency> - + <dependency> - <groupId>org.rhq</groupId> - <artifactId>rhq-core-domain</artifactId> - <version>${project.version}</version> - <type>test-jar</type> + <groupId>org.jboss.as</groupId> + <artifactId>jboss-as-ejb3</artifactId> + <version>${jboss.version}</version> <scope>test</scope> </dependency> - + <dependency> <groupId>org.rhq</groupId> - <artifactId>rhq-enterprise-server</artifactId> + <artifactId>rhq-scripting-api</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency>
<dependency> <groupId>org.rhq</groupId> - <artifactId>rhq-enterprise-server</artifactId> + <artifactId>rhq-scripting-javascript</artifactId> <version>${project.version}</version> - <type>test-jar</type> <scope>test</scope> </dependency> - + <dependency> <groupId>org.rhq</groupId> - <artifactId>rhq-scripting-javascript</artifactId> + <artifactId>rhq-scripting-python</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency> - + <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>rhq-core-client-api</artifactId> + <groupId>org.rhq</groupId> + <artifactId>rhq-script-bindings</artifactId> <version>${project.version}</version> - <type>test-jar</type> <scope>test</scope> - <exclusions> - <exclusion> - <groupId>org.rhq</groupId> - <artifactId>rhq-enterprise-server</artifactId> - </exclusion> - </exclusions> </dependency>
+ <!-- We need to pull some classes from the server jar and itests-2 - namely the naming hack to be able to test + that it actually works --> <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>rhq-container-lib</artifactId> + <groupId>org.rhq</groupId> + <artifactId>rhq-enterprise-server</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency>
<dependency> - <groupId>${project.groupId}</groupId> - <artifactId>rhq-server-client-api</artifactId> + <groupId>org.rhq</groupId> + <artifactId>rhq-server-itests-2</artifactId> <version>${project.version}</version> - <scope>test</scope> + <type>test-jar</type> + <scope>test</scope> <exclusions> <exclusion> <groupId>org.rhq</groupId> - <artifactId>rhq-enterprise-server</artifactId> + <artifactId>rhq-arquillian-suite-extension</artifactId> </exclusion> - </exclusions> + </exclusions> </dependency> - + + <!-- Arquillian --> <dependency> - <groupId>org.rhq</groupId> - <artifactId>jndi-access-remote-server</artifactId> - <version>${project.version}</version> - <scope>test</scope> + <groupId>org.jboss.arquillian.testng</groupId> + <artifactId>arquillian-testng-container</artifactId> + <scope>test</scope> </dependency> - + <dependency> - <groupId>jboss.jboss-embeddable-ejb3</groupId> - <artifactId>jboss-ejb3-all</artifactId> - <version>${jboss-embeddable-ejb3.version}</version> - <scope>test</scope> + <groupId>org.jboss.arquillian.protocol</groupId> + <artifactId>arquillian-protocol-servlet</artifactId> + <scope>provided</scope> </dependency> - - <!-- NOTE: The remaining test deps correspond to the classes contained - in hibernate-all.jar and thirdparty-all.jar. --> - + <dependency> - <groupId>javassist</groupId> - <artifactId>javassist</artifactId> + <groupId>org.jboss.shrinkwrap</groupId> + <artifactId>shrinkwrap-api</artifactId> <scope>test</scope> </dependency> - - <!-- needed by embedded ejb container --> + <dependency> - <groupId>trove</groupId> - <artifactId>trove</artifactId> - <version>1.0.2</version> + <groupId>org.jboss.shrinkwrap.resolver</groupId> + <artifactId>shrinkwrap-resolver-api</artifactId> <scope>test</scope> </dependency>
- <!-- needed by embedded ejb container --> <dependency> - <groupId>xerces</groupId> - <artifactId>xercesImpl</artifactId> - <version>${xercesImpl.version}</version> + <groupId>org.jboss.shrinkwrap.resolver</groupId> + <artifactId>shrinkwrap-resolver-api-maven</artifactId> <scope>test</scope> </dependency>
- <!-- 3rd Party Deps --> - - <!-- required by RHQ server classes, as well as EJB3 Embedded --> - <dependency> - <groupId>dom4j</groupId> - <artifactId>dom4j</artifactId> - <version>1.6.1-jboss</version> - <scope>runtime</scope> - </dependency> - - <dependency> - <groupId>hibernate</groupId> - <artifactId>hibernate3</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS --> - </dependency> - - <dependency> - <groupId>hibernate-annotations</groupId> - <artifactId>hibernate-annotations</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS --> - </dependency> - - <dependency> - <groupId>hibernate-entitymanager</groupId> - <artifactId>hibernate-entitymanager</artifactId> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> - <version>2.4</version> - <scope>provided</scope> <!-- by JBossAS --> + <groupId>org.jboss.shrinkwrap.resolver</groupId> + <artifactId>shrinkwrap-resolver-impl-maven</artifactId> + <scope>test</scope> </dependency>
+ <!-- We'll try remote connections using JNP --> <dependency> - <groupId>javax.mail</groupId> - <artifactId>mail</artifactId> - <version>1.4</version> - </dependency> - - <dependency> - <groupId>javax.persistence</groupId> - <artifactId>persistence-api</artifactId> - <version>1.0</version> - <scope>provided</scope> <!-- by JBossAS --> - </dependency> - - <dependency> - <groupId>jboss</groupId> - <artifactId>jboss-annotations-ejb3</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS --> + <groupId>jboss</groupId> + <artifactId>jnp-client</artifactId> + <version>4.2.2.GA</version> + <scope>test</scope> </dependency> - - <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed - by the PoolClass annotation used on some of our SLSB's --> - <dependency> - <groupId>jboss</groupId> - <artifactId>jboss-ejb3</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS --> - </dependency> - - <!-- for the transaction interrupt EJB3 interceptor --> - <dependency> - <groupId>org.jboss.transaction</groupId> - <artifactId>jboss-jta</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS --> - </dependency> - - <dependency> - <groupId>org.opensymphony.quartz</groupId> - <artifactId>quartz</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 --> - </dependency> - - <dependency> - <groupId>org.opensymphony.quartz</groupId> - <artifactId>quartz-oracle</artifactId> - <!-- NOTE: The version is defined in the root POM's dependencyManagement - section. --> - <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 --> - </dependency> - - <!-- This is needed cglib which is in turn needed by hibernate --> - <dependency> - <groupId>org.easymock</groupId> - <artifactId>easymockclassextension</artifactId> - <version>2.2</version> - <scope>test</scope> - </dependency> - + + <!-- This is here only to ensure the build order and HAS TO COME AS LAST to avoid any classpath + collisions. --> <dependency> - <groupId>org.freemarker</groupId> - <artifactId>freemarker</artifactId> - <version>2.3.18</version> + <groupId>${project.groupId}</groupId> + <artifactId>jndi-access-remote-server</artifactId> + <version>${project.version}</version> <scope>provided</scope> </dependency>
- <dependency> - <groupId>org.jboss.resteasy</groupId> - <artifactId>resteasy-jaxrs</artifactId> - <version>${resteasy.version}</version> - </dependency> </dependencies>
+ <profiles> + <profile> + <id>managed-test-server</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + + <dependencies> + <dependency> + <groupId>org.jboss.as</groupId> + <artifactId>jboss-as-arquillian-container-managed</artifactId> + <version>${jboss.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + </profile> + + <profile> + <id>remote-test-server</id> + + <dependencies> + <dependency> + <groupId>org.jboss.spec</groupId> + <artifactId>jboss-javaee-6.0</artifactId> + <version>1.0.0.Final</version> + <type>pom</type> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.jboss.as</groupId> + <artifactId>jboss-as-arquillian-container-remote</artifactId> + <version>${jboss.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + </profile> + </profiles> + <build> <testResources> <testResource> @@ -281,25 +200,13 @@ <plugin> <artifactId>maven-antrun-plugin</artifactId> <executions> - <!-- in order to get JMS to work properly in embedded - test container, extract jms-rs.rar classes --> <execution> - <id>Extract JMS classes from RAR needed for JMS tests</id> - <phase>process-classes</phase> + <id>Prepare AS7 for test</id> + <phase>process-test-resources</phase> <configuration> <target> - <unzip src="src/test/resources/jms-ra.rar" - dest="target"> - <patternset> - <include name="jms-ra.jar" /> - </patternset> - </unzip> - <unzip src="target/jms-ra.jar" - dest="target/test-classes"> - <patternset> - <include name="org/**" /> - </patternset> - </unzip> + <unzip src="${jboss.zip}" dest="${jboss.unzip.location}/.." /> + <copy file="src/test/resources/security.policy" toDir="${jboss.unzip.location}"/> </target> </configuration> <goals> @@ -308,6 +215,7 @@ </execution> </executions> </plugin> + <plugin> <artifactId>maven-surefire-plugin</artifactId> <!-- Everything but the web service tests, this is the standard @@ -316,11 +224,10 @@ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups> <groups>${rhq.testng.includedGroups}</groups> <systemPropertyVariables> - <embeddedDeployment>true</embeddedDeployment> <deploymentDirectory>target/test-classes</deploymentDirectory> - <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect> - <clean.db>${clean.db}</clean.db> <test.server.jar.path>${settings.localRepository}/org/rhq/jndi-access-remote-server/${project.version}/jndi-access-remote-server-${project.version}.jar</test.server.jar.path> + <jnp.port>${jnp.port}</jnp.port> + <jnp.rmiPort>${jnp.rmiPort}</jnp.rmiPort> </systemPropertyVariables> <argLine>${jacoco.unit-test.args} -Djava.security.manager -Djava.security.policy==${basedir}/target/test-classes/security.policy</argLine> <additionalClasspathElements> diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java index 40f1ed2..d330ba1 100644 --- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java +++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java @@ -19,11 +19,13 @@
package org.rhq.jndi.test;
+import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.io.PrintWriter; +import java.util.Collection; import java.util.Collections; import java.util.Properties;
@@ -33,70 +35,87 @@ import javax.script.ScriptException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Parameters; import org.testng.annotations.Test;
-import org.rhq.bindings.ScriptEngineFactory; -import org.rhq.bindings.StandardBindings; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.testng.Arquillian; +import org.jboss.shrinkwrap.api.ArchivePaths; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.resolver.api.DependencyResolvers; +import org.jboss.shrinkwrap.resolver.api.maven.MavenDependencyResolver; + import org.rhq.bindings.StandardScriptPermissions; -import org.rhq.bindings.util.PackageFinder; -import org.rhq.core.domain.auth.Subject; -import org.rhq.enterprise.client.LocalClient; import org.rhq.enterprise.server.AllowRhqServerInternalsAccessPermission; -import org.rhq.enterprise.server.test.AbstractEJB3Test; -import org.rhq.enterprise.server.util.LookupUtil; -import org.rhq.test.PortScout; +import org.rhq.enterprise.server.test.StrippedDownStartupBean; +import org.rhq.enterprise.server.test.StrippedDownStartupBeanPreparation; +import org.rhq.scripting.javascript.JsEngineProvider; +import org.rhq.scripting.python.PythonScriptEngineProvider;
/** - * - * !!!!!!! THIS TEST CLASS HAS BEEN MOVED TO ENTERPRISE/SERVER/ITESTS-2 !!!!!! * - * TODO: since this class has been updated and now differs from the version in itests-2 it is left here for - * reference. Also, the jndi access strategy needs to be updated for AS7. When all is settled, this - * whole src branch should be deleted. - * * @author Lukas Krejci */ -@Test(enabled = false) -// TODO JNDI: re-enable after secure JNDI lookups are fixed -public class JndiAccessTest extends AbstractEJB3Test { +@Test +public class JndiAccessTest extends Arquillian { + private static final Log JNP_SERVER_LOG = LogFactory.getLog("Test JNP Server"); - private static final Log LOG = LogFactory.getLog(JndiAccessTest.class); - + + private static final String GROUP_FOR_NORMAL_TESTS = "JndiAccessTest"; + private Process testServerProcess; private Thread testServerStdErrReader; private Thread testServerStdOutReader; - - int jnpPort;
- @BeforeClass - @Parameters({ "test.server.jar.path" }) - public void startTestJnpServer(String testServerJar) throws Exception { - int rmiPort = 0; - PortScout scout = new PortScout(); + @Deployment + public static EnterpriseArchive TestEar() { + JavaArchive testEjb = ShrinkWrap.create(JavaArchive.class, "test-ejb.jar").addClass(TestEjb.class) + .addClass(TestEjbBean.class).addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml"));
- try { - jnpPort = scout.getNextFreePort(); - rmiPort = scout.getNextFreePort(); - } finally { - scout.close(); - } + Collection<JavaArchive> deps = DependencyResolvers.use(MavenDependencyResolver.class) + .loadMetadataFromPom("pom.xml") + .artifacts("jboss:jnp-client", "org.rhq:rhq-scripting-api", "org.rhq:rhq-scripting-javascript", + "org.rhq:rhq-scripting-python").scope("test").resolveAs(JavaArchive.class);
- LOG.info("Starting the remote JNP server on jnpPort=" + jnpPort + ", rmiPort=" + rmiPort); - ProcessBuilder bld = new ProcessBuilder("java", "-Djnp.port=" + jnpPort, "-Djnp.rmiPort=" + rmiPort, "-jar", testServerJar); + //we need to pull in the naming hack classes from the server jar so that our EAR behaves the same + testEjb.addPackages(true, "org.rhq.enterprise.server.naming").addClass( + AllowRhqServerInternalsAccessPermission.class);
- testServerProcess = bld.start(); + //we also need to pull in the special startup beans from the server/itests-2 that will initialize the naming + //subsystem + testEjb.addClasses(StrippedDownStartupBean.class, StrippedDownStartupBeanPreparation.class);
+ //to work around https://issues.jboss.org/browse/ARQ-659 + //we need to include this test class in the EAR manually + + //Instead of pulling the whole rhq-script-bindings (which has a lot of deps), we're just picking the + //StandardScriptPermissions from there so that it can be used in the tests + JavaArchive classes = ShrinkWrap.create(JavaArchive.class, "test-class.jar").addClasses(JndiAccessTest.class, + StandardScriptPermissions.class); + + return ShrinkWrap.create(EnterpriseArchive.class, "test-ear.ear").addAsModule(testEjb).addAsLibraries(deps) + .addAsLibrary(classes); + } + + @RunAsClient + @Parameters({ "test.server.jar.path", "jnp.port", "jnp.rmiPort" }) + public void startTestJnpServer(String testServerJar, int jnpPort, int rmiPort) throws Exception { + ProcessBuilder bld = new ProcessBuilder("java", "-Djnp.port=" + jnpPort, "-Djnp.rmiPort=" + rmiPort, "-jar", + testServerJar); + + testServerProcess = bld.start(); + testServerStdErrReader = new Thread(new Runnable() { @Override public void run() { BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getErrorStream())); try { String line; - while((line = rdr.readLine()) != null) { + while ((line = rdr.readLine()) != null) { JNP_SERVER_LOG.warn(line); } } catch (IOException e) { @@ -111,14 +130,14 @@ public class JndiAccessTest extends AbstractEJB3Test { } }); testServerStdErrReader.start(); - + testServerStdOutReader = new Thread(new Runnable() { @Override public void run() { BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getInputStream())); try { String line; - while((line = rdr.readLine()) != null) { + while ((line = rdr.readLine()) != null) { JNP_SERVER_LOG.debug(line); } } catch (IOException e) { @@ -133,73 +152,108 @@ public class JndiAccessTest extends AbstractEJB3Test { } }); testServerStdOutReader.start(); - + //give the JNP server some time to start up Thread.sleep(5000); } - - @AfterClass + + @RunAsClient + @Test(dependsOnGroups = GROUP_FOR_NORMAL_TESTS, alwaysRun = true) public void stopTestJnpServer() throws Exception { testServerProcess.destroy(); testServerStdErrReader.join(); testServerStdOutReader.join(); } - - public void testRemoteConnectionWorkingFromJava() throws Exception { + + @Test(dependsOnMethods = "startTestJnpServer", groups = GROUP_FOR_NORMAL_TESTS) + @Parameters("jnp.port") + public void testRemoteConnectionWorkingFromJava(int jnpPort) throws Exception { Properties env = new Properties(); - env.put("java.naming.factory.initial", "org.jboss.naming.NamingContextFactory"); + env.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); + env.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); env.put("java.naming.provider.url", "jnp://localhost:" + jnpPort); InitialContext ctx = new InitialContext(env); Object kachny = ctx.lookup("kachny"); - - assert kachny != null; + + assertNotNull(kachny); + } + + @Test(dependsOnMethods = "startTestJnpServer", groups = GROUP_FOR_NORMAL_TESTS) + @Parameters("jnp.port") + public void testRemoteConnectionWorkingFromScripts_javascript(int jnpPort) throws Exception { + getJavascriptScriptEngine().eval("" // + + "var env = new java.util.Properties;" // + + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.NamingContextFactory');" // + + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces');" // + + "env.put('java.naming.provider.url', 'jnp://localhost:" + jnpPort + "');" // + + "var ctx = new javax.naming.InitialContext(env);" // + + "var kachny = ctx.lookup('kachny');" // + + "if (kachny == null) throw 'The object retrieved from the remote server should not be null';"); + } + + @Test(dependsOnMethods = "startTestJnpServer", groups = GROUP_FOR_NORMAL_TESTS) + @Parameters("jnp.port") + public void testRemoteConnectionWorkingFromScripts_python(int jnpPort) throws Exception { + getPythonScriptEngine() + .eval( + "" // + + "import java.util as u\n" // + + "import javax.naming as n\n" // + + "env = u.Properties()\n" // + + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.NamingContextFactory')\n" // + + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces')\n" // + + "env.put('java.naming.provider.url', 'jnp://localhost:" + + jnpPort + + "')\n" // + + "ctx = n.InitialContext(env)\n" // + + "kachny = ctx.lookup('kachny')\n" // + + "if (kachny is None):\n raise Exception('The object retrieved from the remote server should not be null')\n"); + } + + @Test(dependsOnMethods = "startTestJnpServer", groups = GROUP_FOR_NORMAL_TESTS) + public void testLocalJNDILookupWorksFromJava() throws Exception { + InitialContext ctx = new InitialContext(); + Object bean = ctx.lookup("java:app/test-ejb/TestEjbBean"); + + assertNotNull(bean); } - - public void testLocalJNDILookupFailsFromScripts() throws Exception { - Subject overlord = LookupUtil.getSubjectManager().getOverlord(); - - ScriptEngine engine = getEngine(overlord);
+ @Test(dependsOnMethods = "startTestJnpServer", groups = GROUP_FOR_NORMAL_TESTS) + public void testLocalJNDILookupFailsFromScripts_javascript() throws Exception { try { - engine.eval("" - + "var ctx = new javax.naming.InitialContext();\n" - + "var entityManagerFactory = ctx.lookup('java:/RHQEntityManagerFactory');\n" - + "var entityManager = entityManagerFactory.createEntityManager();\n" - + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));"); - - Assert.fail("The script shouldn't have been able to use the EntityManager."); - } catch (ScriptException e) { + getJavascriptScriptEngine().eval( + "var ctx = new javax.naming.InitialContext();\n" + + "var bean = ctx.lookup('java:app/test-ejb/TestEjbBean');\n"); + fail("Script was able to perform local JNDI lookup."); + } catch (Exception e) { checkIsDesiredSecurityException(e); - } + } } - - public void testRemoteJNDILookupWorksFromScripts() throws Exception { - Subject overlord = LookupUtil.getSubjectManager().getOverlord(); - - ScriptEngine engine = getEngine(overlord);
+ @Test(dependsOnMethods = "startTestJnpServer", groups = GROUP_FOR_NORMAL_TESTS) + public void testLocalJNDILookupFailsFromScripts_python() throws Exception { try { - engine.eval("" - + "var env = new java.util.Hashtable();" - + "env.put('java.naming.factory.initial', 'org.jboss.naming.NamingContextFactory');" - + "env.put('java.naming.provider.url', 'jnp://localhost:" + jnpPort + "');" - + "var ctx = new javax.naming.InitialContext(env);\n" - + "var kachny = ctx.lookup('kachny');\n" - + "assertNotNull(kachny);\n"); - } catch (ScriptException e) { - Assert.fail("The script should have been able to access a remote JNDI server.", e); - } + getPythonScriptEngine().eval("import javax.naming as n\n" // + + "ctx = n.InitialContext()\n" // + + "bean = ctx.lookup('java:app/test-ejb/TestEjbBean')\n"); + fail("Script was able to perform local JNDI lookup."); + } catch (Exception e) { + checkIsDesiredSecurityException(e); + } } - - private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException { - StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject)); - return ScriptEngineFactory.getSecuredScriptEngine("javascript", new PackageFinder(Collections.<File>emptyList()), bindings, new StandardScriptPermissions()); + + private ScriptEngine getJavascriptScriptEngine() throws ScriptException { + return new JsEngineProvider().getInitializer().instantiate(Collections.<String> emptySet(), + new StandardScriptPermissions()); + } + + private ScriptEngine getPythonScriptEngine() throws ScriptException { + return new PythonScriptEngineProvider().getInitializer().instantiate(Collections.<String> emptySet(), + new StandardScriptPermissions()); + } + + private void checkIsDesiredSecurityException(Throwable t) { + //TODO implement + System.out.println(t); } - - private static void checkIsDesiredSecurityException(ScriptException e) { - String message = e.getMessage(); - String permissionTrace = null; // TODO JNDI: AllowRhqServerInternalsAccessPermission.class.getName(); - - Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message); - } } diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/arquillian.xml b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/arquillian.xml index 23502f1..fbf2891 100644 --- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/arquillian.xml +++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/arquillian.xml @@ -9,9 +9,4 @@ <property name="javaVmArguments">-Xmx512m -XX:MaxPermSize=128m -Djava.security.manager -Djava.security.policy==${jboss.unzip.location}/security.policy -Djnp.port=${jnp.port}</property> </configuration> </container> - - <extension qualifier="jacoco"> - <property name="includes">org.rhq.*</property> - </extension> - </arquillian> diff --git a/modules/integration-tests/jndi-access/remote-server/pom.xml b/modules/integration-tests/jndi-access/remote-server/pom.xml index 453687f..2bc2fdd 100644 --- a/modules/integration-tests/jndi-access/remote-server/pom.xml +++ b/modules/integration-tests/jndi-access/remote-server/pom.xml @@ -7,7 +7,6 @@ <version>4.6.0-SNAPSHOT</version> </parent>
- <groupId>org.rhq</groupId> <artifactId>jndi-access-remote-server</artifactId> <packaging>jar</packaging>
@@ -34,7 +33,6 @@ <dependency> <groupId>oswego-concurrent</groupId> <artifactId>concurrent</artifactId> - <version>1.3.4-jboss</version> </dependency>
<dependency> diff --git a/modules/integration-tests/pom.xml b/modules/integration-tests/pom.xml index 4818c3a..95d947a 100644 --- a/modules/integration-tests/pom.xml +++ b/modules/integration-tests/pom.xml @@ -10,7 +10,6 @@ </parent> <modelVersion>4.0.0</modelVersion>
- <groupId>org.rhq</groupId> <artifactId>rhq-integration-tests</artifactId> <packaging>pom</packaging>
@@ -59,7 +58,7 @@ </activation> <modules> <module>apache-plugin-test</module> - <!--<module>jndi-access</module> commented out until Lukas updates for AS7 --> + <module>jndi-access</module> <!--<module>mod_cluster-plugin-test</module>--> <!--<module>rest-api</module>--> </modules>
commit bd0cba4c258ef0f6884ce1465e744e0d37acc9a9 Author: Remy Maucherat rmaucher@redhat.com Date: Fri Dec 14 11:53:16 2012 -0500
[BZ 865459] adding support for adding users for tomcat 7 UserDatabase.
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java index bb13097..23a20e1 100644 --- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java +++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java @@ -47,6 +47,7 @@ public class TomcatUserDatabaseComponent extends MBeanResourceComponent<TomcatSe try { if (TomcatGroupComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) { name = report.getResourceConfiguration().getSimple("groupname").getStringValue(); + report.getResourceConfiguration().remove(TomcatGroupComponent.CONFIG_ROLES); objectName = String.format("Users:type=Group,groupname="%s",database=UserDatabase", name); operation = "createGroup"; } else if (TomcatRoleComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) { @@ -55,6 +56,8 @@ public class TomcatUserDatabaseComponent extends MBeanResourceComponent<TomcatSe operation = "createRole"; } else if (TomcatUserComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) { name = report.getResourceConfiguration().getSimple("username").getStringValue(); + report.getResourceConfiguration().remove(TomcatUserComponent.CONFIG_ROLES); + report.getResourceConfiguration().remove(TomcatUserComponent.CONFIG_GROUPS); objectName = String.format("Users:type=User,username="%s",database=UserDatabase", name); operation = "createUser"; } else {
commit 49a48ea47dde77506b48bb1c699dd6aab0ab8a20 Author: Jirka Kremser jkremser@redhat.com Date: Fri Dec 14 14:50:57 2012 +0100
[BZ 886287 - NullPointerException when another exception should have been thrown] quick fix, lazy evaluation of Java should ensure the prevention of throwing NPE
diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java index 6521d2e..006e1e4 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java @@ -87,14 +87,14 @@ public class SystemServiceType extends AbstractBundleType { }
public void init() throws BuildException { - if (!OS_NAME.equals("Linux") || !REDHAT_RELEASE_FILE.exists()) { + if (!"Linux".equals(OS_NAME) || !REDHAT_RELEASE_FILE.exists()) { throw new BuildException("The system-service element is only supported on Red Hat Linux systems."); }
if (!this.scriptFile.exists() || this.scriptFile.isDirectory()) { throw new BuildException("The 'scriptFile' attribute must be set to the path of an existing regular file."); } - if (this.configFile != null && !this.configFile.exists() || this.configFile.isDirectory()) { + if (this.configFile != null && (!this.configFile.exists() || this.configFile.isDirectory())) { throw new BuildException("The 'configFile' attribute must be set to the path of an existing regular file."); } }
commit 3b27674c0810da01bd7d4031f5f3ea852b62e538 Author: Jay Shaughnessy jshaughn@jshaughn.csb Date: Thu Dec 13 20:27:06 2012 -0500
Add test dep to ensure the oracle driver can be found when testing against oracle.
diff --git a/modules/enterprise/server/itests-2/pom.xml b/modules/enterprise/server/itests-2/pom.xml index ba7dd7e..407dc0b 100644 --- a/modules/enterprise/server/itests-2/pom.xml +++ b/modules/enterprise/server/itests-2/pom.xml @@ -26,10 +26,10 @@ <jboss.vm.args>-Xmx700m -XX:MaxPermSize=200m -Djava.security.manager -Djava.security.policy==${jboss.unzip.location}/security.policy</jboss.vm.args> <jboss.vm.args.debug></jboss.vm.args.debug> <!-- -Ditest.debug can override this, see below --> - <!-- These properties guide which datasources are used for integration tests. Only one should be true. - The default is Postgres, specify -Pitest.oracle to use Oracle --> - <skip.postgres>false</skip.postgres> - <skip.oracle>true</skip.oracle> + <!-- These properties guide which datasources are used for integration tests. Only one should be true. + The default is Postgres, specify -Pitest.oracle to use Oracle --> + <skip.postgres>false</skip.postgres> + <skip.oracle>true</skip.oracle> </properties>
<dependencies> @@ -683,6 +683,17 @@ <skip.postgres>true</skip.postgres> <skip.oracle>false</skip.oracle> </properties> + + <dependencies> + <!-- The provided scope in the root pom is not sufficient, we need this fo shrinkwrap to resolve + dependency and add the jar to the deployment. --> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc6</artifactId> + <version>${ojdbc6.version}</version> + <scope>test</scope> + </dependency> + </dependencies> </profile>
<profile>
commit 8dbf3bd0b887c1b371f11394112755a714fa9e2b Author: Jay Shaughnessy jshaughn@jshaughn.csb Date: Thu Dec 13 17:12:57 2012 -0500
Make sure oracle driver dependency is in place for -Ddbreset
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml index c8fef74..aa9a2ce 100644 --- a/modules/core/dbutils/pom.xml +++ b/modules/core/dbutils/pom.xml @@ -435,6 +435,17 @@
<profile> <id>ojdbc-driver</id> + <dependencies> + <!-- The provided scope in the root pom is not sufficient, we need this + dependency for dbreset, if it is used. --> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc6</artifactId> + <version>${ojdbc6.version}</version> + <scope>compile</scope> + </dependency> + </dependencies> + <!-- TODO: defer to root pom version when we can agree on a version --> <build> <plugins>
commit d5a7ec0bed4d88493a5213ea0a43a9cda0f60610 Author: Jay Shaughnessy jshaughn@redhat.com Date: Thu Dec 13 16:12:49 2012 -0500
Add ability to specify Double comparison tolerances in our matcher test utils. Hopefully this will handle the minor roundoff errors that are sinking some some tests. When we move to cassandra we may be able to remove these tolerances from the tests, given more precision in our math.
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBeanTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBeanTest.java index e87bff2..9e8b4e3 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBeanTest.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBeanTest.java @@ -169,9 +169,9 @@ public class MeasurementDataManagerBeanTest extends AbstractEJB3Test { buckets.get(29), Double.NaN, Double.NaN, Double.NaN);
assertPropertiesMatch("The data for bucket 0 does not match the expected values.", expectedBucket0Data, - actualData.get(0)); + actualData.get(0), 0.0001D); assertPropertiesMatch("The data for bucket 59 does not match the expected values.", expectedBucket59Data, - actualData.get(59)); + actualData.get(59), 0.0001D); assertPropertiesMatch("The data for bucket 29 does not match the expected values.", expectedBucket29Data, actualData.get(29)); } @@ -206,7 +206,7 @@ public class MeasurementDataManagerBeanTest extends AbstractEJB3Test { MeasurementAggregate expected = new MeasurementAggregate(1.1, divide((1.1 + 2.2 + 3.3 + 4.4 + 5.5 + 6.6), 6), 6.6);
- AssertUtils.assertPropertiesMatch(expected, actual, "Aggregate does not match"); + AssertUtils.assertPropertiesMatch("Aggregate does not match", expected, actual, 0.0001D); }
@Test(enabled = ENABLED) @@ -242,9 +242,9 @@ public class MeasurementDataManagerBeanTest extends AbstractEJB3Test { buckets.get(59), divide((5.0 + 5.0 + 3.0), 3), 9.0, 2.0);
assertPropertiesMatch("The data for bucket 0 does not match the expected values.", expectedBucket0Data, - actualData.get(0)); + actualData.get(0), 0.0001D); assertPropertiesMatch("The data for bucket 59 does not match the expected values.", expectedBucket59Data, - actualData.get(59)); + actualData.get(59), 0.0001D); }
private void createInventory() throws Exception { diff --git a/modules/test-utils/src/main/java/org/rhq/test/AssertUtils.java b/modules/test-utils/src/main/java/org/rhq/test/AssertUtils.java index 7524fc8..50c1212 100644 --- a/modules/test-utils/src/main/java/org/rhq/test/AssertUtils.java +++ b/modules/test-utils/src/main/java/org/rhq/test/AssertUtils.java @@ -23,14 +23,14 @@
package org.rhq.test;
+import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List;
-import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - public class AssertUtils {
/** @@ -44,7 +44,7 @@ public class AssertUtils { * @param <T> The type of the objects to be compared */ public static <T> void assertPropertiesMatch(T expected, T actual, String msg) { - assertPropertiesMatch(msg, expected, actual, Collections.<String>emptyList()); + assertPropertiesMatch(msg, expected, actual, null, Collections.<String> emptyList()); }
/** @@ -55,7 +55,20 @@ public class AssertUtils { * @param <T> The type of the objects to be compared. */ public static <T> void assertPropertiesMatch(String msg, T expected, T actual, String... ignoredProperties) { - assertPropertiesMatch(msg, expected, actual, Arrays.asList(ignoredProperties)); + assertPropertiesMatch(msg, expected, actual, null, Arrays.asList(ignoredProperties)); + } + + /** + * @param msg An error message + * @param expected The expected object to compare against. Should be non-null. + * @param actual The actual object to be compared. Should be non-null. + * @param ignoredProperties A list of property names to exclude from comparison. + * @param maxDifference When matching doubles, the max roundoff difference still considered equal. If null Double.equals() is used. + * @param <T> The type of the objects to be compared. + */ + public static <T> void assertPropertiesMatch(String msg, T expected, T actual, Double maxDifference, + String... ignoredProperties) { + assertPropertiesMatch(msg, expected, actual, maxDifference, Arrays.asList(ignoredProperties)); }
/** @@ -70,12 +83,30 @@ public class AssertUtils { * @param <T> The type of the objects to be compared. */ public static <T> void assertPropertiesMatch(String msg, T expected, T actual, List<String> ignoredProperties) { + assertPropertiesMatch(msg, expected, actual, null, ignoredProperties); + } + + /** + * Verifies that all public, accessible properties of the two objects are equal, excluding those specified in the + * <code>ignoredProperties</code> argument. This method might be used when you want to compare two objects without + * using their <code>equals()</code> methods or when they do not implement <code>equals</code>. + * + * @param msg An error message + * @param expected The expected object to compare against. Should be non-null. + * @param actual The actual object to be compared. Should be non-null. + * @param maxDifference When matching doubles, the max roundoff difference still considered equal. If null Double.equals() is used. + * @param ignoredProperties A list of property names to exclude from comparison. + * @param <T> The type of the objects to be compared. + */ + public static <T> void assertPropertiesMatch(String msg, T expected, T actual, Double maxDifference, + List<String> ignoredProperties) { assertNotNull(expected, "Expected object should not be null"); assertNotNull(actual, "Actual object should not be null");
PropertyMatcher<T> matcher = new PropertyMatcher<T>(); matcher.setExpected(expected); matcher.setActual(actual); + matcher.setMaxDifference(maxDifference); matcher.setIgnoredProperties(ignoredProperties);
MatchResult result = matcher.execute(); diff --git a/modules/test-utils/src/main/java/org/rhq/test/PropertyMatcher.java b/modules/test-utils/src/main/java/org/rhq/test/PropertyMatcher.java index 8d9b3cc..7f07c2d 100644 --- a/modules/test-utils/src/main/java/org/rhq/test/PropertyMatcher.java +++ b/modules/test-utils/src/main/java/org/rhq/test/PropertyMatcher.java @@ -23,14 +23,14 @@
package org.rhq.test;
-import org.apache.commons.beanutils.PropertyUtils; - import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set;
+import org.apache.commons.beanutils.PropertyUtils; + public class PropertyMatcher<T> {
private T expected; @@ -39,6 +39,8 @@ public class PropertyMatcher<T> {
private Set<String> ignoredProperties = new HashSet<String>();
+ private Double maxDifference; + public void setExpected(T expected) { this.expected = expected; } @@ -51,6 +53,10 @@ public class PropertyMatcher<T> { this.ignoredProperties.addAll(ignoredProperties); }
+ public void setMaxDifference(Double maxDifference) { + this.maxDifference = maxDifference; + } + public MatchResult execute() { try { Map<String, ?> expectedProps = PropertyUtils.describe(expected); @@ -96,6 +102,18 @@ public class PropertyMatcher<T> { if (expected == null && actual != null) { return false; } + + if (maxDifference != null && expected instanceof Double) { + boolean result = expected.equals(actual); + if (!result) { + Double dExpected = (Double) expected; + Double dActual = (Double) actual; + Double diff = Math.abs(dExpected - dActual); + result = ((!diff.isNaN()) && (!diff.isInfinite()) && (diff < maxDifference)); + } + return result; + } + return expected.equals(actual); } }
commit 165b4f583ca08f6a7c20ebcdaad7fe7f43508b90 Author: Jay Shaughnessy jshaughn@jshaughn.csb Date: Thu Dec 13 13:18:09 2012 -0500
Fix an issue where the domain and server itests needed one of -Ppostgres or -Poracle to be defined. Now it will default to postgres unless -Pitest.oracle is set.
Also, removed some ojdbc-driver profile declarations that were redundant with what is already defined in the root pom and should be inherited.
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml index c110636..c8fef74 100644 --- a/modules/core/dbutils/pom.xml +++ b/modules/core/dbutils/pom.xml @@ -435,13 +435,7 @@
<profile> <id>ojdbc-driver</id> - <dependencies> - <dependency> - <groupId>com.oracle</groupId> - <artifactId>ojdbc6</artifactId> - <version>${ojdbc6.version}</version> - </dependency> - </dependencies> + <!-- TODO: defer to root pom version when we can agree on a version --> <build> <plugins> <plugin> diff --git a/modules/core/domain/pom.xml b/modules/core/domain/pom.xml index cb7699b..23d5fe0 100644 --- a/modules/core/domain/pom.xml +++ b/modules/core/domain/pom.xml @@ -18,6 +18,10 @@ <jboss.zip>${settings.localRepository}/org/jboss/as/jboss-as-dist/${jboss.version}/jboss-as-dist-${jboss.version}.zip</jboss.zip> <jboss.unzip.location>${basedir}/target/jboss-as-${jboss.version}</jboss.unzip.location> <rhq.internal>false</rhq.internal> + <!-- These properties guide which datasources are used for integration tests. Only one should be true. + The default is Postgres, specify -Pitest.oracle to use Oracle --> + <skip.postgres>false</skip.postgres> + <skip.oracle>true</skip.oracle> </properties>
@@ -542,18 +546,14 @@ </build>
- <profiles> - - <!-- if you want to test on oracle, this can pull down the oracle jdbc driver that is needed --> - <profile> - <id>ojdbc-driver</id> - <dependencies> - <dependency> - <groupId>com.oracle</groupId> - <artifactId>ojdbc6</artifactId> - <version>${ojdbc6.version}</version> - </dependency> - </dependencies> + <profiles> + <!-- If testing against oracle, override the default property settings --> + <profile> + <id>itest.oracle</id> + <properties> + <skip.postgres>true</skip.postgres> + <skip.oracle>false</skip.oracle> + </properties> </profile>
<profile> @@ -669,26 +669,7 @@ </plugins> </build> </profile> - - <profile> - <id>postgres</id> - <activation> - <activeByDefault>true</activeByDefault> - </activation> - <properties> - <skip.postgres>false</skip.postgres> - <skip.oracle>true</skip.oracle> - </properties> - </profile> - - <profile> - <id>oracle</id> - <properties> - <skip.postgres>true</skip.postgres> - <skip.oracle>false</skip.oracle> - </properties> - </profile> - + <profile> <id>itest.debug</id> <activation> diff --git a/modules/enterprise/server/itests-2/pom.xml b/modules/enterprise/server/itests-2/pom.xml index 01b377f..ba7dd7e 100644 --- a/modules/enterprise/server/itests-2/pom.xml +++ b/modules/enterprise/server/itests-2/pom.xml @@ -26,6 +26,10 @@ <jboss.vm.args>-Xmx700m -XX:MaxPermSize=200m -Djava.security.manager -Djava.security.policy==${jboss.unzip.location}/security.policy</jboss.vm.args> <jboss.vm.args.debug></jboss.vm.args.debug> <!-- -Ditest.debug can override this, see below --> + <!-- These properties guide which datasources are used for integration tests. Only one should be true. + The default is Postgres, specify -Pitest.oracle to use Oracle --> + <skip.postgres>false</skip.postgres> + <skip.oracle>true</skip.oracle> </properties>
<dependencies> @@ -672,19 +676,9 @@ </build>
<profiles> + <!-- If testing against oracle, override the default property settings --> <profile> - <id>postgres</id> - <activation> - <activeByDefault>true</activeByDefault> - </activation> - <properties> - <skip.postgres>false</skip.postgres> - <skip.oracle>true</skip.oracle> - </properties> - </profile> - - <profile> - <id>oracle</id> + <id>itest.oracle</id> <properties> <skip.postgres>true</skip.postgres> <skip.oracle>false</skip.oracle> diff --git a/modules/enterprise/server/jar/pom.xml b/modules/enterprise/server/jar/pom.xml index 98a7895..2033a2c 100644 --- a/modules/enterprise/server/jar/pom.xml +++ b/modules/enterprise/server/jar/pom.xml @@ -694,19 +694,6 @@ </build> </profile>
- <!-- if you want to test on oracle, this can pull down the oracle jdbc driver that is needed --> - <profile> - <id>ojdbc-driver</id> - <dependencies> - <dependency> - <groupId>com.oracle</groupId> - <artifactId>ojdbc6</artifactId> - <version>${ojdbc6.version}</version> - </dependency> - </dependencies> - </profile> - - <profile> <id>dev</id>
rhq-commits@lists.fedorahosted.org