Unit tests - run task programmatically - groovy

I'm creating custom task for gradle. I don't know how I can create task which will use my custom task class. Is it possible? I want to create this task for functional tests which will be runned on jenkins.
This is my custom task:
package pl.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class MyCustomTask extends DefaultTask {
public MyCustomTask() {
// do something
}
#TaskAction
def build() {
ant.echo(message: "only for tests")
}
}
And this is my test class:
package pl.gradle
import static org.junit.Assert.*
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.api.Project
import org.junit.Before;
import org.junit.Test
class MyCustomTaskTest {
private Project project;
def task
#Before
public void setUp() {
project = ProjectBuilder.builder().build()
task = project.task("build", type: MyCustomTask)
}
#Test
public void taskCreatedProperly() {
assertTrue(task instanceof MyCustomTask)
}
#Test
public void shouldRunTask() {
// task.execute() // how to run this task? I want to run build() method from MyCustomTask class which is #TaskAction
}
}

ProjectBuilder is meant for lower-level tests that don't execute tasks. Its sweet spot is testing plugins. In addition you'd write higher-level tests that execute real builds (and therefore also tasks). You'd typically use the Gradle tooling API to kick off these builds. Check out the tooling API samples in the full Gradle distribution.

Call Action.execute yourself for each of the task actions:
project.tasks.getByName("myTask").with { Task task ->
assertEquals task.group, 'My Group'
task.actions.each { Action action ->
action.execute task
}
}
I've previously mentioned this here: https://stackoverflow.com/a/63613564/410939

Related

groovy is not finding annotated tests

Still new to Groovy and trying to figure out unit testing. I'm trying to use the Junit4 style of testing.
import org.junit.Test
import junit.framework.*
import junit.textui.TestRunner
class DegenerateTestCase {
#Test
void testAlwaysTrue() {
assert true
}
#Test
void someMethodName() {
assert true
}
}
TestRunner.run(DegenerateTestCase)
But when I run the script, I get
There was 1 failure:
warning(junit.framework.TestSuite$1)junit.framework.AssertionFailedError:> No tests found in DegenerateTestCase
This has to be something simple that I'm missing.
I am using Eclipse Java EE IDE for Web Developers, Oxygen.3a Release (4.7.3a). I have the Groovy plugin downloaded from the marketplace (compiler level 2.5).
I tried running it with junit5 which had only one difference which was instead of having import org.junit.Test I had import static org.junit.jupiter.api.Assertions.*. I didnt need import junit.framework.* or import junit.textui.TestRunner I just ran it as is and worked fine.
I then switched to Junit4 and did the same but switched import static org.junit.jupiter.api.Assertions.* to import org.junit.Test and it works.
my code looks like this:
import org.junit.Test
class DegenerateTestCase {
#Test
void testAlwaysTrue() {
assert true
}
#Test
void someMethodName() {
assert true
}
}

Spring Batch thread-safe Map job repository

