kandi background
Explore Kits

spock | The Enterprise-ready testing and specification framework | Unit Testing library

 by   spockframework Java Version: spock-2.2-M1 License: Apache-2.0

 by   spockframework Java Version: spock-2.2-M1 License: Apache-2.0

Download this library from

kandi X-RAY | spock Summary

spock is a Java library typically used in Testing, Unit Testing, Framework applications. spock has no bugs, it has no vulnerabilities, it has build file available, it has a Permissive License and it has high support. You can download it from GitHub.
Spock is a BDD-style developer testing and specification framework for Java and [Groovy](https://groovy-lang.org/) applications. To learn more about Spock, visit https://spockframework.org. To run a sample spec in your browser, go to https://meetspock.appspot.com/.
Support
Support
Quality
Quality
Security
Security
License
License
Reuse
Reuse

kandi-support Support

  • spock has a highly active ecosystem.
  • It has 3151 star(s) with 432 fork(s). There are 150 watchers for this library.
  • There were 4 major release(s) in the last 12 months.
  • There are 213 open issues and 672 have been closed. On average issues are closed in 173 days. There are 31 open pull requests and 0 closed requests.
  • It has a positive sentiment in the developer community.
  • The latest version of spock is spock-2.2-M1
spock Support
Best in #Unit Testing
Average in #Unit Testing
spock Support
Best in #Unit Testing
Average in #Unit Testing

quality kandi Quality

  • spock has 0 bugs and 0 code smells.
spock Quality
Best in #Unit Testing
Average in #Unit Testing
spock Quality
Best in #Unit Testing
Average in #Unit Testing

securitySecurity

  • spock has no vulnerabilities reported, and its dependent libraries have no vulnerabilities reported.
  • spock code analysis shows 0 unresolved vulnerabilities.
  • There are 0 security hotspots that need review.
spock Security
Best in #Unit Testing
Average in #Unit Testing
spock Security
Best in #Unit Testing
Average in #Unit Testing

license License

  • spock is licensed under the Apache-2.0 License. This license is Permissive.
  • Permissive licenses have the least restrictions, and you can use them in most projects.
spock License
Best in #Unit Testing
Average in #Unit Testing
spock License
Best in #Unit Testing
Average in #Unit Testing

buildReuse

  • spock releases are available to install and integrate.
  • Build file is available. You can build the component from source.
  • Installation instructions are not available. Examples and code snippets are available.
  • spock saves you 12373 person hours of effort in developing the same functionality from scratch.
  • It has 24512 lines of code, 3268 functions and 580 files.
  • It has medium code complexity. Code complexity directly impacts maintainability of the code.
spock Reuse
Best in #Unit Testing
Average in #Unit Testing
spock Reuse
Best in #Unit Testing
Average in #Unit Testing
Top functions reviewed by kandi - BETA

kandi has reviewed spock and discovered the below as its top functions. This is intended to give you an instant insight into spock implemented functionality, and help decide if they suit your requirements.

  • Creates an annotation for the data provider .
  • This method converts all expressions to NaN .
  • Writes a string .
  • Handle multiple failures .
  • Create a feature info object .
  • Checks if the given type is a super type .
  • Do the actual invoke method .
  • Adds the specified elements to this set .
  • Create data providers .
  • Evaluate an expression and return the result .

spock Key Features

The Enterprise-ready testing and specification framework.

Ad-Hoc Intermediate Releases

copy iconCopydownload iconDownload
repositories {
    // ...
    maven { url 'https://jitpack.io' }
}

dependencies {
    testImplementation 'org.spockframework.spock:spock-core:spock-2.1-M2'
    testImplementation 'org.spockframework.spock:spock-spring:spock-2.1-M2'
}

Supported versions

copy iconCopydownload iconDownload
./gradlew clean build

Java 9 Module Names

copy iconCopydownload iconDownload
open module foo.bar {
  requires org.spockframework.core;
  requires org.spockframework.spring;
}

java.lang.RuntimeException: not supported: class org.spockframework.gentyref.CaptureTypeImpl

copy iconCopydownload iconDownload
public class Foo {

    public ResponseEntity<?> bar(Long id) {
        ...
    }
}
setup:
Foo mockFoo = Stub()

given:
String id = '123'

and:
ResponseEntity<String> response = new ResponseEntity<String>('Hello World', HttpStatus.OK)

and:
mockFoo.bar(id) >> response

...
then:
mockFoo.bar(id) >> response
0 * _  // don't allow any other interaction
Handler dispatch failed; nested exception is Too many invocations for:

0 * _  // don't allow any other interaction   (1 invocation)
-----------------------
public class Foo {

    public ResponseEntity<?> bar(Long id) {
        ...
    }
}
setup:
Foo mockFoo = Stub()

given:
String id = '123'

and:
ResponseEntity<String> response = new ResponseEntity<String>('Hello World', HttpStatus.OK)

and:
mockFoo.bar(id) >> response

...
then:
mockFoo.bar(id) >> response
0 * _  // don't allow any other interaction
Handler dispatch failed; nested exception is Too many invocations for:

0 * _  // don't allow any other interaction   (1 invocation)
-----------------------
public class Foo {

    public ResponseEntity<?> bar(Long id) {
        ...
    }
}
setup:
Foo mockFoo = Stub()

given:
String id = '123'

and:
ResponseEntity<String> response = new ResponseEntity<String>('Hello World', HttpStatus.OK)

and:
mockFoo.bar(id) >> response

...
then:
mockFoo.bar(id) >> response
0 * _  // don't allow any other interaction
Handler dispatch failed; nested exception is Too many invocations for:

0 * _  // don't allow any other interaction   (1 invocation)
-----------------------
public class Foo {

    public ResponseEntity<?> bar(Long id) {
        ...
    }
}
setup:
Foo mockFoo = Stub()

given:
String id = '123'

and:
ResponseEntity<String> response = new ResponseEntity<String>('Hello World', HttpStatus.OK)

and:
mockFoo.bar(id) >> response

...
then:
mockFoo.bar(id) >> response
0 * _  // don't allow any other interaction
Handler dispatch failed; nested exception is Too many invocations for:

0 * _  // don't allow any other interaction   (1 invocation)

How do I get spock-reports to generate index.html instead of getting 'ClassCastException class [B cannot be cast to class [C'

copy iconCopydownload iconDownload
groovy.json.faststringutils.disable=true
<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <systemPropertyVariables>
      <groovy.json.faststringutils.disable>true</groovy.json.faststringutils.disable>
    </systemPropertyVariables>
    ...
  ...
</plugin>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>3.0.10</version>
    <scope>test</scope>
    <type>pom</type>
</dependency>
-----------------------
groovy.json.faststringutils.disable=true
<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <systemPropertyVariables>
      <groovy.json.faststringutils.disable>true</groovy.json.faststringutils.disable>
    </systemPropertyVariables>
    ...
  ...
</plugin>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>3.0.10</version>
    <scope>test</scope>
    <type>pom</type>
</dependency>
-----------------------
groovy.json.faststringutils.disable=true
<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <systemPropertyVariables>
      <groovy.json.faststringutils.disable>true</groovy.json.faststringutils.disable>
    </systemPropertyVariables>
    ...
  ...
</plugin>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>3.0.10</version>
    <scope>test</scope>
    <type>pom</type>
</dependency>

How to tell if Spock is actually executing tests in parallel

copy iconCopydownload iconDownload
import static org.spockframework.runtime.model.parallel.ExecutionMode.CONCURRENT

runner {
  parallel {
    enabled true
    // These values are the default already, specifying them is redundant
    // defaultSpecificationExecutionMode = CONCURRENT
    // defaultExecutionMode = CONCURRENT
    fixed 4
  }
}
package de.scrum_master.testing

import spock.lang.Specification

import static java.lang.System.currentTimeMillis
import static java.lang.Thread.currentThread

class ParallelExecutionTest extends Specification {
  static long startTime = currentTimeMillis()
  static volatile int execCount = 0

  def "feature-A-#count"() {
    given:
    def i = ++execCount
    printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
    sleep 1000
    printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName

    where:
    count << (1..8)
  }

  def "feature-B-#count"() {
    given:
    def i = ++execCount
    printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
    sleep 1000
    printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName

    where:
    count << (1..8)
  }
}
   68  1 [ForkJoinPool-1-worker-3] >> feature-B-1
   68  2 [ForkJoinPool-1-worker-2] >> feature-A-5
   68  3 [ForkJoinPool-1-worker-1] >> feature-B-6
   68  4 [ForkJoinPool-1-worker-4] >> feature-B-2
 1177  1 [ForkJoinPool-1-worker-3] << feature-B-1
 1177  3 [ForkJoinPool-1-worker-1] << feature-B-6
 1179  4 [ForkJoinPool-1-worker-4] << feature-B-2
 1180  2 [ForkJoinPool-1-worker-2] << feature-A-5

 1191  5 [ForkJoinPool-1-worker-3] >> feature-B-3
 1199  6 [ForkJoinPool-1-worker-4] >> feature-B-4
 1200  7 [ForkJoinPool-1-worker-1] >> feature-B-5
 1204  8 [ForkJoinPool-1-worker-2] >> feature-A-6
 2199  5 [ForkJoinPool-1-worker-3] << feature-B-3
 2205  7 [ForkJoinPool-1-worker-1] << feature-B-5
 2213  6 [ForkJoinPool-1-worker-4] << feature-B-4
 2213  8 [ForkJoinPool-1-worker-2] << feature-A-6

 2203  9 [ForkJoinPool-1-worker-3] >> feature-B-7
 2207 10 [ForkJoinPool-1-worker-1] >> feature-A-1
 2217 11 [ForkJoinPool-1-worker-4] >> feature-B-8
 2222 12 [ForkJoinPool-1-worker-2] >> feature-A-8
 3205  9 [ForkJoinPool-1-worker-3] << feature-B-7
 3213 10 [ForkJoinPool-1-worker-1] << feature-A-1
 3229 12 [ForkJoinPool-1-worker-2] << feature-A-8
 3230 11 [ForkJoinPool-1-worker-4] << feature-B-8

 3208 13 [ForkJoinPool-1-worker-3] >> feature-A-2
 3216 14 [ForkJoinPool-1-worker-1] >> feature-A-3
 3234 15 [ForkJoinPool-1-worker-4] >> feature-A-4
 3237 16 [ForkJoinPool-1-worker-2] >> feature-A-7
 4214 13 [ForkJoinPool-1-worker-3] << feature-A-2
 4230 14 [ForkJoinPool-1-worker-1] << feature-A-3
 4245 15 [ForkJoinPool-1-worker-4] << feature-A-4
 4245 16 [ForkJoinPool-1-worker-2] << feature-A-7
-----------------------
import static org.spockframework.runtime.model.parallel.ExecutionMode.CONCURRENT

runner {
  parallel {
    enabled true
    // These values are the default already, specifying them is redundant
    // defaultSpecificationExecutionMode = CONCURRENT
    // defaultExecutionMode = CONCURRENT
    fixed 4
  }
}
package de.scrum_master.testing

import spock.lang.Specification

import static java.lang.System.currentTimeMillis
import static java.lang.Thread.currentThread

class ParallelExecutionTest extends Specification {
  static long startTime = currentTimeMillis()
  static volatile int execCount = 0

  def "feature-A-#count"() {
    given:
    def i = ++execCount
    printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
    sleep 1000
    printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName

    where:
    count << (1..8)
  }

  def "feature-B-#count"() {
    given:
    def i = ++execCount
    printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
    sleep 1000
    printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName

    where:
    count << (1..8)
  }
}
   68  1 [ForkJoinPool-1-worker-3] >> feature-B-1
   68  2 [ForkJoinPool-1-worker-2] >> feature-A-5
   68  3 [ForkJoinPool-1-worker-1] >> feature-B-6
   68  4 [ForkJoinPool-1-worker-4] >> feature-B-2
 1177  1 [ForkJoinPool-1-worker-3] << feature-B-1
 1177  3 [ForkJoinPool-1-worker-1] << feature-B-6
 1179  4 [ForkJoinPool-1-worker-4] << feature-B-2
 1180  2 [ForkJoinPool-1-worker-2] << feature-A-5

 1191  5 [ForkJoinPool-1-worker-3] >> feature-B-3
 1199  6 [ForkJoinPool-1-worker-4] >> feature-B-4
 1200  7 [ForkJoinPool-1-worker-1] >> feature-B-5
 1204  8 [ForkJoinPool-1-worker-2] >> feature-A-6
 2199  5 [ForkJoinPool-1-worker-3] << feature-B-3
 2205  7 [ForkJoinPool-1-worker-1] << feature-B-5
 2213  6 [ForkJoinPool-1-worker-4] << feature-B-4
 2213  8 [ForkJoinPool-1-worker-2] << feature-A-6

 2203  9 [ForkJoinPool-1-worker-3] >> feature-B-7
 2207 10 [ForkJoinPool-1-worker-1] >> feature-A-1
 2217 11 [ForkJoinPool-1-worker-4] >> feature-B-8
 2222 12 [ForkJoinPool-1-worker-2] >> feature-A-8
 3205  9 [ForkJoinPool-1-worker-3] << feature-B-7
 3213 10 [ForkJoinPool-1-worker-1] << feature-A-1
 3229 12 [ForkJoinPool-1-worker-2] << feature-A-8
 3230 11 [ForkJoinPool-1-worker-4] << feature-B-8

 3208 13 [ForkJoinPool-1-worker-3] >> feature-A-2
 3216 14 [ForkJoinPool-1-worker-1] >> feature-A-3
 3234 15 [ForkJoinPool-1-worker-4] >> feature-A-4
 3237 16 [ForkJoinPool-1-worker-2] >> feature-A-7
 4214 13 [ForkJoinPool-1-worker-3] << feature-A-2
 4230 14 [ForkJoinPool-1-worker-1] << feature-A-3
 4245 15 [ForkJoinPool-1-worker-4] << feature-A-4
 4245 16 [ForkJoinPool-1-worker-2] << feature-A-7
-----------------------
import static org.spockframework.runtime.model.parallel.ExecutionMode.CONCURRENT

runner {
  parallel {
    enabled true
    // These values are the default already, specifying them is redundant
    // defaultSpecificationExecutionMode = CONCURRENT
    // defaultExecutionMode = CONCURRENT
    fixed 4
  }
}
package de.scrum_master.testing

import spock.lang.Specification

import static java.lang.System.currentTimeMillis
import static java.lang.Thread.currentThread

class ParallelExecutionTest extends Specification {
  static long startTime = currentTimeMillis()
  static volatile int execCount = 0

  def "feature-A-#count"() {
    given:
    def i = ++execCount
    printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
    sleep 1000
    printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName

    where:
    count << (1..8)
  }

  def "feature-B-#count"() {
    given:
    def i = ++execCount
    printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
    sleep 1000
    printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName

    where:
    count << (1..8)
  }
}
   68  1 [ForkJoinPool-1-worker-3] >> feature-B-1
   68  2 [ForkJoinPool-1-worker-2] >> feature-A-5
   68  3 [ForkJoinPool-1-worker-1] >> feature-B-6
   68  4 [ForkJoinPool-1-worker-4] >> feature-B-2
 1177  1 [ForkJoinPool-1-worker-3] << feature-B-1
 1177  3 [ForkJoinPool-1-worker-1] << feature-B-6
 1179  4 [ForkJoinPool-1-worker-4] << feature-B-2
 1180  2 [ForkJoinPool-1-worker-2] << feature-A-5

 1191  5 [ForkJoinPool-1-worker-3] >> feature-B-3
 1199  6 [ForkJoinPool-1-worker-4] >> feature-B-4
 1200  7 [ForkJoinPool-1-worker-1] >> feature-B-5
 1204  8 [ForkJoinPool-1-worker-2] >> feature-A-6
 2199  5 [ForkJoinPool-1-worker-3] << feature-B-3
 2205  7 [ForkJoinPool-1-worker-1] << feature-B-5
 2213  6 [ForkJoinPool-1-worker-4] << feature-B-4
 2213  8 [ForkJoinPool-1-worker-2] << feature-A-6

 2203  9 [ForkJoinPool-1-worker-3] >> feature-B-7
 2207 10 [ForkJoinPool-1-worker-1] >> feature-A-1
 2217 11 [ForkJoinPool-1-worker-4] >> feature-B-8
 2222 12 [ForkJoinPool-1-worker-2] >> feature-A-8
 3205  9 [ForkJoinPool-1-worker-3] << feature-B-7
 3213 10 [ForkJoinPool-1-worker-1] << feature-A-1
 3229 12 [ForkJoinPool-1-worker-2] << feature-A-8
 3230 11 [ForkJoinPool-1-worker-4] << feature-B-8

 3208 13 [ForkJoinPool-1-worker-3] >> feature-A-2
 3216 14 [ForkJoinPool-1-worker-1] >> feature-A-3
 3234 15 [ForkJoinPool-1-worker-4] >> feature-A-4
 3237 16 [ForkJoinPool-1-worker-2] >> feature-A-7
 4214 13 [ForkJoinPool-1-worker-3] << feature-A-2
 4230 14 [ForkJoinPool-1-worker-1] << feature-A-3
 4245 15 [ForkJoinPool-1-worker-4] << feature-A-4
 4245 16 [ForkJoinPool-1-worker-2] << feature-A-7

Testing an SFTP client with Spock Framework

copy iconCopydownload iconDownload
package de.scrum_master.stackoverflow.q71081881;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.InMemoryDestFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class SFTPFileDownloader {
  private String host;
  private int port;
  private String user;
  private String password;

  public SFTPFileDownloader(String host, int port, String user, String password) {
    this.host = host;
    this.port = port;
    this.user = user;
    this.password = password;
  }

  protected static class ByteArrayInMemoryDestFile extends InMemoryDestFile {
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    @Override
    public ByteArrayOutputStream getOutputStream() {
      return outputStream;
    }
  }

  public String getFileContent(String path) throws IOException {
    try (
      SSHClient sshClient = setupSshj();
      SFTPClient sftpClient = sshClient.newSFTPClient()
    )
    {
      ByteArrayInMemoryDestFile inMemoryDestFile = new ByteArrayInMemoryDestFile();
      sftpClient.get(path, inMemoryDestFile);
      return inMemoryDestFile.getOutputStream().toString("UTF-8");
    }
  }

  private SSHClient setupSshj() throws IOException {
    SSHClient client = new SSHClient();
    client.addHostKeyVerifier(new PromiscuousVerifier());
    client.connect(host, port);
    client.authPassword(user, password);
    return client;
  }
}
package de.scrum_master.stackoverflow.q71081881

import com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer

class CloseableFakeSftpServer implements AutoCloseable {
  @Delegate
  private FakeSftpServer fakeSftpServer
  private Closeable closeServer

  CloseableFakeSftpServer() {
    fakeSftpServer = new FakeSftpServer(FakeSftpServer.createFileSystem())
    closeServer = fakeSftpServer.start(0)
  }

  @Override
  void close() throws Exception {
    fakeSftpServer.fileSystem.close()
    closeServer.close()
  }
}
package de.scrum_master.stackoverflow.q71081881

import spock.lang.AutoCleanup
import spock.lang.Specification

import static com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer.withSftpServer
import static java.nio.charset.StandardCharsets.UTF_8

class SFTPServerTest extends Specification {
  @AutoCleanup
  def server = new CloseableFakeSftpServer()
  def user = "someone"
  def password = "secret"

  def "use original server class"() {
    given:
    def fileContent = null

    when:
    withSftpServer { server ->
      server.addUser(user, password)
      server.putFile("/directory/file.txt", "content of file", UTF_8)
      // Interact with the subject under test
      def client = new SFTPFileDownloader("localhost", server.port, user, password)
      fileContent = client.getFileContent("/directory/file.txt")
    }

    then:
    fileContent == "content of file"
  }

  def "use custom server class"() {
    given: "a preconfigured fake SFTP server"
    server.addUser(user, password)
    server.putFile("/directory/file.txt", "content of file", UTF_8)

    and: "an SFTP client under test"
    def client = new SFTPFileDownloader("localhost", server.port, user, password)

    expect:
    client.getFileContent("/directory/file.txt") == "content of file"
  }

}
-----------------------
package de.scrum_master.stackoverflow.q71081881;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.InMemoryDestFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class SFTPFileDownloader {
  private String host;
  private int port;
  private String user;
  private String password;

  public SFTPFileDownloader(String host, int port, String user, String password) {
    this.host = host;
    this.port = port;
    this.user = user;
    this.password = password;
  }

  protected static class ByteArrayInMemoryDestFile extends InMemoryDestFile {
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    @Override
    public ByteArrayOutputStream getOutputStream() {
      return outputStream;
    }
  }

  public String getFileContent(String path) throws IOException {
    try (
      SSHClient sshClient = setupSshj();
      SFTPClient sftpClient = sshClient.newSFTPClient()
    )
    {
      ByteArrayInMemoryDestFile inMemoryDestFile = new ByteArrayInMemoryDestFile();
      sftpClient.get(path, inMemoryDestFile);
      return inMemoryDestFile.getOutputStream().toString("UTF-8");
    }
  }

  private SSHClient setupSshj() throws IOException {
    SSHClient client = new SSHClient();
    client.addHostKeyVerifier(new PromiscuousVerifier());
    client.connect(host, port);
    client.authPassword(user, password);
    return client;
  }
}
package de.scrum_master.stackoverflow.q71081881

import com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer

class CloseableFakeSftpServer implements AutoCloseable {
  @Delegate
  private FakeSftpServer fakeSftpServer
  private Closeable closeServer

  CloseableFakeSftpServer() {
    fakeSftpServer = new FakeSftpServer(FakeSftpServer.createFileSystem())
    closeServer = fakeSftpServer.start(0)
  }

  @Override
  void close() throws Exception {
    fakeSftpServer.fileSystem.close()
    closeServer.close()
  }
}
package de.scrum_master.stackoverflow.q71081881

import spock.lang.AutoCleanup
import spock.lang.Specification

import static com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer.withSftpServer
import static java.nio.charset.StandardCharsets.UTF_8

class SFTPServerTest extends Specification {
  @AutoCleanup
  def server = new CloseableFakeSftpServer()
  def user = "someone"
  def password = "secret"

  def "use original server class"() {
    given:
    def fileContent = null

    when:
    withSftpServer { server ->
      server.addUser(user, password)
      server.putFile("/directory/file.txt", "content of file", UTF_8)
      // Interact with the subject under test
      def client = new SFTPFileDownloader("localhost", server.port, user, password)
      fileContent = client.getFileContent("/directory/file.txt")
    }

    then:
    fileContent == "content of file"
  }

  def "use custom server class"() {
    given: "a preconfigured fake SFTP server"
    server.addUser(user, password)
    server.putFile("/directory/file.txt", "content of file", UTF_8)

    and: "an SFTP client under test"
    def client = new SFTPFileDownloader("localhost", server.port, user, password)

    expect:
    client.getFileContent("/directory/file.txt") == "content of file"
  }

}
-----------------------
package de.scrum_master.stackoverflow.q71081881;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.InMemoryDestFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class SFTPFileDownloader {
  private String host;
  private int port;
  private String user;
  private String password;

  public SFTPFileDownloader(String host, int port, String user, String password) {
    this.host = host;
    this.port = port;
    this.user = user;
    this.password = password;
  }

  protected static class ByteArrayInMemoryDestFile extends InMemoryDestFile {
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    @Override
    public ByteArrayOutputStream getOutputStream() {
      return outputStream;
    }
  }

  public String getFileContent(String path) throws IOException {
    try (
      SSHClient sshClient = setupSshj();
      SFTPClient sftpClient = sshClient.newSFTPClient()
    )
    {
      ByteArrayInMemoryDestFile inMemoryDestFile = new ByteArrayInMemoryDestFile();
      sftpClient.get(path, inMemoryDestFile);
      return inMemoryDestFile.getOutputStream().toString("UTF-8");
    }
  }

  private SSHClient setupSshj() throws IOException {
    SSHClient client = new SSHClient();
    client.addHostKeyVerifier(new PromiscuousVerifier());
    client.connect(host, port);
    client.authPassword(user, password);
    return client;
  }
}
package de.scrum_master.stackoverflow.q71081881

import com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer

class CloseableFakeSftpServer implements AutoCloseable {
  @Delegate
  private FakeSftpServer fakeSftpServer
  private Closeable closeServer

  CloseableFakeSftpServer() {
    fakeSftpServer = new FakeSftpServer(FakeSftpServer.createFileSystem())
    closeServer = fakeSftpServer.start(0)
  }

  @Override
  void close() throws Exception {
    fakeSftpServer.fileSystem.close()
    closeServer.close()
  }
}
package de.scrum_master.stackoverflow.q71081881

import spock.lang.AutoCleanup
import spock.lang.Specification

import static com.github.stefanbirkner.fakesftpserver.lambda.FakeSftpServer.withSftpServer
import static java.nio.charset.StandardCharsets.UTF_8

class SFTPServerTest extends Specification {
  @AutoCleanup
  def server = new CloseableFakeSftpServer()
  def user = "someone"
  def password = "secret"

  def "use original server class"() {
    given:
    def fileContent = null

    when:
    withSftpServer { server ->
      server.addUser(user, password)
      server.putFile("/directory/file.txt", "content of file", UTF_8)
      // Interact with the subject under test
      def client = new SFTPFileDownloader("localhost", server.port, user, password)
      fileContent = client.getFileContent("/directory/file.txt")
    }

    then:
    fileContent == "content of file"
  }

  def "use custom server class"() {
    given: "a preconfigured fake SFTP server"
    server.addUser(user, password)
    server.putFile("/directory/file.txt", "content of file", UTF_8)

    and: "an SFTP client under test"
    def client = new SFTPFileDownloader("localhost", server.port, user, password)

    expect:
    client.getFileContent("/directory/file.txt") == "content of file"
  }

}

MissingPropertyException in Spock test

copy iconCopydownload iconDownload
public void $spock_feature_0_0() {
        org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
        org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
        java.lang.Object someId = 'someId'
        java.lang.Object event = new apackage.SomeEventObject()
        this.getSpecificationContext().getMockController().enterScope()
        this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(25, 9, '1 * eventPublisher.publishEvent(new SomeNextEvent(updatedValue))').setFixedCount(1).addEqualTarget(eventPublisher).addEqualMethodName('publishEvent').setArgListKind(true, false).addEqualArg(new apackage.SomeNextEvent(updatedValue)).build())
        sut.handle(event)
        this.getSpecificationContext().getMockController().leaveScope()
        java.lang.Object updatedValue = myClassRepository.findTestClass(someId)
        try {
            org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'updatedTestClass.cash == 100', 23, 13, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(3), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), updatedTestClass).cash) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), 100)))
        }
        catch (java.lang.Throwable throwable) {
            org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'updatedTestClass.cash == 100', 23, 13, null, throwable)}
        finally {
        }
        this.getSpecificationContext().getMockController().leaveScope()
    }
