How to persist enums as ordinals with Spring Boot and Cassandra? - spring-boot

To the enum field of my entity I have added #CassandraType(type = DataType.Name.INT). However not the ordinal of the enum, but the string representation instead, is used in the statement sent to Cassandra. Thus I get the following error:
org.springframework.data.cassandra.CassandraInvalidQueryException: SessionCallback; CQL [INSERT INTO thing (thing_id,some_enum) VALUES (1,'Foo');]; Expected 4 or 0 byte int (3); nested exception is com.datastax.driver.core.exceptions.InvalidQueryException: Expected 4 or 0 byte int (3)
Below you can find a minimal example, reproducing the problem.
What am I doing wrong?
test/src/main/kotlin/enumtest/Application.kt
package enumtest
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
#SpringBootApplication
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
test/src/main/kotlin/enumtest/SomeEnum.kt
package enumtest
enum class SomeEnum {
Foo,
Bar
}
test/src/main/kotlin/enumtest/Thing.kt
package enumtest
import com.datastax.driver.core.DataType
import org.springframework.data.cassandra.core.cql.PrimaryKeyType
import org.springframework.data.cassandra.core.mapping.CassandraType
import org.springframework.data.cassandra.core.mapping.Column
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn
import org.springframework.data.cassandra.core.mapping.Table
#Table("thing")
#Suppress("unused")
class Thing(
#PrimaryKeyColumn(name = "thing_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
var thingId: Long,
#CassandraType(type = DataType.Name.INT)
#Column("some_enum")
var someEnum: SomeEnum
)
test/src/main/kotlin/enumtest/ThingRepository.kt
package enumtest
import org.springframework.data.cassandra.repository.CassandraRepository
import org.springframework.stereotype.Repository
#Repository
interface ThingRepository : CassandraRepository<Thing, Long>
test/src/main/resources/application.yml
spring:
data:
cassandra:
contact-points: localhost
port: 9142
keyspace_name: enumtest
test/src/test/kotlin/enumtest/PersistenceTest.kt
package enumtest
import org.cassandraunit.spring.CassandraDataSet
import org.cassandraunit.spring.CassandraUnitDependencyInjectionTestExecutionListener
import org.cassandraunit.spring.EmbeddedCassandra
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.TestExecutionListeners
import org.springframework.test.context.junit4.SpringRunner
#RunWith(SpringRunner::class)
#SpringBootTest
#TestExecutionListeners(
listeners = [CassandraUnitDependencyInjectionTestExecutionListener::class],
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
)
#CassandraDataSet(value = ["cql/cassandra_schema.cql"], keyspace = "enumtest")
#EmbeddedCassandra
class PersistenceTest {
#Autowired
lateinit var thingRepository: ThingRepository
#Test
fun `test save`() {
thingRepository.save(Thing(1, SomeEnum.Foo))
val things = thingRepository.findAll()
Assert.assertEquals(1, things.size)
val thing = things[0]
Assert.assertEquals(SomeEnum.Foo, thing.someEnum)
}
}
test/src/test/resources/cql/cassandra_schema.cql
CREATE KEYSPACE IF NOT exists enumtest
WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':1};
CREATE TABLE IF NOT exists enumtest.thing (
thing_id bigint,
some_enum int,
PRIMARY KEY (thing_id)
);
test/build.gradle
plugins {
id 'org.springframework.boot' version '2.1.4.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.3.30'
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.30'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url "https://repository.apache.org/snapshots/" }
}
dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-cassandra'
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8'
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect'
testImplementation group: 'org.cassandraunit', name: 'cassandra-unit-spring', version: '3.5.0.1'
testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}
compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}
Here is the full version of the minimal example as a download to faciliate experimentation: https://drive.google.com/open?id=1zzIDhbWycaj4WXrze2sAmw8xRPacA8Js
Edit: Since it seems to be a bug, I just opened a Jira issue.

