Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract classes and start writing more tests (WIP) #13

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions src/main/java/com/cqse/teamscaleupload/InputManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.cqse.teamscaleupload;

import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;
import okhttp3.HttpUrl;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;

/**
* Manages (i.e. parses and holds) the command line argument for this application.
*/
class InputManager {
public final String project;
public final String username;
public final String accessKey;
public final String partition;
public final String format;
public final String commit;
public final boolean autoDetectedCommit;
public final String timestamp;
public final HttpUrl url;
public final List<String> files;
public final Path input;
public final Boolean validateSsl;

private InputManager(Namespace namespace) {
this.project = namespace.getString("project");
this.username = namespace.getString("user");
this.accessKey = namespace.getString("accesskey");
this.partition = namespace.getString("partition");
this.commit = namespace.getString("commit");
this.autoDetectedCommit = namespace.getBoolean("detect_commit");
this.timestamp = namespace.getString("branch_and_timestamp");
this.files = namespace.getList("files");
this.url = HttpUrl.parse(namespace.getString("server"));
this.validateSsl = namespace.getBoolean("validate_ssl");

String inputFilePath = namespace.getString("input");
if (inputFilePath != null) {
this.input = Paths.get(inputFilePath);
} else {
this.input = null;
}

String formatRaw = namespace.getString("format");
if (formatRaw != null) {
this.format = formatRaw.toUpperCase();
} else {
this.format = null;
}
}
public static InputManager parseArguments(String[] args) {
ArgumentParser parser = ArgumentParsers.newFor("teamscale-upload").build()
.defaultHelp(true)
.description("Upload coverage, findings, ... to Teamscale.");

parser.addArgument("-s", "--server").type(String.class).metavar("URL").required(true)
.help("The url under which the Teamscale server can be reached.");
parser.addArgument("-p", "--project").type(String.class).metavar("PROJECT").required(true)
.help("The project ID or alias (NOT the project name!) to which to upload the data.");
parser.addArgument("-u", "--user").type(String.class).metavar("USER").required(true)
.help("The username used to perform the upload. Must have the 'Perform External Uploads' permission for the given Teamscale project.");
parser.addArgument("-a", "--accesskey").type(String.class).metavar("ACCESSKEY").required(true)
.help("The IDE access key of the given user. Can be retrieved in Teamscale under Admin > Users.");
parser.addArgument("-t", "--partition").type(String.class).metavar("PARTITION").required(true)
.help("The partition into which the data is inserted in Teamscale." +
" Successive uploads into the same partition will overwrite the data" +
" previously inserted there, so use different partitions if you'd instead" +
" like to merge data from different sources (e.g. one for Findbugs findings" +
" and one for JaCoCo coverage).");
parser.addArgument("-f", "--format").type(String.class).metavar("FORMAT").required(false)
.help("The default file format of the uploaded report files. This is applied for all files given as" +
" command line arguments or via -i/--input where no format is specified." +
" See https://docs.teamscale.com/reference/upload-formats-and-samples/#supported-formats-for-upload" +
" for a full list of supported file formats.");
parser.addArgument("-c", "--commit").type(String.class).metavar("REVISION").required(false)
.help("The version control commit for which you obtained the report files." +
" E.g. if you obtained a test coverage report in your CI pipeline, then this" +
" is the commit the CI pipeline built before running the tests." +
" Can be either a Git SHA1, a SVN revision number or an Team Foundation changeset ID.");
parser.addArgument("-b", "--branch-and-timestamp").type(String.class).metavar("BRANCH_AND_TIMESTAMP").required(false)
.help("The branch and Unix Epoch timestamp for which you obtained the report files." +
" E.g. if you obtained a test coverage report in your CI pipeline, then this" +
" is the branch and the commit timestamp of the commit that the CI pipeline built before running the tests." +
" The timestamp must be milliseconds since 00:00:00 UTC Thursday, 1 January 1970." +
"\nFormat: BRANCH:TIMESTAMP" +
"\nExample: master:1597845930000");
parser.addArgument("-i", "--input").type(String.class).metavar("INPUT").required(false)
.help("A file which contains additional report file patterns. See INPUTFILE for a detailed description of the file format.\n");
parser.addArgument("--detect-commit").action(Arguments.storeTrue()).required(false)
.help("Tries to automatically detect the code commit to which to upload from environment variables or" +
" a Git or SVN checkout in the current working directory. If guessing fails, the upload will fail." +
" This feature supports many common CI tools like Jenkins, GitLab, GitHub Actions, Travis CI etc.");
parser.addArgument("--validate-ssl").action(Arguments.storeTrue()).required(false)
.help("By default, SSL certificates are accepted without validation, which makes using this tool with self-signed" +
" certificates easier. This flag enables validation.");
parser.addArgument("files").metavar("FILES").type(String.class).nargs("*").
help("Path(s) or pattern(s) of the report files to upload. Alternatively, you may provide input files via -i or --input");

parser.epilog("INPUTFILE" +
"\n" +
"\n" +
"The file you provide via --input consists of file patterns in the same format as used on the command line" +
" and optionally sections that specify additional report file formats." +
" The entries in the file are separated by line breaks. Uses the format specified with --format," +
" unless you overwrite the format explicitly for a set of patterns:\n\n" +
"pattern1/**.simple\n" +
"[jacoco]\n" +
"pattern1/**.xml\n" +
"pattern2/**.xml\n" +
"[findbugs]\n" +
"pattern1/**.findbugs.xml\n" +
"pattern2/**.findbugs.xml");

try {
Namespace namespace = parser.parseArgs(args);
InputManager inputManager = new InputManager(namespace);
inputManager.validate(parser);
return inputManager;
} catch (ArgumentParserException e) {
parser.handleError(e);
System.exit(1);
return null;
}
}

private void validate(ArgumentParser parser) throws ArgumentParserException {
if (url == null) {
throw new ArgumentParserException("You provided an invalid URL in the --server option", parser);
}

if (hasMoreThanOneCommitOptionSet()) {
throw new ArgumentParserException("You used more than one of --detect-commit, --commit and --timestamp." +
" You must choose one of these three options to specify the commit for which you would like to" +
" upload data to Teamscale", parser);
}

if (files.isEmpty() && input == null) {
throw new ArgumentParserException("No report files provided." +
" You must either specify the paths of the coverage files as command line" +
" arguments or provide them in an input file via --input", parser);
}

if (format == null) {
throw new ArgumentParserException("Please provide the default report format with --format", parser);
}
}

private boolean hasMoreThanOneCommitOptionSet() {
if (commit != null && timestamp != null) {
return true;
}
if (commit != null && autoDetectedCommit) {
return true;
}
return timestamp != null && autoDetectedCommit;
}
}
27 changes: 27 additions & 0 deletions src/test/java/com/cqse/teamscaleupload/InputManagerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.cqse.teamscaleupload;