given:
def capturedEvent

when:
...

then:
1 * eventPublisher.publishEvent(_) >> { capturedEvent = it[0} }

and:

def updatedValue = myClassRepository.findTestClass(someId)
capturedEvent instanceof SomeNextEvent
capturedEvent.value == updatedValue 
-----------------------
public void $spock_feature_0_0() {
        org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
        org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
        java.lang.Object someId = 'someId'
        java.lang.Object event = new apackage.SomeEventObject()
        this.getSpecificationContext().getMockController().enterScope()
        this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(25, 9, '1 * eventPublisher.publishEvent(new SomeNextEvent(updatedValue))').setFixedCount(1).addEqualTarget(eventPublisher).addEqualMethodName('publishEvent').setArgListKind(true, false).addEqualArg(new apackage.SomeNextEvent(updatedValue)).build())
        sut.handle(event)
        this.getSpecificationContext().getMockController().leaveScope()
        java.lang.Object updatedValue = myClassRepository.findTestClass(someId)
        try {
            org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'updatedTestClass.cash == 100', 23, 13, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(3), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), updatedTestClass).cash) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), 100)))
        }
        catch (java.lang.Throwable throwable) {
            org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'updatedTestClass.cash == 100', 23, 13, null, throwable)}
        finally {
        }
        this.getSpecificationContext().getMockController().leaveScope()
    }
