3776 add https support for hapi fhir cli using tls (#3777)
* wip functional
TODO
- add tests
- look at adding TLS to other RestfulClientFactory classes (FhirwebRestfulClientFactory, JaxRsRestfulClientFactory, OkHttpRestfulClientFactory)
* move BaseRestServerHelper to Hapi-Fhir
* - add TLS support for JaxRsClient and OkHttpClient
- add tests
* - to use resources and files
* - ci fixes
* - ci fixes
* - ci fixes
* - ci fixes
* - refactor and tests
* - ci fixes
* - tests
* - tests
* - tests / refactor
* - clean up
* - changelog
* - remove OkHttpClient HTTPS support
* - ci
* - Ken's code review changes
* - Ken's code review: method renaming
* - Ken's code review: javadoc
* - Code coverage
* - Create HapiFhirCliRestfulClientFactory to encapsulate new HTTPS functionality. Remove modifications to the FhirContext API.
* - version bump
* - fix unable to bind port errors by using Jetty functionality to assign random ports
* Revert "- version bump"
This reverts commit cfce82576a
.
* - version bump
Co-authored-by: nathaniel.doef <nathaniel.doef@smilecdr.com>
This commit is contained in:
parent
8740c10ed9
commit
e2bed96d74
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.rest.client.api.IBasicClient;
|
|||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
|
@ -888,8 +889,8 @@ public class FhirContext {
|
|||
* {@link #newRestfulClient(Class, String) non-generic clients}).
|
||||
*
|
||||
* <p>
|
||||
* Performance Note: <b>This method is cheap</b> to call, and may be called once for every operation invocation
|
||||
* without incurring any performance penalty
|
||||
* Performance Note: This method performs an additional GET request to /metadata before
|
||||
* the desired request is performed.
|
||||
* </p>
|
||||
*
|
||||
* @param theServerBase The URL of the base for the restful FHIR server to connect to
|
||||
|
|
|
@ -25,7 +25,7 @@ public final class Msg {
|
|||
|
||||
/**
|
||||
* IMPORTANT: Please update the following comment after you add a new code
|
||||
* Last code value: 2109
|
||||
* Last code value: 2123
|
||||
*/
|
||||
|
||||
private Msg() {}
|
||||
|
|
|
@ -20,12 +20,12 @@ package ca.uhn.fhir.rest.client.api;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IRestfulClientFactory {
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package ca.uhn.fhir.tls;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public class KeyStoreInfo extends StoreInfo {
|
||||
|
||||
private final char[] myKeyPass;
|
||||
|
||||
public KeyStoreInfo(String theFilePath, String theStorePass, String theKeyPass, String theAlias) {
|
||||
super(theFilePath, theStorePass, theAlias);
|
||||
this.myKeyPass = toCharArray(theKeyPass);
|
||||
}
|
||||
|
||||
public char[] getKeyPass() {
|
||||
return myKeyPass;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package ca.uhn.fhir.tls;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public enum KeyStoreType {
|
||||
|
||||
PKCS12("p12", "pfx"),
|
||||
JKS("jks");
|
||||
|
||||
private List<String> myFileExtensions;
|
||||
|
||||
KeyStoreType(String... theFileExtensions){
|
||||
myFileExtensions = Arrays.asList(theFileExtensions);
|
||||
}
|
||||
|
||||
public List<String> getFileExtensions() {
|
||||
return myFileExtensions;
|
||||
}
|
||||
|
||||
public static KeyStoreType fromFileExtension(String theFileExtension) {
|
||||
for(KeyStoreType type : KeyStoreType.values()){
|
||||
if(type.getFileExtensions().contains(theFileExtension.toLowerCase())){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(Msg.code(2121)+"Invalid KeyStore Type");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package ca.uhn.fhir.tls;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public enum PathType {
|
||||
|
||||
FILE("file://"),
|
||||
RESOURCE("classpath:");
|
||||
|
||||
private String myPrefix;
|
||||
|
||||
PathType(String thePrefix) {
|
||||
myPrefix = thePrefix;
|
||||
}
|
||||
|
||||
public String getPrefix(){
|
||||
return myPrefix;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package ca.uhn.fhir.tls;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public abstract class StoreInfo {
|
||||
|
||||
private final String myFilePath;
|
||||
private final PathType myPathType;
|
||||
private final char[] myStorePass;
|
||||
private final String myAlias;
|
||||
private final KeyStoreType myType;
|
||||
|
||||
public StoreInfo(String theFilePath, String theStorePass, String theAlias) {
|
||||
if(theFilePath.startsWith(PathType.RESOURCE.getPrefix())){
|
||||
myFilePath = theFilePath.substring(PathType.RESOURCE.getPrefix().length());
|
||||
myPathType = PathType.RESOURCE;
|
||||
}
|
||||
else if(theFilePath.startsWith(PathType.FILE.getPrefix())){
|
||||
myFilePath = theFilePath.substring(PathType.FILE.getPrefix().length());
|
||||
myPathType = PathType.FILE;
|
||||
}
|
||||
else {
|
||||
throw new StoreInfoException(Msg.code(2117)+"Invalid path prefix");
|
||||
}
|
||||
|
||||
myStorePass = toCharArray(theStorePass);
|
||||
myAlias = theAlias;
|
||||
|
||||
String extension = FilenameUtils.getExtension(theFilePath);
|
||||
myType = KeyStoreType.fromFileExtension(extension);
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return myFilePath;
|
||||
}
|
||||
|
||||
public char[] getStorePass() {
|
||||
return myStorePass;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return myAlias;
|
||||
}
|
||||
|
||||
public KeyStoreType getType() {
|
||||
return myType;
|
||||
}
|
||||
|
||||
public PathType getPathType() {
|
||||
return myPathType;
|
||||
}
|
||||
|
||||
protected char[] toCharArray(String theString){
|
||||
return isBlank(theString) ? "".toCharArray() : theString.toCharArray();
|
||||
}
|
||||
|
||||
public static class StoreInfoException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1l;
|
||||
public StoreInfoException(String theMessage) {
|
||||
super(theMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package ca.uhn.fhir.tls;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class TlsAuthentication {
|
||||
|
||||
private final Optional<KeyStoreInfo> myKeyStoreInfo;
|
||||
private final Optional<TrustStoreInfo> myTrustStoreInfo;
|
||||
|
||||
public TlsAuthentication(Optional<KeyStoreInfo> theKeyStoreInfo, Optional<TrustStoreInfo> theTrustStoreInfo) {
|
||||
myKeyStoreInfo = theKeyStoreInfo;
|
||||
myTrustStoreInfo = theTrustStoreInfo;
|
||||
}
|
||||
|
||||
public Optional<KeyStoreInfo> getKeyStoreInfo() {
|
||||
return myKeyStoreInfo;
|
||||
}
|
||||
|
||||
public Optional<TrustStoreInfo> getTrustStoreInfo() {
|
||||
return myTrustStoreInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package ca.uhn.fhir.tls;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public class TrustStoreInfo extends StoreInfo{
|
||||
|
||||
public TrustStoreInfo(String theFilePath, String theStorePass, String theAlias) {
|
||||
super(theFilePath, theStorePass, theAlias);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-bom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>HAPI FHIR BOM</name>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -20,14 +20,21 @@ package ca.uhn.fhir.cli;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.cli.client.HapiFhirCliRestfulClientFactory;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import ca.uhn.fhir.tls.KeyStoreInfo;
|
||||
import ca.uhn.fhir.tls.TrustStoreInfo;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.OptionGroup;
|
||||
|
@ -56,6 +63,7 @@ import java.io.Console;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -65,6 +73,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
@ -80,6 +89,9 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
protected static final String BASE_URL_PARAM_LONGOPT = "target";
|
||||
protected static final String BASE_URL_PARAM_NAME = "target";
|
||||
protected static final String BASE_URL_PARAM_DESC = "Base URL for the target server (e.g. \"http://example.com/fhir\").";
|
||||
protected static final String TLS_AUTH_PARAM_LONGOPT = "tls-auth";
|
||||
protected static final String TLS_AUTH_PARAM_NAME = "tls-auth";
|
||||
protected static final String TLS_AUTH_PARAM_DESC = "If specified, this parameter supplies a path and filename for a json authentication file that will be used to authenticate HTTPS requests.";
|
||||
protected static final String BASIC_AUTH_PARAM = "b";
|
||||
protected static final String BASIC_AUTH_PARAM_LONGOPT = "basic-auth";
|
||||
protected static final String BASIC_AUTH_PARAM_NAME = "basic-auth";
|
||||
|
@ -118,6 +130,10 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
addOptionalOption(theOptions, null, THREAD_COUNT, "count", "If specified, this argument specifies the number of worker threads used (default is " + DEFAULT_THREAD_COUNT + ")");
|
||||
}
|
||||
|
||||
protected void addHttpsAuthOption(Options theOptions){
|
||||
addOptionalOption(theOptions, null, TLS_AUTH_PARAM_LONGOPT, TLS_AUTH_PARAM_NAME, TLS_AUTH_PARAM_DESC);
|
||||
}
|
||||
|
||||
|
||||
protected String promptUser(String thePrompt) throws ParseException {
|
||||
System.out.print(ansi().bold().fgBrightDefault());
|
||||
|
@ -457,10 +473,11 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
}
|
||||
|
||||
protected IGenericClient newClient(CommandLine theCommandLine) throws ParseException {
|
||||
return newClient(theCommandLine, BASE_URL_PARAM, BASIC_AUTH_PARAM, BEARER_TOKEN_PARAM_LONGOPT);
|
||||
return newClient(theCommandLine, BASE_URL_PARAM, BASIC_AUTH_PARAM, BEARER_TOKEN_PARAM_LONGOPT, TLS_AUTH_PARAM_LONGOPT);
|
||||
}
|
||||
|
||||
protected IGenericClient newClient(CommandLine theCommandLine, String theBaseUrlParamName, String theBasicAuthOptionName, String theBearerTokenOptionName) throws ParseException {
|
||||
protected IGenericClient newClient(CommandLine theCommandLine, String theBaseUrlParamName, String theBasicAuthOptionName,
|
||||
String theBearerTokenOptionName, String theTlsAuthOptionName) throws ParseException {
|
||||
String baseUrl = theCommandLine.getOptionValue(theBaseUrlParamName);
|
||||
if (isBlank(baseUrl)) {
|
||||
throw new ParseException(Msg.code(1579) + "No target server (-" + BASE_URL_PARAM + ") specified.");
|
||||
|
@ -468,10 +485,18 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
throw new ParseException(Msg.code(1580) + "Invalid target server specified, must begin with 'http' or 'file'.");
|
||||
}
|
||||
|
||||
return newClientWithBaseUrl(theCommandLine, baseUrl, theBasicAuthOptionName, theBearerTokenOptionName);
|
||||
return newClientWithBaseUrl(theCommandLine, baseUrl, theBasicAuthOptionName, theBearerTokenOptionName, theTlsAuthOptionName);
|
||||
}
|
||||
|
||||
protected IGenericClient newClientWithBaseUrl(CommandLine theCommandLine, String theBaseUrl, String theBasicAuthOptionName, String theBearerTokenOptionName) throws ParseException {
|
||||
protected IGenericClient newClientWithBaseUrl(CommandLine theCommandLine, String theBaseUrl, String theBasicAuthOptionName,
|
||||
String theBearerTokenOptionName, String theTlsAuthOptionName) throws ParseException {
|
||||
|
||||
Optional<TlsAuthentication> tlsConfig = createTlsConfig(theCommandLine, theTlsAuthOptionName);
|
||||
RestfulClientFactory restfulClientFactory = tlsConfig.isPresent()
|
||||
? new HapiFhirCliRestfulClientFactory(myFhirCtx, tlsConfig.get())
|
||||
: new HapiFhirCliRestfulClientFactory(myFhirCtx);
|
||||
|
||||
myFhirCtx.setRestfulClientFactory(restfulClientFactory);
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout((int) DateUtils.MILLIS_PER_HOUR);
|
||||
IGenericClient retVal = myFhirCtx.newRestfulGenericClient(theBaseUrl);
|
||||
|
||||
|
@ -490,6 +515,62 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private Optional<TlsAuthentication> createTlsConfig(CommandLine theCommandLine, String theTlsAuthOptionName){
|
||||
String httpAuthFilePath = theCommandLine.getOptionValue(theTlsAuthOptionName);
|
||||
if(isBlank(httpAuthFilePath)){
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try(FileReader fileReader = new FileReader(httpAuthFilePath)) {
|
||||
JsonObject json = JsonParser.parseReader(fileReader).getAsJsonObject();
|
||||
Optional<KeyStoreInfo> keyStoreInfo = createKeyStoreInfo(json.get("keyStore").getAsJsonObject());
|
||||
Optional<TrustStoreInfo> trustStoreInfo = createTrustStoreInfo(json.get("trustStore").getAsJsonObject());
|
||||
if(keyStoreInfo.isEmpty() && trustStoreInfo.isEmpty()){
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new TlsAuthentication(keyStoreInfo, trustStoreInfo));
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException(Msg.code(2115)+"Could not create TLS configuration options", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<KeyStoreInfo> createKeyStoreInfo(JsonObject theJson) throws ParseException {
|
||||
String filePath = theJson.get("filePath").getAsString();
|
||||
if(isBlank(filePath)){
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String storePass = theJson.get("storePass").getAsString();
|
||||
if (PROMPT.equals(storePass)) {
|
||||
storePass = trim(promptUser("Enter the store password for the keystore: "));
|
||||
}
|
||||
String keyPass = theJson.get("keyPass").getAsString();
|
||||
if (PROMPT.equals(keyPass)) {
|
||||
keyPass = trim(promptUser("Enter the key password for the keystore: "));
|
||||
}
|
||||
String alias = theJson.get("alias").getAsString();
|
||||
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo(filePath, storePass, keyPass, alias);
|
||||
return Optional.of(keyStoreInfo);
|
||||
}
|
||||
|
||||
private Optional<TrustStoreInfo> createTrustStoreInfo(JsonObject theJson) throws ParseException {
|
||||
String filePath = theJson.get("filePath").getAsString();
|
||||
if(isBlank(filePath)){
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String storePass = theJson.get("storePass").getAsString();
|
||||
if (PROMPT.equals(storePass)) {
|
||||
storePass = trim(promptUser("Enter the store password for the truststore: "));
|
||||
}
|
||||
|
||||
String alias = theJson.get("alias").getAsString();
|
||||
TrustStoreInfo trustStoreInfo = new TrustStoreInfo(filePath, storePass, alias);
|
||||
return Optional.of(trustStoreInfo);
|
||||
}
|
||||
|
||||
private String getAndParseBearerTokenAuthHeader(CommandLine theCommandLine, String theBearerTokenOptionName) throws ParseException {
|
||||
String value = theCommandLine.getOptionValue(theBearerTokenOptionName);
|
||||
if (PROMPT.equals(value)) {
|
||||
|
|
|
@ -42,7 +42,8 @@ public abstract class BaseRequestGeneratingCommand extends BaseCommand {
|
|||
BASE_URL,
|
||||
BASIC_AUTH,
|
||||
VERBOSE_LOGGING,
|
||||
HEADER_PASSTHROUGH
|
||||
HEADER_PASSTHROUGH,
|
||||
TLS_AUTH
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,16 +83,21 @@ public abstract class BaseRequestGeneratingCommand extends BaseCommand {
|
|||
addHeaderPassthroughOption(options);
|
||||
}
|
||||
|
||||
if (! theExcludeOptions.contains(BaseRequestGeneratingCommandOptions.TLS_AUTH)) {
|
||||
addHttpsAuthOption(options);
|
||||
}
|
||||
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected IGenericClient newClientWithBaseUrl(CommandLine theCommandLine, String theBaseUrl,
|
||||
String theBasicAuthOptionName, String theBearerTokenOptionName) throws ParseException {
|
||||
String theBasicAuthOptionName, String theBearerTokenOptionName, String theTlsAuthOptionName) throws ParseException {
|
||||
|
||||
IGenericClient client = super.newClientWithBaseUrl(
|
||||
theCommandLine, theBaseUrl, theBasicAuthOptionName, theBearerTokenOptionName);
|
||||
theCommandLine, theBaseUrl, theBasicAuthOptionName, theBearerTokenOptionName, theTlsAuthOptionName);
|
||||
registerHeaderPassthrough(theCommandLine, client);
|
||||
|
||||
return client;
|
||||
|
|
|
@ -129,7 +129,7 @@ public class BulkImportCommand extends BaseCommand {
|
|||
|
||||
String targetBaseUrl = theCommandLine.getOptionValue(TARGET_BASE);
|
||||
ourLog.info("Initiating bulk import against server: {}", targetBaseUrl);
|
||||
IGenericClient client = newClient(theCommandLine, TARGET_BASE, BASIC_AUTH_PARAM, BEARER_TOKEN_PARAM_LONGOPT);
|
||||
IGenericClient client = newClient(theCommandLine, TARGET_BASE, BASIC_AUTH_PARAM, BEARER_TOKEN_PARAM_LONGOPT, TLS_AUTH_PARAM_LONGOPT);
|
||||
client.registerInterceptor(new LoggingInterceptor(false));
|
||||
|
||||
IBaseParameters request = createRequest(sourceBaseUrl, indexes, resourceTypes);
|
||||
|
|
|
@ -46,6 +46,7 @@ import java.util.concurrent.ExecutionException;
|
|||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
public class ExportConceptMapToCsvCommand extends AbstractImportExportCsvConceptMapCommand {
|
||||
public static final String COMMAND = "export-conceptmap-to-csv";
|
||||
// TODO: Don't use qualified names for loggers in HAPI CLI.
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExportConceptMapToCsvCommand.class);
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class ImportCsvToConceptMapCommand extends AbstractImportExportCsvConceptMapCommand {
|
||||
public static final String COMMAND = "import-csv-to-conceptmap";
|
||||
|
||||
// TODO: Don't use qualified names for loggers in HAPI CLI.
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ImportCsvToConceptMapCommand.class);
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
package ca.uhn.fhir.cli.client;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Command Line Client - API
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.tls.TlsAuthenticationSvc;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Intended for use with the HapiFhir CLI only.
|
||||
* <br/><br/>
|
||||
* A Restful Factory to create clients, requests and responses based on the Apache httpclient library.
|
||||
* This class supports HTTP and HTTPS protocol and attempts to use the same client whenever possible.
|
||||
* The method {@link HapiFhirCliRestfulClientFactory#useHttp()} should be used if the protocol needs to be changed to HTTP.
|
||||
* Similarly, the method {@link HapiFhirCliRestfulClientFactory#useHttps(TlsAuthentication)} should be used if the protocol
|
||||
* needs to be changed to HTTPS or if new TLS credentials are required for a client request.
|
||||
*/
|
||||
public class HapiFhirCliRestfulClientFactory extends RestfulClientFactory {
|
||||
|
||||
private HttpClient myHttpClient;
|
||||
private TlsAuthentication myTlsAuthentication;
|
||||
|
||||
public HapiFhirCliRestfulClientFactory(FhirContext theFhirContext) {
|
||||
this(theFhirContext, null);
|
||||
}
|
||||
|
||||
public HapiFhirCliRestfulClientFactory(FhirContext theFhirContext, TlsAuthentication theTlsAuthentication) {
|
||||
super(theFhirContext);
|
||||
myTlsAuthentication = theTlsAuthentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized IHttpClient getHttpClient(String theServerBase) {
|
||||
return getHttpClient(new StringBuilder(theServerBase), null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams,
|
||||
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
|
||||
return new ApacheHttpClient(getNativeHttpClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
|
||||
}
|
||||
|
||||
public HttpClient getNativeHttpClient() {
|
||||
if (myHttpClient == null) {
|
||||
|
||||
RequestConfig defaultRequestConfig =
|
||||
RequestConfig.custom()
|
||||
.setSocketTimeout(getSocketTimeout())
|
||||
.setConnectTimeout(getConnectTimeout())
|
||||
.setConnectionRequestTimeout(getConnectionRequestTimeout())
|
||||
.setStaleConnectionCheckEnabled(true)
|
||||
.build();
|
||||
|
||||
HttpClientBuilder builder = HttpClients.custom()
|
||||
.useSystemProperties()
|
||||
.setDefaultRequestConfig(defaultRequestConfig)
|
||||
.disableCookieManagement();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager;
|
||||
if(myTlsAuthentication != null){
|
||||
SSLContext sslContext = TlsAuthenticationSvc.createSslContext(myTlsAuthentication);
|
||||
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
|
||||
builder.setSSLSocketFactory(sslConnectionSocketFactory);
|
||||
Registry<ConnectionSocketFactory> registry = RegistryBuilder
|
||||
.<ConnectionSocketFactory> create()
|
||||
.register("https", sslConnectionSocketFactory)
|
||||
.build();
|
||||
connectionManager = new PoolingHttpClientConnectionManager(
|
||||
registry, null, null, null, 5000, TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
connectionManager.setMaxTotal(getPoolMaxTotal());
|
||||
connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
|
||||
builder.setConnectionManager(connectionManager);
|
||||
|
||||
myHttpClient = builder.build();
|
||||
}
|
||||
|
||||
return myHttpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetHttpClient() {
|
||||
myHttpClient = null;
|
||||
}
|
||||
|
||||
public void useHttp(){
|
||||
myTlsAuthentication = null;
|
||||
resetHttpClient();
|
||||
}
|
||||
|
||||
public void useHttps(TlsAuthentication theTlsAuthentication){
|
||||
myTlsAuthentication = theTlsAuthentication;
|
||||
resetHttpClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setHttpClient(Object theHttpClient) {
|
||||
throw new UnsupportedOperationException(Msg.code(2119));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProxy(String theHost, Integer thePort) {
|
||||
throw new UnsupportedOperationException(Msg.code(2120));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class ApacheRestfulClientFactoryTest extends BaseFhirVersionParameterizedTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) throws Exception {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
ApacheRestfulClientFactory clientFactory = new ApacheRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
HttpClient client = clientFactory.getNativeHttpClient();
|
||||
|
||||
HttpUriRequest request = new HttpGet(fhirVersionParams.getPatientEndpoint());
|
||||
HttpResponse response = client.execute(request);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
|
||||
String json = EntityUtils.toString(response.getEntity());
|
||||
IBaseResource bundle = fhirVersionParams.parseResource(json);
|
||||
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
ApacheRestfulClientFactory clientFactory = new ApacheRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
HttpClient unauthenticatedClient = clientFactory.getNativeHttpClient();
|
||||
|
||||
try{
|
||||
HttpUriRequest request = new HttpGet(fhirVersionParams.getSecuredPatientEndpoint());
|
||||
unauthenticatedClient.execute(request);
|
||||
fail();
|
||||
}
|
||||
catch(Exception e){
|
||||
assertEquals(SSLHandshakeException.class, e.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttp(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String base = fhirVersionParams.getBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new ApacheRestfulClientFactory(context));
|
||||
IBaseResource bundle = context.newRestfulGenericClient(base).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String secureBase = fhirVersionParams.getSecureBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new ApacheRestfulClientFactory(context));
|
||||
try {
|
||||
context.newRestfulGenericClient(secureBase).search().forResource("Patient").execute();
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.getMessage().contains("HAPI-1357: Failed to retrieve the server metadata statement during client initialization"));
|
||||
assertEquals(SSLHandshakeException.class, e.getCause().getCause().getClass());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,25 +32,26 @@ class BaseRequestGeneratingCommandTest {
|
|||
@Test
|
||||
void getOptions() {
|
||||
Options options = tested.getOptions();
|
||||
assertEquals(6, options.getOptions().size());
|
||||
assertEquals(7, 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));
|
||||
assertTrue(options.hasShortOption(BaseRequestGeneratingCommand.TLS_AUTH_PARAM_NAME));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "Excluding {0}")
|
||||
@EnumSource(value = BaseRequestGeneratingCommandOptions.class,
|
||||
names = {"VERSION", "BASE_URL", "BASIC_AUTH", "VERBOSE_LOGGING", "HEADER_PASSTHROUGH"})
|
||||
names = {"VERSION", "BASE_URL", "BASIC_AUTH", "VERBOSE_LOGGING", "HEADER_PASSTHROUGH", "TLS_AUTH"})
|
||||
void getSomeOptionsExcludingOne(BaseRequestGeneratingCommandOptions excludedOption) {
|
||||
Collection<BaseRequestGeneratingCommandOptions> excludeOptions = Collections.singleton(excludedOption);
|
||||
|
||||
Options options = tested.getSomeOptions(excludeOptions);
|
||||
|
||||
// BASIC_AUTH exclusion excludes 2 options
|
||||
int expectedSize = excludedOption == BASIC_AUTH ? 4 : 5;
|
||||
int expectedSize = excludedOption == BASIC_AUTH ? 5 : 6;
|
||||
assertEquals(expectedSize, options.getOptions().size());
|
||||
|
||||
assertFalse(options.hasShortOption(getOptionForExcludedOption(excludedOption)));
|
||||
|
@ -86,6 +87,9 @@ class BaseRequestGeneratingCommandTest {
|
|||
|
||||
case HEADER_PASSTHROUGH:
|
||||
return BaseRequestGeneratingCommand.HEADER_PASSTHROUGH;
|
||||
|
||||
case TLS_AUTH:
|
||||
return BaseCommand.TLS_AUTH_PARAM_NAME;
|
||||
}
|
||||
throw new InvalidParameterException("unexpected exclude option " + excludeOption);
|
||||
}
|
||||
|
@ -94,11 +98,12 @@ class BaseRequestGeneratingCommandTest {
|
|||
void getSomeOptionsExcludeTwo() {
|
||||
Options options = tested.getSomeOptions(Lists.newArrayList(VERSION, HEADER_PASSTHROUGH));
|
||||
|
||||
assertEquals(4, options.getOptions().size());
|
||||
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(BaseCommand.TLS_AUTH_PARAM_NAME));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
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 ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
@ -24,10 +28,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
|
||||
class ExampleDataUploaderTest {
|
||||
|
||||
private FhirContext myCtx = FhirContext.forR4();
|
||||
|
||||
@RegisterExtension
|
||||
public final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(myCtx);
|
||||
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper();
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
|
||||
private final ExampleDataUploader testedCommand = new RequestCapturingExampleDataUploader(myCapturingInterceptor);
|
||||
|
@ -40,19 +44,20 @@ class ExampleDataUploaderTest {
|
|||
inputFilePath = resourcesPath + "/sample.json.zip";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testHeaderPassthrough() throws ParseException {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testHeaderPassthrough(boolean theIncludeTls) 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
|
||||
};
|
||||
String[] args = myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
"-v", "r4", // BaseRequestGeneratingCommandTest required
|
||||
"-d", inputFilePath,
|
||||
"-hp", headerKey + ":" + headerValue // optional
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper // BaseRequestGeneratingCommandTest required
|
||||
);
|
||||
|
||||
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
|
||||
testedCommand.run(commandLine);
|
||||
|
@ -65,8 +70,13 @@ class ExampleDataUploaderTest {
|
|||
assertEquals(1, allHeaders.get(headerKey).size());
|
||||
|
||||
assertThat(allHeaders.get(headerKey), hasItems(headerValue));
|
||||
}
|
||||
|
||||
assertEquals(1, myRestServerR4Helper.getTransactions().size());
|
||||
Bundle bundle = myRestServerR4Helper.getTransactions().get(0);
|
||||
Resource resource = bundle.getEntry().get(0).getResource();
|
||||
assertEquals(Patient.class, resource.getClass());
|
||||
assertEquals("EX3152", resource.getIdElement().getIdPart());
|
||||
}
|
||||
|
||||
private static class RequestCapturingExampleDataUploader extends ExampleDataUploader {
|
||||
private final CapturingInterceptor myCapturingInterceptor;
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.LoggingExtension;
|
||||
import ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.ConceptMap;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.hl7.fhir.dstu3.model.UriType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -38,30 +34,50 @@ public class ExportConceptMapToCsvCommandDstu3Test {
|
|||
private static final String CS_URL_3 = "http://example.com/codesystem/3";
|
||||
private static final String FILE = "./target/output_dstu3.csv";
|
||||
|
||||
private static String ourBase;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourVersion = "dstu3";
|
||||
private final FhirContext myCtx = FhirContext.forDstu3();
|
||||
private final String myVersion = "dstu3";
|
||||
|
||||
static {
|
||||
System.setProperty("test", "true");
|
||||
}
|
||||
|
||||
@RegisterExtension
|
||||
public LoggingExtension myLoggingExtension = new LoggingExtension();
|
||||
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
@Test
|
||||
public void testExportConceptMapToCsvCommand() throws IOException {
|
||||
ourLog.debug("ConceptMap:\n" + ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
|
||||
@BeforeEach
|
||||
public void before(){
|
||||
myRestServerDstu3Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapDstu3(myCtx));
|
||||
myRestServerDstu3Helper.getClient().create().resource(createConceptMap()).execute();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
myRestServerDstu3Helper.clearDataAndCounts();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll(){
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testExportConceptMapToCsvCommandNoTls(boolean theIncludeTls) throws IOException {
|
||||
ourLog.debug("ConceptMap:\n" + myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
|
||||
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ExportConceptMapToCsvCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", CM_URL,
|
||||
"-f", FILE,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerDstu3Helper
|
||||
));
|
||||
|
||||
App.main(new String[]{"export-conceptmap-to-csv",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", CM_URL,
|
||||
"-f", FILE,
|
||||
"-l"});
|
||||
await().until(() -> new File(FILE).exists());
|
||||
|
||||
String expected = "\"SOURCE_CODE_SYSTEM\",\"SOURCE_CODE_SYSTEM_VERSION\",\"TARGET_CODE_SYSTEM\",\"TARGET_CODE_SYSTEM_VERSION\",\"SOURCE_CODE\",\"SOURCE_DISPLAY\",\"TARGET_CODE\",\"TARGET_DISPLAY\",\"EQUIVALENCE\",\"COMMENT\"\n" +
|
||||
|
@ -85,36 +101,6 @@ public class ExportConceptMapToCsvCommandDstu3Test {
|
|||
FileUtils.deleteQuietly(new File(FILE));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
ServletHandler servletHandler = new ServletHandler();
|
||||
|
||||
RestfulServer restfulServer = new RestfulServer(ourCtx);
|
||||
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
|
||||
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapDstu3(ourCtx));
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder(restfulServer);
|
||||
servletHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(servletHandler);
|
||||
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
ourBase = "http://localhost:" + ourPort;
|
||||
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourBase);
|
||||
|
||||
ourClient.create().resource(createConceptMap()).execute();
|
||||
}
|
||||
|
||||
static ConceptMap createConceptMap() {
|
||||
ConceptMap conceptMap = new ConceptMap();
|
||||
conceptMap
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.hl7.fhir.r4.model.UriType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -36,27 +34,50 @@ public class ExportConceptMapToCsvCommandR4Test {
|
|||
private static final String CS_URL_3 = "http://example.com/codesystem/3";
|
||||
private static final String FILE = new File("./target/output_r4.csv").getAbsolutePath();
|
||||
|
||||
private static String ourBase;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourVersion = "r4";
|
||||
|
||||
static {
|
||||
System.setProperty("test", "true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportConceptMapToCsvCommand() throws IOException {
|
||||
ourLog.info("ConceptMap:\n" + ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
|
||||
@RegisterExtension
|
||||
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
private final FhirContext myCtx = FhirContext.forR4();
|
||||
private final String myVersion = "r4";
|
||||
|
||||
@BeforeEach
|
||||
public void before(){
|
||||
myRestServerR4Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapR4(myCtx));
|
||||
myRestServerR4Helper.getClient().create().resource(createConceptMap()).execute();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
myRestServerR4Helper.clearDataAndCounts();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll(){
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testExportConceptMapToCsvCommand(boolean theIncludeTls) throws IOException {
|
||||
ourLog.info("ConceptMap:\n" + myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createConceptMap()));
|
||||
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ExportConceptMapToCsvCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", CM_URL,
|
||||
"-f", FILE,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
App.main(new String[]{"export-conceptmap-to-csv",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", CM_URL,
|
||||
"-f", FILE,
|
||||
"-l"});
|
||||
await().until(() -> new File(FILE).exists());
|
||||
|
||||
String expected = "\"SOURCE_CODE_SYSTEM\",\"SOURCE_CODE_SYSTEM_VERSION\",\"TARGET_CODE_SYSTEM\",\"TARGET_CODE_SYSTEM_VERSION\",\"SOURCE_CODE\",\"SOURCE_DISPLAY\",\"TARGET_CODE\",\"TARGET_DISPLAY\",\"EQUIVALENCE\",\"COMMENT\"\n" +
|
||||
|
@ -78,36 +99,6 @@ public class ExportConceptMapToCsvCommandR4Test {
|
|||
FileUtils.deleteQuietly(new File(FILE));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
ServletHandler servletHandler = new ServletHandler();
|
||||
|
||||
RestfulServer restfulServer = new RestfulServer(ourCtx);
|
||||
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
|
||||
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapR4(ourCtx));
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder(restfulServer);
|
||||
servletHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(servletHandler);
|
||||
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
ourBase = "http://localhost:" + ourPort;
|
||||
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourBase);
|
||||
|
||||
ourClient.create().resource(createConceptMap()).execute();
|
||||
}
|
||||
|
||||
static ConceptMap createConceptMap() {
|
||||
ConceptMap conceptMap = new ConceptMap();
|
||||
conceptMap
|
||||
|
|
|
@ -2,14 +2,9 @@ package ca.uhn.fhir.cli;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.ConceptMap;
|
||||
import org.hl7.fhir.dstu3.model.ConceptMap.ConceptMapGroupComponent;
|
||||
|
@ -18,9 +13,11 @@ import org.hl7.fhir.dstu3.model.ConceptMap.TargetElementComponent;
|
|||
import org.hl7.fhir.dstu3.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -37,26 +34,27 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
private static final String CS_URL_3 = "http://example.com/codesystem/3";
|
||||
private static final String FILENAME = "import-csv-to-conceptmap-command-test-input.csv";
|
||||
|
||||
private static String file;
|
||||
private static String ourBase;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourVersion = "dstu3";
|
||||
|
||||
private static RestfulServer restfulServer;
|
||||
|
||||
private static HashMapResourceProviderConceptMapDstu3 hashMapResourceProviderConceptMapDstu3;
|
||||
private final FhirContext myCtx = FhirContext.forDstu3();
|
||||
private final String myVersion = "dstu3";
|
||||
private String myFile;
|
||||
|
||||
static {
|
||||
System.setProperty("test", "true");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterClearResourceProvider() {
|
||||
HashMapResourceProviderConceptMapDstu3 resourceProvider = (HashMapResourceProviderConceptMapDstu3) restfulServer.getResourceProviders().iterator().next();
|
||||
resourceProvider.clear();
|
||||
@RegisterExtension
|
||||
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
@BeforeEach
|
||||
public void before(){
|
||||
myRestServerDstu3Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapDstu3(myCtx));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll(){
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -65,7 +63,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
String conceptMapUrl = conceptMap.getUrl();
|
||||
|
||||
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
|
||||
MethodOutcome methodOutcome = ourClient
|
||||
MethodOutcome methodOutcome = myRestServerDstu3Helper.getClient()
|
||||
.update()
|
||||
.resource(conceptMap)
|
||||
.conditional()
|
||||
|
@ -78,11 +76,11 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
@Test
|
||||
public void testConditionalUpdateResultsInUpdate() {
|
||||
ConceptMap conceptMap = ExportConceptMapToCsvCommandDstu3Test.createConceptMap();
|
||||
ourClient.create().resource(conceptMap).execute();
|
||||
myRestServerDstu3Helper.getClient().create().resource(conceptMap).execute();
|
||||
String conceptMapUrl = conceptMap.getUrl();
|
||||
|
||||
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
|
||||
MethodOutcome methodOutcome = ourClient
|
||||
MethodOutcome methodOutcome = myRestServerDstu3Helper.getClient()
|
||||
.update()
|
||||
.resource(conceptMap)
|
||||
.conditional()
|
||||
|
@ -95,9 +93,9 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
@Test
|
||||
public void testNonConditionalUpdate() {
|
||||
ConceptMap conceptMap = ExportConceptMapToCsvCommandDstu3Test.createConceptMap();
|
||||
ourClient.create().resource(conceptMap).execute();
|
||||
myRestServerDstu3Helper.getClient().create().resource(conceptMap).execute();
|
||||
|
||||
Bundle response = ourClient
|
||||
Bundle response = myRestServerDstu3Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value(CM_URL))
|
||||
|
@ -106,7 +104,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
|
||||
ConceptMap resultConceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
MethodOutcome methodOutcome = ourClient
|
||||
MethodOutcome methodOutcome = myRestServerDstu3Helper.getClient()
|
||||
.update()
|
||||
.resource(resultConceptMap)
|
||||
.withId(resultConceptMap.getIdElement())
|
||||
|
@ -115,22 +113,27 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
assertNull(methodOutcome.getCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportCsvToConceptMapCommand() throws FHIRException {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testImportCsvToConceptMapCommandNoTls(boolean theIncludeTls) throws FHIRException {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
File fileToImport = new File(classLoader.getResource(FILENAME).getFile());
|
||||
ImportCsvToConceptMapCommandDstu3Test.file = fileToImport.getAbsolutePath();
|
||||
myFile = fileToImport.getAbsolutePath();
|
||||
|
||||
App.main(new String[]{"import-csv-to-conceptmap",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", file,
|
||||
"-l"});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ImportCsvToConceptMapCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", myFile,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerDstu3Helper
|
||||
));
|
||||
|
||||
Bundle response = ourClient
|
||||
Bundle response = myRestServerDstu3Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value(CM_URL))
|
||||
|
@ -139,9 +142,9 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
|
||||
ConceptMap conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
ourLog.info(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
||||
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/1", conceptMap.getId());
|
||||
assertEquals(myRestServerDstu3Helper.getBase() + "/ConceptMap/1/_history/1", conceptMap.getId());
|
||||
|
||||
assertEquals(CM_URL, conceptMap.getUrl());
|
||||
assertEquals(VS_URL_1, conceptMap.getSourceUriType().getValueAsString());
|
||||
|
@ -317,16 +320,20 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence());
|
||||
assertEquals("3d This is a comment.", target.getComment());
|
||||
|
||||
App.main(new String[]{"import-csv-to-conceptmap",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", file,
|
||||
"-l"});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ImportCsvToConceptMapCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", myFile,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerDstu3Helper
|
||||
));
|
||||
|
||||
response = ourClient
|
||||
response = myRestServerDstu3Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value(CM_URL))
|
||||
|
@ -335,34 +342,7 @@ public class ImportCsvToConceptMapCommandDstu3Test {
|
|||
|
||||
conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/2", conceptMap.getId());
|
||||
assertEquals(myRestServerDstu3Helper.getBase() + "/ConceptMap/1/_history/2", conceptMap.getId());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
ServletHandler servletHandler = new ServletHandler();
|
||||
|
||||
restfulServer = new RestfulServer(ourCtx);
|
||||
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
|
||||
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapDstu3(ourCtx));
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder(restfulServer);
|
||||
servletHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(servletHandler);
|
||||
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
ourBase = "http://localhost:" + ourPort;
|
||||
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourBase);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,9 @@ package ca.uhn.fhir.cli;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.VerboseLoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
|
@ -18,9 +13,11 @@ import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
|
|||
import org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent;
|
||||
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -38,26 +35,27 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
private static final String CS_URL_3 = "http://example.com/codesystem/3";
|
||||
private static final String FILENAME = "import-csv-to-conceptmap-command-test-input.csv";
|
||||
|
||||
private static String file;
|
||||
private static String ourBase;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourVersion = "r4";
|
||||
|
||||
private static RestfulServer restfulServer;
|
||||
|
||||
private static HashMapResourceProviderConceptMapR4 hashMapResourceProviderConceptMapR4;
|
||||
|
||||
static {
|
||||
System.setProperty("test", "true");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterClearResourceProvider() {
|
||||
HashMapResourceProviderConceptMapR4 resourceProvider = (HashMapResourceProviderConceptMapR4) restfulServer.getResourceProviders().iterator().next();
|
||||
resourceProvider.clear();
|
||||
private final FhirContext myFhirContext = FhirContext.forR4();
|
||||
private final String myVersion = "r4";
|
||||
private String myFilePath;
|
||||
|
||||
@RegisterExtension
|
||||
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
@BeforeEach
|
||||
public void before(){
|
||||
myRestServerR4Helper.setConceptMapResourceProvider(new HashMapResourceProviderConceptMapR4(myFhirContext));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll(){
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -66,7 +64,7 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
String conceptMapUrl = conceptMap.getUrl();
|
||||
|
||||
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
|
||||
MethodOutcome methodOutcome = ourClient
|
||||
MethodOutcome methodOutcome = myRestServerR4Helper.getClient()
|
||||
.update()
|
||||
.resource(conceptMap)
|
||||
.conditional()
|
||||
|
@ -80,11 +78,11 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
@Test
|
||||
public void testConditionalUpdateResultsInUpdate() {
|
||||
ConceptMap conceptMap = ExportConceptMapToCsvCommandR4Test.createConceptMap();
|
||||
ourClient.create().resource(conceptMap).execute();
|
||||
myRestServerR4Helper.getClient().create().resource(conceptMap).execute();
|
||||
String conceptMapUrl = conceptMap.getUrl();
|
||||
|
||||
ourLog.info("Searching for existing ConceptMap with specified URL (i.e. ConceptMap.url): {}", conceptMapUrl);
|
||||
MethodOutcome methodOutcome = ourClient
|
||||
MethodOutcome methodOutcome = myRestServerR4Helper.getClient()
|
||||
.update()
|
||||
.resource(conceptMap)
|
||||
.conditional()
|
||||
|
@ -98,9 +96,9 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
@Test
|
||||
public void testNonConditionalUpdate() {
|
||||
ConceptMap conceptMap = ExportConceptMapToCsvCommandR4Test.createConceptMap();
|
||||
ourClient.create().resource(conceptMap).execute();
|
||||
myRestServerR4Helper.getClient().create().resource(conceptMap).execute();
|
||||
|
||||
Bundle response = ourClient
|
||||
Bundle response = myRestServerR4Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value(CM_URL))
|
||||
|
@ -109,7 +107,7 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
|
||||
ConceptMap resultConceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
MethodOutcome methodOutcome = ourClient
|
||||
MethodOutcome methodOutcome = myRestServerR4Helper.getClient()
|
||||
.update()
|
||||
.resource(resultConceptMap)
|
||||
.withId(resultConceptMap.getIdElement())
|
||||
|
@ -121,22 +119,27 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
assertTrue(!Boolean.TRUE.equals(methodOutcome.getCreated()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportCsvToConceptMapCommand() throws FHIRException {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testImportCsvToConceptMapCommand(boolean theIncludeTls) throws Exception {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
File fileToImport = new File(classLoader.getResource(FILENAME).getFile());
|
||||
ImportCsvToConceptMapCommandR4Test.file = fileToImport.getAbsolutePath();
|
||||
myFilePath = fileToImport.getAbsolutePath();
|
||||
|
||||
App.main(new String[]{"import-csv-to-conceptmap",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", file,
|
||||
"-l"});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ImportCsvToConceptMapCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", myFilePath,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
Bundle response = ourClient
|
||||
Bundle response = myRestServerR4Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value(CM_URL))
|
||||
|
@ -145,9 +148,9 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
|
||||
ConceptMap conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
||||
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/1", conceptMap.getId());
|
||||
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/1", conceptMap.getId());
|
||||
|
||||
assertEquals(CM_URL, conceptMap.getUrl());
|
||||
assertEquals(VS_URL_1, conceptMap.getSourceUriType().getValueAsString());
|
||||
|
@ -323,16 +326,20 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence());
|
||||
assertEquals("3d This is a comment.", target.getComment());
|
||||
|
||||
App.main(new String[]{"import-csv-to-conceptmap",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", file,
|
||||
"-l"});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ImportCsvToConceptMapCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", CM_URL,
|
||||
"-i", VS_URL_1,
|
||||
"-o", VS_URL_2,
|
||||
"-f", myFilePath,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
response = ourClient
|
||||
response = myRestServerR4Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value(CM_URL))
|
||||
|
@ -341,25 +348,30 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
|
||||
conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/2", conceptMap.getId());
|
||||
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/2", conceptMap.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportCsvToConceptMapCommandWithByteOrderMark() throws FHIRException {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testImportCsvToConceptMapCommandWithByteOrderMark(boolean theIncludeTls) throws FHIRException {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
File fileToImport = new File(classLoader.getResource("loinc-to-phenx.csv").getFile());
|
||||
ImportCsvToConceptMapCommandR4Test.file = fileToImport.getAbsolutePath();
|
||||
myFilePath = fileToImport.getAbsolutePath();
|
||||
|
||||
App.main(new String[]{"import-csv-to-conceptmap",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", "http://loinc.org/cm/loinc-to-phenx",
|
||||
"-i", "http://loinc.org",
|
||||
"-o", "http://phenxtoolkit.org",
|
||||
"-f", file,
|
||||
"-l"});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ImportCsvToConceptMapCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", "http://loinc.org/cm/loinc-to-phenx",
|
||||
"-i", "http://loinc.org",
|
||||
"-o", "http://phenxtoolkit.org",
|
||||
"-f", myFilePath,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
Bundle response = ourClient
|
||||
Bundle response = myRestServerR4Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value("http://loinc.org/cm/loinc-to-phenx"))
|
||||
|
@ -368,9 +380,9 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
|
||||
ConceptMap conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
||||
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/1", conceptMap.getId());
|
||||
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/1", conceptMap.getId());
|
||||
|
||||
assertEquals("http://loinc.org/cm/loinc-to-phenx", conceptMap.getUrl());
|
||||
assertEquals("http://loinc.org", conceptMap.getSourceUriType().getValueAsString());
|
||||
|
@ -398,16 +410,20 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
assertEquals(ConceptMapEquivalence.EQUIVALENT, target.getEquivalence());
|
||||
assertNull(target.getComment());
|
||||
|
||||
App.main(new String[]{"import-csv-to-conceptmap",
|
||||
"-v", ourVersion,
|
||||
"-t", ourBase,
|
||||
"-u", "http://loinc.org/cm/loinc-to-phenx",
|
||||
"-i", "http://loinc.org",
|
||||
"-o", "http://phenxtoolkit.org",
|
||||
"-f", file,
|
||||
"-l"});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ImportCsvToConceptMapCommand.COMMAND,
|
||||
"-v", myVersion,
|
||||
"-u", "http://loinc.org/cm/loinc-to-phenx",
|
||||
"-i", "http://loinc.org",
|
||||
"-o", "http://phenxtoolkit.org",
|
||||
"-f", myFilePath,
|
||||
"-l"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
response = ourClient
|
||||
response = myRestServerR4Helper.getClient()
|
||||
.search()
|
||||
.forResource(ConceptMap.class)
|
||||
.where(ConceptMap.URL.matches().value("http://loinc.org/cm/loinc-to-phenx"))
|
||||
|
@ -416,34 +432,6 @@ public class ImportCsvToConceptMapCommandR4Test {
|
|||
|
||||
conceptMap = (ConceptMap) response.getEntryFirstRep().getResource();
|
||||
|
||||
assertEquals("http://localhost:" + ourPort + "/ConceptMap/1/_history/2", conceptMap.getId());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
ServletHandler servletHandler = new ServletHandler();
|
||||
|
||||
restfulServer = new RestfulServer(ourCtx);
|
||||
restfulServer.registerInterceptor(new VerboseLoggingInterceptor());
|
||||
restfulServer.setResourceProviders(new HashMapResourceProviderConceptMapR4(ourCtx));
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder(restfulServer);
|
||||
servletHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(servletHandler);
|
||||
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
ourBase = "http://localhost:" + ourPort;
|
||||
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourBase);
|
||||
assertEquals(myRestServerR4Helper.getBase() + "/ConceptMap/1/_history/2", conceptMap.getId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,15 @@ package ca.uhn.fhir.cli;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
|
||||
import ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseParameters;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
|
@ -17,7 +20,7 @@ import java.io.PrintStream;
|
|||
import static ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider.RESP_PARAM_SUCCESS;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
@ -31,8 +34,9 @@ class ReindexTerminologyCommandTest {
|
|||
private BaseJpaSystemProvider<?, ?> myProvider = spy(new BaseJpaSystemProvider<>());
|
||||
|
||||
@RegisterExtension
|
||||
public final RestfulServerExtension myRestfulServerExtension =
|
||||
new RestfulServerExtension(myContext, myProvider);
|
||||
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
|
||||
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
|
||||
|
@ -41,65 +45,89 @@ class ReindexTerminologyCommandTest {
|
|||
System.setProperty("test", "true");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach(){
|
||||
myRestServerR4Helper.registerProvider(myProvider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProviderMethodInvoked() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testProviderMethodInvoked(boolean theIncludeTls) {
|
||||
System.setOut(new PrintStream(outputStreamCaptor));
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, true);
|
||||
doReturn(retVal).when(myProvider).reindexTerminology(any());
|
||||
|
||||
App.main(new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4",
|
||||
"-t", myRestfulServerExtension.getBaseUrl()
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
assertThat(outputStreamCaptor.toString().trim(),
|
||||
outputStreamCaptor.toString().trim(), containsString("<valueBoolean value=\"true\"/>"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoVersionThrows() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testNoVersionThrows(boolean theIncludeTls) {
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, true);
|
||||
doReturn(retVal).when(myProvider).reindexTerminology(any());
|
||||
|
||||
Error thrown = assertThrows(Error.class, () ->
|
||||
App.main(new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-t", myRestfulServerExtension.getBaseUrl()
|
||||
})
|
||||
);
|
||||
assertThat(thrown.getMessage(), containsString("Missing required option: v"));
|
||||
try {
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
fail();
|
||||
} catch (Error e) {
|
||||
assertThat(e.getMessage(), containsString("Missing required option: v"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoTargetThrows() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testNoTargetThrows(boolean theIncludeTls) {
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, true);
|
||||
doReturn(retVal).when(myProvider).reindexTerminology(any());
|
||||
|
||||
Error thrown = assertThrows(Error.class, () ->
|
||||
App.main(new String[]{ReindexTerminologyCommand.REINDEX_TERMINOLOGY, "-v", "r4"})
|
||||
);
|
||||
assertThat(thrown.getMessage(), containsString("Missing required option: t"));
|
||||
try {
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4"
|
||||
},
|
||||
null, theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
fail();
|
||||
} catch (Error e) {
|
||||
assertThat(e.getMessage(), containsString("Missing required option: t"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHandleUnexpectedResponse() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testHandleUnexpectedResponse(boolean theIncludeTls) {
|
||||
System.setOut(new PrintStream(outputStreamCaptor));
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
|
||||
doReturn(retVal).when(myProvider).reindexTerminology(any());
|
||||
|
||||
App.main(new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4",
|
||||
"-t", myRestfulServerExtension.getBaseUrl()
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
assertThat(outputStreamCaptor.toString().trim(),
|
||||
outputStreamCaptor.toString().trim(), containsString("<valueBoolean value=\"false\"/>"));
|
||||
|
@ -110,8 +138,9 @@ class ReindexTerminologyCommandTest {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHandleServiceError() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
public void testHandleServiceError(boolean theIncludeTls) {
|
||||
System.setOut(new PrintStream(outputStreamCaptor));
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(myContext);
|
||||
ParametersUtil.addParameterToParametersBoolean(myContext, retVal, RESP_PARAM_SUCCESS, false);
|
||||
|
@ -119,11 +148,13 @@ class ReindexTerminologyCommandTest {
|
|||
"Freetext service is not configured. Operation didn't run.");
|
||||
doReturn(retVal).when(myProvider).reindexTerminology(any());
|
||||
|
||||
App.main(new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4",
|
||||
"-t", myRestfulServerExtension.getBaseUrl()
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
ReindexTerminologyCommand.REINDEX_TERMINOLOGY,
|
||||
"-v", "r4"
|
||||
},
|
||||
"-t", theIncludeTls, myRestServerR4Helper
|
||||
));
|
||||
|
||||
assertThat(outputStreamCaptor.toString().trim(),
|
||||
outputStreamCaptor.toString().trim(), containsString("<valueBoolean value=\"false\"/>"));
|
||||
|
|
|
@ -5,20 +5,21 @@ import ca.uhn.fhir.i18n.Msg;
|
|||
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.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.BaseRestServerHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.TestInfo;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
|
@ -69,8 +70,6 @@ public class UploadTerminologyCommandTest {
|
|||
private final String myICD10URL = "http://hl7.org/fhir/sid/icd-10-cm";
|
||||
private final String myICD10FileName = new File("src/test/resources").getAbsolutePath() + "/icd10cm_tabular_2021.xml";
|
||||
private File myICD10File = new File(myICD10FileName);
|
||||
private Server myServer;
|
||||
private int myPort;
|
||||
|
||||
@Mock
|
||||
protected ITermLoaderSvc myTermLoaderSvc;
|
||||
|
@ -82,35 +81,43 @@ public class UploadTerminologyCommandTest {
|
|||
System.setProperty("test", "true");
|
||||
}
|
||||
|
||||
static Stream<String> paramsProvider() {
|
||||
return Stream.of(FHIR_VERSION_DSTU3, FHIR_VERSION_R4);
|
||||
static Stream<Arguments> paramsProvider(){
|
||||
return Stream.of(
|
||||
// [0] theFhirVersion, [1] theIncludeTls
|
||||
Arguments.arguments(FHIR_VERSION_DSTU3, true),
|
||||
Arguments.arguments(FHIR_VERSION_DSTU3, false),
|
||||
Arguments.arguments(FHIR_VERSION_R4, true),
|
||||
Arguments.arguments(FHIR_VERSION_R4, false)
|
||||
);
|
||||
}
|
||||
|
||||
@RegisterExtension
|
||||
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
|
||||
@RegisterExtension
|
||||
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
private BaseRestServerHelper myBaseRestServerHelper;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach(TestInfo testInfo) throws Exception {
|
||||
writeConceptAndHierarchyFiles();
|
||||
if (testInfo.getDisplayName().endsWith(FHIR_VERSION_DSTU3)) {
|
||||
if (testInfo.getDisplayName().contains(FHIR_VERSION_DSTU3)) {
|
||||
myCtx = FhirContext.forDstu3();
|
||||
} else if (testInfo.getDisplayName().endsWith(FHIR_VERSION_R4)) {
|
||||
myRestServerDstu3Helper.registerProvider(new TerminologyUploaderProvider(myCtx, myTermLoaderSvc));
|
||||
myBaseRestServerHelper = myRestServerDstu3Helper;
|
||||
} else if (testInfo.getDisplayName().contains(FHIR_VERSION_R4)) {
|
||||
myCtx = FhirContext.forR4();
|
||||
myRestServerR4Helper.registerProvider(new TerminologyUploaderProvider(myCtx, myTermLoaderSvc));
|
||||
myBaseRestServerHelper = myRestServerR4Helper;
|
||||
} else {
|
||||
fail("Unknown FHIR Version param provided: " + testInfo.getDisplayName());
|
||||
}
|
||||
myServer = new Server(0);
|
||||
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(myCtx);
|
||||
servlet.registerProvider(provider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
myServer.setHandler(proxyHandler);
|
||||
JettyUtil.startServer(myServer);
|
||||
myPort = JettyUtil.getPortForStartedServer(myServer);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() throws Exception {
|
||||
JettyUtil.closeServer(myServer);
|
||||
FileUtils.deleteQuietly(myConceptsFile);
|
||||
FileUtils.deleteQuietly(myHierarchyFile);
|
||||
FileUtils.deleteQuietly(myCodeSystemFile);
|
||||
|
@ -122,7 +129,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaAdd(String theFhirVersion) throws IOException {
|
||||
public void testDeltaAdd(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
|
||||
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
|
||||
|
@ -131,15 +138,17 @@ public class UploadTerminologyCommandTest {
|
|||
fail("Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadDeltaAdd(eq("http://foo"), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -151,7 +160,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaAddUsingCodeSystemResource(String theFhirVersion) throws IOException {
|
||||
public void testDeltaAddUsingCodeSystemResource(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
|
||||
org.hl7.fhir.dstu3.model.CodeSystem cs = new org.hl7.fhir.dstu3.model.CodeSystem();
|
||||
|
@ -170,14 +179,16 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myCodeSystemFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-u", "http://foo",
|
||||
"-d", myCodeSystemFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadDeltaAdd(eq("http://foo"), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -190,7 +201,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaAddInvalidResource(String theFhirVersion) throws IOException {
|
||||
public void testDeltaAddInvalidResource(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
|
||||
org.hl7.fhir.dstu3.model.Patient patient = new org.hl7.fhir.dstu3.model.Patient();
|
||||
|
@ -208,14 +219,16 @@ public class UploadTerminologyCommandTest {
|
|||
}
|
||||
|
||||
try {
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myCodeSystemFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-u", "http://foo",
|
||||
"-d", myCodeSystemFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
fail();
|
||||
} catch (Error e) {
|
||||
assertThat(e.toString(), containsString("HTTP 400 Bad Request: " + Msg.code(362) + "Request has parameter codeSystem of type Patient but method expects type CodeSystem"));
|
||||
|
@ -224,20 +237,23 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaAddInvalidFileType(String theFhirVersion) throws IOException {
|
||||
public void testDeltaAddInvalidFileType(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
try (FileWriter w = new FileWriter(myTextFileName, false)) {
|
||||
w.append("Help I'm a Bug");
|
||||
}
|
||||
|
||||
try {
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myTextFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-u", "http://foo",
|
||||
"-d", myTextFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
fail();
|
||||
} catch (Error e) {
|
||||
assertThat(e.toString(), containsString("Don't know how to handle file:"));
|
||||
|
@ -246,19 +262,21 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaAddUsingCompressedFile(String theFhirVersion) throws IOException {
|
||||
public void testDeltaAddUsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
writeArchiveFile(myConceptsFile, myHierarchyFile);
|
||||
|
||||
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myArchiveFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-u", "http://foo",
|
||||
"-d", myArchiveFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadDeltaAdd(eq("http://foo"), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -270,17 +288,20 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaAddInvalidFileName(String theFhirVersion) throws IOException {
|
||||
public void testDeltaAddInvalidFileName(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
try {
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName + "/foo.csv",
|
||||
"-d", myHierarchyFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "ADD",
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName + "/foo.csv",
|
||||
"-d", myHierarchyFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
fail();
|
||||
} catch (Error e) {
|
||||
assertThat(e.toString(), Matchers.containsString("FileNotFoundException: target/concepts.csv/foo.csv"));
|
||||
}
|
||||
|
@ -288,7 +309,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testDeltaRemove(String theFhirVersion) throws IOException {
|
||||
public void testDeltaRemove(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
when(myTermLoaderSvc.loadDeltaRemove(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
|
||||
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
|
||||
|
@ -297,15 +318,17 @@ public class UploadTerminologyCommandTest {
|
|||
fail("Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "REMOVE",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "REMOVE",
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadDeltaRemove(eq("http://foo"), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -317,7 +340,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testSnapshot(String theFhirVersion) throws IOException {
|
||||
public void testSnapshot(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
|
||||
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
|
||||
|
@ -326,15 +349,17 @@ public class UploadTerminologyCommandTest {
|
|||
fail("Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "SNAPSHOT",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "SNAPSHOT",
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadCustom(any(), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -346,7 +371,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testPropertiesFile(String theFhirVersion) throws IOException {
|
||||
public void testPropertiesFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
try (FileWriter w = new FileWriter(myPropertiesFileName, false)) {
|
||||
w.append("a=b\n");
|
||||
}
|
||||
|
@ -359,14 +384,16 @@ public class UploadTerminologyCommandTest {
|
|||
fail("Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "SNAPSHOT",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myPropertiesFileName,
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "SNAPSHOT",
|
||||
"-u", "http://foo",
|
||||
"-d", myPropertiesFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadCustom(any(), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -378,7 +405,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testSnapshotLargeFile(String theFhirVersion) throws IOException {
|
||||
public void testSnapshotLargeFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
UploadTerminologyCommand.setTransferSizeLimitForUnitTest(10);
|
||||
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
|
@ -389,15 +416,17 @@ public class UploadTerminologyCommandTest {
|
|||
fail("Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "SNAPSHOT",
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-m", "SNAPSHOT",
|
||||
"-u", "http://foo",
|
||||
"-d", myConceptsFileName,
|
||||
"-d", myHierarchyFileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadCustom(any(), myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
@ -409,7 +438,7 @@ public class UploadTerminologyCommandTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("paramsProvider")
|
||||
public void testUploadICD10UsingCompressedFile(String theFhirVersion) throws IOException {
|
||||
public void testUploadICD10UsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException {
|
||||
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
|
||||
when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
|
||||
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
|
||||
|
@ -418,13 +447,15 @@ public class UploadTerminologyCommandTest {
|
|||
fail("Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
|
||||
App.main(new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-t", "http://localhost:" + myPort,
|
||||
"-u", myICD10URL,
|
||||
"-d", myICD10FileName
|
||||
});
|
||||
App.main(myTlsAuthenticationTestHelper.createBaseRequestGeneratingCommandArgs(
|
||||
new String[]{
|
||||
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
|
||||
"-v", theFhirVersion,
|
||||
"-u", myICD10URL,
|
||||
"-d", myICD10FileName
|
||||
},
|
||||
"-t", theIncludeTls, myBaseRestServerHelper
|
||||
));
|
||||
|
||||
verify(myTermLoaderSvc, times(1)).loadIcd10cm(myDescriptorListCaptor.capture(), any());
|
||||
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
package ca.uhn.fhir.cli.client;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class HapiFhirCliRestfulClientFactoryTest extends BaseFhirVersionParameterizedTest{
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) throws Exception {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
HapiFhirCliRestfulClientFactory clientFactory = new HapiFhirCliRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
HttpClient client = clientFactory.getNativeHttpClient();
|
||||
|
||||
HttpUriRequest request = new HttpGet(fhirVersionParams.getPatientEndpoint());
|
||||
HttpResponse response = client.execute(request);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
|
||||
String json = EntityUtils.toString(response.getEntity());
|
||||
IBaseResource bundle = fhirVersionParams.parseResource(json);
|
||||
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttps(FhirVersionEnum theFhirVersion) throws Exception {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
HapiFhirCliRestfulClientFactory clientFactory = new HapiFhirCliRestfulClientFactory(fhirVersionParams.getFhirContext(), getTlsAuthentication());
|
||||
HttpClient authenticatedClient = clientFactory.getNativeHttpClient();
|
||||
|
||||
HttpUriRequest request = new HttpGet(fhirVersionParams.getSecuredPatientEndpoint());
|
||||
HttpResponse response = authenticatedClient.execute(request);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
|
||||
String json = EntityUtils.toString(response.getEntity());
|
||||
IBaseResource bundle = fhirVersionParams.parseResource(json);
|
||||
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
HapiFhirCliRestfulClientFactory clientFactory = new HapiFhirCliRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
HttpClient unauthenticatedClient = clientFactory.getNativeHttpClient();
|
||||
|
||||
try{
|
||||
HttpUriRequest request = new HttpGet(fhirVersionParams.getSecuredPatientEndpoint());
|
||||
unauthenticatedClient.execute(request);
|
||||
fail();
|
||||
}
|
||||
catch(Exception e){
|
||||
assertEquals(SSLHandshakeException.class, e.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttp(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String base = fhirVersionParams.getBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new HapiFhirCliRestfulClientFactory(context));
|
||||
IBaseResource bundle = context.newRestfulGenericClient(base).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttps(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String secureBase = fhirVersionParams.getSecureBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new HapiFhirCliRestfulClientFactory(context, getTlsAuthentication()));
|
||||
IBaseResource bundle = context.newRestfulGenericClient(secureBase).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String secureBase = fhirVersionParams.getSecureBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new HapiFhirCliRestfulClientFactory(context));
|
||||
try {
|
||||
context.newRestfulGenericClient(secureBase).search().forResource("Patient").execute();
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.getMessage().contains("HAPI-1357: Failed to retrieve the server metadata statement during client initialization"));
|
||||
assertEquals(SSLHandshakeException.class, e.getCause().getCause().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientProtocolChanges(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
String secureBase = fhirVersionParams.getSecureBase();
|
||||
String base = fhirVersionParams.getBase();
|
||||
|
||||
// https
|
||||
HapiFhirCliRestfulClientFactory restfulClientFactory = new HapiFhirCliRestfulClientFactory(context, getTlsAuthentication());
|
||||
context.setRestfulClientFactory(restfulClientFactory);
|
||||
IBaseResource bundle = context.newRestfulGenericClient(secureBase).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
|
||||
// http
|
||||
restfulClientFactory.useHttp();
|
||||
bundle = context.newRestfulGenericClient(base).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
|
||||
// https
|
||||
restfulClientFactory.useHttps(getTlsAuthentication());
|
||||
bundle = context.newRestfulGenericClient(secureBase).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testSetHttpClient(FhirVersionEnum theFhirVersion){
|
||||
try {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
FhirContext fhirContext = fhirVersionParams.getFhirContext();
|
||||
HapiFhirCliRestfulClientFactory hapiFhirCliRestfulClientFactory = new HapiFhirCliRestfulClientFactory(fhirContext);
|
||||
hapiFhirCliRestfulClientFactory.setHttpClient(new Object());
|
||||
} catch (UnsupportedOperationException e){
|
||||
assertEquals(Msg.code(2119), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testSetProxy(FhirVersionEnum theFhirVersion){
|
||||
try {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
FhirContext fhirContext = fhirVersionParams.getFhirContext();
|
||||
HapiFhirCliRestfulClientFactory hapiFhirCliRestfulClientFactory = new HapiFhirCliRestfulClientFactory(fhirContext);
|
||||
hapiFhirCliRestfulClientFactory.setProxy("proxy", 1);
|
||||
} catch (UnsupportedOperationException e){
|
||||
assertEquals(Msg.code(2120), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -57,6 +57,12 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Unit test dependencies -->
|
||||
<dependency>
|
||||
|
|
|
@ -27,12 +27,15 @@ import java.util.concurrent.TimeUnit;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A Restful client factory based on OkHttp.
|
||||
|
@ -53,7 +56,7 @@ public class OkHttpRestfulClientFactory extends RestfulClientFactory {
|
|||
|
||||
@Override
|
||||
protected IHttpClient getHttpClient(String theServerBase) {
|
||||
return new OkHttpRestfulClient(getNativeClient(), new StringBuilder(theServerBase), null, null, null, null);
|
||||
return getHttpClient(new StringBuilder(theServerBase), null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,27 +64,27 @@ public class OkHttpRestfulClientFactory extends RestfulClientFactory {
|
|||
myNativeClient = null;
|
||||
}
|
||||
|
||||
public synchronized Call.Factory getNativeClient() {
|
||||
if (myNativeClient == null) {
|
||||
myNativeClient = new OkHttpClient()
|
||||
public synchronized Call.Factory getNativeClient() {
|
||||
if (myNativeClient == null) {
|
||||
myNativeClient = new OkHttpClient()
|
||||
.newBuilder()
|
||||
.connectTimeout(getConnectTimeout(), TimeUnit.MILLISECONDS)
|
||||
.readTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
|
||||
.readTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(getSocketTimeout(), TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
return myNativeClient;
|
||||
}
|
||||
return myNativeClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpClient getHttpClient(StringBuilder theUrl,
|
||||
Map<String, List<String>> theIfNoneExistParams,
|
||||
String theIfNoneExistString,
|
||||
RequestTypeEnum theRequestType,
|
||||
List<Header> theHeaders) {
|
||||
return new OkHttpRestfulClient(getNativeClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
|
||||
}
|
||||
@Override
|
||||
public IHttpClient getHttpClient(StringBuilder theUrl,
|
||||
Map<String, List<String>> theIfNoneExistParams,
|
||||
String theIfNoneExistString,
|
||||
RequestTypeEnum theRequestType,
|
||||
List<Header> theHeaders) {
|
||||
return new OkHttpRestfulClient(getNativeClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only accepts clients of type {@link OkHttpClient}
|
||||
|
|
|
@ -1,59 +1,136 @@
|
|||
package ca.uhn.fhir.okhttp;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
|
||||
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class OkHttpRestfulClientFactoryTest {
|
||||
public class OkHttpRestfulClientFactoryTest extends BaseFhirVersionParameterizedTest {
|
||||
|
||||
private OkHttpRestfulClientFactory clientFactory;
|
||||
private OkHttpRestfulClientFactory clientFactory;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
clientFactory = new OkHttpRestfulClientFactory();
|
||||
}
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
clientFactory = new OkHttpRestfulClientFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNativeClient_noClientSet_returnsADefault() throws Exception {
|
||||
Call.Factory actualNativeClient = clientFactory.getNativeClient();
|
||||
@Test
|
||||
public void testGetNativeClient_noClientSet_returnsADefault() throws Exception {
|
||||
Call.Factory actualNativeClient = clientFactory.getNativeClient();
|
||||
|
||||
assertNotNull(actualNativeClient);
|
||||
}
|
||||
assertNotNull(actualNativeClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNativeClient_noProxySet_defaultHasNoProxySet() throws Exception {
|
||||
OkHttpClient actualNativeClient = (OkHttpClient) clientFactory.getNativeClient();
|
||||
@Test
|
||||
public void testGetNativeClient_noProxySet_defaultHasNoProxySet() throws Exception {
|
||||
OkHttpClient actualNativeClient = (OkHttpClient) clientFactory.getNativeClient();
|
||||
|
||||
assertEquals(null, actualNativeClient.proxy());
|
||||
}
|
||||
assertEquals(null, actualNativeClient.proxy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHttpClient() {
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder().writeTimeout(5000, TimeUnit.MILLISECONDS).build();
|
||||
@Test
|
||||
public void testSetHttpClient() {
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder().writeTimeout(5000, TimeUnit.MILLISECONDS).build();
|
||||
|
||||
clientFactory.setHttpClient(okHttpClient);
|
||||
clientFactory.setHttpClient(okHttpClient);
|
||||
|
||||
assertSame(okHttpClient, clientFactory.getNativeClient());
|
||||
}
|
||||
assertSame(okHttpClient, clientFactory.getNativeClient());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSocketTimeout() {
|
||||
clientFactory.setSocketTimeout(1515);
|
||||
|
||||
assertEquals(1515, ((OkHttpClient)clientFactory.getNativeClient()).readTimeoutMillis());
|
||||
assertEquals(1515, ((OkHttpClient)clientFactory.getNativeClient()).writeTimeoutMillis());
|
||||
assertEquals(1515, ((OkHttpClient) clientFactory.getNativeClient()).readTimeoutMillis());
|
||||
assertEquals(1515, ((OkHttpClient) clientFactory.getNativeClient()).writeTimeoutMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectTimeout() {
|
||||
clientFactory.setConnectTimeout(1516);
|
||||
|
||||
assertEquals(1516, ((OkHttpClient)clientFactory.getNativeClient()).connectTimeoutMillis());
|
||||
assertEquals(1516, ((OkHttpClient) clientFactory.getNativeClient()).connectTimeoutMillis());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) throws Exception {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
OkHttpRestfulClientFactory clientFactory = new OkHttpRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
OkHttpClient client = (OkHttpClient) clientFactory.getNativeClient();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(fhirVersionParams.getPatientEndpoint())
|
||||
.build();
|
||||
|
||||
Response response = client.newCall(request).execute();
|
||||
assertEquals(200, response.code());
|
||||
String json = response.body().string();
|
||||
IBaseResource bundle = fhirVersionParams.getFhirContext().newJsonParser().parseResource(json);
|
||||
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
OkHttpRestfulClientFactory clientFactory = new OkHttpRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
OkHttpClient unauthenticatedClient = (OkHttpClient) clientFactory.getNativeClient();
|
||||
|
||||
try {
|
||||
Request request = new Request.Builder()
|
||||
.url(fhirVersionParams.getSecuredPatientEndpoint())
|
||||
.build();
|
||||
unauthenticatedClient.newCall(request).execute();
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(SSLHandshakeException.class, e.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttp(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String base = fhirVersionParams.getBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new OkHttpRestfulClientFactory(context));
|
||||
IBaseResource bundle = context.newRestfulGenericClient(base).search().forResource("Patient").execute();
|
||||
assertEquals(theFhirVersion, bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testGenericClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
String secureBase = fhirVersionParams.getSecureBase();
|
||||
FhirContext context = fhirVersionParams.getFhirContext();
|
||||
context.setRestfulClientFactory(new OkHttpRestfulClientFactory(context));
|
||||
try {
|
||||
context.newRestfulGenericClient(secureBase).search().forResource("Patient").execute();
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.getMessage().contains("HAPI-1357: Failed to retrieve the server metadata statement during client initialization"));
|
||||
assertEquals(SSLHandshakeException.class, e.getCause().getCause().getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@ package ca.uhn.fhir.rest.client.apache;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
|
@ -37,11 +37,11 @@ import org.apache.http.impl.client.HttpClients;
|
|||
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* A Restful Factory to create clients, requests and responses based on the Apache httpclient library.
|
||||
|
@ -71,25 +71,19 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected synchronized ApacheHttpClient getHttpClient(String theServerBase) {
|
||||
return new ApacheHttpClient(getNativeHttpClient(), new StringBuilder(theServerBase), null, null, null, null);
|
||||
protected synchronized IHttpClient getHttpClient(String theServerBase) {
|
||||
return getHttpClient(new StringBuilder(theServerBase), null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams,
|
||||
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
|
||||
return new ApacheHttpClient(getNativeHttpClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType,
|
||||
theHeaders);
|
||||
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
|
||||
return new ApacheHttpClient(getNativeHttpClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
|
||||
}
|
||||
|
||||
public HttpClient getNativeHttpClient() {
|
||||
if (myHttpClient == null) {
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000,
|
||||
TimeUnit.MILLISECONDS);
|
||||
connectionManager.setMaxTotal(getPoolMaxTotal());
|
||||
connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
|
||||
|
||||
//TODO: Use of a deprecated method should be resolved.
|
||||
RequestConfig defaultRequestConfig =
|
||||
RequestConfig.custom()
|
||||
|
@ -101,12 +95,16 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
|
|||
.build();
|
||||
|
||||
HttpClientBuilder builder = getHttpClientBuilder()
|
||||
.useSystemProperties()
|
||||
.setConnectionManager(connectionManager)
|
||||
.setDefaultRequestConfig(defaultRequestConfig)
|
||||
.disableCookieManagement();
|
||||
.useSystemProperties()
|
||||
.setDefaultRequestConfig(defaultRequestConfig)
|
||||
.disableCookieManagement();
|
||||
|
||||
if (myProxy != null && StringUtils.isNotBlank(getProxyUsername()) && StringUtils.isNotBlank(getProxyPassword())) {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
connectionManager.setMaxTotal(getPoolMaxTotal());
|
||||
connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
|
||||
builder.setConnectionManager(connectionManager);
|
||||
|
||||
if (myProxy != null && isNotBlank(getProxyUsername()) && isNotBlank(getProxyPassword())) {
|
||||
CredentialsProvider credsProvider = new BasicCredentialsProvider();
|
||||
credsProvider.setCredentials(new AuthScope(myProxy.getHostName(), myProxy.getPort()),
|
||||
new UsernamePasswordCredentials(getProxyUsername(), getProxyPassword()));
|
||||
|
|
|
@ -19,25 +19,35 @@ package ca.uhn.fhir.rest.client.impl;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
|
||||
import ca.uhn.fhir.rest.client.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
|
||||
import ca.uhn.fhir.rest.client.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for a REST client factory implementation
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
package ca.uhn.fhir.rest.client.tls;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.tls.KeyStoreInfo;
|
||||
import ca.uhn.fhir.tls.PathType;
|
||||
import ca.uhn.fhir.tls.StoreInfo;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import ca.uhn.fhir.tls.TrustStoreInfo;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
|
||||
import org.apache.http.ssl.PrivateKeyStrategy;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class TlsAuthenticationSvc {
|
||||
|
||||
private TlsAuthenticationSvc(){}
|
||||
|
||||
public static SSLContext createSslContext(@Nonnull TlsAuthentication theTlsAuthentication){
|
||||
Validate.notNull(theTlsAuthentication, "theTlsAuthentication cannot be null");
|
||||
|
||||
try{
|
||||
SSLContextBuilder contextBuilder = SSLContexts.custom();
|
||||
|
||||
if(theTlsAuthentication.getKeyStoreInfo().isPresent()){
|
||||
KeyStoreInfo keyStoreInfo = theTlsAuthentication.getKeyStoreInfo().get();
|
||||
PrivateKeyStrategy privateKeyStrategy = null;
|
||||
if(isNotBlank(keyStoreInfo.getAlias())){
|
||||
privateKeyStrategy = (aliases, socket) -> keyStoreInfo.getAlias();
|
||||
}
|
||||
KeyStore keyStore = createKeyStore(keyStoreInfo);
|
||||
contextBuilder.loadKeyMaterial(keyStore, keyStoreInfo.getKeyPass(), privateKeyStrategy);
|
||||
}
|
||||
|
||||
if(theTlsAuthentication.getTrustStoreInfo().isPresent()){
|
||||
TrustStoreInfo trustStoreInfo = theTlsAuthentication.getTrustStoreInfo().get();
|
||||
KeyStore trustStore = createKeyStore(trustStoreInfo);
|
||||
contextBuilder.loadTrustMaterial(trustStore, TrustSelfSignedStrategy.INSTANCE);
|
||||
}
|
||||
|
||||
return contextBuilder.build();
|
||||
}
|
||||
catch (Exception e){
|
||||
throw new TlsAuthenticationException(Msg.code(2102)+"Failed to create SSLContext", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyStore createKeyStore(StoreInfo theStoreInfo){
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance(theStoreInfo.getType().toString());
|
||||
|
||||
if(PathType.RESOURCE.equals(theStoreInfo.getPathType())){
|
||||
try(InputStream inputStream = TlsAuthenticationSvc.class.getResourceAsStream(theStoreInfo.getFilePath())){
|
||||
validateKeyStoreExists(inputStream);
|
||||
keyStore.load(inputStream, theStoreInfo.getStorePass());
|
||||
}
|
||||
}
|
||||
else if(PathType.FILE.equals(theStoreInfo.getPathType())){
|
||||
try(InputStream inputStream = new FileInputStream(theStoreInfo.getFilePath())){
|
||||
validateKeyStoreExists(inputStream);
|
||||
keyStore.load(inputStream, theStoreInfo.getStorePass());
|
||||
}
|
||||
}
|
||||
return keyStore;
|
||||
}
|
||||
catch (Exception e){
|
||||
throw new TlsAuthenticationException(Msg.code(2103)+"Failed to create KeyStore", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateKeyStoreExists(InputStream theInputStream){
|
||||
if(theInputStream == null){
|
||||
throw new TlsAuthenticationException(Msg.code(2116)+"Keystore does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
public static X509TrustManager createTrustManager(Optional<TrustStoreInfo> theTrustStoreInfo) {
|
||||
try {
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
if (theTrustStoreInfo.isEmpty()) {
|
||||
trustManagerFactory.init((KeyStore) null); // Load Trust Manager Factory with default Java truststore
|
||||
}
|
||||
else {
|
||||
TrustStoreInfo trustStoreInfo = theTrustStoreInfo.get();
|
||||
KeyStore trustStore = createKeyStore(trustStoreInfo);
|
||||
trustManagerFactory.init(trustStore);
|
||||
}
|
||||
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
|
||||
if (trustManager instanceof X509TrustManager) {
|
||||
return (X509TrustManager) trustManager;
|
||||
}
|
||||
}
|
||||
throw new TlsAuthenticationException(Msg.code(2104)+"Could not find X509TrustManager");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TlsAuthenticationException(Msg.code(2105)+"Failed to create X509TrustManager");
|
||||
}
|
||||
}
|
||||
|
||||
public static HostnameVerifier createHostnameVerifier(Optional<TrustStoreInfo> theTrustStoreInfo){
|
||||
return theTrustStoreInfo.isPresent() ? new DefaultHostnameVerifier() : new NoopHostnameVerifier();
|
||||
}
|
||||
|
||||
public static class TlsAuthenticationException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1l;
|
||||
|
||||
public TlsAuthenticationException(String theMessage, Throwable theCause) {
|
||||
super(theMessage, theCause);
|
||||
}
|
||||
|
||||
public TlsAuthenticationException(String theMessage) {
|
||||
super(theMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package ca.uhn.fhir.rest.client.tls;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.tls.KeyStoreInfo;
|
||||
import ca.uhn.fhir.tls.KeyStoreType;
|
||||
import ca.uhn.fhir.tls.PathType;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class StoreInfoTest {
|
||||
|
||||
@Test
|
||||
public void testPathTypeFile(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("file:///my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
assertEquals("/my-file.p12", keyStoreInfo.getFilePath());
|
||||
assertEquals(PathType.FILE, keyStoreInfo.getPathType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathTypeResource(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("classpath:/my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
assertEquals("/my-file.p12", keyStoreInfo.getFilePath());
|
||||
assertEquals(PathType.RESOURCE, keyStoreInfo.getPathType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathTypeInvalid(){
|
||||
try {
|
||||
new KeyStoreInfo("invalid:///my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(Msg.code(2117)+"Invalid path prefix", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileTypeP12(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("file:///my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
assertEquals(KeyStoreType.PKCS12, keyStoreInfo.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileTypeJks(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("file:///my-file.jks", "storePassword" , "keyPassword", "alias");
|
||||
assertEquals(KeyStoreType.JKS, keyStoreInfo.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileTypeInvalid(){
|
||||
try {
|
||||
new KeyStoreInfo("file:///my-file.invalid", "storePassword" , "keyPassword", "alias");
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(Msg.code(2121)+"Invalid KeyStore Type", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStorePass(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("file:///my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
assertTrue(StringUtils.equals("storePassword", new String(keyStoreInfo.getStorePass())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyPass(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("file:///my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
assertTrue(StringUtils.equals("keyPassword", new String(keyStoreInfo.getKeyPass())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlias(){
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("file:///my-file.p12", "storePassword" , "keyPassword", "alias");
|
||||
assertEquals("alias", keyStoreInfo.getAlias());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
package ca.uhn.fhir.rest.client.tls;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.tls.KeyStoreInfo;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import ca.uhn.fhir.tls.TrustStoreInfo;
|
||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class TlsAuthenticationSvcTest {
|
||||
|
||||
private KeyStoreInfo myServerKeyStoreInfo;
|
||||
private TrustStoreInfo myServerTrustStoreInfo;
|
||||
private TlsAuthentication myServerTlsAuthentication;
|
||||
|
||||
private KeyStoreInfo myClientKeyStoreInfo;
|
||||
private TrustStoreInfo myClientTrustStoreInfo;
|
||||
private TlsAuthentication myClientTlsAuthentication;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach(){
|
||||
myServerKeyStoreInfo = new KeyStoreInfo("classpath:/server-keystore.p12", "changeit", "changeit", "server");
|
||||
myServerTrustStoreInfo = new TrustStoreInfo("classpath:/server-truststore.p12", "changeit", "client");
|
||||
myServerTlsAuthentication = new TlsAuthentication(Optional.of(myServerKeyStoreInfo), Optional.of(myServerTrustStoreInfo));
|
||||
|
||||
myClientKeyStoreInfo = new KeyStoreInfo("classpath:/client-keystore.p12", "changeit", "changeit", "client");
|
||||
myClientTrustStoreInfo = new TrustStoreInfo("classpath:/client-truststore.p12", "changeit", "server");
|
||||
myClientTlsAuthentication = new TlsAuthentication(Optional.of(myClientKeyStoreInfo), Optional.of(myClientTrustStoreInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSslContextEmpty(){
|
||||
TlsAuthentication emptyAuthentication = null;
|
||||
try {
|
||||
TlsAuthenticationSvc.createSslContext(emptyAuthentication);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals("theTlsAuthentication cannot be null", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSslContextPresent(){
|
||||
SSLContext result = TlsAuthenticationSvc.createSslContext(myServerTlsAuthentication);
|
||||
assertEquals("TLS", result.getProtocol());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSslContextPresentInvalid(){
|
||||
KeyStoreInfo invalidKeyStoreInfo = new KeyStoreInfo("file:///INVALID.p12", "changeit", "changeit", "server");
|
||||
TlsAuthentication invalidTlsAuthentication = new TlsAuthentication(Optional.of(invalidKeyStoreInfo), Optional.of(myServerTrustStoreInfo));
|
||||
try {
|
||||
TlsAuthenticationSvc.createSslContext(invalidTlsAuthentication);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(Msg.code(2102)+"Failed to create SSLContext", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateKeyStoreP12() throws Exception {
|
||||
KeyStore keyStore = TlsAuthenticationSvc.createKeyStore(myServerKeyStoreInfo);
|
||||
assertNotNull(keyStore.getKey(myServerKeyStoreInfo.getAlias(), myServerKeyStoreInfo.getKeyPass()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateKeyStoreJKS() throws Exception {
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("classpath:/keystore.jks", "changeit", "changeit", "client");
|
||||
KeyStore keyStore = TlsAuthenticationSvc.createKeyStore(keyStoreInfo);
|
||||
assertNotNull(keyStore.getKey(keyStoreInfo.getAlias(), keyStoreInfo.getKeyPass()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateKeyStoreNonExistentFile() {
|
||||
KeyStoreInfo keyStoreInfo = new KeyStoreInfo("classpath:/non-existent.p12", "changeit", "changeit", "server");
|
||||
try {
|
||||
TlsAuthenticationSvc.createKeyStore(keyStoreInfo);
|
||||
fail();
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertEquals(Msg.code(2103)+"Failed to create KeyStore", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTrustStoreJks() throws Exception {
|
||||
TrustStoreInfo trustStoreInfo = new TrustStoreInfo("classpath:/truststore.jks", "changeit", "client");
|
||||
KeyStore keyStore = TlsAuthenticationSvc.createKeyStore(trustStoreInfo);
|
||||
assertNotNull(keyStore.getCertificate(trustStoreInfo.getAlias()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTrustStoreP12() throws Exception {
|
||||
KeyStore keyStore = TlsAuthenticationSvc.createKeyStore(myServerTrustStoreInfo);
|
||||
assertNotNull(keyStore.getCertificate(myServerTrustStoreInfo.getAlias()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTrustStoreNonExistentFile() throws Exception {
|
||||
TrustStoreInfo trustStoreInfo = new TrustStoreInfo("classpath:/non-existent.p12", "changeit", "server");
|
||||
try {
|
||||
TlsAuthenticationSvc.createKeyStore(trustStoreInfo);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(Msg.code(2103)+"Failed to create KeyStore", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTrustManager() throws Exception {
|
||||
X509TrustManager trustManager = TlsAuthenticationSvc.createTrustManager(Optional.of(myClientTrustStoreInfo));
|
||||
KeyStore keyStore = TlsAuthenticationSvc.createKeyStore(myServerKeyStoreInfo);
|
||||
Certificate serverCertificate = keyStore.getCertificate(myServerKeyStoreInfo.getAlias());
|
||||
|
||||
assertEquals(1, trustManager.getAcceptedIssuers().length);
|
||||
assertEquals(serverCertificate, trustManager.getAcceptedIssuers()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTrustManagerNoTrustStore() {
|
||||
// trust manager should contain common certifications if no trust store information is used
|
||||
X509TrustManager trustManager = TlsAuthenticationSvc.createTrustManager(Optional.empty());
|
||||
assertNotEquals(0, trustManager.getAcceptedIssuers().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTrustManagerInvalid() {
|
||||
TrustStoreInfo invalidKeyStoreInfo = new TrustStoreInfo("file:///INVALID.p12", "changeit", "client");
|
||||
try {
|
||||
TlsAuthenticationSvc.createTrustManager(Optional.of(invalidKeyStoreInfo));
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(Msg.code(2105)+"Failed to create X509TrustManager", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateHostnameVerifierEmptyTrustStoreInfo(){
|
||||
Optional<TrustStoreInfo> trustStoreInfo = Optional.empty();
|
||||
HostnameVerifier result = TlsAuthenticationSvc.createHostnameVerifier(trustStoreInfo);
|
||||
assertEquals(NoopHostnameVerifier.class, result.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateHostnameVerifierPresentTrustStoreInfo(){
|
||||
Optional<TrustStoreInfo> trustStoreInfo = Optional.of(myServerTrustStoreInfo);
|
||||
HostnameVerifier result = TlsAuthenticationSvc.createHostnameVerifier(trustStoreInfo);
|
||||
assertEquals(DefaultHostnameVerifier.class, result.getClass());
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
type: add
|
||||
issue: 3776
|
||||
jira: SMILE-651
|
||||
title: "Previously, the HAPI FHIR CLI commands that made HTTP requests could only be used for HTTP endpoints.
|
||||
This feature adds support for HTTPS endpoints by using TLS authentication for `ExampleDataUploader`,
|
||||
`ExportConceptMapToCsvCommand`, `ImportCsvToConceptMapCommand`, `ReindexTerminologyCommand` and
|
||||
`UploadTerminologyCommand`."
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
package ca.uhn.fhir.jaxrs.client;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JAX-RS Server
|
||||
|
@ -28,10 +21,20 @@ import javax.ws.rs.client.ClientBuilder;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.tls.TlsAuthenticationSvc;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A Restful Client Factory, based on Jax Rs
|
||||
|
@ -67,11 +70,11 @@ public class JaxRsRestfulClientFactory extends RestfulClientFactory {
|
|||
myNativeClient = builder.build();
|
||||
}
|
||||
|
||||
if (registeredComponents != null && !registeredComponents.isEmpty()) {
|
||||
for (Class<?> c : registeredComponents) {
|
||||
myNativeClient = myNativeClient.register(c);
|
||||
}
|
||||
}
|
||||
if (registeredComponents != null && !registeredComponents.isEmpty()) {
|
||||
for (Class<?> c : registeredComponents) {
|
||||
myNativeClient = myNativeClient.register(c);
|
||||
}
|
||||
}
|
||||
|
||||
return myNativeClient;
|
||||
}
|
||||
|
@ -116,8 +119,8 @@ public class JaxRsRestfulClientFactory extends RestfulClientFactory {
|
|||
protected synchronized JaxRsHttpClient getHttpClient(String theServerBase) {
|
||||
return new JaxRsHttpClient(getNativeClientClient(), new StringBuilder(theServerBase), null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
protected void resetHttpClient() {
|
||||
if (myNativeClient != null)
|
||||
myNativeClient.close(); // close client to avoid memory leak
|
||||
|
|
|
@ -1,29 +1,44 @@
|
|||
package ca.uhn.fhir.jaxrs.client;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.test.BaseFhirVersionParameterizedTest;
|
||||
import com.google.common.net.MediaType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Created by Sebastien Riviere on 31/07/2017.
|
||||
*/
|
||||
public class JaxRsRestfulClientFactoryTest {
|
||||
public class JaxRsRestfulClientFactoryTest extends BaseFhirVersionParameterizedTest {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(JaxRsRestfulClientFactoryTest.class);
|
||||
private final FhirContext context = FhirContext.forDstu2();
|
||||
private JaxRsRestfulClientFactory factory;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() throws Exception {
|
||||
factory = new JaxRsRestfulClientFactory(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyConstructorTest() {
|
||||
assertNotNull(new JaxRsRestfulClientFactory());
|
||||
|
@ -52,8 +67,39 @@ public class JaxRsRestfulClientFactoryTest {
|
|||
assertThat(result.getConfiguration().getClasses(), hasItem(ca.uhn.fhir.jaxrs.client.MyFilter.class));
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
factory = new JaxRsRestfulClientFactory(context);
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttp(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
JaxRsRestfulClientFactory factory = new JaxRsRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
Client client = factory.getNativeClientClient();
|
||||
|
||||
Response response = client
|
||||
.target(fhirVersionParams.getPatientEndpoint())
|
||||
.request(MediaType.JSON_UTF_8.toString())
|
||||
.get(Response.class);
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
String json = response.readEntity(String.class);
|
||||
IBaseResource bundle = fhirVersionParams.parseResource(json);
|
||||
assertEquals(fhirVersionParams.getFhirVersion(), bundle.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("baseParamsProvider")
|
||||
public void testNativeClientHttpsNoCredentials(FhirVersionEnum theFhirVersion) {
|
||||
FhirVersionParams fhirVersionParams = getFhirVersionParams(theFhirVersion);
|
||||
JaxRsRestfulClientFactory factory = new JaxRsRestfulClientFactory(fhirVersionParams.getFhirContext());
|
||||
Client unauthenticatedClient = factory.getNativeClientClient();
|
||||
|
||||
try {
|
||||
unauthenticatedClient
|
||||
.target(fhirVersionParams.getSecuredPatientEndpoint())
|
||||
.request(MediaType.JSON_UTF_8.toString())
|
||||
.get(Response.class);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertEquals(SSLHandshakeException.class, e.getCause().getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -38,6 +38,12 @@
|
|||
<version>${fhir_core_version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.dstu3</artifactId>
|
||||
<version>${fhir_core_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- General -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -173,6 +179,15 @@
|
|||
<argLine>@{argLine} ${surefire_jvm_args}</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<configuration>
|
||||
<nonFilteredFileExtensions>
|
||||
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
|
||||
</nonFilteredFileExtensions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package ca.uhn.fhir.test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import ca.uhn.fhir.test.utilities.TlsAuthenticationTestHelper;
|
||||
import ca.uhn.fhir.test.utilities.BaseRestServerHelper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerDstu3Helper;
|
||||
import ca.uhn.fhir.test.utilities.RestServerR4Helper;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class BaseFhirVersionParameterizedTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final RestServerR4Helper myRestServerR4Helper = new RestServerR4Helper(true);
|
||||
@RegisterExtension
|
||||
public final RestServerDstu3Helper myRestServerDstu3Helper = new RestServerDstu3Helper(true);
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
protected final FhirContext myR4FhirContext = FhirContext.forR4();
|
||||
protected final FhirContext myDstu3FhirContext = FhirContext.forDstu3();
|
||||
|
||||
protected static Stream<Arguments> baseParamsProvider(){
|
||||
return Stream.of(
|
||||
Arguments.arguments(FhirVersionEnum.R4),
|
||||
Arguments.arguments(FhirVersionEnum.DSTU3)
|
||||
);
|
||||
}
|
||||
|
||||
protected FhirVersionParams getFhirVersionParams(FhirVersionEnum theFhirVersion){
|
||||
switch(theFhirVersion){
|
||||
case R4:
|
||||
return new FhirVersionParams(myRestServerR4Helper, myR4FhirContext);
|
||||
case DSTU3:
|
||||
return new FhirVersionParams(myRestServerDstu3Helper, myDstu3FhirContext);
|
||||
default:
|
||||
throw new RuntimeException(Msg.code(2114)+"Unknown FHIR Version param provided: " + theFhirVersion);
|
||||
}
|
||||
}
|
||||
|
||||
protected TlsAuthentication getTlsAuthentication(){
|
||||
return myTlsAuthenticationTestHelper.getTlsAuthentication();
|
||||
}
|
||||
|
||||
protected class FhirVersionParams {
|
||||
private final BaseRestServerHelper myBaseRestServerHelper;
|
||||
private final FhirContext myFhirContext;
|
||||
private final FhirVersionEnum myFhirVersion;
|
||||
|
||||
public FhirVersionParams(BaseRestServerHelper theBaseRestServerHelper, FhirContext theFhirContext) {
|
||||
myBaseRestServerHelper = theBaseRestServerHelper;
|
||||
myFhirContext = theFhirContext;
|
||||
myFhirVersion = theFhirContext.getVersion().getVersion();
|
||||
}
|
||||
|
||||
public FhirContext getFhirContext() {
|
||||
return myFhirContext;
|
||||
}
|
||||
|
||||
public FhirVersionEnum getFhirVersion() {
|
||||
return myFhirVersion;
|
||||
}
|
||||
|
||||
public String getBase(){
|
||||
return myBaseRestServerHelper.getBase();
|
||||
}
|
||||
|
||||
public String getSecureBase(){
|
||||
return myBaseRestServerHelper.getSecureBase();
|
||||
}
|
||||
|
||||
public String getPatientEndpoint(){
|
||||
return getBase()+"/Patient";
|
||||
}
|
||||
|
||||
public String getSecuredPatientEndpoint(){
|
||||
return getSecureBase()+"/Patient";
|
||||
}
|
||||
|
||||
public IBaseResource parseResource(String json){
|
||||
return myFhirContext.newJsonParser().parseResource(json);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
package ca.uhn.fhir.test.utilities;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Test Utilities
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IServerAddressStrategy;
|
||||
import ca.uhn.fhir.tls.KeyStoreType;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import java.security.KeyStore;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BaseRestServerHelper {
|
||||
|
||||
private final String SERVER_KEYSTORE_PATH = "/tls/server-keystore.p12";
|
||||
private final String SERVER_TRUSTSTORE_PATH = "/tls/server-truststore.p12";
|
||||
private final String PASSWORD = "changeit";
|
||||
|
||||
protected final FhirContext myFhirContext;
|
||||
protected int myListenerPort;
|
||||
protected int myHttpsListenerPort;
|
||||
protected Server myListenerServer;
|
||||
protected String myBase;
|
||||
protected String mySecureBase;
|
||||
protected IGenericClient myClient;
|
||||
|
||||
@RegisterExtension
|
||||
public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper();
|
||||
|
||||
public BaseRestServerHelper(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
protected void afterEach() throws Exception {
|
||||
stop();
|
||||
}
|
||||
|
||||
public IGenericClient getClient() {
|
||||
return myClient;
|
||||
}
|
||||
|
||||
protected void startServer(Servlet theServlet) throws Exception {
|
||||
myListenerServer = new Server(0);
|
||||
|
||||
myFhirContext.getRestfulClientFactory().setSocketTimeout(120000);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder targetServletHolder = new ServletHolder();
|
||||
targetServletHolder.setServlet(theServlet);
|
||||
proxyHandler.addServlet(targetServletHolder, "/target/*");
|
||||
|
||||
myListenerServer.setHandler(proxyHandler);
|
||||
|
||||
SslContextFactory sslContextFactory = getSslContextFactory();
|
||||
|
||||
HttpConfiguration httpsConfig = new HttpConfiguration();
|
||||
httpsConfig.setSecureScheme("https");
|
||||
httpsConfig.setSecurePort(0);
|
||||
|
||||
ServerConnector sslConnector = new ServerConnector(myListenerServer,
|
||||
new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
|
||||
new HttpConnectionFactory(httpsConfig));
|
||||
sslConnector.setPort(0);
|
||||
|
||||
myListenerServer.addConnector(sslConnector);
|
||||
myListenerServer.start();
|
||||
|
||||
assignHttpAndHttpsPorts();
|
||||
|
||||
myBase = "http://localhost:" + myListenerPort + "/target";
|
||||
mySecureBase = "https://localhost:" + myHttpsListenerPort + "/target";
|
||||
|
||||
myFhirContext.getRestfulClientFactory().setConnectTimeout(60000);
|
||||
myFhirContext.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
||||
myClient = myFhirContext.newRestfulGenericClient(myBase);
|
||||
myClient.registerInterceptor(new LoggingInterceptor(false));
|
||||
}
|
||||
|
||||
private void assignHttpAndHttpsPorts() {
|
||||
myListenerPort = ((ServerConnector)myListenerServer.getConnectors()[0]).getLocalPort();
|
||||
myHttpsListenerPort = ((ServerConnector)myListenerServer.getConnectors()[1]).getLocalPort();
|
||||
}
|
||||
|
||||
private SslContextFactory getSslContextFactory() throws Exception{
|
||||
try {
|
||||
SslContextFactory sslContextFactory = new SslContextFactory.Server();
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStoreType.PKCS12.toString());
|
||||
keyStore.load(BaseRestServerHelper.class.getResourceAsStream(SERVER_KEYSTORE_PATH), PASSWORD.toCharArray());
|
||||
sslContextFactory.setKeyStore(keyStore);
|
||||
sslContextFactory.setKeyStorePassword(PASSWORD);
|
||||
|
||||
KeyStore trustStore = KeyStore.getInstance(KeyStoreType.PKCS12.toString());
|
||||
trustStore.load(BaseRestServerHelper.class.getResourceAsStream(SERVER_TRUSTSTORE_PATH), PASSWORD.toCharArray());
|
||||
sslContextFactory.setTrustStore(trustStore);
|
||||
|
||||
return sslContextFactory;
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException(Msg.code(2123)+"Failed to obtain SslContextFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getBase() {
|
||||
return myBase;
|
||||
}
|
||||
|
||||
public String getSecureBase() {
|
||||
return mySecureBase;
|
||||
}
|
||||
|
||||
public void stop() throws Exception {
|
||||
JettyUtil.closeServer(myListenerServer);
|
||||
}
|
||||
|
||||
public abstract void clearDataAndCounts();
|
||||
|
||||
public abstract void setFailNextPut(boolean theFailNextPut);
|
||||
|
||||
public abstract List<Object> getInterceptors();
|
||||
|
||||
public abstract void unregisterInterceptor(Object theNext);
|
||||
|
||||
public abstract void clearCounts();
|
||||
|
||||
public abstract long getPatientCountSearch();
|
||||
|
||||
public abstract long getPatientCountDelete();
|
||||
|
||||
public abstract long getPatientCountUpdate();
|
||||
|
||||
public abstract long getPatientCountRead();
|
||||
|
||||
public abstract long getObservationCountSearch();
|
||||
|
||||
public abstract long getObservationCountDelete();
|
||||
|
||||
public abstract long getObservationCountUpdate();
|
||||
|
||||
public abstract long getObservationCountRead();
|
||||
|
||||
public abstract boolean registerInterceptor(Object theInterceptorAdapter);
|
||||
|
||||
public abstract IResourceProvider getObservationResourceProvider();
|
||||
|
||||
public abstract IResourceProvider getPatientResourceProvider();
|
||||
|
||||
public abstract IResourceProvider getConceptMapResourceProvider();
|
||||
|
||||
public abstract IIdType createPatientWithId(String theId);
|
||||
|
||||
public abstract IIdType createPatient(IBaseResource theBaseResource);
|
||||
|
||||
public abstract IIdType createObservationForPatient(IIdType theFirstTargetPatientId);
|
||||
|
||||
public abstract IIdType createObservation(IBaseResource theBaseResource);
|
||||
|
||||
public void setServerAddressStrategy(boolean theUseHttps){
|
||||
String path = theUseHttps ? mySecureBase : myBase;
|
||||
HardcodedServerAddressStrategy strategy = new HardcodedServerAddressStrategy(path);
|
||||
setServerAddressStrategy(strategy);
|
||||
}
|
||||
|
||||
protected abstract void setServerAddressStrategy(IServerAddressStrategy theServerAddressStrategy);
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
package ca.uhn.fhir.test.utilities;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Test Utilities
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.rest.annotation.Transaction;
|
||||
import ca.uhn.fhir.rest.annotation.TransactionParam;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
|
||||
import ca.uhn.test.concurrency.IPointcutLatch;
|
||||
import ca.uhn.test.concurrency.PointcutLatch;
|
||||
import org.hl7.fhir.dstu3.model.ConceptMap;
|
||||
import org.hl7.fhir.dstu3.model.Observation;
|
||||
import org.hl7.fhir.dstu3.model.Organization;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Reference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class RestServerDstu3Helper extends BaseRestServerHelper implements IPointcutLatch, BeforeEachCallback, AfterEachCallback {
|
||||
protected final MyRestfulServer myRestServer;
|
||||
|
||||
public RestServerDstu3Helper() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public RestServerDstu3Helper(boolean theInitialize) {
|
||||
super(FhirContext.forDstu3());
|
||||
myRestServer = new MyRestfulServer(myFhirContext);
|
||||
if(theInitialize){
|
||||
try {
|
||||
myRestServer.initialize();
|
||||
} catch (ServletException e) {
|
||||
throw new RuntimeException(Msg.code(2112)+"Failed to initialize server", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) throws Exception {
|
||||
startServer(myRestServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext context) throws Exception {
|
||||
super.afterEach();
|
||||
myRestServer.getInterceptorService().unregisterAllAnonymousInterceptors();
|
||||
myRestServer.clearDataAndCounts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearDataAndCounts() {
|
||||
myRestServer.clearDataAndCounts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFailNextPut(boolean theFailNextPut) {
|
||||
myRestServer.setFailNextPut(theFailNextPut);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getInterceptors() {
|
||||
return myRestServer.getInterceptorService().getAllRegisteredInterceptors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterInterceptor(Object theInterceptor) {
|
||||
myRestServer.getInterceptorService().unregisterInterceptor(theInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCounts() {
|
||||
myRestServer.clearCounts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountSearch() {
|
||||
return myRestServer.getPatientResourceProvider().getCountSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountDelete() {
|
||||
return myRestServer.getPatientResourceProvider().getCountDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountUpdate() {
|
||||
return myRestServer.getPatientResourceProvider().getCountUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountRead() {
|
||||
return myRestServer.getPatientResourceProvider().getCountRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountSearch() {
|
||||
return myRestServer.getObservationResourceProvider().getCountSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountDelete() {
|
||||
return myRestServer.getObservationResourceProvider().getCountDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountUpdate() {
|
||||
return myRestServer.getObservationResourceProvider().getCountUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountRead() {
|
||||
return myRestServer.getObservationResourceProvider().getCountRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerInterceptor(Object theInterceptor) {
|
||||
return myRestServer.getInterceptorService().registerInterceptor(theInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
myRestServer.getPlainProvider().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectedCount(int theCount) {
|
||||
myRestServer.getPlainProvider().setExpectedCount(theCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HookParams> awaitExpected() throws InterruptedException {
|
||||
return myRestServer.getPlainProvider().awaitExpected();
|
||||
}
|
||||
|
||||
public void registerProvider(Object theProvider) {
|
||||
myRestServer.registerProvider(theProvider);
|
||||
}
|
||||
|
||||
public static class MyPlainProvider implements IPointcutLatch {
|
||||
private final PointcutLatch myPointcutLatch = new PointcutLatch("Transaction Counting Provider");
|
||||
private final List<IBaseBundle> myTransactions = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
@Transaction
|
||||
public synchronized IBaseBundle transaction(@TransactionParam IBaseBundle theBundle) {
|
||||
myPointcutLatch.call(theBundle);
|
||||
myTransactions.add(theBundle);
|
||||
return theBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
myPointcutLatch.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectedCount(int theCount) {
|
||||
myPointcutLatch.setExpectedCount(theCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HookParams> awaitExpected() throws InterruptedException {
|
||||
return myPointcutLatch.awaitExpected();
|
||||
}
|
||||
|
||||
public List<IBaseBundle> getTransactions() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(myTransactions));
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyRestfulServer extends RestfulServer {
|
||||
private boolean myFailNextPut;
|
||||
private HashMapResourceProvider<Patient> myPatientResourceProvider;
|
||||
private HashMapResourceProvider<Observation> myObservationResourceProvider;
|
||||
private HashMapResourceProvider<Organization> myOrganizationResourceProvider;
|
||||
private HashMapResourceProvider<ConceptMap> myConceptMapResourceProvider;
|
||||
private MyPlainProvider myPlainProvider;
|
||||
|
||||
public MyRestfulServer(FhirContext theFhirContext) {
|
||||
super(theFhirContext);
|
||||
}
|
||||
|
||||
public MyPlainProvider getPlainProvider() {
|
||||
return myPlainProvider;
|
||||
}
|
||||
|
||||
public void setFailNextPut(boolean theFailNextPut) {
|
||||
myFailNextPut = theFailNextPut;
|
||||
}
|
||||
|
||||
public void clearCounts() {
|
||||
for (IResourceProvider next : getResourceProviders()) {
|
||||
if (next instanceof HashMapResourceProvider) {
|
||||
HashMapResourceProvider provider = (HashMapResourceProvider) next;
|
||||
provider.clearCounts();
|
||||
}
|
||||
}
|
||||
myPlainProvider.clear();
|
||||
}
|
||||
|
||||
public void clearDataAndCounts() {
|
||||
for (IResourceProvider next : getResourceProviders()) {
|
||||
if (next instanceof HashMapResourceProvider) {
|
||||
HashMapResourceProvider provider = (HashMapResourceProvider) next;
|
||||
provider.clear();
|
||||
}
|
||||
}
|
||||
clearCounts();
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<Observation> getObservationResourceProvider() {
|
||||
return myObservationResourceProvider;
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<Organization> getOrganizationResourceProvider() {
|
||||
return myOrganizationResourceProvider;
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
|
||||
return myConceptMapResourceProvider;
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
|
||||
return myPatientResourceProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
FhirContext fhirContext = getFhirContext();
|
||||
myPatientResourceProvider = new MyHashMapResourceProvider(fhirContext, Patient.class);
|
||||
registerProvider(myPatientResourceProvider);
|
||||
myObservationResourceProvider = new MyHashMapResourceProvider(fhirContext, Observation.class);
|
||||
registerProvider(myObservationResourceProvider);
|
||||
myOrganizationResourceProvider = new MyHashMapResourceProvider(fhirContext, Organization.class);
|
||||
registerProvider(myOrganizationResourceProvider);
|
||||
myConceptMapResourceProvider = new MyHashMapResourceProvider(fhirContext, ConceptMap.class);
|
||||
registerProvider(myConceptMapResourceProvider);
|
||||
|
||||
myPlainProvider = new MyPlainProvider();
|
||||
registerProvider(myPlainProvider);
|
||||
}
|
||||
|
||||
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
|
||||
myConceptMapResourceProvider.getStoredResources().forEach(c -> theResourceProvider.store(c));
|
||||
|
||||
unregisterProvider(myConceptMapResourceProvider);
|
||||
registerProvider(theResourceProvider);
|
||||
myConceptMapResourceProvider = theResourceProvider;
|
||||
}
|
||||
|
||||
|
||||
public class MyHashMapResourceProvider<T extends IBaseResource> extends HashMapResourceProvider<T> {
|
||||
public MyHashMapResourceProvider(FhirContext theContext, Class theType) {
|
||||
super(theContext, theType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome update(T theResource, String theConditional, RequestDetails theRequestDetails) {
|
||||
if (myFailNextPut) {
|
||||
throw new PreconditionFailedException(Msg.code(2113)+"Failed update operation");
|
||||
}
|
||||
return super.update(theResource, theConditional, theRequestDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMapResourceProvider<Observation> getObservationResourceProvider() {
|
||||
return myRestServer.getObservationResourceProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
|
||||
return myRestServer.getPatientResourceProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
|
||||
return myRestServer.getConceptMapResourceProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createPatientWithId(String theId) {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/" + theId);
|
||||
patient.addIdentifier().setSystem("http://foo").setValue(theId);
|
||||
return this.createPatient(patient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createPatient(IBaseResource theBaseResource) {
|
||||
return myRestServer.getPatientResourceProvider().store((Patient) theBaseResource);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createObservationForPatient(IIdType theFirstTargetPatientId) {
|
||||
Observation observation = new Observation();
|
||||
observation.setSubject(new Reference(theFirstTargetPatientId));
|
||||
return this.createObservation(observation);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createObservation(IBaseResource theBaseResource) {
|
||||
return myRestServer.getObservationResourceProvider().store((Observation) theBaseResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setServerAddressStrategy(IServerAddressStrategy theServerAddressStrategy) {
|
||||
myRestServer.setServerAddressStrategy(theServerAddressStrategy);
|
||||
}
|
||||
|
||||
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
|
||||
myRestServer.setConceptMapResourceProvider(theResourceProvider);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,387 @@
|
|||
package ca.uhn.fhir.test.utilities;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Test Utilities
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.IncomingRequestAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEachCallback, AfterEachCallback {
|
||||
protected final MyRestfulServer myRestServer;
|
||||
|
||||
public RestServerR4Helper() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public RestServerR4Helper(boolean theInitialize) {
|
||||
super(FhirContext.forR4Cached());
|
||||
myRestServer = new MyRestfulServer(myFhirContext);
|
||||
if(theInitialize){
|
||||
try {
|
||||
myRestServer.initialize();
|
||||
} catch (ServletException e) {
|
||||
throw new RuntimeException(Msg.code(2110)+"Failed to initialize server", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) throws Exception {
|
||||
startServer(myRestServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext context) throws Exception {
|
||||
super.afterEach();
|
||||
myRestServer.getInterceptorService().unregisterAllAnonymousInterceptors();
|
||||
myRestServer.clearDataAndCounts();
|
||||
}
|
||||
|
||||
public List<Bundle> getTransactions() {
|
||||
return myRestServer
|
||||
.getPlainProvider()
|
||||
.getTransactions()
|
||||
.stream()
|
||||
.map(t -> (Bundle) t)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearDataAndCounts() {
|
||||
myRestServer.clearDataAndCounts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFailNextPut(boolean theFailNextPut) {
|
||||
myRestServer.setFailNextPut(theFailNextPut);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getInterceptors() {
|
||||
return myRestServer.getInterceptorService().getAllRegisteredInterceptors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterInterceptor(Object theInterceptor) {
|
||||
myRestServer.getInterceptorService().unregisterInterceptor(theInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCounts() {
|
||||
myRestServer.clearCounts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountSearch() {
|
||||
return myRestServer.getPatientResourceProvider().getCountSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountDelete() {
|
||||
return myRestServer.getPatientResourceProvider().getCountDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountUpdate() {
|
||||
return myRestServer.getPatientResourceProvider().getCountUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPatientCountRead() {
|
||||
return myRestServer.getPatientResourceProvider().getCountRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountSearch() {
|
||||
return myRestServer.getObservationResourceProvider().getCountSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountDelete() {
|
||||
return myRestServer.getObservationResourceProvider().getCountDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountUpdate() {
|
||||
return myRestServer.getObservationResourceProvider().getCountUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObservationCountRead() {
|
||||
return myRestServer.getObservationResourceProvider().getCountRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerInterceptor(Object theInterceptor) {
|
||||
return myRestServer.getInterceptorService().registerInterceptor(theInterceptor);
|
||||
}
|
||||
|
||||
public void registerProvider(Object theProvider) {
|
||||
myRestServer.registerProvider(theProvider);
|
||||
}
|
||||
|
||||
public void setExpectedCount(int theCount) {
|
||||
myRestServer.getPlainProvider().setExpectedCount(theCount);
|
||||
}
|
||||
|
||||
public List<HookParams> awaitExpected() throws InterruptedException {
|
||||
return myRestServer.getPlainProvider().awaitExpected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMapResourceProvider<Observation> getObservationResourceProvider() {
|
||||
return myRestServer.getObservationResourceProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
|
||||
return myRestServer.getPatientResourceProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
|
||||
return myRestServer.getConceptMapResourceProvider();
|
||||
}
|
||||
|
||||
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
|
||||
myRestServer.setConceptMapResourceProvider(theResourceProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createPatientWithId(String theId) {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/" + theId);
|
||||
patient.addIdentifier().setSystem("http://foo").setValue(theId);
|
||||
return this.createPatient(patient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createPatient(IBaseResource theBaseResource) {
|
||||
return myRestServer.getPatientResourceProvider().store((Patient) theBaseResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createObservationForPatient(IIdType thePatientId) {
|
||||
Observation observation = new Observation();
|
||||
observation.setSubject(new Reference(thePatientId));
|
||||
return this.createObservation(observation);
|
||||
//TODO maybe add some data to this obs?
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType createObservation(IBaseResource theBaseResource) {
|
||||
return myRestServer.getObservationResourceProvider().store((Observation) theBaseResource);
|
||||
}
|
||||
|
||||
public List<String> getRequestUrls() {
|
||||
return myRestServer.myRequestUrls;
|
||||
}
|
||||
|
||||
public List<String> getRequestVerbs() {
|
||||
return myRestServer.myRequestVerbs;
|
||||
}
|
||||
|
||||
public void setObservationResourceProvider(HashMapResourceProvider<Observation> theResourceProvider) {
|
||||
myRestServer.setObservationResourceProvider(theResourceProvider);
|
||||
}
|
||||
|
||||
public List<Map<String, String>> getRequestHeaders() {
|
||||
return myRestServer.myRequestHeaders;
|
||||
}
|
||||
|
||||
public IInterceptorService getInterceptorService() {
|
||||
return myRestServer.getInterceptorService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServerAddressStrategy(IServerAddressStrategy theServerAddressStrategy){
|
||||
myRestServer.setServerAddressStrategy(theServerAddressStrategy);
|
||||
}
|
||||
|
||||
private static class MyRestfulServer extends RestfulServer {
|
||||
private boolean myFailNextPut;
|
||||
private HashMapResourceProvider<Patient> myPatientResourceProvider;
|
||||
private HashMapResourceProvider<Observation> myObservationResourceProvider;
|
||||
private HashMapResourceProvider<Organization> myOrganizationResourceProvider;
|
||||
private HashMapResourceProvider<ConceptMap> myConceptMapResourceProvider;
|
||||
private RestServerDstu3Helper.MyPlainProvider myPlainProvider;
|
||||
private final List<String> myRequestUrls = Collections.synchronizedList(new ArrayList<>());
|
||||
private final List<String> myRequestVerbs = Collections.synchronizedList(new ArrayList<>());
|
||||
private final List<Map<String, String>> myRequestHeaders= Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
public MyRestfulServer(FhirContext theFhirContext) {
|
||||
super(theFhirContext);
|
||||
}
|
||||
|
||||
public RestServerDstu3Helper.MyPlainProvider getPlainProvider() {
|
||||
return myPlainProvider;
|
||||
}
|
||||
|
||||
public void setFailNextPut(boolean theFailNextPut) {
|
||||
myFailNextPut = theFailNextPut;
|
||||
}
|
||||
|
||||
public void clearCounts() {
|
||||
for (IResourceProvider next : getResourceProviders()) {
|
||||
if (next instanceof HashMapResourceProvider) {
|
||||
HashMapResourceProvider provider = (HashMapResourceProvider) next;
|
||||
provider.clearCounts();
|
||||
}
|
||||
}
|
||||
myPlainProvider.clear();
|
||||
myRequestUrls.clear();
|
||||
myRequestVerbs.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException {
|
||||
Request request = (Request) theReq;
|
||||
|
||||
Map<String, String> headers = pullOutHeaders(theReq);
|
||||
myRequestHeaders.add(headers);
|
||||
myRequestUrls.add(request.getOriginalURI());
|
||||
myRequestVerbs.add(request.getMethod());
|
||||
super.service(theReq, theResp);
|
||||
}
|
||||
|
||||
private Map<String,String> pullOutHeaders(HttpServletRequest theReq) {
|
||||
Enumeration<String> headerNames = theReq.getHeaderNames();
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
headers.put(headerName, theReq.getHeader(headerName));
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void clearDataAndCounts() {
|
||||
for (IResourceProvider next : getResourceProviders()) {
|
||||
if (next instanceof HashMapResourceProvider) {
|
||||
HashMapResourceProvider provider = (HashMapResourceProvider) next;
|
||||
provider.clear();
|
||||
}
|
||||
}
|
||||
clearCounts();
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<Observation> getObservationResourceProvider() {
|
||||
return myObservationResourceProvider;
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<Organization> getOrganizationResourceProvider() {
|
||||
return myOrganizationResourceProvider;
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<ConceptMap> getConceptMapResourceProvider() {
|
||||
return myConceptMapResourceProvider;
|
||||
}
|
||||
|
||||
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
|
||||
return myPatientResourceProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
FhirContext fhirContext = getFhirContext();
|
||||
myPatientResourceProvider = new MyHashMapResourceProvider(fhirContext, Patient.class);
|
||||
registerProvider(myPatientResourceProvider);
|
||||
myObservationResourceProvider = new MyHashMapResourceProvider(fhirContext, Observation.class);
|
||||
registerProvider(myObservationResourceProvider);
|
||||
myOrganizationResourceProvider = new MyHashMapResourceProvider(fhirContext, Organization.class);
|
||||
registerProvider(myOrganizationResourceProvider);
|
||||
myConceptMapResourceProvider = new MyHashMapResourceProvider(fhirContext, ConceptMap.class);
|
||||
registerProvider(myConceptMapResourceProvider);
|
||||
|
||||
myPlainProvider = new RestServerDstu3Helper.MyPlainProvider();
|
||||
registerProvider(myPlainProvider);
|
||||
|
||||
setPagingProvider(new FifoMemoryPagingProvider(20));
|
||||
}
|
||||
|
||||
public void setObservationResourceProvider(HashMapResourceProvider<Observation> theResourceProvider) {
|
||||
myObservationResourceProvider.getStoredResources().forEach(o -> theResourceProvider.store(o));
|
||||
|
||||
unregisterProvider(myObservationResourceProvider);
|
||||
registerProvider(theResourceProvider);
|
||||
myObservationResourceProvider = theResourceProvider;
|
||||
}
|
||||
|
||||
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
|
||||
myConceptMapResourceProvider.getStoredResources().forEach(c -> theResourceProvider.store(c));
|
||||
|
||||
unregisterProvider(myConceptMapResourceProvider);
|
||||
registerProvider(theResourceProvider);
|
||||
myConceptMapResourceProvider = theResourceProvider;
|
||||
}
|
||||
|
||||
|
||||
public class MyHashMapResourceProvider<T extends IBaseResource> extends HashMapResourceProvider<T> {
|
||||
public MyHashMapResourceProvider(FhirContext theContext, Class theType) {
|
||||
super(theContext, theType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome update(T theResource, String theConditional, RequestDetails theRequestDetails) {
|
||||
if (myFailNextPut) {
|
||||
throw new PreconditionFailedException(Msg.code(2111)+"Failed update operation");
|
||||
}
|
||||
return super.update(theResource, theConditional, theRequestDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package ca.uhn.fhir.test.utilities;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Test Utilities
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.tls.KeyStoreInfo;
|
||||
import ca.uhn.fhir.tls.TlsAuthentication;
|
||||
import ca.uhn.fhir.tls.TrustStoreInfo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TlsAuthenticationTestHelper implements AfterEachCallback {
|
||||
|
||||
private static final String KEYSTORE_RESOURCE_PATH = "classpath:/tls/client-keystore.p12";
|
||||
private static final String KEYSTORE_STOREPASS = "changeit";
|
||||
private static final String KEYSTORE_KEYPASS = "changeit";
|
||||
private static final String KEYSTORE_ALIAS = "client";
|
||||
|
||||
private static final String TRUSTSTORE_RESOURCE_PATH = "classpath:/tls/client-truststore.p12";
|
||||
private static final String TRUSTSTORE_STOREPASS = "changeit";
|
||||
private static final String TRUSTSTORE_ALIAS = "client";
|
||||
|
||||
private final TlsAuthentication myTlsAuthentication;
|
||||
private final KeyStoreInfo myKeystoreInfo;
|
||||
private final TrustStoreInfo myTrustStoreInfo;
|
||||
private File myTempFile;
|
||||
|
||||
public TlsAuthenticationTestHelper(){
|
||||
myKeystoreInfo = new KeyStoreInfo(KEYSTORE_RESOURCE_PATH, KEYSTORE_STOREPASS, KEYSTORE_KEYPASS, KEYSTORE_ALIAS);
|
||||
myTrustStoreInfo = new TrustStoreInfo(TRUSTSTORE_RESOURCE_PATH, TRUSTSTORE_STOREPASS, TRUSTSTORE_ALIAS);
|
||||
myTlsAuthentication = new TlsAuthentication(Optional.of(myKeystoreInfo), Optional.of(myTrustStoreInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext theExtensionContext) throws Exception {
|
||||
if(myTempFile != null && myTempFile.exists()){
|
||||
assertTrue(myTempFile.delete());
|
||||
myTempFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String[] createBaseRequestGeneratingCommandArgs(String[] theBaseArgs, String theUrlFlag, boolean theAddTls, BaseRestServerHelper theRestServerHelper){
|
||||
if(isBlank(theUrlFlag)){
|
||||
return theBaseArgs;
|
||||
}
|
||||
|
||||
String[] retVal;
|
||||
if(theAddTls){
|
||||
int newSize = theBaseArgs.length + 4;
|
||||
retVal = Arrays.copyOf(theBaseArgs, newSize);
|
||||
|
||||
retVal[newSize - 4] = theUrlFlag;
|
||||
retVal[newSize - 3] = theRestServerHelper.getSecureBase(); // HTTPS
|
||||
|
||||
myTempFile = createTlsAuthenticationFile();
|
||||
retVal[newSize - 2] = "--tls-auth";
|
||||
retVal[newSize - 1] = myTempFile.getAbsolutePath();
|
||||
}
|
||||
else {
|
||||
int newSize = theBaseArgs.length + 2;
|
||||
retVal = Arrays.copyOf(theBaseArgs, newSize);
|
||||
retVal[newSize - 2] = theUrlFlag;
|
||||
retVal[newSize - 1] = theRestServerHelper.getBase(); // HTTP
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public TlsAuthentication getTlsAuthentication(){
|
||||
return myTlsAuthentication;
|
||||
}
|
||||
|
||||
public File createTlsAuthenticationFile() {
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
ObjectNode keyStore = mapper.createObjectNode();
|
||||
keyStore.put("filePath", KEYSTORE_RESOURCE_PATH);
|
||||
keyStore.put("storePass", KEYSTORE_STOREPASS);
|
||||
keyStore.put("keyPass", KEYSTORE_KEYPASS);
|
||||
keyStore.put("alias", KEYSTORE_ALIAS);
|
||||
|
||||
ObjectNode trustStore = mapper.createObjectNode();
|
||||
trustStore.put("filePath", TRUSTSTORE_RESOURCE_PATH);
|
||||
trustStore.put("storePass", TRUSTSTORE_STOREPASS);
|
||||
trustStore.put("alias", TRUSTSTORE_ALIAS);
|
||||
|
||||
ObjectNode json = mapper.createObjectNode();
|
||||
json.set("keyStore", keyStore);
|
||||
json.set("trustStore", trustStore);
|
||||
|
||||
File inputFile = File.createTempFile("smile-unit-test", ".json");
|
||||
try (FileWriter inputFileWriter = new FileWriter(inputFile, StandardCharsets.UTF_8, false)) {
|
||||
IOUtils.write(json.toString(), inputFileWriter);
|
||||
}
|
||||
return inputFile;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(Msg.code(2122)+"Failed to load test TLS authentication file", e);
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.1.0-PRE27-SNAPSHOT</version>
|
||||
<version>6.1.0-PRE29-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue