You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2012/05/16 20:50:32 UTC
[32/44] git commit: Convert TestNG to Spock
Convert TestNG to Spock
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/99f88df2
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/99f88df2
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/99f88df2
Branch: refs/heads/master
Commit: 99f88df25dbe753eca5742f2189fbe6f7a713651
Parents: a1da91b
Author: Howard M. Lewis Ship <hl...@gmail.com>
Authored: Mon Apr 16 10:55:43 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed May 16 11:49:41 2012 -0700
----------------------------------------------------------------------
.../org/apache/tapestry/ioc/EagerLoadSpec.groovy | 24 +
.../org/apache/tapestry/ioc/ReloadSpec.groovy | 403 +++++++++++++++
.../apache/tapestry5/ioc/EagerLoadServiceImpl.java | 4 +-
.../tapestry5/ioc/EagerProxyReloadModule.java | 4 +-
.../java/org/apache/tapestry5/ioc/ReloadTest.java | 399 --------------
5 files changed, 432 insertions(+), 402 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/99f88df2/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/EagerLoadSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/EagerLoadSpec.groovy b/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/EagerLoadSpec.groovy
new file mode 100644
index 0000000..4ee948a
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/EagerLoadSpec.groovy
@@ -0,0 +1,24 @@
+package org.apache.tapestry.ioc
+
+import org.apache.tapestry5.ioc.EagerProxyReloadModule
+
+
+class EagerLoadSpec extends IOCSpecification {
+
+ def "proxied service does eager load"()
+ {
+ expect:
+
+ EagerProxyReloadModule.eagerLoadServiceDidLoad == false
+
+ when:
+
+ buildRegistry EagerProxyReloadModule
+
+ performRegistryStartup()
+
+ then:
+
+ EagerProxyReloadModule.eagerLoadServiceDidLoad == true
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/99f88df2/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/ReloadSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/ReloadSpec.groovy b/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/ReloadSpec.groovy
new file mode 100644
index 0000000..a9ca812
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/org/apache/tapestry/ioc/ReloadSpec.groovy
@@ -0,0 +1,403 @@
+package org.apache.tapestry.ioc
+
+import org.apache.tapestry5.internal.plastic.PlasticInternalUtils
+import org.apache.tapestry5.internal.plastic.asm.ClassWriter
+import org.apache.tapestry5.ioc.Registry
+import org.apache.tapestry5.ioc.RegistryBuilder
+import org.apache.tapestry5.services.UpdateListenerHub
+import spock.lang.AutoCleanup
+import spock.lang.Specification
+import com.example.*
+
+import static org.apache.tapestry5.internal.plastic.asm.Opcodes.*
+
+class ReloadSpec extends Specification {
+
+ private static final String PACKAGE = "com.example";
+
+ private static final String CLASS = PACKAGE + ".ReloadableServiceImpl";
+
+ private static final String BASE_CLASS = PACKAGE + ".BaseReloadableServiceImpl";
+
+
+ @AutoCleanup("shutdown")
+ Registry registry
+
+ @AutoCleanup("deleteDir")
+ File classesDir
+
+ ClassLoader classLoader
+
+ File classFile;
+
+ def createRegistry() {
+ registry = new RegistryBuilder(classLoader).add(ReloadModule).build()
+ }
+
+ /** Any unrecognized methods are evaluated against the registry. */
+ def methodMissing(String name, args) {
+ registry."$name"(* args)
+ }
+
+
+ def setup() {
+ def uid = UUID.randomUUID().toString()
+
+ classesDir = new File(System.getProperty("java.io.tmpdir"), uid)
+
+ def classesURL = new URL("file:" + classesDir.getCanonicalPath() + "/")
+
+ classLoader = new URLClassLoader([classesURL] as URL[],
+ Thread.currentThread().contextClassLoader)
+
+ classFile = new File(classesDir, PlasticInternalUtils.toClassPath(CLASS))
+ }
+
+ def createImplementationClass(String status) {
+ createImplementationClass CLASS, status
+ }
+
+ def createImplementationClass(String className, String status) {
+
+ String internalName = PlasticInternalUtils.toInternalName className
+
+ createClassWriter(internalName, "java/lang/Object", ACC_PUBLIC).with {
+
+ // Add default constructor
+
+ visitMethod(ACC_PUBLIC, "<init>", "()V", null, null).with {
+ visitCode()
+ visitVarInsn ALOAD, 0
+ visitMethodInsn INVOKESPECIAL, "java/lang/Object", "<init>", "()V"
+ visitInsn RETURN
+ visitMaxs 1, 1
+ visitEnd()
+ }
+
+
+ visitMethod(ACC_PUBLIC, "getStatus", "()Ljava/lang/String;", null, null).with {
+ visitCode()
+ visitLdcInsn status
+ visitInsn ARETURN
+ visitMaxs 1, 1
+ visitEnd()
+ }
+
+ visitEnd()
+
+ writeBytecode it, internalName
+ }
+
+ }
+
+ def createClassWriter(String internalName, String baseClassInternalName, int classModifiers) {
+ ClassWriter cw = new ClassWriter(0);
+
+ cw.visit V1_5, classModifiers, internalName, null,
+ baseClassInternalName, [
+ PlasticInternalUtils.toInternalName(ReloadableService.name)
+ ] as String[]
+
+
+ return cw
+ }
+
+
+ def writeBytecode(ClassWriter cw, String internalName) {
+ byte[] bytecode = cw.toByteArray();
+
+ writeBytecode(bytecode, pathForInternalName(internalName))
+ }
+
+ def writeBytecode(byte[] bytecode, String path) {
+ File file = new File(path)
+
+ file.parentFile.mkdirs()
+
+ file.withOutputStream { it.write bytecode }
+ }
+
+
+ def pathForInternalName(String internalName) {
+ return String.format("%s/%s.class",
+ classesDir.getAbsolutePath(),
+ internalName)
+ }
+
+ def update() {
+ getService(UpdateListenerHub).fireCheckForUpdates()
+ }
+
+ def "reload a service implementation"() {
+
+ when:
+
+ createImplementationClass "initial"
+
+ createRegistry()
+
+ ReloadableService reloadable = getService(ReloadableService);
+
+ update()
+
+ then:
+
+ reloadable.status == "initial"
+
+ when:
+
+ update()
+
+ touch classFile
+
+ createImplementationClass "updated"
+
+ then:
+
+ // Changes do not take effect until after update check
+
+ reloadable.status == "initial"
+
+ when:
+
+ update()
+
+ then:
+
+ reloadable.status == "updated"
+ }
+
+ def "reload a base class"() {
+
+ setup:
+
+ def baseClassInternalName = PlasticInternalUtils.toInternalName BASE_CLASS
+ def internalName = PlasticInternalUtils.toInternalName CLASS
+
+ createImplementationClass BASE_CLASS, "initial from base"
+
+ createClassWriter(internalName, baseClassInternalName, ACC_PUBLIC).with {
+
+ visitMethod(ACC_PUBLIC, "<init>", "()V", null, null).with {
+ visitCode()
+ visitVarInsn ALOAD, 0
+ visitMethodInsn INVOKESPECIAL, baseClassInternalName, "<init>", "()V"
+ visitInsn RETURN
+ visitMaxs 1, 1
+ visitEnd()
+ }
+
+ visitEnd()
+
+ writeBytecode it, internalName
+ }
+
+ createRegistry()
+
+ when:
+
+ ReloadableService reloadable = getService(ReloadableService)
+
+ update()
+
+ then:
+
+ reloadable.status == "initial from base"
+
+ when:
+
+ touch(new File(pathForInternalName(baseClassInternalName)))
+
+ createImplementationClass BASE_CLASS, "updated from base"
+
+ update()
+
+ then:
+
+ reloadable.status == "updated from base"
+ }
+
+ def "deleting an implementation class results in a runtime exception when reloading"() {
+
+ when:
+
+ createImplementationClass "before delete"
+
+ createRegistry()
+
+ ReloadableService reloadable = getService ReloadableService
+
+ then:
+
+ reloadable.status == "before delete"
+
+ assert classFile.exists()
+
+ when:
+
+ classFile.delete()
+
+ update()
+
+ reloadable.getStatus()
+
+ then:
+
+ RuntimeException e = thrown()
+
+ e.message.contains "Unable to reload class $CLASS"
+ }
+
+
+ def "reload a proxy object"() {
+ when:
+
+ createImplementationClass "initial proxy"
+
+ createRegistry()
+
+ def clazz = classLoader.loadClass CLASS
+
+ ReloadableService reloadable = proxy(ReloadableService, clazz)
+
+ then:
+
+ reloadable.status == "initial proxy"
+
+ when:
+
+ touch classFile
+
+ createImplementationClass "updated proxy"
+
+ update()
+
+ then:
+
+ reloadable.status == "updated proxy"
+
+ when:
+
+ touch classFile
+
+ createImplementationClass "re-updated proxy"
+
+ update()
+
+ then:
+
+ reloadable.status == "re-updated proxy"
+ }
+
+ def "check exception message for invalid service implementation (lacking a public constructor)"() {
+
+ when:
+
+ createImplementationClass "initial"
+
+ createRegistry()
+
+ ReloadableService reloadable = getService ReloadableService
+
+ touch classFile
+
+ createInvalidImplementationClass()
+
+ update()
+
+ reloadable.getStatus()
+
+ then:
+
+ Exception e = thrown()
+
+ e.message == "Service implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor."
+ }
+
+ def "ensure ReloadAware services are notified when services are reloaded"() {
+
+ when:
+
+ registry = new RegistryBuilder().add(ReloadAwareModule).build()
+
+ then:
+
+ ReloadAwareModule.counterInstantiations == 0
+ ReloadAwareModule.counterReloads == 0
+
+ when:
+
+ Counter counter = proxy(Counter, CounterImpl)
+
+ then:
+
+ ReloadAwareModule.counterInstantiations == 0
+
+ expect:
+
+ counter.increment() == 1
+ counter.increment() == 2
+
+ ReloadAwareModule.counterInstantiations == 1
+
+ when:
+
+ def classURL = CounterImpl.getResource("CounterImpl.class")
+ def classFile = new File(classURL.toURI())
+
+ touch classFile
+
+ update()
+
+ // Check that the internal state has reset
+
+ assert counter.increment() == 1
+
+ then:
+
+ ReloadAwareModule.counterInstantiations == 2
+ ReloadAwareModule.counterReloads == 1
+ }
+
+ def createInvalidImplementationClass() {
+ def internalName = PlasticInternalUtils.toInternalName CLASS
+
+ createClassWriter(internalName, "java/lang/Object", ACC_PUBLIC).with {
+
+ visitMethod(ACC_PROTECTED, "<init>", "()V", null, null).with {
+ visitVarInsn ALOAD, 0
+ visitMethodInsn INVOKESPECIAL, "java/lang/Object", "<init>", "()V"
+ visitInsn RETURN
+ visitMaxs 1, 1
+ visitEnd()
+ }
+
+ visitEnd()
+
+ writeBytecode it, internalName
+ }
+ }
+
+
+ def touch(File f) {
+ long startModified = f.lastModified();
+
+ int index = 0;
+
+ while (true) {
+ f.setLastModified System.currentTimeMillis()
+
+ long newModified = f.lastModified()
+
+ if (newModified != startModified) {
+ return;
+ }
+
+ // Sleep an ever increasing amount, to ensure that the filesystem
+ // catches the change to the file. The Ubuntu CI Server appears
+ // to need longer waits.
+
+ Thread.sleep 50 * (2 ^ index++)
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/99f88df2/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerLoadServiceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerLoadServiceImpl.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerLoadServiceImpl.java
index b578092..f73eb86 100644
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerLoadServiceImpl.java
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerLoadServiceImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,6 +21,6 @@ public class EagerLoadServiceImpl implements EagerLoadService
{
public EagerLoadServiceImpl()
{
- ReloadTest.eagerLoadServiceWasInstantiated = true;
+ EagerProxyReloadModule.eagerLoadServiceDidLoad = true;
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/99f88df2/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerProxyReloadModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerProxyReloadModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerProxyReloadModule.java
index 12e16b3..8859003 100644
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerProxyReloadModule.java
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/EagerProxyReloadModule.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@ package org.apache.tapestry5.ioc;
public class EagerProxyReloadModule
{
+ public static boolean eagerLoadServiceDidLoad;
+
public static void bind(ServiceBinder binder)
{
binder.bind(EagerLoadService.class, EagerLoadServiceImpl.class);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/99f88df2/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
deleted file mode 100644
index a802c24..0000000
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
+++ /dev/null
@@ -1,399 +0,0 @@
-// Copyright 2010, 2011 The Apache Software Foundation
-//
-// Licensed 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.tapestry5.ioc;
-
-import com.example.*;
-import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
-import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
-import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
-import org.apache.tapestry5.ioc.test.IOCTestCase;
-import org.apache.tapestry5.services.UpdateListenerHub;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.net.URLClassLoader;
-
-import static org.apache.tapestry5.internal.plastic.asm.Opcodes.*;
-
-/**
- * Test the ability to perform live class reloading of a service implementation.
- */
-@SuppressWarnings("unchecked")
-public class ReloadTest extends IOCTestCase
-{
- private static final String PACKAGE = "com.example";
-
- private static final String CLASS = PACKAGE + ".ReloadableServiceImpl";
-
- private static final String BASE_CLASS = PACKAGE + ".BaseReloadableServiceImpl";
-
- private File classesDir;
-
- private ClassLoader classLoader;
-
- public static boolean eagerLoadServiceWasInstantiated;
-
- private File classFile;
-
- @BeforeClass
- public void setup() throws Exception
- {
- String uid = Long.toHexString(System.currentTimeMillis());
-
- classesDir = new File(System.getProperty("java.io.tmpdir"), uid);
-
- // URLClassLoader REQUIRES that File URLs end with a slash! That's a half hour of my life gone!
-
- URL classesURL = new URL("file:" + classesDir.getCanonicalPath() + "/");
-
- System.out.println("Reload classes dir: " + classesURL);
-
- classLoader = new URLClassLoader(new URL[]
- {classesURL}, Thread.currentThread().getContextClassLoader());
-
- classFile = new File(classesDir, "com/example/ReloadableServiceImpl.class");
- }
-
- @Test
- public void reload_a_service_implementation() throws Exception
- {
- // First, create the initial implementation
-
- createImplementationClass("initial");
-
- Registry registry = createRegistry();
-
- ReloadableService reloadable = registry.getService(ReloadableService.class);
-
- fireUpdateCheck(registry);
-
- assertEquals(reloadable.getStatus(), "initial");
-
- fireUpdateCheck(registry);
-
- touch(classFile);
-
- createImplementationClass("updated");
-
- // Doesn't take effect until after the update check
-
- assertEquals(reloadable.getStatus(), "initial");
-
- fireUpdateCheck(registry);
-
- assertEquals(reloadable.getStatus(), "updated");
-
- registry.shutdown();
- }
-
- @Test
- public void reload_a_base_class() throws Exception
- {
- String baseClassInternalName = PlasticInternalUtils.toInternalName(BASE_CLASS);
- String internalName = PlasticInternalUtils.toInternalName(CLASS);
-
- createImplementationClass(BASE_CLASS, "initial from base");
-
-
- ClassWriter cw = createClassWriter(internalName, baseClassInternalName, ACC_PUBLIC);
-
- // Add default constructor
-
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKESPECIAL, baseClassInternalName, "<init>", "()V");
- mv.visitInsn(RETURN);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
-
- cw.visitEnd();
-
- writeBytecode(cw, internalName);
-
- Registry registry = createRegistry();
-
- ReloadableService reloadable = registry.getService(ReloadableService.class);
-
- fireUpdateCheck(registry);
-
- assertEquals(reloadable.getStatus(), "initial from base");
-
- touch(new File(pathForInternalName(baseClassInternalName)));
-
- createImplementationClass(BASE_CLASS, "updated from base");
-
- fireUpdateCheck(registry);
-
- assertEquals(reloadable.getStatus(), "updated from base");
-
- registry.shutdown();
-
- }
-
- @Test
- public void delete_class() throws Exception
- {
- createImplementationClass("before delete");
-
- Registry registry = createRegistry();
-
- ReloadableService reloadable = registry.getService(ReloadableService.class);
-
- assertEquals(reloadable.getStatus(), "before delete");
-
- assertTrue(classFile.exists(), "The class file must exist.");
-
- classFile.delete();
-
- fireUpdateCheck(registry);
-
- try
- {
- reloadable.getStatus();
- unreachable();
- } catch (RuntimeException ex)
- {
- assertMessageContains(ex, "Unable to reload", CLASS);
- }
-
- registry.shutdown();
- }
-
- @Test
- public void reload_a_proxy_object() throws Exception
- {
- createImplementationClass("initial proxy");
-
- Registry registry = createRegistry();
-
- Class<ReloadableService> clazz = (Class<ReloadableService>) classLoader.loadClass(CLASS);
-
- ReloadableService reloadable = registry.proxy(ReloadableService.class, clazz);
-
- assertEquals(reloadable.getStatus(), "initial proxy");
-
- touch(classFile);
-
- createImplementationClass("updated proxy");
-
- fireUpdateCheck(registry);
-
- assertEquals(reloadable.getStatus(), "updated proxy");
-
- touch(classFile);
-
- createImplementationClass("re-updated proxy");
-
- fireUpdateCheck(registry);
-
- assertEquals(reloadable.getStatus(), "re-updated proxy");
-
- registry.shutdown();
- }
-
- private void fireUpdateCheck(Registry registry)
- {
- registry.getService(UpdateListenerHub.class).fireCheckForUpdates();
- }
-
- private Registry createRegistry()
- {
- RegistryBuilder builder = new RegistryBuilder(classLoader);
-
- builder.add(ReloadModule.class);
-
- return builder.build();
- }
-
- @Test
- public void invalid_service_implementation() throws Exception
- {
- createImplementationClass("initial");
-
- Registry registry = createRegistry();
-
- ReloadableService reloadable = registry.getService(ReloadableService.class);
-
- touch(classFile);
-
- createInvalidImplentationClass();
-
- fireUpdateCheck(registry);
-
- try
- {
- reloadable.getStatus();
-
- unreachable();
- } catch (Exception ex)
- {
- assertEquals(ex.getMessage(),
- "Service implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor.");
- }
-
- registry.shutdown();
- }
-
- private void createImplementationClass(String status) throws Exception
- {
- createImplementationClass(CLASS, status);
- }
-
- private void createImplementationClass(String className, String status) throws Exception
- {
- String internalName = PlasticInternalUtils.toInternalName(className);
-
- ClassWriter cw = createClassWriter(internalName, "java/lang/Object", ACC_PUBLIC);
-
- // Add default constructor
-
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
- mv.visitCode();
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
- mv.visitInsn(RETURN);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
-
-
- mv = cw.visitMethod(ACC_PUBLIC, "getStatus", "()Ljava/lang/String;", null, null);
- mv.visitCode();
- mv.visitLdcInsn(status);
- mv.visitInsn(ARETURN);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
-
- cw.visitEnd();
-
- writeBytecode(cw, internalName);
- }
-
- private ClassWriter createClassWriter(String internalName, String baseClassInternalName, int classModifiers)
- {
- ClassWriter cw = new ClassWriter(0);
-
- cw.visit(V1_5, classModifiers, internalName, null,
- baseClassInternalName, new String[]{
- PlasticInternalUtils.toInternalName(ReloadableService.class.getName())
- });
-
- return cw;
- }
-
- private void writeBytecode(ClassWriter cw, String internalName) throws Exception
- {
- byte[] bytecode = cw.toByteArray();
-
- writeBytecode(bytecode, pathForInternalName(internalName));
- }
-
- private String pathForInternalName(String internalName)
- {
- return String.format("%s/%s.class",
- classesDir.getAbsolutePath(),
- internalName);
- }
-
- private void writeBytecode(byte[] bytecode, String path) throws Exception
- {
- File file = new File(path);
-
- file.getParentFile().mkdirs();
-
- OutputStream stream = new BufferedOutputStream(new FileOutputStream(file));
-
- stream.write(bytecode);
-
- stream.close();
- }
-
- private void createInvalidImplentationClass() throws Exception
- {
- String internalName = PlasticInternalUtils.toInternalName(CLASS);
-
- ClassWriter cw = createClassWriter(internalName, "java/lang/Object", ACC_PUBLIC);
-
- // Add default constructor
-
- MethodVisitor mv = cw.visitMethod(ACC_PROTECTED, "<init>", "()V", null, null);
- mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
- mv.visitInsn(RETURN);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
-
- // Notice the class is abstract, so no implementation.
-
- cw.visitEnd();
-
- writeBytecode(cw, internalName);
- }
-
- @Test
- public void eager_load_service_with_proxy()
- {
- eagerLoadServiceWasInstantiated = false;
-
- Registry r = new RegistryBuilder().add(EagerProxyReloadModule.class).build();
-
- r.performRegistryStartup();
-
- assertTrue(eagerLoadServiceWasInstantiated);
- }
-
- @Test
- public void reload_aware() throws Exception
- {
- Registry r = buildRegistry(ReloadAwareModule.class);
-
- assertEquals(ReloadAwareModule.counterInstantiations, 0);
- assertEquals(ReloadAwareModule.counterReloads, 0);
-
- Counter counter = r.proxy(Counter.class, CounterImpl.class);
-
- assertEquals(ReloadAwareModule.counterInstantiations, 0);
-
- assertEquals(counter.increment(), 1);
- assertEquals(counter.increment(), 2);
-
- assertEquals(ReloadAwareModule.counterInstantiations, 1);
-
- URL classURL = CounterImpl.class.getResource("CounterImpl.class");
-
- File classFile = new File(classURL.toURI());
-
- touch(classFile);
-
- assertEquals(ReloadAwareModule.counterInstantiations, 1);
- assertEquals(ReloadAwareModule.counterReloads, 0);
-
- fireUpdateCheck(r);
-
- assertEquals(ReloadAwareModule.counterInstantiations, 2);
- assertEquals(ReloadAwareModule.counterReloads, 1);
-
- // Check that internal state has reset
-
- assertEquals(counter.increment(), 1);
-
- r.shutdown();
- }
-}