given:
def capturedEvent

when:
...

then:
1 * eventPublisher.publishEvent(_) >> { capturedEvent = it[0} }

and:

def updatedValue = myClassRepository.findTestClass(someId)
capturedEvent instanceof SomeNextEvent
capturedEvent.value == updatedValue 

How to mock Grails request object method in Spock controller test

copy iconCopydownload iconDownload
def "validerHtml: håndterer MalformedInputException"() {
    given:
        String charset = "UTF-16"
        GrailsMockHttpServletRequest mockRequest = Spy(GrailsMockHttpServletRequest)
        mockRequest.getReader() >> {
            throw new MalformedInputException(1)
        }
        mockRequest.setContentType("text/html;charset=${charset}")

        GrailsMockHttpServletResponse mockResponse = new GrailsMockHttpServletResponse()
        GrailsWebRequest webRequest = new GrailsWebRequest(mockRequest, mockResponse, mockRequest.getServletContext())
        mockRequest.setAttribute(GrailsApplicationAttributes.WEB_REQUEST, webRequest)
        RequestContextHolder.setRequestAttributes(webRequest)  // Here we overwrite the web request
    when:
        controller.validateHtml()
    then:
        0 * controller.myService.validateMessage(*_)
        // Have to check would-be response on our mocked response
        mockResponse.status == HttpStatus.BAD_REQUEST.value()
        mockResponse.text.startsWith("Could not read request body using charset: ${charset}")
}