I've been trying to get this working for quite awhile and it seems I finally got it!
I was running into the same issue you were with the codec...I have no idea why that's not working. According to their documentation you were doing it exactly right.
So I implemented my own Cassandra Write Converter. See below
#Configuration
class CassandraConfig(val cluster: Cluster){
#Bean
fun setCustomCassandraConversions() = CassandraCustomConversions(listOf(EnumWriteConverter.INSTANCE, EnumReadConverter.INSTANCE))
#WritingConverter
enum class EnumWriteConverter : Converter<Enum<MyEnum>, Int> {
INSTANCE;
override fun convert(source: Enum<MyEnum>) = source.ordinal
}
#ReadingConverter
enum class EnumReadConverter : Converter<Int, Enum<MyEnum>> {
INSTANCE;
override fun convert(source: Int) = MyEnum.values()[source]
}
}
This should on every write you do to Cassandra convert all enums it sees of type MyEnum to an Int using the overridden converter. This opens you up to the possibility of having multiple of these for different types of Enums where maybe for some reason you would like to write other custom values from them instead of always converting all enums.
Hope this works!
EDIT
Note the change in removing { } for INSTANCE on each converter, and registering the ReadingConverter with the CassandraCustomConversions

This is fixed since Spring Boot version 2.1.5.
However, the #CassandraType needs to be placed at the getter explicitly in Kotlin, because otherwise it is not seen at runtime.
In practice this simply means replacing this:
#CassandraType(type = DataType.Name.INT)
var someEnum: SomeEnum
with that:
#get: CassandraType(type = DataType.Name.INT)
var someEnum: SomeEnum

Related

SpringBoot Service Injection using private final not working

I am new to springboot and am trying to follow this example: https://github.com/eugenp/tutorials/tree/master/spring-caching-2
In my app I keep getting "error: variable myApplicationService not initialized in the default constructor" but in comparison to the tutorial I am following, I don't understand how it gets initialized, this is my controller:
package com.springbootredis.controllers;
import com.springbootredis.service.MyApplicationService;
import lombok.AllArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
#RestController
#AllArgsConstructor
#RequestMapping(value = "/person", produces = { MediaType.APPLICATION_JSON_VALUE })
public class PersonController {
private final MyApplicationService myApplicationService;//ERROR HERE
#GetMapping("/uuid")
public String generateRandomUUID() {
return UUID.randomUUID().toString();
}
#GetMapping("/addperson/{name}")
public String addPerson(#PathVariable String name) {
String ret = myApplicationService.addNewPerson(name);
return "Added person with name: " + name + " and id: " + ret;
}
#GetMapping("/deleteperson/{id}")
public String deletePerson(#PathVariable String id) {
String ret = myApplicationService.delete(id);
return "Deleted person. ID:" + id + " Name: " + ret;
}
#GetMapping("/updateperson/{id}/{name}")
public String updatePerson(#PathVariable String id, #PathVariable String name) {
myApplicationService.updatePerson(id, name);
return "Updated person. ID:" + id + " with Name: " + name;
}
#GetMapping("/getperson/{id}")
public String getPerson(#PathVariable String id) {
String ret = myApplicationService.findById(id);
return "Got person. ID:" + id + " Name: " + ret;
}
}
I tried autowired annotation but it says it is not recommended, and the build still fails. My build.gradle looks like this:
plugins {
id 'org.springframework.boot' version '2.7.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'war'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-data-redis:2.7.0")
implementation("org.springframework.boot:spring-boot-starter-cache:2.7.1")
implementation("org.projectlombok:lombok:1.18.24")
implementation("org.springframework.boot:spring-boot-dependencies:2.7.1")
runtimeOnly("mysql:mysql-connector-java:8.0.29")
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
Any help/pointers would be much appreciated.
Edit: (For completeness' sake) As you've already found out, the annotationProcessor entry for Lombok is missing from your build.gradle file. In addition, your Lombok entry can be compileOnly and does not need to be included at runtime.
Original Answer follows.
Your code as-is should still work. As mentioned by #m-deinum, you should also avoid doing manual dependency management on Spring versions.
That said, Lombok does its magic via Annotation Processing, a feature that might not be enabled by default in your IDE Project.
One possible culprit for your error is that this feature is disabled, hence Lombok is not generating the constructor and only a default, no-args constructor is available. Once you enable it, the compile-error should go away.
That said, I've found #AllArgsConstructor to not be very robust when designing classes. Prefer #RequiredArgsConstructor or simply explicit constructors and design your classes to have immutable state.
To resolve my issue I added the following to the build.gradle file under the dependencies section:
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
annotationProcessor("org.projectlombok:lombok:1.18.24")

not able to use ai.djl.modality.cv.util.BufferedImageUtils in my application

I am new to AI technology .I dded every DJL which are required to my
project . But when I go to use
ai.djl.modality.cv.util.BufferedImageUtils. I am not able to import it
in my project.It show me an error create local variable
BuffredImageUtils.
Unresolved reference: BufferedImageUtils
here all my graddle depedency I added in my Project
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.5.4"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.5.21"
kotlin("plugin.spring") version "1.5.21"
}
group = "com.main"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.springframework.boot:spring-boot-starter-web")
// https://mvnrepository.com/artifact/commons-io/commons-io
implementation("commons-io:commons-io:2.6")
// https://mvnrepository.com/artifact/ai.djl/api
implementation("ai.djl:api:0.9.0")
// https://mvnrepository.com/artifact/ai.djl.tensorflow/tensorflow-api
implementation("ai.djl.tensorflow:tensorflow-api:0.9.0")
// https://mvnrepository.com/artifact/ai.djl.tensorflow/tensorflow-engine
implementation("ai.djl.tensorflow:tensorflow-engine:0.9.0")
// https://mvnrepository.com/artifact/net.java.dev.jna/jna
implementation("net.java.dev.jna:jna:5.8.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// https://mvnrepository.com/artifact/ai.djl.tensorflow/tensorflow-native-auto
runtimeOnly("ai.djl.tensorflow:tensorflow-native-auto:2.3.1")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
DJLConfig.kt
package com.main.xrayaiapplication.config
import ai.djl.modality.Classifications
import ai.djl.modality.cv.util.NDImageUtils
import ai.djl.ndarray.NDArray
import ai.djl.ndarray.NDList
import ai.djl.translate.Batchifier
import ai.djl.translate.Translator
import ai.djl.translate.TranslatorContext
import org.springframework.context.annotation.Configuration
import java.awt.image.BufferedImage
#Configuration
class DjlConfig{
class XrayTranslator: Translator<BufferedImage,Classifications> {
override fun processInput(ctx: TranslatorContext?, input: BufferedImage?): NDList {
var array: NDArray? = BufferedImageUtils.toNDArray(
ctx.ndManager, input, NDImageUtils.Flag.COLOR
)
array = NDImageUtils.resize(array, 224).div(255.0f)
return NDList(array)
}
override fun processOutput(ctx: TranslatorContext?, list: NDList?): Classifications {
TODO("Not yet implemented")
}
override fun getBatchifier(): Batchifier {
TODO("Not yet implemented")
}
}
}
I get error exact at this line
var array: NDArray? = BufferedImageUtils.toNDArray(
Not able to access the DJL AI features , and contents
The BufferedImageUtils has been removed in newer version fo DJL api. You need to use ImageFactory instead:
ImageFactory factory = ImageFactory.getInstance();
# Image image = factory.fromFile(Paths.get("..."));
# Image image = factory.fromUrl("...");
Image image = factory.fromImage(bufferedImage);
NDArray array = image.toNDArray(ctx.getManager());

IntelliJ Could not set unknown property 'mainClassName' for root project 'Blue Bot' of type org.gradle.api.Project

I am following a tutorial to make a basic Discord Bot, (https://medium.com/discord-bots/making-a-basic-discord-bot-with-java-834949008c2b) and i got the error, Could not set unknown property 'mainClassName' for root project 'Blue Bot' of type org.gradle.api.Project and I don't know how to fix it. Here is my build.grade code
plugins {
id 'java'
}
mainClassName = "Main"
group 'BlueBot'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
jcenter()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile 'net.dv8tion:JDA:4.0.0_62'
}
and here is my Main.java code
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import javax.security.auth.login.LoginException;
public class Main extends ListenerAdapter {
public static void main(String[] args) throws LoginException {
JDABuilder builder = new JDABuilder(AccountType.BOT);
String token = "enter token here";
builder.setToken(token);
builder.addEventListeners(new Main());
builder.build();
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
System.out.println("We received a message from " +
event.getAuthor().getName() + ": " +
event.getMessage().getContentDisplay()
);
if (event.getMessage().getContentRaw().equals("I am lonely")) {
event.getChannel().sendMessage("Who isn't?").queue();
}
}
}
Let me know if you need more info.
You need to apply the application plugin:
plugins {
id 'application'
}

Gradle + Embedded Jetty

I have modified an existing Jetty project and after I builded, I got 404. Maybe I need to modify other files which I do not know.
I am using gradle to build. Here is the build.gradle :
apply plugin: 'java'
apply plugin: 'jetty'
apply plugin: 'eclipse'
repositories {
mavenCentral()
}
dependencies {
compile 'org.springframework:spring-webmvc:4.1.6.RELEASE'
compile 'org.hibernate:hibernate-core:4.3.6.Final'
testImplementation 'junit:junit:4.12'
testCompile 'junit:junit:4.11'
testCompile 'org.hamcrest:hamcrest-all:1.3'
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.14'
}
test {
exclude '**/*IntegrationTest*'
}
task integrationTest(type: Test) {
include '**/*IntegrationTest*'
doFirst {
jettyRun.contextPath = '/';
jettyRun.httpPort = 8080 // Port for test
jettyRun.daemon = true
jettyRun.execute()
}
doLast {
jettyStop.stopPort = 8091 // Port for stop signal
jettyStop.stopKey = 'stopKey'
jettyStop.execute()
}
}
// Embeded Jetty for testing
jettyRun{
contextPath = "spring4"
httpPort = 8080
}
jettyRunWar{
contextPath = "spring4"
httpPort = 8080
}
//For Eclipse IDE only
eclipse {
wtp {
component {
//define context path, default to project folder name
contextPath = 'spring4'
}
}
}
Here the other class:
package com.hello.webapp;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import com.hello.service.SignUpService;
#Path("/signUp")
public class SignUpWebapp {
private static SignUpService signUpService = new SignUpService();
#GET()
public String hello() {
return signUpService.sayHello();
}
}
here the simple service:
package com.hello.service;
public class SignUpService {
public String sayHello() {
return "signUp";
}
}
this is another the integration test class
package com.hello.webapp;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import org.junit.Test;
public class SignUpIntegrationTest {
private static String SIGNUP = "http://localhost:8080/signUp";
#Test
public void testHello() throws Exception {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(SIGNUP);
String response = webTarget.request().get(String.class);
assertThat(response, is("signUp"));
}
}
So, when I run gradle integrationTest I get an error saying that Jetty is already running. And when I try to visit localhost/signUp I get a 404.
One solution is to use gretty instead:
apply plugin: 'org.akhikhl.gretty'
....
classpath 'org.akhikhl.gretty:gretty:1.4.0'
...
gretty {
port = 8083
contextPath = '/'
servletContainer = 'jetty9'
jvmArgs = [
'-Xms700m',
'-Xmx2048m'
]
loggingLevel='INFO'
debugPort = 5005 // default
debugSuspend = true // default
httpsEnabled = true
httpsPort = 8443
sslKeyStorePath = 'some.jks'
sslKeyStorePassword = 'somepwd'
}
and then gradle appStart
Let me know if that helps.

gradle task and imports on groovy file

I have the following buil.gradle
apply plugin: "groovy"
repositories {
mavenCentral()
jcenter()
}
dependencies {
groovy group: "org.codehaus.groovy", name:"groovy-all", version: "1.8.6"
compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '2.53.0'
compile "org.testng:testng:6.3.1"
compile group: 'com.jcraft', name: 'jsch', version: '0.1.53'
compile group: 'net.schmizz', name: 'sshj', version: '0.3.1'
compile group: 'commons-lang', name: 'commons-lang', version: '2.3'
compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.21'
compile group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.46'
compile group: 'net.sf.expectit', name: 'expectit-core', version: '0.8.1'
compile group: 'net.sf.expectit', name: 'expectit-ant', version: '0.8.1'
compile group: 'net.sf.expectit', name: 'expectit-parent', version: '0.8.1', ext: 'pom'
compile "log4j:log4j:1.2.17"
testCompile "org.spockframework:spock-core:0.7-groovy-1.8"
testCompile "junit:junit:4.10"
testCompile "cglib:cglib-nodep:2.2.2"
testCompile "org.objenesis:objenesis:1.2"
testRuntime "org.slf4j:slf4j-api:1.7.10"
}
sourceSets {
test { groovy {
srcDir 'foo/bar/'
} }
}
buildscript {
repositories {
mavenCentral()
jcenter()
}
}
task runA << {
new GroovyShell().run(file('foo/bar/ATest.groovy'));
}
If I run gradle clean -Dtest.single=A test it works and test runs with success but if I run gradle -q runA it shows unrecognized imports like:
foo/bar/ATest.groovy: 16: unable to resolve class net.schmizz.sshj.SSHClient
# line 16, column 1.
import net.schmizz.sshj.SSHClient;
^
foo/bar/ATest.groovy: 28: unable to resolve class org.openqa.selenium.firefox.FirefoxDriver
# line 28, column 1.
import org.openqa.selenium.firefox.FirefoxDriver;
^
Here is my ATest.groovy
package foo.bar;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets;
import java.nio.file.Files
import java.nio.file.Paths;
import java.security.PublicKey
import org.apache.log4j.Logger;
import org.junit.Before
import org.junit.After
import org.junit.Test;
import org.junit.*;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Shell;
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import net.sf.expectit.Expect;
import net.sf.expectit.ExpectBuilder;
import static net.sf.expectit.filter.Filters.removeColors;
import static net.sf.expectit.filter.Filters.removeNonPrintable;
import static net.sf.expectit.matcher.Matchers.contains;
import static net.sf.expectit.matcher.Matchers.regexp;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select
import java.util.regex.Pattern
import javax.naming.directory.InvalidAttributesException;
import java.util.concurrent.TimeUnit
import org.apache.log4j.Logger;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
public class ATest{
private WebDriver driver;
private static final Logger logger = Logger.getLogger(ATest.class);
Properties props = new Properties();
private StringBuffer verificationErrors = new StringBuffer();
private Expect expect = null;
Session session = null;
SSHClient ssh = null;
#Before
public void setUp() throws Exception {
logger.info("========================================================================");
logger.info("Starting...");
// setting up Webdriver instance
try {
driver = new FirefoxDriver();
}
catch (Exception e) {
logger.info("Could not open Firefox instance: " + e.getMessage());
fail("Could not open Firefox instance: " + e.getMessage());
}
// setting up SSH connection
try {
ssh = new SSHClient();
ssh.addHostKeyVerifier(
new HostKeyVerifier() {
#Override
public boolean verify(String s, int i, PublicKey publicKey) {
return true;
}
});
ssh.connect(props.getProperty("host"), Integer.parseInt(props.getProperty("port")));
ssh.authPassword(props.getProperty("user"), props.getProperty("password"));
session = ssh.startSession();
session.allocateDefaultPTY();
} catch (Exception e) {
fail("Could not open SSH connection with " + props.getProperty("host") + "\nError: " + e.getMessage());
}
// start a interactive remote shell
Shell shell = session.startShell();
expect = new ExpectBuilder().withOutput(shell.getOutputStream())
.withInputs(shell.getInputStream(), shell.getErrorStream())
//.withEchoInput(System.out)
.withInputFilters(removeColors(), removeNonPrintable())
.withExceptionOnFailure()
.build();
try {
Thread.sleep(3000);
// log as 'su' user in the remote shell
expect.sendLine(props.getProperty("suuser"));
expect.expect(contains("Password: "));
expect.sendLine(props.getProperty("supassword"));
expect.expect(regexp("root#"));
}
catch (Exception e) {
fail("Error: " + e.getMessage());
}
}
#Test
public void run() {
...
}
#After
public void tearDown() throws Exception {
if (driver != null) {
driver.quit();
}
}
}
Am I missing some config?
This is expected behavior. When you run a test with gradle, it's gradle job to configure the classpath, classloader - namely, the whole environment.
If you run the the file, script on your it's your job to provide the configuration.
Have a look at GroovyShells, constructor summary. It takes a ClassLoader object and a CompileConfiguration. It's your job to provide these objects.

Resources