From d15aa2b5e2901d85d35b1ae2b6d2a4c57b4a11b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lanouette?= Date: Wed, 20 Apr 2016 14:17:03 -0400 Subject: [PATCH 1/2] Allow a delay for a service to be present in the remote test container before installing the test probe This modification can allow specific scenarios where a specialized service is registered to indicate that the framework is ready for the test. This can be especially useful for tests using blueprint or test using bundles that load other bundles in the container without being explicitely in the boot features defined by the pax exam test. --- .../internal/KarafTestContainer.java | 14 ++++++ .../options/KarafDistributionOption.java | 4 ++ .../karaf/options/WaitForServiceOption.java | 43 +++++++++++++++++++ .../rbc/client/RemoteBundleContextClient.java | 8 +++- .../intern/RemoteBundleContextClientImpl.java | 5 +++ .../rbc/internal/RemoteBundleContext.java | 2 + .../rbc/internal/RemoteBundleContextImpl.java | 6 +++ 7 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/WaitForServiceOption.java diff --git a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java index 776c1bef9..6426ad8ae 100644 --- a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java +++ b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java @@ -233,6 +233,16 @@ private void startKaraf(ExamSystem subsystem, File karafBase, File karafHome) { else { LOGGER .info("System runs in Server Mode. Which means, no Test facility bundles available on target system."); + for (WaitForServiceOption waitForServiceOption : subsystem.getOptions(WaitForServiceOption.class)) { + LOGGER.info("Waiting for service {}, timeout:[{}]", waitForServiceOption.getServiceClassName(), waitForServiceOption.getTimeout().toString()); + try { + waitForService(waitForServiceOption.getServiceClassName(), waitForServiceOption.getTimeout()); + LOGGER.info("Service {} has been found in the test container", waitForServiceOption.getServiceClassName()); + } catch (NoSuchServiceException e) { + LOGGER.error("Service {} could not be found in the test container", waitForServiceOption.getServiceClassName()); + } catch (RemoteException e) { + LOGGER.error("Error waiting for service {} in the test container: {}", waitForServiceOption.getServiceClassName(), e.toString()); + } } } @@ -580,6 +590,10 @@ private void waitForState(final long bundleId, final int state, final RelativeTi target.getClientRBC().waitForState(bundleId, state, timeout); } + private void waitForService(String serviceClassName, final RelativeTimeout timeout) throws NoSuchServiceException, RemoteException { + target.getClientRBC().waitForService(serviceClassName, timeout); + } + @Override public synchronized void call(TestAddress address) { target.call(address); diff --git a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/KarafDistributionOption.java b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/KarafDistributionOption.java index 2ffb4859b..fbeaaec15 100644 --- a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/KarafDistributionOption.java +++ b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/KarafDistributionOption.java @@ -65,6 +65,10 @@ public static Option useOwnKarafExamSystemConfiguration(String invoker) { return new KarafExamSystemConfigurationOption(invoker); } + public static Option waitForServiceOption(String serviceClassName, long timeout){ + return new WaitForServiceOption(serviceClassName, timeout); + } + /** * The karaf pax-logging configuration is typically not a file manipulated very often. Therefore * we take the freedom of adding a console logger and changing the log level directly. IF you diff --git a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/WaitForServiceOption.java b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/WaitForServiceOption.java new file mode 100644 index 000000000..359c0c499 --- /dev/null +++ b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/options/WaitForServiceOption.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ops4j.pax.exam.karaf.options; + +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.RelativeTimeout; + +/** + * Per default the folder pax-exam is deleting the test directories after a test is over. If you want to keep those + * directories (for later evaluation) simply set this option. + */ +public class WaitForServiceOption implements Option { + final private String serviceClassName; + + final private RelativeTimeout timeout; + + public WaitForServiceOption(String serviceClassName, long timeout) { + this.serviceClassName = serviceClassName; + this.timeout = new RelativeTimeout(timeout); + } + + public String getServiceClassName() { + return serviceClassName; + } + + public RelativeTimeout getTimeout() { + return timeout; + } +} diff --git a/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/RemoteBundleContextClient.java b/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/RemoteBundleContextClient.java index bd1d3d21a..7ad03af40 100644 --- a/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/RemoteBundleContextClient.java +++ b/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/RemoteBundleContextClient.java @@ -17,12 +17,14 @@ */ package org.ops4j.pax.exam.rbc.client; -import java.io.InputStream; - import org.ops4j.pax.exam.RelativeTimeout; import org.ops4j.pax.exam.TestAddress; +import org.ops4j.pax.exam.rbc.internal.NoSuchServiceException; import org.ops4j.pax.exam.rbc.internal.RemoteBundleContext; +import java.io.InputStream; +import java.rmi.RemoteException; + /** * A {@link RemoteBundleContext} client, that takes away RMI handling. * @@ -46,5 +48,7 @@ public interface RemoteBundleContextClient { void waitForState(final long bundleId, final int state, final RelativeTimeout timeout); + void waitForService(String serviceClassName, RelativeTimeout timeout) throws NoSuchServiceException, RemoteException; + void call(TestAddress address); } diff --git a/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RemoteBundleContextClientImpl.java b/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RemoteBundleContextClientImpl.java index 3403df679..e06c6e70e 100644 --- a/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RemoteBundleContextClientImpl.java +++ b/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RemoteBundleContextClientImpl.java @@ -218,6 +218,11 @@ public void waitForState(final long bundleId, final int state, final RelativeTim } } + @Override + public void waitForService(String serviceClassName, RelativeTimeout timeout) throws NoSuchServiceException, RemoteException { + getRemoteBundleContext().waitForService(serviceClassName, null, timeout); + } + /** * Looks up the {@link RemoteBundleContext} via RMI. The lookup will timeout in the specified * number of millis. diff --git a/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContext.java b/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContext.java index d582c7d03..f358d0cfc 100644 --- a/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContext.java +++ b/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContext.java @@ -75,6 +75,8 @@ Object remoteCall(Class serviceType, String methodName, Class[] methodPara NoSuchServiceException, NoSuchMethodException, IllegalAccessException, InvocationTargetException; + void waitForService(final String serviceClassName, final String filter, final RelativeTimeout timeout) throws NoSuchServiceException, RemoteException; + /** * Installs a bundle remotly. * diff --git a/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContextImpl.java b/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContextImpl.java index 91d3b6f99..354c9961c 100644 --- a/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContextImpl.java +++ b/core/pax-exam-container-rbc/src/main/java/org/ops4j/pax/exam/rbc/internal/RemoteBundleContextImpl.java @@ -80,6 +80,12 @@ public Object remoteCall(final Class serviceType, final String methodName, return serviceType.getMethod(methodName, methodParams).invoke(service, actualParams); } + @Override + public void waitForService(String serviceClassName, String filter, RelativeTimeout timeout) throws NoSuchServiceException, RemoteException { + LOG.trace("Retrieving service of [" + serviceClassName + "]"); + ServiceLookup.getService(bundleContext, serviceClassName, timeout.getValue(), filter); + } + public long installBundle(final String bundleUrl) throws BundleException { LOG.trace("Install bundle from URL [" + bundleUrl + "]"); return bundleContext.installBundle(bundleUrl).getBundleId(); From 217037f81db58257d59c5d43ede296c84734a16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lanouette?= Date: Wed, 20 Apr 2016 14:24:41 -0400 Subject: [PATCH 2/2] Fix import errors from previous commit --- .../internal/KarafTestContainer.java | 80 +++++-------------- .../RetryRemoteBundleContextClient.java | 20 +++-- 2 files changed, 35 insertions(+), 65 deletions(-) diff --git a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java index 6426ad8ae..79eccd126 100644 --- a/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java +++ b/containers/pax-exam-container-karaf/src/main/java/org/ops4j/pax/exam/karaf/container/internal/KarafTestContainer.java @@ -16,78 +16,39 @@ */ package org.ops4j.pax.exam.karaf.container.internal; -import static org.ops4j.pax.exam.CoreOptions.maven; -import static org.ops4j.pax.exam.CoreOptions.options; -import static org.ops4j.pax.exam.CoreOptions.systemProperty; -import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFileExtend; -import static org.ops4j.pax.exam.rbc.Constants.RMI_HOST_PROPERTY; -import static org.ops4j.pax.exam.rbc.Constants.RMI_NAME_PROPERTY; -import static org.ops4j.pax.exam.rbc.Constants.RMI_PORT_PROPERTY; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.URL; -import java.rmi.NoSuchObjectException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.UnicastRemoteObject; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; - import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.ops4j.net.FreePort; -import org.ops4j.pax.exam.ExamSystem; -import org.ops4j.pax.exam.Info; -import org.ops4j.pax.exam.Option; -import org.ops4j.pax.exam.RelativeTimeout; -import org.ops4j.pax.exam.TestAddress; -import org.ops4j.pax.exam.TestContainer; -import org.ops4j.pax.exam.TestContainerException; +import org.ops4j.pax.exam.*; import org.ops4j.pax.exam.container.remote.RBCRemoteTarget; import org.ops4j.pax.exam.karaf.container.internal.adaptions.KarafManipulator; import org.ops4j.pax.exam.karaf.container.internal.adaptions.KarafManipulatorFactory; import org.ops4j.pax.exam.karaf.container.internal.runner.Runner; -import org.ops4j.pax.exam.karaf.options.DoNotModifyLogOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionBaseConfigurationOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationConsoleOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationFileExtendOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationFileOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationFilePutOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationFileReplacementOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationSecurityOption; -import org.ops4j.pax.exam.karaf.options.KarafDistributionOption; -import org.ops4j.pax.exam.karaf.options.KarafExamSystemConfigurationOption; -import org.ops4j.pax.exam.karaf.options.KarafFeaturesOption; -import org.ops4j.pax.exam.karaf.options.KeepRuntimeFolderOption; -import org.ops4j.pax.exam.karaf.options.LogLevelOption; +import org.ops4j.pax.exam.karaf.options.*; import org.ops4j.pax.exam.karaf.options.configs.CustomProperties; import org.ops4j.pax.exam.karaf.options.configs.FeaturesCfg; -import org.ops4j.pax.exam.options.BootDelegationOption; -import org.ops4j.pax.exam.options.MavenArtifactUrlReference; -import org.ops4j.pax.exam.options.PropagateSystemPropertyOption; -import org.ops4j.pax.exam.options.ServerModeOption; -import org.ops4j.pax.exam.options.SystemPackageOption; -import org.ops4j.pax.exam.options.SystemPropertyOption; +import org.ops4j.pax.exam.options.*; import org.ops4j.pax.exam.options.extra.VMOption; import org.ops4j.pax.exam.rbc.client.RemoteBundleContextClient; +import org.ops4j.pax.exam.rbc.internal.NoSuchServiceException; import org.osgi.framework.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.*; +import java.net.InetAddress; +import java.net.URL; +import java.rmi.NoSuchObjectException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.UnicastRemoteObject; +import java.util.*; + +import static org.ops4j.pax.exam.CoreOptions.*; +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFileExtend; +import static org.ops4j.pax.exam.rbc.Constants.*; + public class KarafTestContainer implements TestContainer { private static final Logger LOGGER = LoggerFactory.getLogger(KarafTestContainer.class); @@ -231,8 +192,9 @@ private void startKaraf(ExamSystem subsystem, File karafBase, File karafHome) { Bundle.ACTIVE, subsystem.getTimeout()); } else { - LOGGER - .info("System runs in Server Mode. Which means, no Test facility bundles available on target system."); + LOGGER.info("System runs in Server Mode. Which means, no Test facility bundles available on target system."); + } + for (WaitForServiceOption waitForServiceOption : subsystem.getOptions(WaitForServiceOption.class)) { LOGGER.info("Waiting for service {}, timeout:[{}]", waitForServiceOption.getServiceClassName(), waitForServiceOption.getTimeout().toString()); try { diff --git a/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RetryRemoteBundleContextClient.java b/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RetryRemoteBundleContextClient.java index 2711cc861..664c97afc 100644 --- a/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RetryRemoteBundleContextClient.java +++ b/core/pax-exam-container-rbc-client/src/main/java/org/ops4j/pax/exam/rbc/client/intern/RetryRemoteBundleContextClient.java @@ -17,17 +17,20 @@ */ package org.ops4j.pax.exam.rbc.client.intern; +import org.ops4j.pax.exam.ExceptionHelper; +import org.ops4j.pax.exam.RelativeTimeout; +import org.ops4j.pax.exam.TestAddress; +import org.ops4j.pax.exam.rbc.client.RemoteBundleContextClient; +import org.ops4j.pax.exam.rbc.internal.NoSuchServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.InputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.NoSuchObjectException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.ops4j.pax.exam.ExceptionHelper; -import org.ops4j.pax.exam.RelativeTimeout; -import org.ops4j.pax.exam.TestAddress; -import org.ops4j.pax.exam.rbc.client.RemoteBundleContextClient; +import java.rmi.RemoteException; /** * @@ -122,6 +125,11 @@ public void waitForState(long bundleId, int state, RelativeTimeout timeout) { proxy.waitForState(bundleId, state, timeout); } + @Override + public void waitForService(String serviceClassName, RelativeTimeout timeout) throws NoSuchServiceException, RemoteException { + proxy.waitForService(serviceClassName, timeout); + } + public void call(TestAddress address) { proxy.call(address); }