Upgrade to Spring Boot 2.4 break Spock Spring mocks

copy iconCopydownload iconDownload
spring.main.allow-bean-definition-overriding=true

Verify Spock mock asynchonous interaction after an exception is thrown

copy iconCopydownload iconDownload
class ServiceAImplTest extends Specification {

    ServiceB serviceB = Mock()
    ServiceC serviceC = Mock()

    @Subject
    def subject = new ServiceAImpl(serviceB, serviceC)

    def "createAccount - should throw Exception and save error"() {
        given:
        def result = new BlockingVariable<Boolean>(10.0)
        
        when:
        subject.createAccount("userId")
        

        then: 'first catch the exception and wait for the result'
        thrown(Exception)
        result.get()
        
        then: 'verify mock interactions'
        1 * serviceB.createUserAccount(_) >> { throw new Exception() }
        1 * serviceC.save(_) >> { result.set(true) }
        0 * _
    }
}

Immutable configuration in Micronaut with list in YAML

copy iconCopydownload iconDownload
{
  "name": "T1",
  "endpoint": "http://t1",
  "version": "1.5.3.24305,2021-08-09 18:01",
  "read-timeout": 20
}
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.convert.TypeConverter;

import javax.inject.Singleton;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@ConfigurationProperties("a.b")
public interface MyConfig {

    List<Instance> getInstances();

    interface Instance {
        String getName();
        URL getEndpoint();
        String getVersion();
        int getReadTimeout();
    }

    @Singleton
    class MapToInstanceConverter implements TypeConverter<Map, Instance> {

        @Override
        public Optional<Instance> convert(Map object, Class<Instance> targetType, ConversionContext context) {
            return Optional.of(new Instance() {
                @Override
                public String getName() {
                    return object.getOrDefault("name", "").toString();
                }

                @Override
                public URL getEndpoint() {
                    try {
                        return new URI(object.getOrDefault("endpoint", "").toString()).toURL();
                    } catch (MalformedURLException | URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public String getVersion() {
                    return object.getOrDefault("version", "").toString();
                }

                @Override
                public int getReadTimeout() {
                    return Integer.parseInt(object.getOrDefault("read-timeout", 0).toString());
                }
            });
        }
    }
}

@ConfigurationProperties("a.b")
public interface MyConfig {

    Instance getInstance();

    @ConfigurationProperties("instance")
    interface Instance {
        String getName();
        URL getEndpoint();
        String getVersion();
        int getReadTimeout();
    }
}
-----------------------
{
  "name": "T1",
  "endpoint": "http://t1",
  "version": "1.5.3.24305,2021-08-09 18:01",
  "read-timeout": 20
}
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.convert.TypeConverter;

import javax.inject.Singleton;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@ConfigurationProperties("a.b")
public interface MyConfig {

    List<Instance> getInstances();

    interface Instance {
        String getName();
        URL getEndpoint();
        String getVersion();
        int getReadTimeout();
    }

    @Singleton
    class MapToInstanceConverter implements TypeConverter<Map, Instance> {

        @Override
        public Optional<Instance> convert(Map object, Class<Instance> targetType, ConversionContext context) {
            return Optional.of(new Instance() {
                @Override
                public String getName() {
                    return object.getOrDefault("name", "").toString();
                }

                @Override
                public URL getEndpoint() {
                    try {
                        return new URI(object.getOrDefault("endpoint", "").toString()).toURL();
                    } catch (MalformedURLException | URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public String getVersion() {
                    return object.getOrDefault("version", "").toString();
                }

                @Override
                public int getReadTimeout() {
                    return Integer.parseInt(object.getOrDefault("read-timeout", 0).toString());
                }
            });
        }
    }
}

@ConfigurationProperties("a.b")
public interface MyConfig {

    Instance getInstance();

    @ConfigurationProperties("instance")
    interface Instance {
        String getName();
        URL getEndpoint();
        String getVersion();
        int getReadTimeout();
    }
}
-----------------------
{
  "name": "T1",
  "endpoint": "http://t1",
  "version": "1.5.3.24305,2021-08-09 18:01",
  "read-timeout": 20
}
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.convert.TypeConverter;

import javax.inject.Singleton;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@ConfigurationProperties("a.b")
public interface MyConfig {

    List<Instance> getInstances();

    interface Instance {
        String getName();
        URL getEndpoint();
        String getVersion();
        int getReadTimeout();
    }

    @Singleton
    class MapToInstanceConverter implements TypeConverter<Map, Instance> {