the Spring Batch docs say of the Map-backed job repository:
Note that the in-memory repository is volatile and so does not allow restart between JVM instances. It also cannot guarantee that two job instances with the same parameters are launched simultaneously, and is not suitable for use in a multi-threaded Job, or a locally partitioned Step. So use the database version of the repository wherever you need those features.
I would like to use a Map job repository, and I do not care about restarting, prevention of concurrent job executions, etc. but I do care about being able to use multi-threading and local partitioning.
My batch application has some partitioned steps, and at first glance it seems to run just fine with a Map-backed job repository.
What is the reason it said to be not possible with MapJobRepositoryFactoryBean? Looking at the implementation of Map DAOs, they are using ConcurrentHashMap. Is this not thread-safe ?
I would advise you to follow the documentation, rather than relying on implementation details. Even if the maps are individually thread-safe, there might be race conditions in changes than involve more than one of these maps.
You can use an in-memory database very easily. Example
#Grapes([
#Grab('org.springframework:spring-jdbc:4.0.5.RELEASE'),
#Grab('com.h2database:h2:1.3.175'),
#Grab('org.springframework.batch:spring-batch-core:3.0.6.RELEASE'),
// must be passed with -cp, for whatever reason the GroovyClassLoader
// is not used for com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver
//#Grab('org.codehaus.jettison:jettison:1.2'),
])
import org.h2.jdbcx.JdbcDataSource
import org.springframework.batch.core.Job
import org.springframework.batch.core.JobParameters
import org.springframework.batch.core.Step
import org.springframework.batch.core.StepContribution
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory
import org.springframework.batch.core.launch.JobLauncher
import org.springframework.batch.core.scope.context.ChunkContext
import org.springframework.batch.core.step.tasklet.Tasklet
import org.springframework.batch.repeat.RepeatStatus
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ResourceLoader
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
import javax.annotation.PostConstruct
import javax.sql.DataSource
#Configuration
#EnableBatchProcessing
class AppConfig {
#Autowired
private JobBuilderFactory jobs
#Autowired
private StepBuilderFactory steps
#Bean
public Job job() {
return jobs.get("myJob").start(step1()).build()
}
#Bean
Step step1() {
this.steps.get('step1')
.tasklet(new MyTasklet())
.build()
}
#Bean
DataSource dataSource() {
new JdbcDataSource().with {
url = 'jdbc:h2:mem:temp_db;DB_CLOSE_DELAY=-1'
user = 'sa'
password = 'sa'
it
}
}
#Bean
BatchSchemaPopulator batchSchemaPopulator() {
new BatchSchemaPopulator()
}
}
class BatchSchemaPopulator {
#Autowired
ResourceLoader resourceLoader
#Autowired
DataSource dataSource
#PostConstruct
void init() {
def populator = new ResourceDatabasePopulator()
populator.addScript(
resourceLoader.getResource(
'classpath:/org/springframework/batch/core/schema-h2.sql'))
DatabasePopulatorUtils.execute populator, dataSource
}
}
class MyTasklet implements Tasklet {
#Override
RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
println 'TEST!'
}
}
def ctx = new AnnotationConfigApplicationContext(AppConfig)
def launcher = ctx.getBean(JobLauncher)
def jobExecution = launcher.run(ctx.getBean(Job), new JobParameters([:]))
println "Status is: ${jobExecution.status}"

Shared #Input properties on Gradle Plugin tasks, ideally nested config

My gradle plugin generates a number of tasks that have shared configuration. This configuration needs to be marked as #Input, so when it's changed, the task is marked as stale and re-evaluated. I'm finding it challenging to share the config when it should apply to multiple tasks. I'm using avoiding project.afterEvaluate to allow incremental compilation. This example is a reduced version of what I currently have:
Current Plugin Code:
class MyPluginTaskOne extends DefaultTask {
#Input config = "default"
#TaskAction
public void action() {
// something that depends on config
}
}
class MyPluginTaskTwo extends DefaultTask {
#Input config = "default"
#TaskAction
public void action() {
// something that depends on config
}
}
class MyPluginExtension {
// blank for now
}
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("myPluginConfig", MyPluginExtension)
project.tasks.create(name: 'myPluginTaskOne', type: MyPluginTaskOne) {}
project.tasks.create(name: 'myPluginTaskTwo', type: MyPluginTaskTwo) {}
}
}
Current Config:
Currently the best way I have to share state is the following. This has the problem is that it's error prone and doesn't automatically sharing the setting:
apply plugin: MyPlugin
// Kludgy way of sharing configuration across two tasks:
def sharedConfig = "SHARED-CONFIG"
myPluginTaskOne {
config sharedConfig
}
myPluginTaskTwo {
config sharedConfig
}
Preferred Config:
What I'd like to do is a configuration something like the following, but with all the benefits of tracking #Input dependencies and up-to-date tests.
myPluginConfig {
config "SHARED-CONFIG"
// myPluginTaskOne and myPluginTaskTwo both gets automatic
// 'SHARED-CONFIG' through Gradle
}
It appears that you can automatically add dependencies between tasks (see below). Is it possible to configure only the first task and then have that #Input trickle down to the #Input on the second task?
Let us try removing the task dependencies by relying on how CopySpec.from() evaluates arguments with Project.files(). Gradle can automatically add task dependencies for us. This also adds the output of the generator task as inputs to the zip task.
From https://gradle.org/feature-spotlight-incremental-builds/
To build on Mark's comments. Here is an example of a property that applies to all tasks and cannot be overridden (config).
class MyPluginTaskOne extends DefaultTask {
#Input String getConfig() { project.myPluginConfig.config }
#TaskAction
public void action() {
// something that depends on config
}
}
class MyPluginTaskTwo extends DefaultTask {
#Input String getConfig() { project.myPluginConfig.config }
#TaskAction
public void action() {
// something that depends on config
}
}
class MyPluginExtension {
String config
}
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.with {
extensions.create("myPluginConfig", MyPluginExtension)
tasks.create(name: 'myPluginTaskOne', type: MyPluginTaskOne) {}
tasks.create(name: 'myPluginTaskTwo', type: MyPluginTaskTwo) {}
}
}
}
The most common convention is to use an extension to do this. It looks like you've started to do this. You would then define the property on the extension, then your plugin would read the extension and set the property on all relevant tasks.
myPluginConfig {
sharedConfig 'value'
}
In your plugin:
def extension = extensions.create("myPluginConfig", MyPluginExtension)
project.afterEvaluate {
// read prop from `extension` and set prop on tasks
}

