From b7d07c7708ce3489a45aef9e26fb348c5fb137b9 Mon Sep 17 00:00:00 2001 From: JoshuaCWebDeveloper Date: Fri, 21 Dec 2018 12:12:59 -0800 Subject: [PATCH 1/5] Fix MessagingIntegrationSpec, ExpressionEvaluating...Receiver only accept methods in its own scope --- .../org/grails/ignite/MessagingIntegrationSpec.groovy | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy b/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy index 7080019..abbc7a1 100644 --- a/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy +++ b/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy @@ -21,7 +21,7 @@ class MessagingIntegrationSpec extends IntegrationSpec { messagingService.sendMessage(queue: 'hello', "world") messagingService.sendMessage(queue: 'hello', "goodbye") - messagingService.registerReceiver(topic: 'hello', new ExpressionEvaluatingMessageReceiver('iGotTheMessage')) + messagingService.registerReceiver(topic: 'hello', new ExpressionEvaluatingMessageReceiver('is')) messagingService.sendMessage(topic: 'hello', "world") try {// will throw exception @@ -33,8 +33,4 @@ class MessagingIntegrationSpec extends IntegrationSpec { then: exceptionThrown } - - private boolean iGotTheMessage(message) { - println "iGotTheMessage: ${message}" - } } From 24e646f302979435ce07afd639c854b1fb7e79a4 Mon Sep 17 00:00:00 2001 From: JoshuaCWebDeveloper Date: Fri, 21 Dec 2018 12:14:34 -0800 Subject: [PATCH 2/5] Fix messagingService.sendMessage() test, non existent queue logs warning, doesn't throw error --- grails-app/conf/BuildConfig.groovy | 1 + .../grails/ignite/MessagingIntegrationSpec.groovy | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/grails-app/conf/BuildConfig.groovy b/grails-app/conf/BuildConfig.groovy index 28a935f..dcd4db5 100644 --- a/grails-app/conf/BuildConfig.groovy +++ b/grails-app/conf/BuildConfig.groovy @@ -79,6 +79,7 @@ grails.project.dependency.resolution = { test { dependencies { compile "com.h2database:h2:1.4.195" + compile "org.springframework.boot:spring-boot-test:2.1.1.RELEASE" } } } diff --git a/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy b/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy index abbc7a1..3bb46a3 100644 --- a/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy +++ b/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy @@ -1,11 +1,16 @@ package org.grails.ignite import grails.test.spock.IntegrationSpec +import org.junit.Rule +import org.springframework.boot.test.rule.OutputCapture class MessagingIntegrationSpec extends IntegrationSpec { def messagingService + @Rule + OutputCapture capture = new OutputCapture() + def setup() { } @@ -24,13 +29,10 @@ class MessagingIntegrationSpec extends IntegrationSpec { messagingService.registerReceiver(topic: 'hello', new ExpressionEvaluatingMessageReceiver('is')) messagingService.sendMessage(topic: 'hello', "world") - try {// will throw exception - messagingService.sendMessage(queue: 'noreceiver', "goodbye") - } catch (RuntimeException r) { - exceptionThrown = true - } + //will log warning + messagingService.sendMessage(queue: 'noreceiver', "goodbye") then: - exceptionThrown + capture.toString().contains("WARN ignite.IgniteMessagingQueueReceiverWrapper - No receiver configured for queue noreceiver") } } From c12048a155bbe2683f984ec045140be821c476e7 Mon Sep 17 00:00:00 2001 From: JoshuaCWebDeveloper Date: Fri, 21 Dec 2018 12:15:06 -0800 Subject: [PATCH 3/5] Test output from messagingService.sendMessage() --- .../org/grails/ignite/MessagingIntegrationSpec.groovy | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy b/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy index 3bb46a3..02b3502 100644 --- a/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy +++ b/test/integration/org/grails/ignite/MessagingIntegrationSpec.groovy @@ -20,11 +20,15 @@ class MessagingIntegrationSpec extends IntegrationSpec { void "test something"() { setup: def exceptionThrown = false + def testStrings = [ + "world test 123232", + "goodbye test 5353535" + ] when: messagingService.registerReceiver(queue: 'hello', new ExpressionEvaluatingMessageReceiver('println')) - messagingService.sendMessage(queue: 'hello', "world") - messagingService.sendMessage(queue: 'hello', "goodbye") + messagingService.sendMessage(queue: 'hello', testStrings[0]) + messagingService.sendMessage(queue: 'hello', testStrings[1]) messagingService.registerReceiver(topic: 'hello', new ExpressionEvaluatingMessageReceiver('is')) messagingService.sendMessage(topic: 'hello', "world") @@ -33,6 +37,7 @@ class MessagingIntegrationSpec extends IntegrationSpec { messagingService.sendMessage(queue: 'noreceiver', "goodbye") then: + testStrings.each { capture.toString().contains(it) } capture.toString().contains("WARN ignite.IgniteMessagingQueueReceiverWrapper - No receiver configured for queue noreceiver") } } From faa561423a9dfc9e90d272edbcd3680e9b3518ed Mon Sep 17 00:00:00 2001 From: JoshuaCWebDeveloper Date: Fri, 21 Dec 2018 12:15:45 -0800 Subject: [PATCH 4/5] Test creation of grid bean in separate test in ConfigurationIntegrationSpec --- .../ConfigurationIntegrationSpec.groovy | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/integration/org/grails/ignite/ConfigurationIntegrationSpec.groovy b/test/integration/org/grails/ignite/ConfigurationIntegrationSpec.groovy index a9210c3..d17267e 100644 --- a/test/integration/org/grails/ignite/ConfigurationIntegrationSpec.groovy +++ b/test/integration/org/grails/ignite/ConfigurationIntegrationSpec.groovy @@ -1,6 +1,7 @@ package org.grails.ignite import grails.test.spock.IntegrationSpec +import org.apache.ignite.Ignite import org.apache.ignite.cache.CacheAtomicityMode import org.apache.ignite.cache.CacheMode import org.apache.ignite.cache.CacheWriteSynchronizationMode @@ -10,11 +11,17 @@ class ConfigurationIntegrationSpec extends IntegrationSpec { def grid def sessionFactory - void "test cache configuration"() { - setup: - assert grid.name() != null // force creation of grid - assert grid.underlyingIgnite != null + void "test grid creation"() { + when: + grid + then: + grid.name() != null + grid.underlyingIgnite != null + grid instanceof Ignite + } + + void "test cache configuration"() { when: def caches = grid.configuration().cacheConfiguration.collectEntries { [(it.name): it] } @@ -31,10 +38,6 @@ class ConfigurationIntegrationSpec extends IntegrationSpec { } void "test l2 cache configuration"() { - setup: - assert grid.name() != null // force creation of grid - assert grid.underlyingIgnite != null - when: def caches = grid.configuration().cacheConfiguration.collectEntries { [(it.name): it] } From ea03528944f845fe38c6046872cc34e40d8ab047 Mon Sep 17 00:00:00 2001 From: JoshuaCWebDeveloper Date: Fri, 21 Dec 2018 12:16:32 -0800 Subject: [PATCH 5/5] Write tests for DistributedSchedulerService --- grails-app/conf/BuildConfig.groovy | 7 ++ scripts/_Events.groovy | 3 + ...DistributedSchedulerIntegrationSpec.groovy | 110 ++++++++++++++++++ .../integration/resources/MockRunnable.groovy | 31 +++++ 4 files changed, 151 insertions(+) create mode 100644 scripts/_Events.groovy create mode 100644 test/integration/org/grails/ignite/DistributedSchedulerIntegrationSpec.groovy create mode 100644 test/integration/resources/MockRunnable.groovy diff --git a/grails-app/conf/BuildConfig.groovy b/grails-app/conf/BuildConfig.groovy index dcd4db5..6f5a324 100644 --- a/grails-app/conf/BuildConfig.groovy +++ b/grails-app/conf/BuildConfig.groovy @@ -2,6 +2,13 @@ grails.project.class.dir = "target/classes" grails.project.test.class.dir = "target/test-classes" grails.project.test.reports.dir = "target/test-reports" +grails.war.resources = { stagingDir -> + //delete test classes + delete(verbose: true) { + fileset dir: stagingDir, includes: 'test/**/*.class' + } +} + grails.project.fork = [ // configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required // compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true], diff --git a/scripts/_Events.groovy b/scripts/_Events.groovy new file mode 100644 index 0000000..d2fda25 --- /dev/null +++ b/scripts/_Events.groovy @@ -0,0 +1,3 @@ +eventCompileStart = { + projectCompiler.srcDirectories << "${basedir}/test/" +} diff --git a/test/integration/org/grails/ignite/DistributedSchedulerIntegrationSpec.groovy b/test/integration/org/grails/ignite/DistributedSchedulerIntegrationSpec.groovy new file mode 100644 index 0000000..5ae4bd3 --- /dev/null +++ b/test/integration/org/grails/ignite/DistributedSchedulerIntegrationSpec.groovy @@ -0,0 +1,110 @@ +package org.grails.ignite + +import grails.test.spock.IntegrationSpec +import java.util.concurrent.TimeUnit +import resources.MockRunnable + +class DistributedSchedulerIntegrationSpec extends IntegrationSpec { + + DistributedSchedulerService distributedSchedulerService + + def setup() { + } + + def cleanup() { + } + + void "schedules at a fixed rate"() { + setup: + def runnable = new MockRunnable() + distributedSchedulerService.startScheduler() + + when: + distributedSchedulerService.scheduleAtFixedRate(runnable, 0, 100, TimeUnit.MILLISECONDS, 0) + sleep(1000) + + then: + runnable.callCount >= 2 + def avg = runnable.delayTimes[1..-1].with { + sum() / size() + } + avg >= 50 && avg <= 150 + } + + void "schedules with a fixed delay"() { + setup: + def runnable = new MockRunnable() + distributedSchedulerService.startScheduler() + + when: + distributedSchedulerService.scheduleWithFixedDelay(runnable, 0, 50, TimeUnit.MILLISECONDS, 0) + sleep(120) + + then: + runnable.callCount >= 2 + runnable.delayTimes[1..-1].each { assert it >= 50 } + } + + void "schedules a single time"() { + setup: + def runnable = new MockRunnable() + distributedSchedulerService.startScheduler() + + when: + distributedSchedulerService.schedule(runnable, 0, TimeUnit.MILLISECONDS, 0) + sleep(120) + + then: + runnable.callCount == 1 + } + + void "schedules using a cron expression"() { + setup: + def runnable = new MockRunnable() + distributedSchedulerService.startScheduler() + def cronExp = "* * * * *" + + when: + IgniteCronDistributedRunnableScheduledFuture future = (IgniteCronDistributedRunnableScheduledFuture) distributedSchedulerService.scheduleWithCron( + runnable, cronExp, 0, "name" + ) + + then: + future.cronTaskId + future.toDataMap().cronExpression == cronExp + } + + void "schedules an anonymous class"() { + setup: + def runnable = new Runnable () { + public boolean called = false + + public void run () { + called = true + } + } + distributedSchedulerService.startScheduler() + + when: + distributedSchedulerService.schedule(runnable, 0, TimeUnit.MILLISECONDS, 0) + sleep(120) + + then: + runnable.called + } + + //because Groovy 2.x doesn't support lambdas (use Groovy 3) + void "schedules a closure"() { + setup: + def called = false + Runnable runnable = { called = true } as Runnable + distributedSchedulerService.startScheduler() + + when: + distributedSchedulerService.schedule(runnable, 0, TimeUnit.MILLISECONDS, 0) + sleep(120) + + then: + called + } +} diff --git a/test/integration/resources/MockRunnable.groovy b/test/integration/resources/MockRunnable.groovy new file mode 100644 index 0000000..02ad5a8 --- /dev/null +++ b/test/integration/resources/MockRunnable.groovy @@ -0,0 +1,31 @@ +package resources + +/* + * I tried using both Spock to mock a runnable, but I couldn't get it to serialize correctly + * I also tried using Mockito but couldn't get it work either. However, it is likely that + * my ultimate solution of compiling the test classes would have worked with Mockito + */ +class MockRunnable implements Runnable, Serializable { + + private Long callCount = 0 + private ArrayList delayTimes = [] + private lastCallTime = System.currentTimeMillis() + + @Override + public void run () { + //increment call count + callCount++ + Long callTime = System.currentTimeMillis() + //store call time + delayTimes << callTime - lastCallTime + lastCallTime = callTime + } + + public Long getCallCount() { + return callCount + } + + public ArrayList getDelayTimes() { + return delayTimes + } +}