        @Override
        public Optional<Instance> convert(Map object, Class<Instance> targetType, ConversionContext context) {
            return Optional.of(new Instance() {
                @Override
                public String getName() {
                    return object.getOrDefault("name", "").toString();
                }

                @Override
                public URL getEndpoint() {
                    try {
                        return new URI(object.getOrDefault("endpoint", "").toString()).toURL();
                    } catch (MalformedURLException | URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public String getVersion() {
                    return object.getOrDefault("version", "").toString();
                }

                @Override
                public int getReadTimeout() {
                    return Integer.parseInt(object.getOrDefault("read-timeout", 0).toString());
                }
            });
        }
    }
}

@ConfigurationProperties("a.b")
public interface MyConfig {

    Instance getInstance();

    @ConfigurationProperties("instance")
    interface Instance {
        String getName();
        URL getEndpoint();
        String getVersion();
        int getReadTimeout();
    }
}

Micronaut 3: How to use PubSubEmulatorContainer

copy iconCopydownload iconDownload
applicationContext = ApplicationContext.run(               
["pubsub.emulator.host": emulatorHost])
package no.myproject.testframework.testcontainers

import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName

class PubSubEmulator {
    static PubSubEmulatorContainer pubSubEmulatorContainer

    static init() {
        if (pubSubEmulatorContainer == null) {
            pubSubEmulatorContainer = new PubSubEmulatorContainer(
                    DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
            pubSubEmulatorContainer.start()
        }
    }
}
package no.myproject.testframework.testcontainers

trait PubSubEmulatorFixture {
    Map<String, Object> getPubSubConfiguration() {
        if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
            PubSubEmulator.init()
        }
        [
                "pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
        ]
    }
}
package no.myproject.testframework

import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

abstract class PubSubSpecification extends Specification
        implements PubSubEmulatorFixture, EnvironmentFixture {

    @AutoCleanup
    @Shared
    EmbeddedServer embeddedServer

    @AutoCleanup
    @Shared
    ApplicationContext applicationContext

    def setupSpec() {

        // start the pubsub emulator
        def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")

        // start a temporary applicationContext in order to read config
        // keep any pubsub subscriptions out of context at this stage
        applicationContext = ApplicationContext.run()

        def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
        def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)

        def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
                .usePlaintext()
                .build()

        def channelProvider =
                FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))

        // START creating topic

        def topicAdminClient =
                TopicAdminClient.create(
                        TopicAdminSettings.newBuilder()
                                .setCredentialsProvider(NoCredentialsProvider.create())
                                .setTransportChannelProvider(channelProvider)
                                .build())

        def topic = TopicName.of(
                gcpConfigProperties.getProjectId(),
                pubSubConfigProperties.getTopicName())

        try {
            topicAdminClient.createTopic(topic)
        } catch (AlreadyExistsException) {
            // this is fine, already created
            topicAdminClient.getTopic(topic)
        }

        // START creating subscription

        pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
            def subscription =
                    ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)

            def subscriptionAdminClient =
                    SubscriptionAdminClient.create(
                            SubscriptionAdminSettings.newBuilder()
                                    .setTransportChannelProvider(channelProvider)
                                    .setCredentialsProvider(NoCredentialsProvider.create())
                                    .build())

            try {
                subscriptionAdminClient
                        .createSubscription(
                                subscription,
                                topic,
                                PushConfig.getDefaultInstance(),
                                100)

                System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
            } catch (AlreadyExistsException) {
                // this is fine, already created
                subscriptionAdminClient.getSubscription(subscription)
            }
        })

        channel.shutdown()

        // stop the temporary applicationContext
        applicationContext.stop()

        // start the actual applicationContext
        embeddedServer = ApplicationContext.run(
                EmbeddedServer,
                [
                        'spec.name'           : "PubSubEmulatorSpec",
                        "pubsub.emulator.host": emulatorHost
                ],
                environments)

        applicationContext = embeddedServer.applicationContext
    }
}
package no.myproject.pubsub

import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires

import javax.inject.Singleton


@Factory
@Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {

    @Singleton
    @Replaces(GoogleCredentials)
    GoogleCredentials mockCredentials() {
        return GoogleCredentials.create(new AccessToken("", new Date()))
    }
}
package no.myproject.pubsub

import no.myproject.testframework.PubSubSpecification

import java.util.stream.IntStream

class PubSubIntegrationSpec extends PubSubSpecification {

    def NUMBER_OF_MESSAGES_IN_TEST = 5
    def DELAY_IN_MILLISECONDS_PER_MSG = 100

    def "when a number of messages is sent, same amount of messages is received"() {
        given:
        def documentPublisher = applicationContext.getBean(DocumentPublisher)
        def listener = applicationContext.getBean(IncomingDocListenerWithAck)
        def initialReceiveCount = listener.getReceiveCount()

        when:
        IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
                .forEach(it -> documentPublisher.send("Hello World!"))

        // wait a bit in order to let all messages propagate through the queue
        Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)

        then:
        NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
    }
}
-----------------------
applicationContext = ApplicationContext.run(               
["pubsub.emulator.host": emulatorHost])
package no.myproject.testframework.testcontainers

import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName

class PubSubEmulator {
    static PubSubEmulatorContainer pubSubEmulatorContainer

    static init() {
        if (pubSubEmulatorContainer == null) {
            pubSubEmulatorContainer = new PubSubEmulatorContainer(
                    DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
            pubSubEmulatorContainer.start()
        }
    }
}
package no.myproject.testframework.testcontainers

trait PubSubEmulatorFixture {
    Map<String, Object> getPubSubConfiguration() {
        if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
            PubSubEmulator.init()
        }
        [
                "pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
        ]
    }
}
package no.myproject.testframework

import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

abstract class PubSubSpecification extends Specification
        implements PubSubEmulatorFixture, EnvironmentFixture {

    @AutoCleanup
    @Shared
    EmbeddedServer embeddedServer

    @AutoCleanup
    @Shared
    ApplicationContext applicationContext

    def setupSpec() {

        // start the pubsub emulator
        def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")

        // start a temporary applicationContext in order to read config
        // keep any pubsub subscriptions out of context at this stage
        applicationContext = ApplicationContext.run()

        def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
        def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)

        def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
                .usePlaintext()
                .build()

        def channelProvider =
                FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))

        // START creating topic

        def topicAdminClient =
                TopicAdminClient.create(
                        TopicAdminSettings.newBuilder()
                                .setCredentialsProvider(NoCredentialsProvider.create())
                                .setTransportChannelProvider(channelProvider)
                                .build())

        def topic = TopicName.of(
                gcpConfigProperties.getProjectId(),
                pubSubConfigProperties.getTopicName())

        try {
            topicAdminClient.createTopic(topic)
        } catch (AlreadyExistsException) {
            // this is fine, already created
            topicAdminClient.getTopic(topic)
        }

        // START creating subscription

        pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
            def subscription =
                    ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)

            def subscriptionAdminClient =
                    SubscriptionAdminClient.create(
                            SubscriptionAdminSettings.newBuilder()
                                    .setTransportChannelProvider(channelProvider)
                                    .setCredentialsProvider(NoCredentialsProvider.create())
                                    .build())

            try {
                subscriptionAdminClient
                        .createSubscription(
                                subscription,
                                topic,
                                PushConfig.getDefaultInstance(),
                                100)

                System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
            } catch (AlreadyExistsException) {
                // this is fine, already created
                subscriptionAdminClient.getSubscription(subscription)
            }
        })

        channel.shutdown()

        // stop the temporary applicationContext
        applicationContext.stop()

        // start the actual applicationContext
        embeddedServer = ApplicationContext.run(
                EmbeddedServer,
                [
                        'spec.name'           : "PubSubEmulatorSpec",
                        "pubsub.emulator.host": emulatorHost
                ],
                environments)

        applicationContext = embeddedServer.applicationContext
    }
}
package no.myproject.pubsub

import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires

import javax.inject.Singleton


@Factory
@Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {

    @Singleton
    @Replaces(GoogleCredentials)
    GoogleCredentials mockCredentials() {
        return GoogleCredentials.create(new AccessToken("", new Date()))
    }
}
package no.myproject.pubsub

import no.myproject.testframework.PubSubSpecification

import java.util.stream.IntStream

class PubSubIntegrationSpec extends PubSubSpecification {

    def NUMBER_OF_MESSAGES_IN_TEST = 5
    def DELAY_IN_MILLISECONDS_PER_MSG = 100

