You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by mh...@apache.org on 2011/05/06 03:57:07 UTC
svn commit: r1100024 - in /shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/js/
test/java/org/apache/shindig/gadgets/js/
Author: mhermanto
Date: Fri May 6 01:57:06 2011
New Revision: 1100024
URL: http://svn.apache.org/viewvc?rev=1100024&view=rev
Log:
JSL beacon now keeps track of loaded features.
http://codereview.appspot.com/4486043/
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessor.java
- copied, changed from r1099980, shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessor.java
- copied, changed from r1099942, shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessor.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessorTest.java
- copied, changed from r1099980, shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessorTest.java
- copied, changed from r1099942, shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessorTest.java
Removed:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java
Copied: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessor.java (from r1099980, shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java)
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessor.java?p2=shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessor.java&p1=shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java&r1=1099980&r2=1100024&rev=1100024&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessor.java Fri May 6 01:57:06 2011
@@ -22,7 +22,7 @@ import com.google.common.annotations.Vis
import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
-public class AddJsLoadCallbackProcessor implements JsProcessor {
+public class AddJslCallbackProcessor implements JsProcessor {
private static final String CODE_ID = "[jsload-callback]";
@VisibleForTesting
Copied: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessor.java (from r1099942, shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java)
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessor.java?p2=shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessor.java&p1=shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java&r1=1099942&r2=1100024&rev=1100024&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessor.java Fri May 6 01:57:06 2011
@@ -36,7 +36,7 @@ import java.util.List;
*
* Used when loading embedded JS configuration in core.config/config.js.
*/
-public class InjectJsInfoVariableProcessor implements JsProcessor {
+public class AddJslInfoVariableProcessor implements JsProcessor {
private static final String CODE_ID = "[jsload-code-info]";
@VisibleForTesting
@@ -48,7 +48,7 @@ public class InjectJsInfoVariableProcess
private final JsUriManager jsUriManager;
@Inject
- public InjectJsInfoVariableProcessor(JsUriManager jsUriManager) {
+ public AddJslInfoVariableProcessor(JsUriManager jsUriManager) {
this.jsUriManager = jsUriManager;
}
Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessor.java?rev=1100024&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessor.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessor.java Fri May 6 01:57:06 2011
@@ -0,0 +1,95 @@
+/*
+ * 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.apache.shindig.gadgets.js;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.features.FeatureRegistry;
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Injects a global ___jsl.l variable with information about the JS request.
+ *
+ * Used when loading embedded JS configuration in core.config/config.js.
+ */
+public class AddJslLoadedVariableProcessor implements JsProcessor {
+ private static final String CODE_ID = "[jsload-loaded-info]";
+ private static final Joiner UNKNOWN_FEATURE_ERR = Joiner.on(", ");
+
+ @VisibleForTesting
+ static final String TEMPLATE =
+ "window['___jsl']['l'] = (window['___jsl']['l'] || []).concat(%s);";
+
+ private final FeatureRegistry registry;
+
+ @Inject
+ public AddJslLoadedVariableProcessor(FeatureRegistry featureRegistry) {
+ this.registry = featureRegistry;
+ }
+
+ public boolean process(JsRequest jsRequest, JsResponseBuilder builder) throws JsException {
+ JsUri jsUri = jsRequest.getJsUri();
+ if (!jsUri.isNohint()) {
+ Set<String> result = getBundleNames(jsUri, false);
+ result.removeAll(getBundleNames(jsUri, true));
+ String array = toArrayString(result);
+ builder.appendJs(String.format(TEMPLATE, array), CODE_ID);
+ }
+ return true;
+ }
+
+ // TODO: factor this logic into somewhere shared. it's now used in GetJsContentProcessor.
+ private Set<String> getBundleNames(JsUri jsUri, boolean loaded) throws JsException {
+ GadgetContext ctx = new JsGadgetContext(jsUri);
+ Collection<String> libs = loaded ? jsUri.getLoadedLibs() : jsUri.getLibs();
+ List<String> unsupported = Lists.newLinkedList();
+ FeatureRegistry.LookupResult lookup = registry.getFeatureResources(ctx, libs, unsupported);
+ if (!unsupported.isEmpty()) {
+ String message = loaded ? "loaded" : "requested";
+ throw new JsException(HttpResponse.SC_BAD_REQUEST,
+ "Unknown " + message + " feature(s): " + UNKNOWN_FEATURE_ERR.join(unsupported));
+ }
+ Set<String> ret = Sets.newLinkedHashSet(); // ordered set for testability.
+ for (FeatureBundle bundle : lookup.getBundles()) {
+ ret.add(bundle.getName());
+ }
+ return ret;
+ }
+
+ private String toArrayString(Set<String> bundles) {
+ StringBuilder builder = new StringBuilder();
+ for (String bundle : bundles) {
+ if (builder.length() > 0) builder.append(",");
+ builder.append("'").append(StringEscapeUtils.escapeJavaScript(bundle)).append("'");
+ }
+ return "[" + builder.toString() + "]";
+ }
+}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java?rev=1100024&r1=1100023&r2=1100024&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java Fri May 6 01:57:06 2011
@@ -38,7 +38,7 @@ public class JsServingPipelineModule ext
@Provides
@Inject
public List<JsProcessor> provideProcessors(
- InjectJsInfoVariableProcessor injectJsInfoVariableProcessor,
+ AddJslInfoVariableProcessor addJslInfoVariableProcessor,
JsLoadProcessor jsLoaderGeneratorProcessor,
IfModifiedSinceProcessor ifModifiedSinceProcessor,
GetJsContentProcessor getJsContentProcessor,
@@ -46,12 +46,13 @@ public class JsServingPipelineModule ext
ExportJsProcessor exportJsProcessor,
SeparatorCommentingProcessor separatorCommentingProcessor,
ConfigInjectionProcessor configInjectionProcessor,
+ AddJslLoadedVariableProcessor addJslLoadedVariableProcessor,
AddOnloadFunctionProcessor addOnloadFunctionProcessor,
- AddJsLoadCallbackProcessor addJsLoadCallbackProcessor,
+ AddJslCallbackProcessor addJslCallbackProcessor,
CompilationProcessor compilationProcessor,
AnonFuncWrappingProcessor anonFuncProcessor) {
return ImmutableList.of(
- injectJsInfoVariableProcessor,
+ addJslInfoVariableProcessor,
jsLoaderGeneratorProcessor,
ifModifiedSinceProcessor,
getJsContentProcessor,
@@ -59,8 +60,9 @@ public class JsServingPipelineModule ext
exportJsProcessor,
separatorCommentingProcessor,
configInjectionProcessor,
+ addJslLoadedVariableProcessor,
addOnloadFunctionProcessor,
- addJsLoadCallbackProcessor,
+ addJslCallbackProcessor,
compilationProcessor,
anonFuncProcessor);
}
Copied: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessorTest.java (from r1099980, shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java)
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessorTest.java?p2=shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessorTest.java&p1=shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java&r1=1099980&r2=1100024&rev=1100024&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslCallbackProcessorTest.java Fri May 6 01:57:06 2011
@@ -26,13 +26,13 @@ import org.easymock.IMocksControl;
import org.junit.Before;
import org.junit.Test;
-public class AddJsLoadCallbackProcessorTest {
+public class AddJslCallbackProcessorTest {
private IMocksControl control;
private JsUri jsUri;
private JsRequest request;
private JsResponseBuilder response;
- private AddJsLoadCallbackProcessor processor;
+ private AddJslCallbackProcessor processor;
@Before
public void setUp() {
@@ -40,7 +40,7 @@ public class AddJsLoadCallbackProcessorT
jsUri = control.createMock(JsUri.class);
request = control.createMock(JsRequest.class);
response = new JsResponseBuilder();
- processor = new AddJsLoadCallbackProcessor();
+ processor = new AddJslCallbackProcessor();
EasyMock.expect(request.getJsUri()).andReturn(jsUri);
}
@@ -49,7 +49,7 @@ public class AddJsLoadCallbackProcessorT
EasyMock.expect(jsUri.isNohint()).andReturn(false);
control.replay();
assertTrue(processor.process(request, response));
- assertEquals(AddJsLoadCallbackProcessor.JSL_CALLBACK_JS,
+ assertEquals(AddJslCallbackProcessor.JSL_CALLBACK_JS,
response.build().toJsString());
control.verify();
}
Copied: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessorTest.java (from r1099942, shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java)
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessorTest.java?p2=shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessorTest.java&p1=shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java&r1=1099942&r2=1100024&rev=1100024&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslInfoVariableProcessorTest.java Fri May 6 01:57:06 2011
@@ -36,9 +36,9 @@ import java.util.List;
/**
- * Tests for {@link InjectJsInfoVariableProcessor}.
+ * Tests for {@link AddJslInfoVariableProcessor}.
*/
-public class InjectJsInfoVariableProcessorTest {
+public class AddJslInfoVariableProcessorTest {
private static final String URI = "http://localhost";
private static final List<String> LIBS = ImmutableList.of("fo'o", "bar", "baz");
@@ -52,7 +52,7 @@ public class InjectJsInfoVariableProcess
private JsUriManager jsUriManager;
private JsUri jsUri;
private JsResponseBuilder response;
- private InjectJsInfoVariableProcessor processor;
+ private AddJslInfoVariableProcessor processor;
@Before
public void setUp() {
@@ -60,7 +60,7 @@ public class InjectJsInfoVariableProcess
request = control.createMock(JsRequest.class);
jsUriManager = control.createMock(JsUriManager.class);
response = new JsResponseBuilder();
- processor = new InjectJsInfoVariableProcessor(jsUriManager);
+ processor = new AddJslInfoVariableProcessor(jsUriManager);
}
@Test
@@ -77,7 +77,7 @@ public class InjectJsInfoVariableProcess
setJsUri(URI);
control.replay();
processor.process(request, response);
- String expected = String.format(InjectJsInfoVariableProcessor.HINT_TEMPLATE, URI_JS, LIBS_JS);
+ String expected = String.format(AddJslInfoVariableProcessor.HINT_TEMPLATE, URI_JS, LIBS_JS);
assertEquals(expected, response.build().toJsString());
control.verify();
}
@@ -89,7 +89,7 @@ public class InjectJsInfoVariableProcess
EasyMock.expect(jsUriManager.makeExternJsUri(EasyMock.capture(captureJsUri))).andReturn(Uri.parse(GENERATED_URI));
control.replay();
processor.process(request, response);
- String expected = String.format(InjectJsInfoVariableProcessor.HINT_TEMPLATE, GENERATED_URI_JS, LIBS_JS);
+ String expected = String.format(AddJslInfoVariableProcessor.HINT_TEMPLATE, GENERATED_URI_JS, LIBS_JS);
assertEquals(expected, response.build().toJsString());
assertFalse(captureJsUri.getValue().isJsload());
assertTrue(captureJsUri.getValue().isNohint());
Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessorTest.java?rev=1100024&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessorTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJslLoadedVariableProcessorTest.java Fri May 6 01:57:06 2011
@@ -0,0 +1,123 @@
+/*
+ * 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.apache.shindig.gadgets.js;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.features.FeatureRegistry;
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.features.FeatureRegistry.LookupResult;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+import org.apache.shindig.gadgets.uri.UriStatus;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Tests for {@link AddJslLoadedVariableProcessor}.
+ */
+public class AddJslLoadedVariableProcessorTest {
+ private static final List<String> EMPTY_STRING_LIST = ImmutableList.<String>of();
+
+ private static final String REQ_1_LIB = "foo";
+ private static final String REQ_1_DEP_LIB = "bar";
+ private static final String REQ_2_LIB = "gig";
+ private static final String LOAD_LIB = "bar";
+ private static final String URI = "http://localhost";
+ private static final List<String> REQ_LIBS = ImmutableList.of(
+ REQ_1_LIB, REQ_2_LIB, REQ_1_LIB, REQ_2_LIB);
+ private static final List<String> LOAD_LIBS = ImmutableList.of(
+ LOAD_LIB, LOAD_LIB);
+
+ private IMocksControl control;
+ private JsRequest request;
+ private FeatureRegistry registry;
+ private JsUri jsUri;
+ private JsResponseBuilder response;
+ private AddJslLoadedVariableProcessor processor;
+
+ @Before
+ public void setUp() {
+ control = EasyMock.createControl();
+ request = control.createMock(JsRequest.class);
+ registry = control.createMock(FeatureRegistry.class);
+ response = new JsResponseBuilder();
+ processor = new AddJslLoadedVariableProcessor(registry);
+ }
+
+ @Test
+ public void testSucceeds() throws Exception {
+ setUpJsUri(URI + "/" + REQ_1_LIB + ".js");
+ setUpRegistry();
+ control.replay();
+ processor.process(request, response);
+ assertEquals(String.format(AddJslLoadedVariableProcessor.TEMPLATE,
+ "['foo','gig']"), response.build().toJsString());
+ control.verify();
+ }
+
+ @Test
+ public void testSkips() throws Exception {
+ setUpJsUri(URI + "?nohint=1");
+ control.replay();
+ processor.process(request, response);
+ assertEquals("", response.build().toJsString());
+ control.verify();
+ }
+
+ private void setUpJsUri(String uri) {
+ jsUri = new JsUri(UriStatus.VALID_UNVERSIONED, Uri.parse(uri), REQ_LIBS, LOAD_LIBS);
+ EasyMock.expect(request.getJsUri()).andReturn(jsUri);
+ }
+
+ private void setUpRegistry() {
+ FeatureBundle bundle1 = mockBundle(REQ_1_LIB);
+ FeatureBundle bundle2 = mockBundle(REQ_1_DEP_LIB);
+ FeatureBundle bundle3 = mockBundle(REQ_2_LIB);
+ FeatureBundle bundle4 = mockBundle(LOAD_LIB);
+ LookupResult reqResult = mockLookupResult(Lists.newArrayList(bundle1, bundle2, bundle3));
+ expect(registry.getFeatureResources(isA(JsGadgetContext.class), eq(REQ_LIBS),
+ eq(EMPTY_STRING_LIST))).andReturn(reqResult);
+ LookupResult loadResult = mockLookupResult(Lists.newArrayList(bundle4));
+ expect(registry.getFeatureResources(isA(JsGadgetContext.class), eq(LOAD_LIBS),
+ eq(EMPTY_STRING_LIST))).andReturn(loadResult);
+ }
+
+ private LookupResult mockLookupResult(List<FeatureBundle> bundles) {
+ LookupResult result = control.createMock(LookupResult.class);
+ expect(result.getBundles()).andReturn(bundles);
+ return result;
+ }
+
+ private FeatureBundle mockBundle(String name) {
+ FeatureBundle result = control.createMock(FeatureBundle.class);
+ expect(result.getName()).andReturn(name);
+ return result;
+ }
+}