import okhttp3.HttpUrl;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;

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

public class InputManagerTest {

/**
* TODO
*/
@Test
public void testArgumentParsing() {
InputManager inputManager = InputManager.parseArguments(new TestArgumentHolder().toStringArray());

assertThat(inputManager).hasFieldOrPropertyWithValue("project", TestConstants.project);
assertThat(inputManager).hasFieldOrPropertyWithValue("url", HttpUrl.parse(TestConstants.url));
assertThat(inputManager).hasFieldOrPropertyWithValue("username", TestConstants.user);
assertThat(inputManager).hasFieldOrPropertyWithValue("accessKey", TestConstants.accessKey);
assertThat(inputManager).hasFieldOrPropertyWithValue("format", TestConstants.format.toUpperCase());
assertThat(inputManager).hasFieldOrPropertyWithValue("partition", TestConstants.partition);
assertThat(inputManager).hasFieldOrPropertyWithValue("pattern", TestConstants.pattern);
}
}
11 changes: 11 additions & 0 deletions src/test/java/com/cqse/teamscaleupload/TeamscaleUploadTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.cqse.teamscaleupload;

import org.junit.jupiter.api.Test;

public class TeamscaleUploadTest {

@Test
public void test() {

}
}
69 changes: 69 additions & 0 deletions src/test/java/com/cqse/teamscaleupload/TestArgumentHolder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.cqse.teamscaleupload;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* TODO
*/
class TestArgumentHolder {
private String url = TestConstants.url;
private String user = TestConstants.user;
private String accessKey = getAccessKeyFromCi();
private String project = TestConstants.project;
private final String format = TestConstants.format;
private final String partition = TestConstants.partition;
private String pattern = TestConstants.pattern;
private String input = null;

public TestArgumentHolder withPattern(String pattern) {
this.pattern = pattern;
return this;
}

public TestArgumentHolder withUrl(String url) {
this.url = url;
return this;
}

public TestArgumentHolder withAccessKey(String accessKey) {
this.accessKey = accessKey;
return this;
}

public TestArgumentHolder withUser(String user) {
this.user = user;
return this;
}

public TestArgumentHolder withProject(String project) {
this.project = project;
return this;
}

public TestArgumentHolder withInput(String input) {
this.input = input;
return this;
}

public String[] toStringArray() {
List<String> arguments = new ArrayList<>(Arrays.asList("-s", url, "-u", user, "-a", accessKey, "-f", format,
"-p", project, "-t", partition));
if (input != null) {
arguments.add("-i");
arguments.add(input);
}
arguments.add(pattern);

return arguments.toArray(new String[arguments.size()]);
}

private static String getAccessKeyFromCi() {
String accessKey = System.getenv("ACCESS_KEY");
if (accessKey == null) {
return TestConstants.accessKey;
}
return accessKey;
}
}
13 changes: 13 additions & 0 deletions src/test/java/com/cqse/teamscaleupload/TestConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.cqse.teamscaleupload;

/** TODO */
public class TestConstants {
public static final String project = "teamscale-upload";
public static final String url = "https://demo.teamscale.com";
public static final String user = "build";
public static final String accessKey = "not-a-ci-build";
public static final String format = "simple";
public static final String partition = "NativeImageIT";
public static final String pattern = "**.simple";
public static final String input = "coverage_files/input_file";
}