    def "when a number of messages is sent, same amount of messages is received"() {
        given:
        def documentPublisher = applicationContext.getBean(DocumentPublisher)
        def listener = applicationContext.getBean(IncomingDocListenerWithAck)
        def initialReceiveCount = listener.getReceiveCount()

        when:
        IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
                .forEach(it -> documentPublisher.send("Hello World!"))

        // wait a bit in order to let all messages propagate through the queue
        Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)

        then:
        NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
    }
}
-----------------------
applicationContext = ApplicationContext.run(               
["pubsub.emulator.host": emulatorHost])
package no.myproject.testframework.testcontainers

import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName

class PubSubEmulator {
    static PubSubEmulatorContainer pubSubEmulatorContainer

    static init() {
        if (pubSubEmulatorContainer == null) {
            pubSubEmulatorContainer = new PubSubEmulatorContainer(
                    DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
            pubSubEmulatorContainer.start()
        }
    }
}
package no.myproject.testframework.testcontainers

trait PubSubEmulatorFixture {
    Map<String, Object> getPubSubConfiguration() {
        if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
            PubSubEmulator.init()
        }
        [
                "pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
        ]
    }
}
package no.myproject.testframework

import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

abstract class PubSubSpecification extends Specification
        implements PubSubEmulatorFixture, EnvironmentFixture {

    @AutoCleanup
    @Shared
    EmbeddedServer embeddedServer

    @AutoCleanup
    @Shared
    ApplicationContext applicationContext

    def setupSpec() {

        // start the pubsub emulator
        def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")

        // start a temporary applicationContext in order to read config
        // keep any pubsub subscriptions out of context at this stage
        applicationContext = ApplicationContext.run()

        def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
        def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)

        def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
                .usePlaintext()
                .build()

        def channelProvider =
                FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))

        // START creating topic

        def topicAdminClient =
                TopicAdminClient.create(
                        TopicAdminSettings.newBuilder()
                                .setCredentialsProvider(NoCredentialsProvider.create())
                                .setTransportChannelProvider(channelProvider)
                                .build())

        def topic = TopicName.of(
                gcpConfigProperties.getProjectId(),
                pubSubConfigProperties.getTopicName())

        try {
            topicAdminClient.createTopic(topic)
        } catch (AlreadyExistsException) {
            // this is fine, already created
            topicAdminClient.getTopic(topic)
        }

        // START creating subscription

        pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
            def subscription =
                    ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)

            def subscriptionAdminClient =
                    SubscriptionAdminClient.create(
                            SubscriptionAdminSettings.newBuilder()
                                    .setTransportChannelProvider(channelProvider)
                                    .setCredentialsProvider(NoCredentialsProvider.create())
                                    .build())

            try {
                subscriptionAdminClient
                        .createSubscription(
                                subscription,
                                topic,
                                PushConfig.getDefaultInstance(),
                                100)

                System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
            } catch (AlreadyExistsException) {
                // this is fine, already created
                subscriptionAdminClient.getSubscription(subscription)
            }
        })

        channel.shutdown()

        // stop the temporary applicationContext
        applicationContext.stop()

        // start the actual applicationContext
        embeddedServer = ApplicationContext.run(
                EmbeddedServer,
                [
                        'spec.name'           : "PubSubEmulatorSpec",
                        "pubsub.emulator.host": emulatorHost
                ],
                environments)

        applicationContext = embeddedServer.applicationContext
    }
}
package no.myproject.pubsub

import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires

import javax.inject.Singleton


@Factory
@Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {

    @Singleton
    @Replaces(GoogleCredentials)
    GoogleCredentials mockCredentials() {
        return GoogleCredentials.create(new AccessToken("", new Date()))
    }
}
package no.myproject.pubsub

import no.myproject.testframework.PubSubSpecification

import java.util.stream.IntStream

class PubSubIntegrationSpec extends PubSubSpecification {

    def NUMBER_OF_MESSAGES_IN_TEST = 5
    def DELAY_IN_MILLISECONDS_PER_MSG = 100

    def "when a number of messages is sent, same amount of messages is received"() {
        given:
        def documentPublisher = applicationContext.getBean(DocumentPublisher)
        def listener = applicationContext.getBean(IncomingDocListenerWithAck)
        def initialReceiveCount = listener.getReceiveCount()

        when:
        IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
                .forEach(it -> documentPublisher.send("Hello World!"))

        // wait a bit in order to let all messages propagate through the queue
        Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)

        then:
        NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
    }
}
-----------------------
applicationContext = ApplicationContext.run(               
["pubsub.emulator.host": emulatorHost])
package no.myproject.testframework.testcontainers

import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName

class PubSubEmulator {
    static PubSubEmulatorContainer pubSubEmulatorContainer

    static init() {
        if (pubSubEmulatorContainer == null) {
            pubSubEmulatorContainer = new PubSubEmulatorContainer(
                    DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
            pubSubEmulatorContainer.start()
        }
    }
}
package no.myproject.testframework.testcontainers

trait PubSubEmulatorFixture {
    Map<String, Object> getPubSubConfiguration() {
        if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
            PubSubEmulator.init()
        }
        [
                "pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
        ]
    }
}
package no.myproject.testframework

import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

abstract class PubSubSpecification extends Specification
        implements PubSubEmulatorFixture, EnvironmentFixture {

    @AutoCleanup
    @Shared
    EmbeddedServer embeddedServer

    @AutoCleanup
    @Shared
    ApplicationContext applicationContext

    def setupSpec() {

        // start the pubsub emulator
        def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")

        // start a temporary applicationContext in order to read config
        // keep any pubsub subscriptions out of context at this stage
        applicationContext = ApplicationContext.run()

        def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
        def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)

        def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
                .usePlaintext()
                .build()

        def channelProvider =
                FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))

        // START creating topic

        def topicAdminClient =
                TopicAdminClient.create(
                        TopicAdminSettings.newBuilder()
                                .setCredentialsProvider(NoCredentialsProvider.create())
                                .setTransportChannelProvider(channelProvider)
                                .build())

        def topic = TopicName.of(
                gcpConfigProperties.getProjectId(),
                pubSubConfigProperties.getTopicName())

        try {
            topicAdminClient.createTopic(topic)
        } catch (AlreadyExistsException) {
            // this is fine, already created
            topicAdminClient.getTopic(topic)
        }

        // START creating subscription

        pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
            def subscription =
                    ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)

            def subscriptionAdminClient =
                    SubscriptionAdminClient.create(
                            SubscriptionAdminSettings.newBuilder()
                                    .setTransportChannelProvider(channelProvider)
                                    .setCredentialsProvider(NoCredentialsProvider.create())
                                    .build())

            try {
                subscriptionAdminClient
                        .createSubscription(
                                subscription,
                                topic,
                                PushConfig.getDefaultInstance(),
                                100)

                System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
            } catch (AlreadyExistsException) {
                // this is fine, already created
                subscriptionAdminClient.getSubscription(subscription)
            }
        })

        channel.shutdown()

        // stop the temporary applicationContext
        applicationContext.stop()

        // start the actual applicationContext
        embeddedServer = ApplicationContext.run(
                EmbeddedServer,
                [
                        'spec.name'           : "PubSubEmulatorSpec",
                        "pubsub.emulator.host": emulatorHost
                ],
                environments)

        applicationContext = embeddedServer.applicationContext
    }
}
package no.myproject.pubsub

import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires

import javax.inject.Singleton


@Factory
@Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {

    @Singleton
    @Replaces(GoogleCredentials)
    GoogleCredentials mockCredentials() {
        return GoogleCredentials.create(new AccessToken("", new Date()))
    }
}
package no.myproject.pubsub

import no.myproject.testframework.PubSubSpecification

import java.util.stream.IntStream

class PubSubIntegrationSpec extends PubSubSpecification {

    def NUMBER_OF_MESSAGES_IN_TEST = 5
    def DELAY_IN_MILLISECONDS_PER_MSG = 100

    def "when a number of messages is sent, same amount of messages is received"() {
        given:
        def documentPublisher = applicationContext.getBean(DocumentPublisher)
        def listener = applicationContext.getBean(IncomingDocListenerWithAck)
        def initialReceiveCount = listener.getReceiveCount()

        when:
        IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
                .forEach(it -> documentPublisher.send("Hello World!"))

        // wait a bit in order to let all messages propagate through the queue
        Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)

        then:
        NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
    }
}
-----------------------
applicationContext = ApplicationContext.run(               
["pubsub.emulator.host": emulatorHost])
package no.myproject.testframework.testcontainers

import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName

class PubSubEmulator {
    static PubSubEmulatorContainer pubSubEmulatorContainer

