Add header-passthrough option to hapi-fhir-cli commands which generate http requests.
Add class to parent request-generating commands. Allow ValidationResult to be set number of detected errors to inform.
This commit is contained in:
parent
d762a07817
commit
5f36fe56b0
|
@ -39,18 +39,22 @@ import ca.uhn.fhir.util.OperationOutcomeUtil;
|
|||
* @since 0.7
|
||||
*/
|
||||
public class ValidationResult {
|
||||
public static final int ERROR_DISPLAY_LIMIT_DEFAULT = 1;
|
||||
|
||||
private final FhirContext myCtx;
|
||||
private final boolean myIsSuccessful;
|
||||
private final List<SingleValidationMessage> myMessages;
|
||||
|
||||
private int myErrorDisplayLimit = ERROR_DISPLAY_LIMIT_DEFAULT;
|
||||
|
||||
public ValidationResult(FhirContext theCtx, List<SingleValidationMessage> theMessages) {
|
||||
boolean successful = true;
|
||||
myCtx = theCtx;
|
||||
myMessages = theMessages;
|
||||
for (SingleValidationMessage next : myMessages) {
|
||||
next.getSeverity();
|
||||
if (next.getSeverity() == null || next.getSeverity().ordinal() > ResultSeverityEnum.WARNING.ordinal()) {
|
||||
successful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
myIsSuccessful = successful;
|
||||
|
@ -72,22 +76,36 @@ public class ValidationResult {
|
|||
return myIsSuccessful;
|
||||
}
|
||||
|
||||
|
||||
private String toDescription() {
|
||||
StringBuilder b = new StringBuilder(100);
|
||||
if (myMessages.size() > 0) {
|
||||
if (myMessages.get(0).getSeverity() != null) {
|
||||
b.append(myMessages.get(0).getSeverity().name());
|
||||
if (myMessages.isEmpty()) {
|
||||
return "No issues";
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder(100 * myMessages.size());
|
||||
int shownMsgQty = Math.min(myErrorDisplayLimit, myMessages.size());
|
||||
for (int i = 0; i < shownMsgQty; i++) {
|
||||
SingleValidationMessage nextMsg = myMessages.get(i);
|
||||
b.append(ourNewLine);
|
||||
if (i == 0) {
|
||||
if (shownMsgQty < myMessages.size()) {
|
||||
b.append("(showing first ").append(shownMsgQty).append(" messages out of ")
|
||||
.append(myMessages.size()).append(" total)").append(ourNewLine);
|
||||
}
|
||||
}
|
||||
if (nextMsg.getSeverity() != null) {
|
||||
b.append(nextMsg.getSeverity().name());
|
||||
b.append(" - ");
|
||||
}
|
||||
b.append(myMessages.get(0).getMessage());
|
||||
b.append(nextMsg.getMessage());
|
||||
b.append(" - ");
|
||||
b.append(myMessages.get(0).getLocationString());
|
||||
} else {
|
||||
b.append("No issues");
|
||||
b.append(nextMsg.getLocationString());
|
||||
}
|
||||
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #toOperationOutcome()} instead since this method returns a view.
|
||||
* {@link #toOperationOutcome()} is identical to this method, but has a more suitable name so this method
|
||||
|
@ -156,4 +174,11 @@ public class ValidationResult {
|
|||
public FhirContext getContext() {
|
||||
return myCtx;
|
||||
}
|
||||
|
||||
public int getErrorDisplayLimit() { return myErrorDisplayLimit; }
|
||||
|
||||
public void setErrorDisplayLimit(int theErrorDisplayLimit) { myErrorDisplayLimit = theErrorDisplayLimit; }
|
||||
|
||||
|
||||
private static final String ourNewLine = System.getProperty("line.separator");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package ca.uhn.fhir.validation;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
class ValidationResultTest {
|
||||
|
||||
private final @Mock FhirContext myFhirContext = mock(FhirContext.class);
|
||||
|
||||
@Test
|
||||
void testLessThanDefaultDisplayQty() {
|
||||
List<SingleValidationMessage> validationMessages = getTestValidationErrors(2);
|
||||
ValidationResult vr = new ValidationResult(myFhirContext, validationMessages);
|
||||
String toStringValue = vr.toString();
|
||||
assertTrue(toStringValue.contains("Error message #" + 1));
|
||||
assertFalse(toStringValue.contains("Error message #" + 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMoreThanDefaultDisplayQty() {
|
||||
List<SingleValidationMessage> validationMessages =
|
||||
getTestValidationErrors(ValidationResult.ERROR_DISPLAY_LIMIT_DEFAULT * 2);
|
||||
ValidationResult vr = new ValidationResult(myFhirContext, validationMessages);
|
||||
String toStringValue = vr.toString();
|
||||
assertTrue(toStringValue.contains("Error message #" + ValidationResult.ERROR_DISPLAY_LIMIT_DEFAULT));
|
||||
assertFalse(toStringValue.contains("Error message #" + (ValidationResult.ERROR_DISPLAY_LIMIT_DEFAULT + 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDisplayLimitSet() {
|
||||
List<SingleValidationMessage> validationMessages = getTestValidationErrors(10);
|
||||
ValidationResult vr = new ValidationResult(myFhirContext, validationMessages);
|
||||
vr.setErrorDisplayLimit(8);
|
||||
String toStringValue = vr.toString();
|
||||
assertTrue(toStringValue.contains("Error message #" + 8));
|
||||
assertFalse(toStringValue.contains("Error message #" + 9));
|
||||
}
|
||||
|
||||
private List<SingleValidationMessage> getTestValidationErrors(int theSize) {
|
||||
List<SingleValidationMessage> msgList = new ArrayList<>();
|
||||
for (int i = 0; i < theSize; i++) {
|
||||
SingleValidationMessage validationMsg = new SingleValidationMessage();
|
||||
validationMsg.setLocationCol(i);
|
||||
validationMsg.setLocationLine(1);
|
||||
validationMsg.setLocationString("Error #" + (i+1));
|
||||
validationMsg.setMessage("Error message #" + (i+1));
|
||||
validationMsg.setSeverity(ResultSeverityEnum.ERROR);
|
||||
msgList.add(validationMsg);
|
||||
}
|
||||
return msgList;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
|
@ -40,12 +41,13 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
public abstract class AbstractImportExportCsvConceptMapCommand extends BaseCommand {
|
||||
public abstract class AbstractImportExportCsvConceptMapCommand extends BaseRequestGeneratingCommand {
|
||||
// TODO: Don't use qualified names for loggers in HAPI CLI.
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AbstractImportExportCsvConceptMapCommand.class);
|
||||
|
||||
|
@ -63,14 +65,11 @@ public abstract class AbstractImportExportCsvConceptMapCommand extends BaseComma
|
|||
protected FhirVersionEnum fhirVersion;
|
||||
protected String file;
|
||||
|
||||
|
||||
@Override
|
||||
protected void addFhirVersionOption(Options theOptions) {
|
||||
String versions = Arrays.stream(FhirVersionEnum.values())
|
||||
.filter(t -> t != FhirVersionEnum.DSTU2_1 && t != FhirVersionEnum.DSTU2_HL7ORG && t != FhirVersionEnum.DSTU2)
|
||||
.map(t -> t.name().toLowerCase())
|
||||
.sorted()
|
||||
.collect(Collectors.joining(", "));
|
||||
addRequiredOption(theOptions, FHIR_VERSION_PARAM, FHIR_VERSION_PARAM_LONGOPT, FHIR_VERSION_PARAM_NAME, FHIR_VERSION_PARAM_DESC + versions);
|
||||
protected Collection<Object> getFilterOutVersions() {
|
||||
return Sets.newHashSet(FhirVersionEnum.DSTU2_1,
|
||||
FhirVersionEnum.DSTU2_HL7ORG, FhirVersionEnum.DSTU2);
|
||||
}
|
||||
|
||||
protected BufferedReader getBufferedReader() throws IOException {
|
||||
|
@ -139,7 +138,7 @@ public abstract class AbstractImportExportCsvConceptMapCommand extends BaseComma
|
|||
process();
|
||||
}
|
||||
|
||||
protected void parseAdditionalParameters(CommandLine theCommandLine) throws ParseException {}
|
||||
protected void parseAdditionalParameters(CommandLine theCommandLine) {}
|
||||
|
||||
protected abstract void process() throws ParseException, ExecutionException;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
@ -216,43 +217,14 @@ public abstract class BaseApp {
|
|||
}
|
||||
|
||||
if (theArgs[0].equals("help")) {
|
||||
if (theArgs.length < 2) {
|
||||
logUsage();
|
||||
return;
|
||||
}
|
||||
BaseCommand command = null;
|
||||
for (BaseCommand nextCommand : ourCommands) {
|
||||
if (nextCommand.getCommandName().equals(theArgs[1])) {
|
||||
command = nextCommand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (command == null) {
|
||||
String message = "Unknown command: " + theArgs[1];
|
||||
System.err.println(message);
|
||||
exitDueToProblem(message);
|
||||
return;
|
||||
}
|
||||
logCommandUsage(command);
|
||||
processHelp(theArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
BaseCommand command = null;
|
||||
for (BaseCommand nextCommand : ourCommands) {
|
||||
if (nextCommand.getCommandName().equals(theArgs[0])) {
|
||||
command = nextCommand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Optional<BaseCommand> commandOpt = parseCommand(theArgs);
|
||||
if (! commandOpt.isPresent()) return;
|
||||
|
||||
if (command == null) {
|
||||
String message = "Unrecognized command: " + ansi().bold().fg(Ansi.Color.RED) + theArgs[0] + ansi().boldOff().fg(Ansi.Color.WHITE);
|
||||
printMessageToStdout(message);
|
||||
printMessageToStdout("");
|
||||
logUsage();
|
||||
exitDueToProblem(message);
|
||||
return;
|
||||
}
|
||||
BaseCommand command = commandOpt.get();
|
||||
|
||||
myShutdownHook = new MyShutdownHook(command);
|
||||
Runtime.getRuntime().addShutdownHook(myShutdownHook);
|
||||
|
@ -304,11 +276,44 @@ public abstract class BaseApp {
|
|||
} catch (Throwable t) {
|
||||
ourLog.error("Error during execution: ", t);
|
||||
runCleanupHookAndUnregister();
|
||||
exitDueToException(new CommandFailureException("Error: " + t.toString(), t));
|
||||
exitDueToException(new CommandFailureException("Error: " + t, t));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Optional<BaseCommand> parseCommand(String[] theArgs) {
|
||||
Optional<BaseCommand> commandOpt = getNextCommand(theArgs);
|
||||
|
||||
if (! commandOpt.isPresent()) {
|
||||
String message = "Unrecognized command: " + ansi().bold().fg(Ansi.Color.RED) + theArgs[0] + ansi().boldOff().fg(Ansi.Color.WHITE);
|
||||
printMessageToStdout(message);
|
||||
printMessageToStdout("");
|
||||
logUsage();
|
||||
exitDueToProblem(message);
|
||||
}
|
||||
return commandOpt;
|
||||
}
|
||||
|
||||
private Optional<BaseCommand> getNextCommand(String[] theArgs) {
|
||||
return ourCommands.stream().filter(cmd -> cmd.getCommandName().equals(theArgs[0])).findFirst();
|
||||
}
|
||||
|
||||
private void processHelp(String[] theArgs) {
|
||||
if (theArgs.length < 2) {
|
||||
logUsage();
|
||||
return;
|
||||
}
|
||||
Optional<BaseCommand> commandOpt = getNextCommand(theArgs);
|
||||
if (! commandOpt.isPresent()) {
|
||||
String message = "Unknown command: " + theArgs[1];
|
||||
System.err.println(message);
|
||||
exitDueToProblem(message);
|
||||
return;
|
||||
}
|
||||
logCommandUsage(commandOpt.get());
|
||||
}
|
||||
|
||||
|
||||
private void exitDueToProblem(String theDescription) {
|
||||
if ("true".equals(System.getProperty("test"))) {
|
||||
throw new Error(theDescription);
|
||||
|
@ -380,6 +385,7 @@ public abstract class BaseApp {
|
|||
configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
|
||||
((LoggerContext) LoggerFactory.getILoggerFactory()).reset();
|
||||
configurator.doConfigure(App.class.getResourceAsStream("/logback-cli-on.xml"));
|
||||
ourLog.info("Logging configuration set from file logback-cli-on.xml");
|
||||
} catch (JoranException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -391,6 +397,7 @@ public abstract class BaseApp {
|
|||
configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
|
||||
((LoggerContext) LoggerFactory.getILoggerFactory()).reset();
|
||||
configurator.doConfigure(App.class.getResourceAsStream("/logback-cli-on-debug.xml"));
|
||||
ourLog.info("Logging configuration set from file logback-cli-on-debug.xml");
|
||||
} catch (JoranException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -26,13 +26,20 @@ import ca.uhn.fhir.rest.api.Constants;
|
|||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.cli.*;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.OptionGroup;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
@ -109,7 +116,7 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
try {
|
||||
retVal = reader.readLine();
|
||||
} catch (IOException e) {
|
||||
throw new ParseException("Failed to read input from user: " + e.toString());
|
||||
throw new ParseException("Failed to read input from user: " + e);
|
||||
}
|
||||
} else {
|
||||
retVal = new String(console.readPassword());
|
||||
|
@ -120,9 +127,13 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
protected Collection<Object> getFilterOutVersions() {
|
||||
return Sets.newHashSet(FhirVersionEnum.DSTU2_1, FhirVersionEnum.DSTU2_HL7ORG);
|
||||
}
|
||||
|
||||
protected void addFhirVersionOption(Options theOptions) {
|
||||
String versions = Arrays.stream(FhirVersionEnum.values())
|
||||
.filter(t -> t != FhirVersionEnum.DSTU2_1 && t != FhirVersionEnum.DSTU2_HL7ORG)
|
||||
.filter(t -> ! getFilterOutVersions().contains(t))
|
||||
.map(t -> t.name().toLowerCase())
|
||||
.sorted()
|
||||
.collect(Collectors.joining(", "));
|
||||
|
@ -275,12 +286,33 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
byte[] basicAuth = optionValue.getBytes();
|
||||
String base64EncodedBasicAuth = Base64Utils.encodeToString(basicAuth);
|
||||
basicAuthHeaderValue = Constants.HEADER_AUTHORIZATION_VALPREFIX_BASIC + base64EncodedBasicAuth;
|
||||
} else {
|
||||
basicAuthHeaderValue = null;
|
||||
}
|
||||
return basicAuthHeaderValue;
|
||||
}
|
||||
|
||||
|
||||
protected Pair<String, String> parseNameValueParameter(
|
||||
String separator, String theParamName, String theParam) throws ParseException {
|
||||
|
||||
String errorMsg = "Parameter " + theParamName + " must be in the format: \"name:value\"";
|
||||
|
||||
if (! theParam.contains(separator)) {
|
||||
throw new ParseException(errorMsg);
|
||||
}
|
||||
|
||||
String[] nameValue = theParam.split(separator);
|
||||
if (nameValue.length != 2) {
|
||||
throw new ParseException(errorMsg);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(nameValue[0]) || StringUtils.isBlank(nameValue[1])) {
|
||||
throw new ParseException(errorMsg);
|
||||
}
|
||||
|
||||
return Pair.of(nameValue[0], nameValue[1]);
|
||||
}
|
||||
|
||||
|
||||
public <T extends Enum> T getAndParseOptionEnum(CommandLine theCommandLine, String theOption, Class<T> theEnumClass, boolean theRequired, T theDefault) throws ParseException {
|
||||
String val = theCommandLine.getOptionValue(theOption);
|
||||
if (isBlank(val)) {
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.AdditionalRequestHeadersInterceptor;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public abstract class BaseRequestGeneratingCommand extends BaseCommand {
|
||||
|
||||
public enum BaseRequestGeneratingCommandOptions {
|
||||
VERSION,
|
||||
BASE_URL,
|
||||
BASIC_AUTH,
|
||||
VERBOSE_LOGGING,
|
||||
HEADER_PASSTHROUGH
|
||||
}
|
||||
|
||||
|
||||
protected static final String HEADER_PASSTHROUGH = "hp";
|
||||
protected static final String HEADER_PASSTHROUGH_NAME = "header";
|
||||
protected static final String HEADER_PASSTHROUGH_LONGOPT = "header-passthrough";
|
||||
|
||||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
return getSomeOptions(Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows child classes to obtain a subset of the parent-defined options
|
||||
*/
|
||||
protected Options getSomeOptions(Collection<BaseRequestGeneratingCommandOptions> theExcludeOptions) {
|
||||
Options options = new Options();
|
||||
|
||||
if (! theExcludeOptions.contains(BaseRequestGeneratingCommandOptions.VERSION)) {
|
||||
addFhirVersionOption(options);
|
||||
}
|
||||
|
||||
if (! theExcludeOptions.contains(BaseRequestGeneratingCommandOptions.BASE_URL)) {
|
||||
addBaseUrlOption(options);
|
||||
}
|
||||
|
||||
if (! theExcludeOptions.contains(BaseRequestGeneratingCommandOptions.BASIC_AUTH)) {
|
||||
addBasicAuthOption(options);
|
||||
}
|
||||
|
||||
if (! theExcludeOptions.contains(BaseRequestGeneratingCommandOptions.VERBOSE_LOGGING)) {
|
||||
addVerboseLoggingOption(options);
|
||||
}
|
||||
|
||||
if (! theExcludeOptions.contains(BaseRequestGeneratingCommandOptions.HEADER_PASSTHROUGH)) {
|
||||
addHeaderPassthroughOption(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected IGenericClient newClient(CommandLine theCommandLine) throws ParseException {
|
||||
IGenericClient client = super.newClient(theCommandLine);
|
||||
|
||||
if (theCommandLine.hasOption(HEADER_PASSTHROUGH)) {
|
||||
client.registerInterceptor(
|
||||
new AdditionalRequestHeadersInterceptor(
|
||||
getAndParseOptionHeadersPassthrough(theCommandLine, HEADER_PASSTHROUGH)));
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private void addHeaderPassthroughOption(Options theOptions) {
|
||||
addOptionalOption(theOptions, HEADER_PASSTHROUGH, HEADER_PASSTHROUGH_LONGOPT, HEADER_PASSTHROUGH_NAME,
|
||||
"If specified, this argument specifies headers to include in the generated request");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the optional pass-through header name and value
|
||||
*/
|
||||
protected Map<String, List<String>> getAndParseOptionHeadersPassthrough(
|
||||
CommandLine theCommandLine, String theOptionName) throws ParseException {
|
||||
|
||||
if (! theCommandLine.hasOption(theOptionName)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, List<String>> headersMap = new HashMap<>();
|
||||
for (String nextOptionValue: theCommandLine.getOptionValues(theOptionName)) {
|
||||
Pair<String, String> nextHeader = parseNameValueParameter(":", theOptionName, nextOptionValue);
|
||||
headersMap.compute(nextHeader.getKey(), (k, v) -> v == null ? new ArrayList<>() : v).add(nextHeader.getValue());
|
||||
}
|
||||
|
||||
return headersMap;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.cli;
|
|||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
|
@ -39,6 +40,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
|
@ -61,18 +63,20 @@ import java.io.IOException;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class ExampleDataUploader extends BaseCommand {
|
||||
public class ExampleDataUploader extends BaseRequestGeneratingCommand {
|
||||
// TODO: Don't use qualified names for loggers in HAPI CLI.
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleDataUploader.class);
|
||||
|
||||
|
@ -200,8 +204,8 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
ourLog.info("Found example {} - {} - {} chars", nextEntry.getName(), parsed.getClass().getSimpleName(), exampleString.length());
|
||||
|
||||
ValidationResult result = val.validateWithResult(parsed);
|
||||
if (result.isSuccessful() == false) {
|
||||
ourLog.info("FAILED to validate example {} - {}", nextEntry.getName(), result.toString());
|
||||
if (! result.isSuccessful()) {
|
||||
ourLog.info("FAILED to validate example {} - {}", nextEntry.getName(), result);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -284,8 +288,8 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
ourLog.info("Found example {} - {} - {} chars", nextEntry.getName(), parsed.getClass().getSimpleName(), exampleString.length());
|
||||
|
||||
ValidationResult result = val.validateWithResult(parsed);
|
||||
if (result.isSuccessful() == false) {
|
||||
ourLog.info("FAILED to validate example {} - {}", nextEntry.getName(), result.toString());
|
||||
if (! result.isSuccessful()) {
|
||||
ourLog.info("FAILED to validate example {} - {}", nextEntry.getName(), result);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -334,15 +338,9 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = new Options();
|
||||
Options options = super.getOptions();
|
||||
Option opt;
|
||||
|
||||
addFhirVersionOption(options);
|
||||
|
||||
opt = new Option("t", "target", true, "Base URL for the target server (e.g. \"http://example.com/fhir\")");
|
||||
opt.setRequired(true);
|
||||
options.addOption(opt);
|
||||
|
||||
opt = new Option("l", "limit", true, "Sets a limit to the number of resources the uploader will try to upload");
|
||||
opt.setRequired(false);
|
||||
options.addOption(opt);
|
||||
|
@ -356,11 +354,17 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
opt.setRequired(false);
|
||||
options.addOption(opt);
|
||||
|
||||
addBasicAuthOption(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Collection<Object> getFilterOutVersions() {
|
||||
Collection<Object> filterOutCollection = super.getFilterOutVersions();
|
||||
filterOutCollection.add(FhirVersionEnum.R5);
|
||||
return filterOutCollection;
|
||||
}
|
||||
|
||||
private void processBundle(FhirContext ctx, IBaseBundle bundle) {
|
||||
switch (ctx.getVersion().getVersion()) {
|
||||
case DSTU2:
|
||||
|
@ -609,7 +613,7 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
String targetServer = theCommandLine.getOptionValue("t");
|
||||
if (isBlank(targetServer)) {
|
||||
throw new ParseException("No target server (-t) specified");
|
||||
} else if (targetServer.startsWith("http") == false && targetServer.startsWith("file") == false) {
|
||||
} else if (! targetServer.startsWith("http") && ! targetServer.startsWith("file")) {
|
||||
throw new ParseException("Invalid target server specified, must begin with 'http' or 'file'");
|
||||
}
|
||||
|
||||
|
@ -697,7 +701,7 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
String nextTarget = nextRefResourceType + "/EX" + nextRefIdPart;
|
||||
nextRef.getResourceReference().setResource(null);
|
||||
nextRef.getResourceReference().setReference(nextTarget);
|
||||
if (checkedTargets.add(nextTarget) == false) {
|
||||
if (! checkedTargets.add(nextTarget)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.cli;
|
|||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
|
@ -38,6 +39,7 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
@ -60,14 +62,10 @@ public class ExportConceptMapToCsvCommand extends AbstractImportExportCsvConcept
|
|||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = new Options();
|
||||
Options options = super.getOptions();
|
||||
|
||||
this.addFhirVersionOption(options);
|
||||
addBaseUrlOption(options);
|
||||
addRequiredOption(options, CONCEPTMAP_URL_PARAM, CONCEPTMAP_URL_PARAM_LONGOPT, CONCEPTMAP_URL_PARAM_NAME, CONCEPTMAP_URL_PARAM_DESC);
|
||||
addRequiredOption(options, FILE_PARAM, FILE_PARAM_LONGOPT, FILE_PARAM_NAME, FILE_PARAM_DESC);
|
||||
addBasicAuthOption(options);
|
||||
addVerboseLoggingOption(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
|
|
@ -80,18 +80,14 @@ public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConcept
|
|||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = new Options();
|
||||
Options options = super.getOptions();
|
||||
|
||||
this.addFhirVersionOption(options);
|
||||
addBaseUrlOption(options);
|
||||
addRequiredOption(options, CONCEPTMAP_URL_PARAM, CONCEPTMAP_URL_PARAM_LONGOPT, CONCEPTMAP_URL_PARAM_NAME, CONCEPTMAP_URL_PARAM_DESC);
|
||||
// </editor-fold desc="Additional parameters.">
|
||||
addOptionalOption(options, SOURCE_VALUE_SET_PARAM, SOURCE_VALUE_SET_PARAM_LONGOPT, SOURCE_VALUE_SET_PARAM_NAME, SOURCE_VALUE_SET_PARAM_DESC);
|
||||
addOptionalOption(options, TARGET_VALUE_SET_PARAM, TARGET_VALUE_SET_PARAM_LONGOPT, TARGET_VALUE_SET_PARAM_NAME, TARGET_VALUE_SET_PARAM_DESC);
|
||||
// </editor-fold>
|
||||
addRequiredOption(options, FILE_PARAM, FILE_PARAM_LONGOPT, FILE_PARAM_NAME, FILE_PARAM_DESC);
|
||||
addBasicAuthOption(options);
|
||||
addVerboseLoggingOption(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.apache.commons.cli.ParseException;
|
|||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.CountingInputStream;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
|
@ -48,7 +49,7 @@ import java.util.zip.ZipOutputStream;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class UploadTerminologyCommand extends BaseCommand {
|
||||
public class UploadTerminologyCommand extends BaseRequestGeneratingCommand {
|
||||
static final String UPLOAD_TERMINOLOGY = "upload-terminology";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UploadTerminologyCommand.class);
|
||||
private static final long DEFAULT_TRANSFER_SIZE_LIMIT = 10 * FileUtils.ONE_MB;
|
||||
|
@ -66,15 +67,11 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = new Options();
|
||||
Options options = super.getOptions();
|
||||
|
||||
addFhirVersionOption(options);
|
||||
addBaseUrlOption(options);
|
||||
addRequiredOption(options, "u", "url", true, "The code system URL associated with this upload (e.g. " + ITermLoaderSvc.SCT_URI + ")");
|
||||
addOptionalOption(options, "d", "data", true, "Local file to use to upload (can be a raw file or a ZIP containing the raw file)");
|
||||
addOptionalOption(options, "m", "mode", true, "The upload mode: SNAPSHOT (default), ADD, REMOVE");
|
||||
addBasicAuthOption(options);
|
||||
addVerboseLoggingOption(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
@ -101,33 +98,35 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
throw new ParseException("No data file provided");
|
||||
}
|
||||
|
||||
IGenericClient client = super.newClient(theCommandLine);
|
||||
IBaseParameters inputParameters = ParametersUtil.newInstance(myFhirCtx);
|
||||
IGenericClient client = newClient(theCommandLine);
|
||||
|
||||
if (theCommandLine.hasOption(VERBOSE_LOGGING_PARAM)) {
|
||||
client.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
||||
String requestName = null;
|
||||
switch (mode) {
|
||||
case SNAPSHOT:
|
||||
invokeOperation(termUrl, datafile, client, inputParameters, JpaConstants.OPERATION_UPLOAD_EXTERNAL_CODE_SYSTEM);
|
||||
requestName = JpaConstants.OPERATION_UPLOAD_EXTERNAL_CODE_SYSTEM;
|
||||
break;
|
||||
case ADD:
|
||||
invokeOperation(termUrl, datafile, client, inputParameters, JpaConstants.OPERATION_APPLY_CODESYSTEM_DELTA_ADD);
|
||||
requestName = JpaConstants.OPERATION_APPLY_CODESYSTEM_DELTA_ADD;
|
||||
break;
|
||||
case REMOVE:
|
||||
invokeOperation(termUrl, datafile, client, inputParameters, JpaConstants.OPERATION_APPLY_CODESYSTEM_DELTA_REMOVE);
|
||||
requestName = JpaConstants.OPERATION_APPLY_CODESYSTEM_DELTA_REMOVE;
|
||||
break;
|
||||
}
|
||||
|
||||
invokeOperation(termUrl, datafile, client, requestName);
|
||||
}
|
||||
|
||||
private void invokeOperation(String theTermUrl, String[] theDatafile, IGenericClient theClient, IBaseParameters theInputParameters, String theOperationName) throws ParseException {
|
||||
private void invokeOperation(String theTermUrl, String[] theDatafile, IGenericClient theClient, String theOperationName) throws ParseException {
|
||||
IBaseParameters inputParameters = ParametersUtil.newInstance(myFhirCtx);
|
||||
|
||||
boolean isDeltaOperation =
|
||||
theOperationName.equals(JpaConstants.OPERATION_APPLY_CODESYSTEM_DELTA_ADD) ||
|
||||
theOperationName.equals(JpaConstants.OPERATION_APPLY_CODESYSTEM_DELTA_REMOVE);
|
||||
|
||||
ParametersUtil.addParameterToParametersUri(myFhirCtx, theInputParameters, TerminologyUploaderProvider.PARAM_SYSTEM, theTermUrl);
|
||||
ParametersUtil.addParameterToParametersUri(myFhirCtx, inputParameters, TerminologyUploaderProvider.PARAM_SYSTEM, theTermUrl);
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream, Charsets.UTF_8);
|
||||
|
@ -152,7 +151,7 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
CodeSystem resource = encoding.newParser(myFhirCtx).parseResource(CodeSystem.class, contents);
|
||||
ParametersUtil.addParameterToParameters(myFhirCtx, theInputParameters, TerminologyUploaderProvider.PARAM_CODESYSTEM, resource);
|
||||
ParametersUtil.addParameterToParameters(myFhirCtx, inputParameters, TerminologyUploaderProvider.PARAM_CODESYSTEM, resource);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -174,7 +173,7 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
|
||||
ourLog.info("Adding ZIP file: {}", nextDataFile);
|
||||
String fileName = "file:" + nextDataFile;
|
||||
addFileToRequestBundle(theInputParameters, fileName, IOUtils.toByteArray(fileInputStream));
|
||||
addFileToRequestBundle(inputParameters, fileName, IOUtils.toByteArray(fileInputStream));
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -194,13 +193,13 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
byte[] compressedBytes = byteArrayOutputStream.toByteArray();
|
||||
ourLog.info("Compressed {} bytes in {} file(s) into {} bytes", FileUtil.formatFileSize(compressedSourceBytesCount), compressedFileCount, FileUtil.formatFileSize(compressedBytes.length));
|
||||
|
||||
addFileToRequestBundle(theInputParameters, "file:/files.zip", compressedBytes);
|
||||
addFileToRequestBundle(inputParameters, "file:/files.zip", compressedBytes);
|
||||
}
|
||||
|
||||
ourLog.info("Beginning upload - This may take a while...");
|
||||
|
||||
if (ourLog.isDebugEnabled() || "true".equals(System.getProperty("test"))) {
|
||||
ourLog.info("Submitting parameters: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theInputParameters));
|
||||
ourLog.info("Submitting parameters: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(inputParameters));
|
||||
}
|
||||
|
||||
IBaseParameters response;
|
||||
|
@ -209,7 +208,7 @@ public class UploadTerminologyCommand extends BaseCommand {
|
|||
.operation()
|
||||
.onType(myFhirCtx.getResourceDefinition("CodeSystem").getImplementingClass())
|
||||
.named(theOperationName)
|
||||
.withParameters(theInputParameters)
|
||||
.withParameters(inputParameters)
|
||||
.execute();
|
||||
} catch (BaseServerResponseException e) {
|
||||
if (e.getOperationOutcome() != null) {
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class BaseRequestGeneratingCommandTest {
|
||||
|
||||
private final BaseRequestGeneratingCommand tested = new BaseRequestGeneratingCommandChild();
|
||||
|
||||
private final List<BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions> allOptions =
|
||||
Arrays.asList(BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.values());
|
||||
|
||||
@Test
|
||||
void getOptions() {
|
||||
Options options = tested.getOptions();
|
||||
assertEquals(6, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.FHIR_VERSION_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASE_URL_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASIC_AUTH_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BEARER_TOKEN_PARAM_NAME));
|
||||
assertTrue(options.hasShortOption(BaseCommand.VERBOSE_LOGGING_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseRequestGeneratingCommand.HEADER_PASSTHROUGH));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSomeOptionsNoVersion() {
|
||||
Options options = tested.getSomeOptions(
|
||||
Collections.singleton(BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.VERSION));
|
||||
assertEquals(5, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASE_URL_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASIC_AUTH_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BEARER_TOKEN_PARAM_NAME));
|
||||
assertTrue(options.hasShortOption(BaseCommand.VERBOSE_LOGGING_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseRequestGeneratingCommand.HEADER_PASSTHROUGH));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSomeOptionsNoBaseUrl() {
|
||||
Options options = tested.getSomeOptions(
|
||||
Collections.singleton(BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.BASE_URL));
|
||||
assertEquals(5, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.FHIR_VERSION_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASIC_AUTH_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BEARER_TOKEN_PARAM_NAME));
|
||||
assertTrue(options.hasShortOption(BaseCommand.VERBOSE_LOGGING_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseRequestGeneratingCommand.HEADER_PASSTHROUGH));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSomeOptionsNoBasicAuth() {
|
||||
Options options = tested.getSomeOptions(
|
||||
Collections.singleton(BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.BASIC_AUTH));
|
||||
assertEquals(4, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.FHIR_VERSION_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASE_URL_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.VERBOSE_LOGGING_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseRequestGeneratingCommand.HEADER_PASSTHROUGH));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSomeOptionsNoVerboseLogging() {
|
||||
Options options = tested.getSomeOptions(
|
||||
Collections.singleton(BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.VERBOSE_LOGGING));
|
||||
assertEquals(5, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.FHIR_VERSION_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASE_URL_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASIC_AUTH_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BEARER_TOKEN_PARAM_NAME));
|
||||
assertTrue(options.hasShortOption(BaseRequestGeneratingCommand.HEADER_PASSTHROUGH));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSomeOptionsNoHeaderPassthrough() {
|
||||
Options options = tested.getSomeOptions(
|
||||
Collections.singleton(BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.HEADER_PASSTHROUGH));
|
||||
assertEquals(5, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.FHIR_VERSION_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASE_URL_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASIC_AUTH_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BEARER_TOKEN_PARAM_NAME));
|
||||
assertTrue(options.hasShortOption(BaseCommand.VERBOSE_LOGGING_PARAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSomeOptionsExcludeTwo() {
|
||||
Options options = tested.getSomeOptions(Lists.newArrayList(
|
||||
BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.VERSION,
|
||||
BaseRequestGeneratingCommand.BaseRequestGeneratingCommandOptions.HEADER_PASSTHROUGH));
|
||||
assertEquals(4, options.getOptions().size());
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASE_URL_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BASIC_AUTH_PARAM));
|
||||
assertTrue(options.hasShortOption(BaseCommand.BEARER_TOKEN_PARAM_NAME));
|
||||
assertTrue(options.hasShortOption(BaseCommand.VERBOSE_LOGGING_PARAM));
|
||||
}
|
||||
|
||||
|
||||
private static class BaseRequestGeneratingCommandChild extends BaseRequestGeneratingCommand {
|
||||
|
||||
@Override
|
||||
public String getCommandDescription() { return null; }
|
||||
|
||||
@Override
|
||||
public String getCommandName() { return null; }
|
||||
|
||||
@Override
|
||||
public void run(CommandLine theCommandLine) { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ExampleDataUploaderTest {
|
||||
|
||||
private FhirContext myCtx = FhirContext.forR4();
|
||||
|
||||
@RegisterExtension
|
||||
public final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(myCtx);
|
||||
|
||||
private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
|
||||
private final ExampleDataUploader testedCommand = new RequestCapturingExampleDataUploader(myCapturingInterceptor);
|
||||
|
||||
private String inputFilePath;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
String resourcesPath = new File("src/test/resources").getAbsolutePath();
|
||||
inputFilePath = resourcesPath + "/sample.json.zip";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testHeaderPassthrough() throws ParseException {
|
||||
String headerKey = "test-header-key";
|
||||
String headerValue = "test header value";
|
||||
|
||||
String[] args = new String[] {
|
||||
"-v", "r4", // BaseRequestGeneratingCommandTest required
|
||||
"-t", "http://localhost:8000", // BaseRequestGeneratingCommandTest required
|
||||
"-d", inputFilePath,
|
||||
"-hp", headerKey + ":" + headerValue // optional
|
||||
};
|
||||
|
||||
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
|
||||
testedCommand.run(commandLine);
|
||||
|
||||
assertNotNull(myCapturingInterceptor.getLastRequest());
|
||||
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
|
||||
assertFalse(allHeaders.isEmpty());
|
||||
|
||||
assertTrue(allHeaders.containsKey(headerKey));
|
||||
assertEquals(1, allHeaders.get(headerKey).size());
|
||||
|
||||
assertThat(allHeaders.get(headerKey), hasItems(headerValue));
|
||||
}
|
||||
|
||||
|
||||
private static class RequestCapturingExampleDataUploader extends ExampleDataUploader {
|
||||
private final CapturingInterceptor myCapturingInterceptor;
|
||||
|
||||
public RequestCapturingExampleDataUploader(CapturingInterceptor theCapturingInterceptor) {
|
||||
myCapturingInterceptor = theCapturingInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IGenericClient newClient(CommandLine theCommandLine) throws ParseException {
|
||||
IGenericClient client = super.newClient(theCommandLine);
|
||||
client.getInterceptorService().registerInterceptor(myCapturingInterceptor);
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +1,80 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseClient;
|
||||
import ca.uhn.fhir.rest.client.impl.GenericClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
|
||||
import ca.uhn.fhir.test.BaseTest;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.term.UploadStatistics;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.derby.iapi.types.ReaderToUTF8Stream;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.testcontainers.shaded.org.bouncycastle.util.Arrays;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
|
@ -323,6 +366,139 @@ public class UploadTerminologyCommandTest extends BaseTest {
|
|||
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class HeaderPassthroughOptionTests {
|
||||
|
||||
@RegisterExtension
|
||||
public final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(myCtx);
|
||||
|
||||
private final String headerKey1 = "test-header-key-1";
|
||||
private final String headerValue1 = "test header value-1";
|
||||
|
||||
private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
|
||||
private final UploadTerminologyCommand testedCommand =
|
||||
new RequestCapturingUploadTerminologyCommand(myCapturingInterceptor);
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
when(myTermLoaderSvc.loadCustom(eq("http://foo"), anyList(), any()))
|
||||
.thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101")));
|
||||
|
||||
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
|
||||
myRestfulServerExtension.registerProvider(provider);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void oneHeader() throws Exception {
|
||||
String[] args = new String[] {
|
||||
"-v", "r4",
|
||||
"-m", "SNAPSHOT",
|
||||
"-t", "http://localhost:" + myRestfulServerExtension.getPort(),
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName,
|
||||
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\""
|
||||
};
|
||||
|
||||
writeConceptAndHierarchyFiles();
|
||||
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
|
||||
testedCommand.run(commandLine);
|
||||
|
||||
assertNotNull(myCapturingInterceptor.getLastRequest());
|
||||
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
|
||||
assertFalse(allHeaders.isEmpty());
|
||||
|
||||
assertTrue(allHeaders.containsKey(headerKey1));
|
||||
assertEquals(1, allHeaders.get(headerKey1).size());
|
||||
|
||||
assertThat(allHeaders.get(headerKey1), hasItems(headerValue1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void twoHeadersSameKey() throws Exception {
|
||||
final String headerValue2 = "test header value-2";
|
||||
|
||||
String[] args = new String[] {
|
||||
"-v", "r4",
|
||||
"-m", "SNAPSHOT",
|
||||
"-t", "http://localhost:" + myRestfulServerExtension.getPort(),
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName,
|
||||
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\"",
|
||||
"-hp", "\"" + headerKey1 + ":" + headerValue2 + "\""
|
||||
};
|
||||
|
||||
writeConceptAndHierarchyFiles();
|
||||
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
|
||||
testedCommand.run(commandLine);
|
||||
|
||||
assertNotNull(myCapturingInterceptor.getLastRequest());
|
||||
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
|
||||
assertFalse(allHeaders.isEmpty());
|
||||
assertEquals(2, allHeaders.get(headerKey1).size());
|
||||
|
||||
assertTrue(allHeaders.containsKey(headerKey1));
|
||||
assertEquals(2, allHeaders.get(headerKey1).size());
|
||||
|
||||
assertEquals(headerValue1, allHeaders.get(headerKey1).get(0));
|
||||
assertEquals(headerValue2, allHeaders.get(headerKey1).get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoHeadersDifferentKeys() throws Exception {
|
||||
final String headerKey2 = "test-header-key-2";
|
||||
final String headerValue2 = "test header value-2";
|
||||
|
||||
String[] args = new String[] {
|
||||
"-v", "r4",
|
||||
"-m", "SNAPSHOT",
|
||||
"-t", "http://localhost:" + myRestfulServerExtension.getPort(),
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName,
|
||||
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\"",
|
||||
"-hp", "\"" + headerKey2 + ":" + headerValue2 + "\""
|
||||
};
|
||||
|
||||
writeConceptAndHierarchyFiles();
|
||||
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
|
||||
testedCommand.run(commandLine);
|
||||
|
||||
assertNotNull(myCapturingInterceptor.getLastRequest());
|
||||
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
|
||||
assertFalse(allHeaders.isEmpty());
|
||||
|
||||
assertTrue(allHeaders.containsKey(headerKey1));
|
||||
assertEquals(1, allHeaders.get(headerKey1).size());
|
||||
assertThat(allHeaders.get(headerKey1), hasItems(headerValue1));
|
||||
|
||||
assertTrue(allHeaders.containsKey(headerKey2));
|
||||
assertEquals(1, allHeaders.get(headerKey2).size());
|
||||
assertThat(allHeaders.get(headerKey2), hasItems(headerValue2));
|
||||
}
|
||||
|
||||
|
||||
private class RequestCapturingUploadTerminologyCommand extends UploadTerminologyCommand {
|
||||
private CapturingInterceptor myCapturingInterceptor;
|
||||
|
||||
public RequestCapturingUploadTerminologyCommand(CapturingInterceptor theCapturingInterceptor) {
|
||||
myCapturingInterceptor = theCapturingInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IGenericClient newClient(CommandLine theCommandLine) throws ParseException {
|
||||
IGenericClient client = super.newClient(theCommandLine);
|
||||
client.getInterceptorService().registerInterceptor(myCapturingInterceptor);
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void writeArchiveFile(File... theFiles) throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream, Charsets.UTF_8);
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue