/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.cli.command.init;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import joptsimple.OptionSet;
import org.apache.http.Header;
import org.apache.http.client.methods.HttpUriRequest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.cli.command.status.ExitStatus;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link InitCommand}
*
* @author Stephane Nicoll
* @author EddĂș MelĂ©ndez
*/
public class InitCommandTests extends AbstractHttpClientMockTests {
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
private final TestableInitCommandOptionHandler handler;
private final InitCommand command;
@Captor
private ArgumentCaptor<HttpUriRequest> requestCaptor;
@Before
public void setupMocks() {
MockitoAnnotations.initMocks(this);
}
public InitCommandTests() {
InitializrService initializrService = new InitializrService(this.http);
this.handler = new TestableInitCommandOptionHandler(initializrService);
this.command = new InitCommand(this.handler);
}
@Test
public void listServiceCapabilitiesText() throws Exception {
mockSuccessfulMetadataTextGet();
this.command.run("--list", "--target=http://fake-service");
}
@Test
public void listServiceCapabilities() throws Exception {
mockSuccessfulMetadataGet(true);
this.command.run("--list", "--target=http://fake-service");
}
@Test
public void listServiceCapabilitiesV2() throws Exception {
mockSuccessfulMetadataGetV2(true);
this.command.run("--list", "--target=http://fake-service");
}
@Test
public void generateProject() throws Exception {
String fileName = UUID.randomUUID().toString() + ".zip";
File file = new File(fileName);
assertThat(file.exists()).as("file should not exist").isFalse();
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", fileName);
mockSuccessfulProjectGeneration(request);
try {
assertThat(this.command.run()).isEqualTo(ExitStatus.OK);
assertThat(file.exists()).as("file should have been created").isTrue();
}
finally {
assertThat(file.delete()).as("failed to delete test file").isTrue();
}
}
@Test
public void generateProjectNoFileNameAvailable() throws Exception {
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", null);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run()).isEqualTo(ExitStatus.ERROR);
}
@Test
public void generateProjectAndExtract() throws Exception {
File folder = this.temporaryFolder.newFolder();
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", "demo.zip", archive);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run("--extract", folder.getAbsolutePath()))
.isEqualTo(ExitStatus.OK);
File archiveFile = new File(folder, "test.txt");
assertThat(archiveFile).exists();
}
@Test
public void generateProjectAndExtractWithConvention() throws Exception {
File folder = this.temporaryFolder.newFolder();
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", "demo.zip", archive);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run(folder.getAbsolutePath() + "/"))
.isEqualTo(ExitStatus.OK);
File archiveFile = new File(folder, "test.txt");
assertThat(archiveFile).exists();
}
@Test
public void generateProjectArchiveExtractedByDefault() throws Exception {
String fileName = UUID.randomUUID().toString();
assertThat(fileName.contains(".")).as("No dot in filename").isFalse();
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", "demo.zip", archive);
mockSuccessfulProjectGeneration(request);
File file = new File(fileName);
File archiveFile = new File(file, "test.txt");
try {
assertThat(this.command.run(fileName)).isEqualTo(ExitStatus.OK);
assertThat(archiveFile).exists();
}
finally {
archiveFile.delete();
file.delete();
}
}
@Test
public void generateProjectFileSavedAsFileByDefault() throws Exception {
String fileName = UUID.randomUUID().toString();
String content = "Fake Content";
byte[] archive = content.getBytes();
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/octet-stream", "pom.xml", archive);
mockSuccessfulProjectGeneration(request);
File file = new File(fileName);
try {
assertThat(this.command.run(fileName)).isEqualTo(ExitStatus.OK);
assertThat(file.exists()).as("File not saved properly").isTrue();
assertThat(file.isFile()).as("Should not be a directory").isTrue();
}
finally {
file.delete();
}
}
@Test
public void generateProjectAndExtractUnsupportedArchive() throws Exception {
File folder = this.temporaryFolder.newFolder();
String fileName = UUID.randomUUID().toString() + ".zip";
File file = new File(fileName);
assertThat(file.exists()).as("file should not exist").isFalse();
try {
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/foobar", fileName, archive);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run("--extract", folder.getAbsolutePath()))
.isEqualTo(ExitStatus.OK);
assertThat(file.exists()).as("file should have been saved instead").isTrue();
}
finally {
assertThat(file.delete()).as("failed to delete test file").isTrue();
}
}
@Test
public void generateProjectAndExtractUnknownContentType() throws Exception {
File folder = this.temporaryFolder.newFolder();
String fileName = UUID.randomUUID().toString() + ".zip";
File file = new File(fileName);
assertThat(file.exists()).as("file should not exist").isFalse();
try {
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
null, fileName, archive);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run("--extract", folder.getAbsolutePath()))
.isEqualTo(ExitStatus.OK);
assertThat(file.exists()).as("file should have been saved instead").isTrue();
}
finally {
assertThat(file.delete()).as("failed to delete test file").isTrue();
}
}
@Test
public void fileNotOverwrittenByDefault() throws Exception {
File file = this.temporaryFolder.newFile();
long fileLength = file.length();
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", file.getAbsolutePath());
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run()).as("Should have failed")
.isEqualTo(ExitStatus.ERROR);
assertThat(file.length()).as("File should not have changed")
.isEqualTo(fileLength);
}
@Test
public void overwriteFile() throws Exception {
File file = this.temporaryFolder.newFile();
long fileLength = file.length();
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", file.getAbsolutePath());
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run("--force")).isEqualTo(ExitStatus.OK);
assertThat(fileLength != file.length()).as("File should have changed").isTrue();
}
@Test
public void fileInArchiveNotOverwrittenByDefault() throws Exception {
File folder = this.temporaryFolder.newFolder();
File conflict = new File(folder, "test.txt");
assertThat(conflict.createNewFile()).as("Should have been able to create file")
.isTrue();
long fileLength = conflict.length();
// also contains test.txt
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", "demo.zip", archive);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run("--extract", folder.getAbsolutePath()))
.isEqualTo(ExitStatus.ERROR);
assertThat(conflict.length()).as("File should not have changed")
.isEqualTo(fileLength);
}
@Test
public void parseProjectOptions() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("-g=org.demo", "-a=acme", "-v=1.2.3-SNAPSHOT", "-n=acme-sample",
"--description=Acme sample project", "--package-name=demo.foo",
"-t=ant-project", "--build=grunt", "--format=web", "-p=war", "-j=1.9",
"-l=groovy", "-b=1.2.0.RELEASE", "-d=web,data-jpa");
assertThat(this.handler.lastRequest.getGroupId()).isEqualTo("org.demo");
assertThat(this.handler.lastRequest.getArtifactId()).isEqualTo("acme");
assertThat(this.handler.lastRequest.getVersion()).isEqualTo("1.2.3-SNAPSHOT");
assertThat(this.handler.lastRequest.getName()).isEqualTo("acme-sample");
assertThat(this.handler.lastRequest.getDescription())
.isEqualTo("Acme sample project");
assertThat(this.handler.lastRequest.getPackageName()).isEqualTo("demo.foo");
assertThat(this.handler.lastRequest.getType()).isEqualTo("ant-project");
assertThat(this.handler.lastRequest.getBuild()).isEqualTo("grunt");
assertThat(this.handler.lastRequest.getFormat()).isEqualTo("web");
assertThat(this.handler.lastRequest.getPackaging()).isEqualTo("war");
assertThat(this.handler.lastRequest.getJavaVersion()).isEqualTo("1.9");
assertThat(this.handler.lastRequest.getLanguage()).isEqualTo("groovy");
assertThat(this.handler.lastRequest.getBootVersion()).isEqualTo("1.2.0.RELEASE");
List<String> dependencies = this.handler.lastRequest.getDependencies();
assertThat(dependencies).hasSize(2);
assertThat(dependencies.contains("web")).isTrue();
assertThat(dependencies.contains("data-jpa")).isTrue();
}
@Test
public void overwriteFileInArchive() throws Exception {
File folder = this.temporaryFolder.newFolder();
File conflict = new File(folder, "test.txt");
assertThat(conflict.createNewFile()).as("Should have been able to create file")
.isTrue();
long fileLength = conflict.length();
// also contains test.txt
byte[] archive = createFakeZipArchive("test.txt", "Fake content");
MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(
"application/zip", "demo.zip", archive);
mockSuccessfulProjectGeneration(request);
assertThat(this.command.run("--force", "--extract", folder.getAbsolutePath()))
.isEqualTo(ExitStatus.OK);
assertThat(fileLength != conflict.length()).as("File should have changed")
.isTrue();
}
@Test
public void parseTypeOnly() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("-t=ant-project");
assertThat(this.handler.lastRequest.getBuild()).isEqualTo("maven");
assertThat(this.handler.lastRequest.getFormat()).isEqualTo("project");
assertThat(this.handler.lastRequest.isDetectType()).isFalse();
assertThat(this.handler.lastRequest.getType()).isEqualTo("ant-project");
}
@Test
public void parseBuildOnly() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("--build=ant");
assertThat(this.handler.lastRequest.getBuild()).isEqualTo("ant");
assertThat(this.handler.lastRequest.getFormat()).isEqualTo("project");
assertThat(this.handler.lastRequest.isDetectType()).isTrue();
assertThat(this.handler.lastRequest.getType()).isNull();
}
@Test
public void parseFormatOnly() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("--format=web");
assertThat(this.handler.lastRequest.getBuild()).isEqualTo("maven");
assertThat(this.handler.lastRequest.getFormat()).isEqualTo("web");
assertThat(this.handler.lastRequest.isDetectType()).isTrue();
assertThat(this.handler.lastRequest.getType()).isNull();
}
@Test
public void parseLocation() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("foobar.zip");
assertThat(this.handler.lastRequest.getOutput()).isEqualTo("foobar.zip");
}
@Test
public void parseLocationWithSlash() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("foobar/");
assertThat(this.handler.lastRequest.getOutput()).isEqualTo("foobar");
assertThat(this.handler.lastRequest.isExtract()).isTrue();
}
@Test
public void parseMoreThanOneArg() throws Exception {
this.handler.disableProjectGeneration();
assertThat(this.command.run("foobar", "barfoo")).isEqualTo(ExitStatus.ERROR);
}
@Test
public void userAgent() throws Exception {
this.command.run("--list", "--target=http://fake-service");
verify(this.http).execute(this.requestCaptor.capture());
Header agent = this.requestCaptor.getValue().getHeaders("User-Agent")[0];
assertThat(agent.getValue()).startsWith("SpringBootCli/");
}
private byte[] createFakeZipArchive(String fileName, String content)
throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(bos);
try {
ZipEntry entry = new ZipEntry(fileName);
zos.putNextEntry(entry);
zos.write(content.getBytes());
zos.closeEntry();
}
finally {
bos.close();
}
return bos.toByteArray();
}
private static class TestableInitCommandOptionHandler
extends InitCommand.InitOptionHandler {
private boolean disableProjectGeneration;
private ProjectGenerationRequest lastRequest;
TestableInitCommandOptionHandler(InitializrService initializrService) {
super(initializrService);
}
void disableProjectGeneration() {
this.disableProjectGeneration = true;
}
@Override
protected void generateProject(OptionSet options) throws IOException {
this.lastRequest = createProjectGenerationRequest(options);
if (!this.disableProjectGeneration) {
super.generateProject(options);
}
}
}
}