    static init() {
        if (pubSubEmulatorContainer == null) {
            pubSubEmulatorContainer = new PubSubEmulatorContainer(
                    DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
            pubSubEmulatorContainer.start()
        }
    }
}
package no.myproject.testframework.testcontainers

trait PubSubEmulatorFixture {
    Map<String, Object> getPubSubConfiguration() {
        if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
            PubSubEmulator.init()
        }
        [
                "pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
        ]
    }
}
package no.myproject.testframework

import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

abstract class PubSubSpecification extends Specification
        implements PubSubEmulatorFixture, EnvironmentFixture {

    @AutoCleanup
    @Shared
    EmbeddedServer embeddedServer

    @AutoCleanup
    @Shared
    ApplicationContext applicationContext

    def setupSpec() {

        // start the pubsub emulator
        def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")

        // start a temporary applicationContext in order to read config
        // keep any pubsub subscriptions out of context at this stage
        applicationContext = ApplicationContext.run()

        def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
        def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)

        def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
                .usePlaintext()
                .build()

        def channelProvider =
                FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))

        // START creating topic

        def topicAdminClient =
                TopicAdminClient.create(
                        TopicAdminSettings.newBuilder()
                                .setCredentialsProvider(NoCredentialsProvider.create())
                                .setTransportChannelProvider(channelProvider)
                                .build())

        def topic = TopicName.of(
                gcpConfigProperties.getProjectId(),
                pubSubConfigProperties.getTopicName())

        try {
            topicAdminClient.createTopic(topic)
        } catch (AlreadyExistsException) {
            // this is fine, already created
            topicAdminClient.getTopic(topic)
        }

        // START creating subscription

        pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
            def subscription =
                    ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)

            def subscriptionAdminClient =
                    SubscriptionAdminClient.create(
                            SubscriptionAdminSettings.newBuilder()
                                    .setTransportChannelProvider(channelProvider)
                                    .setCredentialsProvider(NoCredentialsProvider.create())
                                    .build())

            try {
                subscriptionAdminClient
                        .createSubscription(
                                subscription,
                                topic,
                                PushConfig.getDefaultInstance(),
                                100)

                System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
            } catch (AlreadyExistsException) {
                // this is fine, already created
                subscriptionAdminClient.getSubscription(subscription)
            }
        })

        channel.shutdown()

        // stop the temporary applicationContext
        applicationContext.stop()

        // start the actual applicationContext
        embeddedServer = ApplicationContext.run(
                EmbeddedServer,
                [
                        'spec.name'           : "PubSubEmulatorSpec",
                        "pubsub.emulator.host": emulatorHost
                ],
                environments)

        applicationContext = embeddedServer.applicationContext
    }
}
package no.myproject.pubsub

import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires

import javax.inject.Singleton


@Factory
@Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {

    @Singleton
    @Replaces(GoogleCredentials)
    GoogleCredentials mockCredentials() {
        return GoogleCredentials.create(new AccessToken("", new Date()))
    }
}
package no.myproject.pubsub

import no.myproject.testframework.PubSubSpecification

import java.util.stream.IntStream

class PubSubIntegrationSpec extends PubSubSpecification {

    def NUMBER_OF_MESSAGES_IN_TEST = 5
    def DELAY_IN_MILLISECONDS_PER_MSG = 100

    def "when a number of messages is sent, same amount of messages is received"() {
        given:
        def documentPublisher = applicationContext.getBean(DocumentPublisher)
        def listener = applicationContext.getBean(IncomingDocListenerWithAck)
        def initialReceiveCount = listener.getReceiveCount()

        when:
        IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
                .forEach(it -> documentPublisher.send("Hello World!"))

        // wait a bit in order to let all messages propagate through the queue
        Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)

        then:
        NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
    }
}
-----------------------
applicationContext = ApplicationContext.run(               
["pubsub.emulator.host": emulatorHost])
package no.myproject.testframework.testcontainers

import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName

class PubSubEmulator {
    static PubSubEmulatorContainer pubSubEmulatorContainer

    static init() {
        if (pubSubEmulatorContainer == null) {
            pubSubEmulatorContainer = new PubSubEmulatorContainer(
                    DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:emulators"))
            pubSubEmulatorContainer.start()
        }
    }
}
package no.myproject.testframework.testcontainers

trait PubSubEmulatorFixture {
    Map<String, Object> getPubSubConfiguration() {
        if (PubSubEmulator.pubSubEmulatorContainer == null || !PubSubEmulator.pubSubEmulatorContainer.isRunning()) {
            PubSubEmulator.init()
        }
        [
                "pubsub.emulator-host": PubSubEmulator.pubSubEmulatorContainer.getEmulatorEndpoint()
        ]
    }
}
package no.myproject.testframework

import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.cloud.pubsub.v1.SubscriptionAdminClient
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings
import com.google.cloud.pubsub.v1.TopicAdminClient
import com.google.cloud.pubsub.v1.TopicAdminSettings
import com.google.pubsub.v1.ProjectSubscriptionName
import com.google.pubsub.v1.PushConfig
import com.google.pubsub.v1.TopicName
import io.grpc.ManagedChannelBuilder
import io.micronaut.context.ApplicationContext
import no.myproject.configuration.GcpConfigProperties
import no.myproject.configuration.PubSubConfigProperties
import no.myproject.testframework.testcontainers.PubSubEmulatorFixture
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

abstract class PubSubSpecification extends Specification
        implements PubSubEmulatorFixture, EnvironmentFixture {

    @AutoCleanup
    @Shared
    EmbeddedServer embeddedServer

    @AutoCleanup
    @Shared
    ApplicationContext applicationContext

    def setupSpec() {

        // start the pubsub emulator
        def emulatorHost = getPubSubConfiguration().get("pubsub.emulator-host")

        // start a temporary applicationContext in order to read config
        // keep any pubsub subscriptions out of context at this stage
        applicationContext = ApplicationContext.run()

        def gcpConfigProperties = applicationContext.getBean(GcpConfigProperties)
        def pubSubConfigProperties = applicationContext.getBean(PubSubConfigProperties)

        def channel = ManagedChannelBuilder.forTarget("dns:///" + emulatorHost)
                .usePlaintext()
                .build()

        def channelProvider =
                FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))

        // START creating topic

        def topicAdminClient =
                TopicAdminClient.create(
                        TopicAdminSettings.newBuilder()
                                .setCredentialsProvider(NoCredentialsProvider.create())
                                .setTransportChannelProvider(channelProvider)
                                .build())

        def topic = TopicName.of(
                gcpConfigProperties.getProjectId(),
                pubSubConfigProperties.getTopicName())

        try {
            topicAdminClient.createTopic(topic)
        } catch (AlreadyExistsException) {
            // this is fine, already created
            topicAdminClient.getTopic(topic)
        }

        // START creating subscription

        pubSubConfigProperties.getSubscriptionNames().forEach(it -> {
            def subscription =
                    ProjectSubscriptionName.of(gcpConfigProperties.getProjectId(), it)

            def subscriptionAdminClient =
                    SubscriptionAdminClient.create(
                            SubscriptionAdminSettings.newBuilder()
                                    .setTransportChannelProvider(channelProvider)
                                    .setCredentialsProvider(NoCredentialsProvider.create())
                                    .build())

            try {
                subscriptionAdminClient
                        .createSubscription(
                                subscription,
                                topic,
                                PushConfig.getDefaultInstance(),
                                100)

                System.out.println("Subscription created " + subscriptionAdminClient.getSubscription(subscription))
            } catch (AlreadyExistsException) {
                // this is fine, already created
                subscriptionAdminClient.getSubscription(subscription)
            }
        })

        channel.shutdown()

        // stop the temporary applicationContext
        applicationContext.stop()

        // start the actual applicationContext
        embeddedServer = ApplicationContext.run(
                EmbeddedServer,
                [
                        'spec.name'           : "PubSubEmulatorSpec",
                        "pubsub.emulator.host": emulatorHost
                ],
                environments)

        applicationContext = embeddedServer.applicationContext
    }
}
package no.myproject.pubsub

import com.google.auth.oauth2.AccessToken
import com.google.auth.oauth2.GoogleCredentials
import io.micronaut.context.annotation.Factory
import io.micronaut.context.annotation.Replaces
import io.micronaut.context.annotation.Requires

import javax.inject.Singleton


@Factory
@Requires(property = 'spec.name', value = 'PubSubEmulatorSpec')
class EmptyCredentialsFactory {

    @Singleton
    @Replaces(GoogleCredentials)
    GoogleCredentials mockCredentials() {
        return GoogleCredentials.create(new AccessToken("", new Date()))
    }
}
package no.myproject.pubsub

import no.myproject.testframework.PubSubSpecification

import java.util.stream.IntStream

class PubSubIntegrationSpec extends PubSubSpecification {