How to properly quit WebDriver after completing all UI tests with Cucumber

We are using Selenium WebDriver to do UI testing, along with Cucumber. The language is Groovy, and the build tool is Gradle. Because it is expensive to create a WebDriver instance, we want to instantiate only one WebDriver instance and use it through all tests. However, we are having trouble to quit the driver properly after all tests are completed. Namely, the browser process spawned during the tests is still alive after running all the tests.
The code is currently structured like below.
// Test base class
class UITestBase {
WebDriver driver
static {
init()
}
static void init() {
// instantiate a webdriver
}
}
// Entry class of cucumber run
RunWith( Cucumber )
Cucumber.Options(...)
class CukeRunEntry {}
// Cucumber step class
class WhenSteps extends UITestBase {
#When(/^something happens$/)
void something_happens() {
// step implmentation
}
}
So, how can I call driver.quit() after all tests are finished but before gradle finishes the test task (we run the tests with ./gradlew test from command line)? I tried overriding the finalize() method, but that didn't help.
Thank you very much.
If I were you, I would prefer using SharedDriver that you can find here => https://github.com/cucumber/cucumber-jvm/blob/master/examples/java-webbit-websockets-selenium/src/test/java/cucumber/examples/java/websockets/SharedDriver.java
It makes life easier.
Edit
If you don't wish to use SharedDriver, you can add a block like below to the UITestBase class as illustrated in the question:
private static final Thread CLOSE_THREAD = new Thread() {
#Override
public void run() {
try {
driver.quit()
} catch ( Exception e ) {
}
}
}
static {
init()
Runtime.getRuntime().addShutdownHook(CLOSE_THREAD)
}
The above code is essentially what's used in SharedDriver to ensure safe close of the WebDriver instance.

Black listing synchronized keyword for groovy scripts

There is an application where users can provide custom groovy scripts. They can write their own functions in those scripts. I want to restrict people from using the 'synchronized' keyword as well as some other keywords in these scripts. For example it should not be possible to write a function like below.
public synchronized void test() {
}
I am creating a CompilerConfiguration and using the SecureASTCustomizer. However adding org.codehaus.groovy.syntax.Types.KEYWORD_SYNCHRONIZED to the list of black listed tokens doesn't seem to do the job. (if I add org.codehaus.groovy.syntax.Types.PLUS it's preventing the usage of '+' within scripts.. but doesn't seem to do the job for synchronized)
Any ideas on how to achieve this ...
You can do something like this:
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.syntax.SyntaxException
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.classgen.GeneratorContext
class SynchronizedRemover extends org.codehaus.groovy.control.customizers.CompilationCustomizer {
SynchronizedRemover() {
super(org.codehaus.groovy.control.CompilePhase.CONVERSION)
}
void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) {
classNode.methods.each { mn ->
if (mn.modifiers & 0x0020) { // 0x0020 is for synchronized
source.addError(new SyntaxException("Synchronized is not allowed", mn.lineNumber, mn.columnNumber))
}
}
}
}
def config = new CompilerConfiguration()
config.addCompilationCustomizers(new SynchronizedRemover())
def shell = new GroovyShell(config)
shell.evaluate '''
class Foo { public synchronized void foo() { println 'bar' } }
'''
The idea is to create a compilation customizer that checks generated classes and for each method, add an error if the synchronized modifier is present. For synchronized block inside methods, you can probably use the SecureASTCustomizer with a custom statement checker.

Resources