Skip to content

Commit

Permalink
fixes asciidoctor#973 Add SpringBoot integration test to showcase cp …
Browse files Browse the repository at this point in the history
…configuration
  • Loading branch information
abelsromero committed Feb 13, 2021
1 parent 0ec51e7 commit 044c1c8
Show file tree
Hide file tree
Showing 15 changed files with 389 additions and 3 deletions.
13 changes: 13 additions & 0 deletions asciidoctorj-springboot-integration-test/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
jar.enabled = false

dependencies {
testCompileOnly project(':asciidoctorj')
testCompile "junit:junit:$junitVersion"
testCompile "org.assertj:assertj-core:$assertjVersion"
testCompile "commons-io:commons-io:$commonsioVersion"
testCompile "org.awaitility:awaitility:4.0.3"
testCompile "com.squareup.okhttp3:okhttp:4.9.1"
testCompile "com.google.code.gson:gson:2.8.6"
}

test.dependsOn(':asciidoctorj-springboot-integration-test:springboot-app:assemble')
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}

group = 'org.asciidoctor.it'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
mavenCentral()
}

ext {
asciidoctorjVersion = '2.4.2'
}

dependencies {
implementation project(':asciidoctorj')
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

bootJar {
requiresUnpack '**/jruby-complete-*.jar'
requiresUnpack '**/asciidoctorj-*.jar'
}

test {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'springboot-app'
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.asciidoctor.it.springboot;

import org.asciidoctor.Asciidoctor;
import org.asciidoctor.OptionsBuilder;
import org.asciidoctor.SafeMode;
import org.springframework.stereotype.Component;

@Component
public class AsciidoctorService {

private final Asciidoctor asciidoctor = Asciidoctor.Factory.create();


public String convert(String source) {
return asciidoctor.convert(source, defaultOptions());
}

private OptionsBuilder defaultOptions() {
return OptionsBuilder.options()
.backend("html5")
.safe(SafeMode.SAFE)
.headerFooter(true)
.toFile(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.asciidoctor.it.springboot;

import java.beans.ConstructorProperties;

public class ConvertedResource {

private final String content;
private final String contentType;

@ConstructorProperties({"content", "contentType"})
public ConvertedResource(String content, String contentType) {
this.content = content;
this.contentType = contentType;
}

public String getContent() {
return content;
}

public String getContentType() {
return contentType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.asciidoctor.it.springboot;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.util.Base64;


/**
* Simple Spring MVC Rest Controller to convert AsciiDoc sources to HTML.
*/
@RestController
public class ConverterController {

private final AsciidoctorService asciidoctorService;

public ConverterController(AsciidoctorService asciidoctorService) {
this.asciidoctorService = asciidoctorService;
}


@PostMapping("/asciidoc")
public ConvertedResource convert(@RequestBody SourceContent content) {
byte[] decodedContent = Base64.getDecoder().decode(content.getData());
String converted = asciidoctorService.convert(new String(decodedContent));

String encodedConvertedContent = Base64.getEncoder().encodeToString(converted.getBytes(StandardCharsets.UTF_8));
return new ConvertedResource(encodedConvertedContent, MediaType.TEXT_HTML_VALUE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.asciidoctor.it.springboot;

public class SourceContent {

/**
* Base64 encoded
*/
private String data;


public void setData(String data) {
this.data = data;
}

public String getData() {
return data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.asciidoctor.it.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* This is a test application for testing purposes.
* It does not in any represent the recommended way to implement an
* Asciidoctorj conversion service with SpringBoot.
*/
@SpringBootApplication
public class SpringbootAppApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootAppApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
spring.main.banner-mode=off
management.endpoint.health.probes.enabled=true
info.app.java.source=${java.version}
info.app.java.target=${java.version}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.asciidoctor.it.springboot;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SpringbootAppApplicationTests {

@Autowired
private TestRestTemplate restTemplate;

@Test
void should_convert_document() {

final SourceContent request = new SourceContent();
String asciidocDocument = "= Title\n" +
"\n" +
"== First chapter\n" +
"first chapter\n" +
"\n" +
"== Second chapter\n" +
"second chapter";
request.setData(base64Encode(asciidocDocument));

ResponseEntity<ConvertedResource> responseEntity = restTemplate.postForEntity("/asciidoc", request, ConvertedResource.class);

assertThat(responseEntity.getStatusCodeValue())
.isEqualTo(HttpStatus.OK.value());
final ConvertedResource response = responseEntity.getBody();
assertThat(response.getContentType())
.isEqualTo(MediaType.TEXT_HTML_VALUE);

assertThat(base64Decode(response))
.contains("<h1>Title</h1>")
.contains("<p>first chapter</p>")
.contains("<h2 id=\"_second_chapter\">Second chapter</h2>");
}

private String base64Encode(String asciidocDocument) {
return new String(Base64.getEncoder().encode(asciidocDocument.getBytes(StandardCharsets.UTF_8)));
}

private String base64Decode(ConvertedResource response) {
return new String(Base64.getDecoder().decode(response.getContent()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.asciidoctor.it.springboot;

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ProcessHelper {

static ProcessOutput run(Map<String, String> env, String... command) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(command)
.directory(new File("springboot-app"));

processBuilder.environment().clear();
String javaHome = System.getProperty("java.home");
processBuilder.environment().put("JAVA_HOME", javaHome);
processBuilder.environment().put("PATH", javaHome + "/bin");
processBuilder.environment().putAll(env);

Process process = processBuilder.start();

final InputStream is = process.getInputStream();
final InputStream es = process.getErrorStream();
boolean status = process.waitFor(10l, TimeUnit.SECONDS);
if (!status) {
byte[] buffer = new byte[1800];
IOUtils.read(is, buffer);
return new ProcessOutput(process, new String(buffer), new String());
}

return new ProcessOutput(IOUtils.toString(es), IOUtils.toString(is));
}


static class ProcessOutput {
final Process process;
final String out, err;

public ProcessOutput(String sto, String err) {
this(null, sto, err);
}

public ProcessOutput(Process process, String sto, String err) {
this.process = process;
this.out = sto;
this.err = err;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.asciidoctor.it.springboot;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import kotlin.collections.ArrayDeque;
import okhttp3.*;
import org.awaitility.Awaitility;
import org.junit.After;
import org.junit.Test;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.asciidoctor.it.springboot.ProcessHelper.run;
import static org.assertj.core.api.Assertions.assertThat;

public class SpringBootTest {

final List<Process> testProcesses = new ArrayDeque<>();


@Test
public void should_start_SpringBoot_service_with_requiresUnpack() throws IOException, InterruptedException {

int serverPort = 8000 + ThreadLocalRandom.current().nextInt(1000);
startSpringBootApp(serverPort);

String asciidocDocument = "= Title\n" +
"\n" +
"== First chapter\n" +
"first chapter\n" +
"\n" +
"== Second chapter\n" +
"second chapter";
Map<String, String> jsonResponse = convertDocument(asciidocDocument, serverPort);

assertThat(jsonResponse.get("contentType"))
.isEqualTo("text/html");
assertThat(base64Decode(jsonResponse.get("content")))
.contains("<h1>Title</h1>")
.contains("<p>first chapter</p>")
.contains("<h2 id=\"_second_chapter\">Second chapter</h2>");
}

@After
public void cleanup() {
testProcesses.forEach(Process::destroy);
}

private Map<String, String> convertDocument(String asciidocDocument, int serverPort) throws IOException {
String body = "{\"data\":\"" + base64Encode(asciidocDocument) + "\"}";

Request request = new Request.Builder()
.url("http://localhost:" + serverPort + "/asciidoc")
.post(RequestBody.create(body, MediaType.parse("application/json")))
.build();
Response response = new OkHttpClient()
.newCall(request)
.execute();

return new Gson()
.fromJson(response.body().string(), new TypeToken<Map<String, String>>() {}.getType());
}

private String base64Encode(String asciidocDocument) {
return new String(Base64.getEncoder().encode(asciidocDocument.getBytes(StandardCharsets.UTF_8)));
}

private String base64Decode(String value) {
return new String(Base64.getDecoder().decode(value));
}

private void startSpringBootApp(int serverPort) throws IOException, InterruptedException {

ProcessHelper.ProcessOutput run = run(singletonMap("SERVER_PORT", String.valueOf(serverPort)),
"java", "-jar", "build/libs/springboot-app-0.0.1-SNAPSHOT.jar");

testProcesses.add(run.process);

Awaitility.await()
.atMost(30, TimeUnit.SECONDS)
.pollInterval(3, TimeUnit.SECONDS)
.until(() -> {
Request request = new Request.Builder()
.url("http://localhost:" + serverPort + "/actuator/health/readiness")
.build();
Response response = new OkHttpClient()
.newCall(request)
.execute();
return response.isSuccessful() && response.body().string().contains("UP");
});
}
}
Loading

0 comments on commit 044c1c8

Please sign in to comment.