    def NUMBER_OF_MESSAGES_IN_TEST = 5
    def DELAY_IN_MILLISECONDS_PER_MSG = 100

    def "when a number of messages is sent, same amount of messages is received"() {
        given:
        def documentPublisher = applicationContext.getBean(DocumentPublisher)
        def listener = applicationContext.getBean(IncomingDocListenerWithAck)
        def initialReceiveCount = listener.getReceiveCount()

        when:
        IntStream.rangeClosed(1, NUMBER_OF_MESSAGES_IN_TEST)
                .forEach(it -> documentPublisher.send("Hello World!"))

        // wait a bit in order to let all messages propagate through the queue
        Thread.sleep(NUMBER_OF_MESSAGES_IN_TEST * DELAY_IN_MILLISECONDS_PER_MSG)

        then:
        NUMBER_OF_MESSAGES_IN_TEST == listener.getReceiveCount() - initialReceiveCount
    }
}

Community Discussions

Trending Discussions on spock
  • java.lang.RuntimeException: not supported: class org.spockframework.gentyref.CaptureTypeImpl
  • How do I get spock-reports to generate index.html instead of getting 'ClassCastException class [B cannot be cast to class [C'
  • How to tell if Spock is actually executing tests in parallel
  • Testing an SFTP client with Spock Framework
  • &quot;No qualifying bean&quot; for repository in Groovy Spring JPA application
  • MissingPropertyException in Spock test
  • Data from test with @Transactional are persisting between tests
  • How to mock Grails request object method in Spock controller test
  • Upgrade to Spring Boot 2.4 break Spock Spring mocks
  • Verify Spock mock asynchonous interaction after an exception is thrown
Trending Discussions on spock

QUESTION

java.lang.RuntimeException: not supported: class org.spockframework.gentyref.CaptureTypeImpl

Asked 2022-Mar-30 at 13:59

Spock is being used to execute an integration test in a Spring Boot project (2.1.18.RELEASE). When I run with 1.3-groovy-2.5, I get this error:

Caused by: java.lang.RuntimeException: not supported: class org.spockframework.gentyref.CaptureTypeImpl
    at org.spockframework.gentyref.GenericTypeReflector.erase(GenericTypeReflector.java:33)
    at org.spockframework.mock.runtime.StaticMockMethod.getReturnType(StaticMockMethod.java:50)
    at org.spockframework.mock.EmptyOrDummyResponse.respond(EmptyOrDummyResponse.java:68)
    at org.spockframework.mock.runtime.MockController.handle(MockController.java:50)
    at org.spockframework.mock.runtime.JavaMockInterceptor.intercept(JavaMockInterceptor.java:72)
    at org.spockframework.mock.runtime.ByteBuddyInterceptorAdapter.interceptNonAbstract(ByteBuddyInterceptorAdapter.java:35)
    at com.foo.controller.ConversionsController.createConversionJob(ConversionsController.java:68)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    ... 18 more

If I update Spock to a more recent version (eg. 2.1-groovy-2.5) I get this error:

[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: There was an error in the forked process
[ERROR] java.util.ServiceConfigurationError: org.junit.platform.engine.TestEngine: org.spockframework.runtime.SpockEngine Unable to get public no-arg constructor
[ERROR]     at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:733)
[ERROR]     at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:305)
[ERROR]     at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:265)
[ERROR]     at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1314)
[ERROR]     at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:1159)
[ERROR]     at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:932)
[ERROR]     at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
[ERROR]     at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
[ERROR]     at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
[ERROR]     at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
[ERROR]     at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
[ERROR]     at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
[ERROR]     at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
[ERROR]     at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
[ERROR]     at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
[ERROR]     at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
[ERROR]     at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
[ERROR]     at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
[ERROR]     at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
[ERROR]     at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
[ERROR]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[ERROR]     at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR]     at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[ERROR]     at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
[ERROR]     at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
[ERROR]     at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
[ERROR]     at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)

I am using Java 11 and Maven 3.6.3. My pom.xml is rather long, so I've reduced it to some snippets that focus on versions and test dependencies:

        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
                <java.version>11</java.version>
                <bytebuddy.version>1.11.0</bytebuddy.version>
                <cglib.version>3.2.12</cglib.version>
                <gmavenplus.version>1.12.0</gmavenplus.version>
                <groovy.version>2.5.15</groovy.version>
                <objenesis.version>3.2</objenesis.version>
                <spock.version>1.3-groovy-2.5</spock.version>
                <maven.buildhelper.version>3.3.0</maven.buildhelper.version>
                <maven.jacoco.version>0.8.7</maven.jacoco.version>
                <maven.surefire.version>3.0.0-M5</maven.surefire.version>
                <maven.failsafe.version>3.0.0-M5</maven.failsafe.version>
        </properties>

                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                        <scope>test</scope>
                        <exclusions>
                                <exclusion>
                                        <groupId>com.vaadin.external.google</groupId>
                                        <artifactId>android-json</artifactId>
                                </exclusion>
                        </exclusions>
                </dependency>
                <dependency>
                        <groupId>org.spockframework</groupId>
                        <artifactId>spock-core</artifactId>
                        <scope>test</scope>
                </dependency>
                <!-- uncommented for 2.1-groovy-2.5 -->
                <!-- dependency>
                        <groupId>org.spockframework</groupId>
                        <artifactId>spock-junit4</artifactId>
                        <scope>test</scope>
                </dependency -->
                <dependency>
                        <groupId>org.spockframework</groupId>
                        <artifactId>spock-spring</artifactId>
                        <scope>test</scope>
                </dependency>
                <dependency> <!-- enables mocking of classes (in addition to interfaces) -->
                        <groupId>net.bytebuddy</groupId>
                        <artifactId>byte-buddy</artifactId>
                        <version>${bytebuddy.version}</version>
                        <scope>test</scope>
                </dependency>
                <dependency> <!-- enables mocking of classes without default constructor (together with ByteBuddy or CGLIB) -->
                        <groupId>org.objenesis</groupId>
                        <artifactId>objenesis</artifactId>
                        <version>${objenesis.version}</version>
                        <scope>test</scope>
                </dependency>

                       <plugin>
                                <!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin,
                                     visit https://github.com/groovy/GMavenPlus/wiki -->
                                <groupId>org.codehaus.gmavenplus</groupId>
                                <artifactId>gmavenplus-plugin</artifactId>
                                <version>${gmavenplus.version}</version>
                                <executions>
                                        <execution>
                                                <goals>
                                                        <goal>compile</goal>
                                                        <goal>compileTests</goal>
                                                </goals>
                                        </execution>
                                </executions>
                                <configuration>
                                        <targetBytecode>11</targetBytecode>
                                </configuration>
                        </plugin>

Any help with troubleshooting this further is greatly appreciated. I modelled my pom.xml after the examples in the spock framework project:

ANSWER

Answered 2022-Mar-28 at 21:40

Regarding java.util.ServiceConfigurationError: org.junit.platform.engine.TestEngine: org.spockframework.runtime.SpockEngine Unable to get public no-arg constructor

Spring Boot 2.1.18.RELEASE is really old, it manages JUnit 5 to 5.3.2 while Spock 2.x requires >= 5.8. You can try setting <junit-jupiter.version>5.8.1</junit-jupiter.version> if you can't upgrade Spring Boot to a more recent version.

As for the type reflection error, we can't say much since you didn't share any code. Only that com.foo.controller.ConversionsController.createConversionJob(ConversionsController.java:68) probably has some weird generics or is calling something that does.

Source https://stackoverflow.com/questions/71653646

Community Discussions, Code Snippets contain sources that include Stack Exchange Network

Vulnerabilities

No vulnerabilities reported

Install spock

You can download it from GitHub.
You can use spock like any standard Java library. Please include the the jar files in your classpath. You can also use any IDE and you can run and debug the spock component as you would do with any other Java program. Best practice is to use a build tool that supports dependency management such as Maven or Gradle. For Maven installation, please refer maven.apache.org. For Gradle installation, please refer gradle.org .

Support

Spock is supported for Java version 8+. Spock is supported for Groovy versions 2.5 and 3.0. The tests are testing Spock with the specific versions (variants) of Groovy and Java. Default Groovy version is 2.5.

DOWNLOAD this Library from

Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from
over 430 million Knowledge Items
Find more libraries
Reuse Solution Kits and Libraries Curated by Popular Use Cases

Save this library and start creating your kit

Explore Related Topics

Share this Page

share link
Consider Popular Unit Testing Libraries
Compare Unit Testing Libraries with Highest Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from
over 430 million Knowledge Items
Find more libraries
Reuse Solution Kits and Libraries Curated by Popular Use Cases

Save this library and start creating your kit

  • © 2022 Open Weaver Inc.