Camel蓝图测试-如何动态替换/代理蓝图中引用的远程服务,以防止使用真实服务



我有以下场景:

我有一个OSGI捆绑包,它有一个在蓝图XML中定义的服务引用,该引用引用引用了远程捆绑包中的接口,还有一个bean,它使用impl的一个方法来填充Properties对象。

Bundle#1的XML(消费者)中的相关片段:

...
<!-- other bean definitions, namespace stuff, etc -->
<!-- reference to the fetching service -->
<reference id="fetchingService"    interface="company.path.to.fetching.bundle.FetchingService" />
<!-- bean to hold the actual Properties object: the getConfigProperties     method is one of the overridden interface methods -->
<bean id="fetchedProperties" class="java.util.Properties" factory-ref="fetchingService" factory-method="getProperties" />
<camelContext id="contextThatNeedsProperties" xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder id="properties" location="ref:fetchedProperties" />
...
<!-- the rest of the context stuff - routes and so on -->
</camelContext>

远程捆绑包的blueprint.xml:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">

<cm:property-placeholder id="config-properties" persistent-id="company.path.configfetcher" />
<bean id="fetchingService" class="company.path.to.fetching.bundle.impl.FetchingServiceImpl" scope="singleton" init-method="createLoader" depends-on="config-properties">
    <property name="environment" value="${environment}" />
    <property name="pathToRestService" value="${restPath}" />
</bean>
<service ref="fetchingService" interface="company.path.to.fetching.bundle.FetchingService" />
<!-- END TESTING -->
</blueprint>

来自Impl类:

public synchronized Properties getProperties() {
    if(!IS_RUNNING) {
// timer task that regularly calls the REST api to check for updates
        timer.schedule(updateTimerTask, 0, pollInterval);
        IS_RUNNING = true;
    }
//Map<String, Properties> to return matching object if it's there 
    if(PROPERTIES_BY_KEY.containsKey(environment)) {
        return PROPERTIES_BY_KEY.get(environment);
    }
    /* if nothing, return an empty Properties object - if this is the case, then whatever bundle is relying on these
    *  properties is going to fail and we'll see it in the logs
    */
    return new Properties();
}

问题:

我有一个测试类(扩展了CamelBlueprintTestSupport),有很多移动部件,所以我不能真正改变事情的顺序。不幸的是,属性bean方法在CamelContext启动之前就被调用了。没什么大不了的,因为在测试环境中没有配置文件可以从中读取必要的属性,所以检索失败,我们得到一个空的属性对象[注意:我们用fakes覆盖属性组件,因为它不是要测试的类],但在一个完美的世界里,我希望能够做两件事:

1) 用新的Impl()替换服务

2) 拦截对getProperties方法的调用,或者将bean绑定到新服务,以便调用从伪impl 返回属性

想法?

编辑#1:

以下是我现在正在做的一件变通方法:

try {
ServiceReference sr =      this.getBundleContext().getServiceReference(FetchingService.class);
        if(sr != null) {
            ((FetchingServiceImpl)this.getBundleContext().getService(sr)).setEnvironment(env);
            ((FetchingServiceImpl)this.getBundleContext().getService(sr)).setPath(path);
        }
    } catch(Exception e) {
        log.error("Error getting Fetching service: {}", e.getMessage());
    }

这里最大的问题是,我必须等到createCamelContext被调用才能存在BundleContext;因此,getProperties调用已经发生过一次。正如我所说,由于在测试环境中不存在FetchingService类的配置来提供环境和路径字符串,因此第一次调用将失败(导致Properties对象为空)。第二次,上面的代码已经在impl类中设置了属性,我们开始比赛了。这不是一个不起作用的问题。相反,它是一个更好、更优雅的解决方案,可以应用于其他场景。

哦,为了在有人问之前澄清一下,这个服务的目的是,我们不必为部署到Servicemix实例的每个OSGI捆绑包都有一个.cfg文件——这个中心服务将去获取其他捆绑包需要的配置,而唯一需要的.cfg文件是用于Fetcher的。

其他相关细节:

Camel 2.13.2-希望是2.14,因为他们在该版本中添加了更多的属性占位符工具,这可能会使更容易

Servicemix-5.3.1

您是否尝试在测试中重写CamelBlueprintTestSupportaddServicesOnStartup(请参阅"启动时添加服务"http://camel.apache.org/blueprint-testing.html)?

在您的情况下,类似于:

@Override
protected void addServicesOnStartup(Map<String, KeyValueHolder<Object, Dictionary>> services) {
    services.put(FetchingService.class.getName(), asService(new FetchServiceImpl(), null));
}

最新更新