diff --git a/pom.xml b/pom.xml index 08d0ff9cf..879ab3cdd 100644 --- a/pom.xml +++ b/pom.xml @@ -155,6 +155,12 @@ knowledge of the CeCILL-B license and that you accept its terms. ${junit.version} test + + uk.org.webcompere + system-stubs-jupiter + 2.1.3 + test + org.springframework spring-test @@ -184,6 +190,12 @@ knowledge of the CeCILL-B license and that you accept its terms. 4.6.1 test + + org.mockito + mockito-junit-jupiter + 4.6.1 + test + org.springframework.security spring-security-test diff --git a/vip-api/pom.xml b/vip-api/pom.xml index 856f3fa78..9b78889f2 100644 --- a/vip-api/pom.xml +++ b/vip-api/pom.xml @@ -111,18 +111,6 @@ knowledge of the CeCILL-B license and that you accept its terms. ${keycloak.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson.version} - - org.hibernate @@ -173,6 +161,21 @@ knowledge of the CeCILL-B license and that you accept its terms. + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + itest diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/SpringWebConfig.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/SpringWebConfig.java index be321cebb..162ce3860 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/SpringWebConfig.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/SpringWebConfig.java @@ -108,15 +108,10 @@ public void addCorsMappings(CorsRegistry registry) { } /* - to verify that the proxy ist still valid each day + to verify that the proxy is still valid each day */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(vipConfigurer); } - - @Bean - public ObjectMapper objectMapper() { - return Jackson2ObjectMapperBuilder.json().build(); - } } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiBusiness.java index 734ff43df..e5fce4016 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiBusiness.java @@ -11,6 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.stereotype.Service; @Service @@ -60,6 +61,9 @@ private User signin(String username, String password) throws ApiException { logger.info("Credentials OK for " + username); return user; } catch (BusinessException e) { + if (e.getMessage().startsWith("Authentication failed")) { + throw new ApiException(ApiException.ApiError.BAD_CREDENTIALS); + } throw new ApiException("Authentication Error", e); } } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java index d296709c1..3a56f4676 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java @@ -256,8 +256,7 @@ public String initExecution(Execution execution) } String resultsLocation = execution.getResultsLocation(); if (resultsLocation != null) { - inputMap.put(CoreConstants.RESULTS_DIRECTORY_PARAM_NAME, - resultsLocation); + inputMap.put(CoreConstants.RESULTS_DIRECTORY_PARAM_NAME, resultsLocation); } checkInputExecNameIsValid(execution.getName()); @@ -326,39 +325,35 @@ private String initExecution(String pipelineId, // Check that all pipeline inputs are present Pipeline p = pipelineBusiness.getPipelineWithResultsDirectory(pipelineId); for (PipelineParameter pp : p.getParameters()) { + // always true on vip if (pp.isReturnedValue()) { continue; } - // pp is an input - if (!(inputValues.get(pp.getName()) == null)) { + // ok if input is present + if ( inputValues.get(pp.getName()) != null) { continue; } - // pp is an empty input + // then ok if input has a default value (and we set it) + // beware : with gwendia, optional always have an defaultValue (either defined or No_Value_Provided) if (pp.getDefaultValue() != null) { inputValues.put(pp.getName(), pp.getDefaultValue().toString()); continue; } - // pp is an empty input with no default value + // then ok if it is optional + // beware, with gwendia it should not be possible to enter this case (see previous condition) if (pp.isOptional()) { - inputValues.put("no", pp.getDefaultValue().toString());//that's how optional values are handled in VIP continue; } - // pp is an empty input with no default value and it is not optional - logger.error("Error initialising {}, missing {} parameter", - pipelineId, pp.getName()); - throw new ApiException("Parameter " + pp.getName() + " is empty while it is not optional and it has no default value."); + // error : pp is an empty input with no default value and it is not optional + logger.error("Error initialising {}, missing {} parameter", pipelineId, pp.getName()); + throw new ApiException(ApiException.ApiError.INPUT_FIELD_MISSING, pp.getName()); } - boolean hasInputResultsDirectory = - inputValues.containsKey( - CoreConstants.RESULTS_DIRECTORY_PARAM_NAME); - - boolean hasPipelineResultsDirectory = - p.getParameters().stream().anyMatch( - param -> + boolean inputsContainsResultsDirectoryInput = inputValues.containsKey(CoreConstants.RESULTS_DIRECTORY_PARAM_NAME); + boolean pipelineHasResultsDirectoryInput = p.getParameters().stream().anyMatch(param -> param.getName().equals(CoreConstants.RESULTS_DIRECTORY_PARAM_NAME)); - if (hasInputResultsDirectory && !hasPipelineResultsDirectory) { + if (inputsContainsResultsDirectoryInput && ! pipelineHasResultsDirectoryInput) { logger.error("Missing results-directory for {}", pipelineId); throw new ApiException( "Input has parameter results-directory but it is not defined in pipeline."); diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java index 2cab3ad52..448ed6fb6 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java @@ -33,25 +33,34 @@ import fr.insalyon.creatis.vip.api.CarminProperties; import fr.insalyon.creatis.vip.api.exception.ApiException; +import fr.insalyon.creatis.vip.api.exception.ApiException.ApiError; import fr.insalyon.creatis.vip.api.model.ParameterType; import fr.insalyon.creatis.vip.api.model.Pipeline; import fr.insalyon.creatis.vip.api.model.PipelineParameter; -import fr.insalyon.creatis.vip.api.exception.ApiException.ApiError; -import fr.insalyon.creatis.vip.application.client.bean.*; +import fr.insalyon.creatis.vip.application.client.bean.AppVersion; +import fr.insalyon.creatis.vip.application.client.bean.Application; +import fr.insalyon.creatis.vip.application.client.bean.Descriptor; +import fr.insalyon.creatis.vip.application.client.bean.Source; import fr.insalyon.creatis.vip.application.server.business.ApplicationBusiness; +import fr.insalyon.creatis.vip.application.server.business.BoutiquesBusiness; import fr.insalyon.creatis.vip.application.server.business.ClassBusiness; import fr.insalyon.creatis.vip.application.server.business.WorkflowBusiness; +import fr.insalyon.creatis.vip.application.server.model.boutiques.BoutiquesDescriptor; +import fr.insalyon.creatis.vip.application.server.model.boutiques.Input; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.client.view.CoreConstants; import fr.insalyon.creatis.vip.core.server.business.BusinessException; -import fr.insalyon.creatis.vip.publication.client.bean.Publication; -import fr.insalyon.creatis.vip.publication.server.business.PublicationBusiness; +import fr.insalyon.creatis.vip.core.server.business.Server; +import fr.insalyon.creatis.vip.datamanager.client.DataManagerConstants; +import fr.insalyon.creatis.vip.datamanager.server.business.DataManagerBusiness; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import java.io.File; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -68,68 +77,115 @@ public class PipelineBusiness { private final Logger logger = LoggerFactory.getLogger(getClass()); - private Environment env; + private final Environment env; + private final Server server; - private Supplier currentUserProvider; + private final Supplier currentUserProvider; private final WorkflowBusiness workflowBusiness; private final ApplicationBusiness applicationBusiness; private final ClassBusiness classBusiness; + private final BoutiquesBusiness boutiquesBusiness; + private final DataManagerBusiness dataManagerBusiness; @Autowired public PipelineBusiness( Supplier currentUserProvider, Environment env, - WorkflowBusiness workflowBusiness, - ApplicationBusiness applicationBusiness, PublicationBusiness publicationBusiness, ClassBusiness classBusiness) { + Server server, WorkflowBusiness workflowBusiness, ApplicationBusiness applicationBusiness, + ClassBusiness classBusiness, BoutiquesBusiness boutiquesBusiness, DataManagerBusiness dataManagerBusiness) { this.currentUserProvider = currentUserProvider; this.env = env; + this.server = server; this.workflowBusiness = workflowBusiness; this.applicationBusiness = applicationBusiness; this.classBusiness = classBusiness; + this.boutiquesBusiness = boutiquesBusiness; + this.dataManagerBusiness = dataManagerBusiness; } - public Pipeline getPipeline(String pipelineId) - throws ApiException { - Pipeline p = getPipelineWithResultsDirectory(pipelineId); + //*********************** pipeline id format validation ********************************** - p.getParameters().removeIf( - param -> - param.getName().equals(CoreConstants.RESULTS_DIRECTORY_PARAM_NAME)); + public String getPipelineIdentifier(String applicationName, String applicationVersion) { + return applicationName + "/" + applicationVersion; + } - return p; + public String getApplicationVersion(String pipelineIdentifier) throws ApiException { + checkIfValidPipelineIdentifier(pipelineIdentifier); + return pipelineIdentifier.substring(pipelineIdentifier.lastIndexOf("/") + 1); } - public Pipeline getPipelineWithResultsDirectory(String pipelineId) - throws ApiException { - try { - String applicationName = getApplicationName(pipelineId); - String applicationVersion = getApplicationVersion(pipelineId); - Pipeline p = getPipelineWithPermissions( - applicationName, applicationVersion); + public String getApplicationName(String pipelineIdentifier) throws ApiException { + checkIfValidPipelineIdentifier(pipelineIdentifier); + return pipelineIdentifier.substring(0, pipelineIdentifier.lastIndexOf("/")); + } - Descriptor d = workflowBusiness.getApplicationDescriptor( - currentUserProvider.get(), p.getName(), p.getVersion()); // Be careful, this copies the Gwendia file from LFC. - p.setDescription(d.getDescription()); + private void checkIfValidPipelineIdentifier(String identifier) throws ApiException { + if (!identifier.contains("/")) { + logger.error("Invalid pipeline identifier {} : missing /", identifier); + throw new ApiException(ApiError.INVALID_PIPELINE_IDENTIFIER, identifier); + } + } - for (Source s : d.getSources()) { - ParameterType sourceType = ParameterType.fromVipType(s.getType()); - if ("flag".equalsIgnoreCase(s.getVipTypeRestriction())) { - sourceType = ParameterType.Boolean; - } - PipelineParameter pp = new PipelineParameter(s.getName(), - sourceType, - s.isOptional(), - false, - s.getDefaultValue(), - s.getDescription()); - p.getParameters().add(pp); - } + // *************************** public methods *********************** + + + /** + * Returns pipeline + parameters without the results-directory param + */ + public Pipeline getPipelineWithoutResultsDirectory(String pipelineId) throws ApiException { + + if (server.useMoteurlite()) { + return getPipelineFromBoutiquesDescriptor(pipelineId); + } else { + Pipeline p = getPipelineFromGwendiaDescriptor(pipelineId); + p.getParameters().removeIf( + param -> CoreConstants.RESULTS_DIRECTORY_PARAM_NAME.equals(param.getName())); return p; - } catch (BusinessException ex) { - throw new ApiException(ex); } } - public Pipeline[] listPipelines(String studyIdentifier) throws ApiException { + /** + * Returns pipeline + parameters with the results-directory param + */ + public Pipeline getPipelineWithResultsDirectory(String pipelineId) throws ApiException { + + if (server.useMoteurlite()) { + // boutiques must not contain it, we always add it + Pipeline p = getPipelineFromBoutiquesDescriptor(pipelineId); + p.getParameters().add(new PipelineParameter( + CoreConstants.RESULTS_DIRECTORY_PARAM_NAME, ParameterType.File, false, false, + DataManagerConstants.ROOT + "/" + DataManagerConstants.USERS_HOME, "Results directory")); + return p; + } else { + return getPipelineFromGwendiaDescriptor(pipelineId); + } + } + + public BoutiquesDescriptor getBoutiquesDescriptor(String pipelineId) throws ApiException { + AppVersion appVersion = getAppVersionFromPipelineId(pipelineId); + + String boutiquesUri = appVersion.getJsonLfn(); + if (boutiquesUri == null || boutiquesUri.isEmpty()) { + logger.error("boutiques lfn not specified for app {}", pipelineId); + throw new ApiException(NOT_COMPATIBLE_WITH_BOUTIQUES, pipelineId); + } + + try { + String boutiquesFilePath = dataManagerBusiness.getRemoteFile(currentUserProvider.get(), boutiquesUri); + File boutiquesFile = Paths.get(boutiquesFilePath).toFile(); + if ( ! boutiquesFile.exists()) { + logger.error("Boutiques file ({}) absent after download in {}", boutiquesUri, boutiquesFilePath); + throw new ApiException(GENERIC_API_ERROR); + } + return boutiquesBusiness.parseBoutiquesFile(boutiquesFile); + } catch (BusinessException e) { + throw new ApiException(e); + } + } + + /** + * List all the pipeline the user can access + */ + public List listPipelines(String studyIdentifier) throws ApiException { try { if (studyIdentifier != null) { @@ -137,60 +193,139 @@ public Pipeline[] listPipelines(String studyIdentifier) throws ApiException { } ArrayList pipelines = new ArrayList<>(); - List classes = classBusiness.getUserClasses(currentUserProvider.get().getEmail(), false); - List classNames = new ArrayList<>(); - for (AppClass c : classes) { - classNames.add(c.getName()); - } + List classNames = classBusiness.getUserClassesName(currentUserProvider.get().getEmail(), false); - List applications = - applicationBusiness.getApplications(classNames); + List applications = applicationBusiness.getApplications(classNames); for (Application a : applications) { - List versions = - applicationBusiness.getVersions(a.getName()); + List versions = applicationBusiness.getVersions(a.getName()); for (AppVersion av : versions) { if (isApplicationVersionUsableInApi(av)) { pipelines.add( new Pipeline(getPipelineIdentifier( a.getName(), av.getVersion()), - a.getName(), av.getVersion(), true) + a.getName(), av.getVersion()) ); } } } - Pipeline[] array_pipelines = new Pipeline[pipelines.size()]; - return pipelines.toArray(array_pipelines); + return pipelines; } catch (BusinessException ex) { throw new ApiException(ex); } } + // Specific stuff that return in 'Application' class format and not 'Pipeline' + // used for the VIP landing page public List listPublicPipelines() throws ApiException { try { - return applicationBusiness.getPublicApplicationsWithGroups(); + return applicationBusiness.getPublicApplicationsWithGroups(); } catch (BusinessException e) { throw new ApiException(e); } } - public String getPipelineIdentifier(String applicationName, String applicationVersion) { - return applicationName + "/" + applicationVersion; + // ********************* Basic stuff ************************************** + + /** + * Get the pipeline parameters from the gwendia file + * Warning : this includes the results-directory parameter + */ + private Pipeline getPipelineFromGwendiaDescriptor(String pipelineId) throws ApiException { + try { + Pipeline p = getPipelineWithoutParameters(pipelineId); + + // download the gwendia file (can be slow) + Descriptor d = workflowBusiness.getApplicationDescriptor( + currentUserProvider.get(), p.getName(), p.getVersion()); + p.setDescription(d.getDescription()); + + for (Source s : d.getSources()) { + ParameterType sourceType = ParameterType.fromVipType(s.getType()); + if ("flag".equalsIgnoreCase(s.getVipTypeRestriction())) { + sourceType = ParameterType.Boolean; + } + PipelineParameter pp = new PipelineParameter( + s.getName(), sourceType, s.isOptional(),false, + s.getDefaultValue(), s.getDescription()); + p.getParameters().add(pp); + } + return p; + } catch (BusinessException ex) { + throw new ApiException(ex); + } } - public String getApplicationVersion(String pipelineIdentifier) throws ApiException { - checkIfValidPipelineIdentifier(pipelineIdentifier); - return pipelineIdentifier.substring(pipelineIdentifier.lastIndexOf("/") + 1); + + /** + * Get the pipeline parameters from the boutiques file + * Warning : this does not include the results-directory parameter + */ + private Pipeline getPipelineFromBoutiquesDescriptor(String pipelineId) throws ApiException { + // download the boutiques file and parse it + BoutiquesDescriptor boutiques = getBoutiquesDescriptor(pipelineId); + Pipeline p = new Pipeline(pipelineId, boutiques.getName(), boutiques.getToolVersion()); + p.setDescription(boutiques.getDescription()); + + for (Input input : boutiques.getInputs()) { + ParameterType type = ParameterType.fromBoutiquesInput(input); + PipelineParameter pp = new PipelineParameter( + input.getId(), type, input.getOptional() != null && input.getOptional(),false, + input.getDefaultValue(), input.getDescription()); + p.getParameters().add(pp); + } + return p; } - public String getApplicationName(String pipelineIdentifier) throws ApiException { - checkIfValidPipelineIdentifier(pipelineIdentifier); - return pipelineIdentifier.substring(0, pipelineIdentifier.lastIndexOf("/")); + // return basic pipeline without parameters + private Pipeline getPipelineWithoutParameters(String pipelineId) throws ApiException { + AppVersion appVersion = getAppVersionFromPipelineId(pipelineId); + + return new Pipeline(pipelineId, appVersion.getApplicationName(), appVersion.getVersion()); } - private void checkIfValidPipelineIdentifier(String identifier) throws ApiException { - if (!identifier.contains("/")) { - logger.error("Invalid pipeline identifier {} : missing /", identifier); - throw new ApiException(ApiError.INVALID_PIPELINE_IDENTIFIER, identifier); + private AppVersion getAppVersionFromPipelineId(String pipelineId) throws ApiException { + try { + String applicationName = getApplicationName(pipelineId); + String applicationVersion = getApplicationVersion(pipelineId); + AppVersion appVersion = applicationBusiness.getVersion(applicationName, applicationVersion); + if (appVersion == null) { + logger.error("Cannot find pipeline {}/{}", applicationName, applicationVersion); + throw new ApiException(PIPELINE_NOT_FOUND, pipelineId); + } + checkAppVersionAccess(appVersion); + return appVersion; + } catch (BusinessException e) { + throw new ApiException(e); + } + } + + // ********************* VERIFICATION STUFF ******************************* + + // should be called it all cases + private void checkAppVersionAccess(AppVersion appVersion) throws ApiException { + String appName = appVersion.getApplicationName(); + String version = appVersion.getVersion(); + + // check it is visible or in white list + if ( ! isApplicationVersionUsableInApi(appVersion)) { + logger.error("Application {}/{} not visible or in api whitelist", appName, version); + throw new ApiException(PIPELINE_NOT_FOUND, getPipelineIdentifier(appName, version)); + } + + // check the user can use it through its classes + try { + List userClassNames = classBusiness.getUserClassesName(currentUserProvider.get().getEmail(), false); + List applicationClassNames = applicationBusiness.getApplication(appName).getApplicationClasses(); + + for (String applicationClassName : applicationClassNames) { + if (userClassNames.contains(applicationClassName)) { + return; + } + } + logger.error("User {} not allowed to access application {}", currentUserProvider.get(), appName); + throw new ApiException(NOT_ALLOWED_TO_USE_PIPELINE, getPipelineIdentifier(appName, version)); + } catch (BusinessException e) { + throw new ApiException(e); } } @@ -209,44 +344,4 @@ private boolean isApplicationVersionUsableInApi(AppVersion appVersion) { && splitAppString[1].equals(appVersion.getVersion()); }); } - - public void checkIfUserCanAccessPipeline(String pipelineId) - throws ApiException { - try { - - String applicationName = getApplicationName(pipelineId); - List userClassNames = classBusiness.getUserClassesName( - currentUserProvider.get().getEmail(), false); - - Application a = applicationBusiness.getApplication(applicationName); - if (a == null) { - logger.error("Cannot find application {}", applicationName); - throw new ApiException(APPLICATION_NOT_FOUND, applicationName); - } - for (String applicationClassName : a.getApplicationClasses()) { - if (userClassNames.contains(applicationClassName)) { - return; - } - } - logger.error("User {} not allowed to access application {}", - currentUserProvider.get(), applicationName); - throw new ApiException(NOT_ALLOWED_TO_USE_APPLICATION, applicationName); - } catch (BusinessException ex) { - throw new ApiException(ex); - } - } - - private Pipeline getPipelineWithPermissions( - String applicationName, String applicationVersion) - throws ApiException { - Pipeline[] pipelines = listPipelines(""); - for (Pipeline p : pipelines) { - if (p.getName().equals(applicationName) && p.getVersion().equals(applicationVersion)) { - return p; - } - } - logger.error("Pipeline {}/{} doesn't exist or user {} cannot access it", - applicationName, applicationVersion , currentUserProvider.get()); - throw new ApiException(PIPELINE_NOT_FOUND, applicationName + "/" + applicationVersion); - } } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/PlatformController.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/PlatformController.java index b25a31f49..401433d39 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/PlatformController.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/PlatformController.java @@ -114,11 +114,8 @@ private List getErrorCodesAndMessages(Class signup( signUpUser.getEmail(), signUpUser.getInstitution(), signUpUser.getPassword(), - signUpUser.getLevel(), - signUpUser.getCountryCode() + signUpUser.getCountryCode(), + null ); user.setRegistration(new Date()); user.setLastLogin(new Date()); diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RestExceptionHandler.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RestExceptionHandler.java index 4bf0a7be0..6e2ec8bb0 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RestExceptionHandler.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RestExceptionHandler.java @@ -60,15 +60,15 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler { private final Logger logger = LoggerFactory.getLogger(getClass()); - @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(ApiException.class) - @ResponseBody - public ErrorCodeAndMessage handleApiException(ApiException e) { + public ResponseEntity handleApiException(ApiException e) { // No need to log, VIP errors are logged when they are created // to find the error message : look for an error code in the vip // ancestor exceptions and use that exception message - return fetchErrorInException(e); + ErrorCodeAndMessage codeAndMessage = fetchErrorInException(e); + HttpStatus status = e.getHttpStatus().map(HttpStatus::resolve).orElse(HttpStatus.BAD_REQUEST); + return new ResponseEntity<>(codeAndMessage, status); } private ErrorCodeAndMessage fetchErrorInException(Throwable throwable) { diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/ExecutionController.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/ExecutionController.java index 2ad1a1819..90ecba09d 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/ExecutionController.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/ExecutionController.java @@ -140,8 +140,6 @@ public Execution updateExecution( public Execution initExecution(@RequestBody @Valid Execution execution) throws ApiException { logMethodInvocation(logger, "initExecution", execution); - pipelineBusiness.checkIfUserCanAccessPipeline( - execution.getPipelineIdentifier()); String execId = executionBusiness.initExecution(execution); return executionBusiness.getExecution(execId, false); } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/PipelineController.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/PipelineController.java index bca179dc4..015a79d27 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/PipelineController.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/processing/PipelineController.java @@ -36,7 +36,7 @@ import fr.insalyon.creatis.vip.api.exception.ApiException; import fr.insalyon.creatis.vip.api.model.Pipeline; import fr.insalyon.creatis.vip.application.client.bean.Application; -import fr.insalyon.creatis.vip.core.client.bean.User; +import fr.insalyon.creatis.vip.application.server.model.boutiques.BoutiquesDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -48,7 +48,6 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.List; -import java.util.function.Supplier; /** * Created by abonnet on 7/28/16. @@ -68,7 +67,7 @@ protected PipelineController(PipelineBusiness pipelineBusiness) { } @RequestMapping - public Pipeline[] listPipelines( + public List listPipelines( @RequestParam(required = false) String studyIdentifier) throws ApiException { logMethodInvocation(logger, "listPipelines", studyIdentifier); return pipelineBusiness.listPipelines(studyIdentifier); @@ -93,8 +92,19 @@ public Pipeline getPipeline(@PathVariable String pipelineId) throws ApiException logger.error("Error decoding pipelineid {}", pipelineId, e); throw new ApiException("cannot decode pipelineId : " + pipelineId); } - pipelineBusiness.checkIfUserCanAccessPipeline(pipelineId); - return pipelineBusiness.getPipeline(pipelineId); + return pipelineBusiness.getPipelineWithoutResultsDirectory(pipelineId); + } + + @RequestMapping(value = "{pipelineId}", params = {"format=boutiques"}) + public BoutiquesDescriptor getBoutiquesDescriptor(@PathVariable String pipelineId) throws ApiException { + logMethodInvocation(logger, "getBoutiquesDescriptor", pipelineId); + try { + pipelineId = URLDecoder.decode(pipelineId, "UTF8"); + } catch (UnsupportedEncodingException e) { + logger.error("Error decoding pipelineid {}", pipelineId, e); + throw new ApiException("cannot decode pipelineId : " + pipelineId); + } + return pipelineBusiness.getBoutiquesDescriptor(pipelineId); } @RequestMapping("{pipelineIdFirstPart}/{pipelineIdSecondPart}") @@ -103,6 +113,12 @@ public Pipeline getPipeline(@PathVariable String pipelineIdFirstPart, return getPipeline(pipelineIdFirstPart + "/" + pipelineIdSecondPart); } + @RequestMapping(value = "{pipelineIdFirstPart}/{pipelineIdSecondPart}", params = {"format=boutiques"}) + public BoutiquesDescriptor getBoutiquesDescriptor(@PathVariable String pipelineIdFirstPart, + @PathVariable String pipelineIdSecondPart) throws ApiException { + return getBoutiquesDescriptor(pipelineIdFirstPart + "/" + pipelineIdSecondPart); + } + @RequestMapping(params = "pipelineId") public Pipeline getPipelineWithRequestParam(@RequestParam String pipelineId) throws ApiException { return getPipeline(pipelineId); diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java index 35d0cd3ca..6d10cc9d9 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java @@ -32,6 +32,7 @@ package fr.insalyon.creatis.vip.api.exception; import fr.insalyon.creatis.vip.core.client.VipException; +import org.springframework.http.HttpStatus; import java.util.Optional; @@ -42,45 +43,61 @@ public class ApiException extends VipException { /* Reserved codes : 8xxx : vip-api */ - public enum ApiError implements VipError{ + public enum ApiError implements VipError { GENERIC_API_ERROR(8000), NOT_IMPLEMENTED(8001), - BAD_CREDENTIALS(8002), + BAD_CREDENTIALS(8002, HttpStatus.UNAUTHORIZED.value()), INSUFFICIENT_AUTH(8003), AUTHENTICATION_ERROR(8004), INVALID_PIPELINE_IDENTIFIER(8005), APPLICATION_NOT_FOUND(8006), PIPELINE_NOT_FOUND(8007), - NOT_ALLOWED_TO_USE_APPLICATION(8008), + NOT_ALLOWED_TO_USE_PIPELINE(8008), INPUT_FIELD_NOT_VALID(8009), WRONG_DATE_FORMAT(8010), WRONG_STAT_SERVICE(8011), COUNTRY_UNKNOWN(8012), UNAUTHORIZED_DATA_ACCESS(8013), WRONG_OIDC_LOGIN(8014), - INVALID_EXECUTION_ID(8015); + INVALID_EXECUTION_ID(8015), + NOT_COMPATIBLE_WITH_BOUTIQUES(8016), + INPUT_FIELD_MISSING(8017); + + private final Integer code; + private final Integer httpStatus; + + ApiError(Integer code) { + this(code, null); + } + + ApiError(Integer code, Integer httpStatus) { + this.code = code; + this.httpStatus = httpStatus; + } - private Integer code; - ApiError(Integer code) { this.code = code; } @Override public Integer getCode() { return code; } - static private String GENERIC_ERROR_MESSAGE = "An error has been encountered on the VIP API"; + public Integer getHttpStatus() {return httpStatus; } + + static private final String GENERIC_ERROR_MESSAGE = "An error has been encountered on the VIP API"; static { addMessage(ApiError.GENERIC_API_ERROR, GENERIC_ERROR_MESSAGE, 0); addMessage(ApiError.NOT_IMPLEMENTED, "The {} method is not implemented in the VIP API", 1); + addMessage(ApiError.BAD_CREDENTIALS, "Bad credentials", 0); addMessage(ApiError.INVALID_PIPELINE_IDENTIFIER, "The {} pipeline identifier is not valid", 1); - addMessage(ApiError.APPLICATION_NOT_FOUND, "The {} application does not exists", 1); addMessage(ApiError.PIPELINE_NOT_FOUND, "The {} pipeline does not exists or cannot be used", 1); - addMessage(ApiError.NOT_ALLOWED_TO_USE_APPLICATION, "Not allowed to access application {}", 1); + addMessage(ApiError.NOT_ALLOWED_TO_USE_PIPELINE, "Not allowed to access pipeline {}", 1); addMessage(ApiError.INPUT_FIELD_NOT_VALID, "Input field '{}' is not valid. Cause : {}", 2); + addMessage(ApiError.INPUT_FIELD_MISSING, "Input field '{}' is missing", 1); addMessage(ApiError.WRONG_DATE_FORMAT, "The date {} have a wrong format (needed : {})", 2); addMessage(ApiError.WRONG_STAT_SERVICE, "The service {} is unknown, only 'vip' is possible", 1); addMessage(ApiError.COUNTRY_UNKNOWN, "Country unknown : {}", 1); addMessage(ApiError.UNAUTHORIZED_DATA_ACCESS, "Unauthorized data access to : {}", 1); addMessage(ApiError.WRONG_OIDC_LOGIN, "The login process encountered an error", 0); addMessage(ApiError.INVALID_EXECUTION_ID, "No execution available with this id : {}", 1); + addMessage(ApiError.NOT_COMPATIBLE_WITH_BOUTIQUES, "The pipeline is not compatible with boutiques : {}", 1); } public Optional getMessage() { @@ -96,6 +113,13 @@ public String formatMessage(Object ...params) { } } + public Optional getHttpStatus() { + return getVipError() + .filter(ApiError.class::isInstance) + .map(ApiError.class::cast) + .map(ApiError::getHttpStatus); + } + public ApiException(String message) { super(message); } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/ParameterType.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/ParameterType.java index 53fc51d94..80fa167f9 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/ParameterType.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/ParameterType.java @@ -31,6 +31,8 @@ */ package fr.insalyon.creatis.vip.api.model; +import fr.insalyon.creatis.vip.application.server.model.boutiques.Input; + /** * * @author Tristan Glatard @@ -42,4 +44,17 @@ public enum ParameterType { public static ParameterType fromVipType(String vipType) { return vipType.equalsIgnoreCase("URI") ? File : String; } + + public static ParameterType fromBoutiquesInput(Input boutiquesInput) { + if (boutiquesInput.getList() != null && boutiquesInput.getList()) { + return List; + } + switch (boutiquesInput.getType()) { + case FILE: return File; + case STRING: return String; + case FLAG: return Boolean; + case NUMBER: return boutiquesInput.getInteger() ? Int64 : Double; + } + return null; + } } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/Pipeline.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/Pipeline.java index 48c0d1a64..0e072b446 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/Pipeline.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/Pipeline.java @@ -51,11 +51,11 @@ public class Pipeline { public Pipeline() { } - public Pipeline(String identifier, String name, String version, boolean canExecute) { + public Pipeline(String identifier, String name, String version) { this.identifier = identifier; this.name = name; this.version = version; - this.canExecute = canExecute; + this.canExecute = true; parameters = new ArrayList<>(); } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java index bac9dd63c..7d69e9ab6 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java @@ -3,6 +3,7 @@ import fr.insalyon.creatis.vip.core.client.view.user.UserLevel; import fr.insalyon.creatis.vip.core.client.view.util.CountryCode; +import javax.validation.constraints.NotNull; import java.util.List; /** @@ -12,26 +13,31 @@ */ public class SignUpUserDTO { + @NotNull private String firstName; + @NotNull private String lastName; + @NotNull private String email; + @NotNull private String institution; + @NotNull private String password; - private UserLevel level; + @NotNull private CountryCode countryCode; private String comments; + @NotNull private List applications; public SignUpUserDTO(){ } - public SignUpUserDTO(String firstName, String lastName, String email, String institution, String password, UserLevel level, CountryCode countryCode, String comments, List applications) { + public SignUpUserDTO(String firstName, String lastName, String email, String institution, String password, CountryCode countryCode, String comments, List applications) { this.firstName = firstName; this.lastName = lastName; this.email = email; this.institution = institution; this.password = password; - this.level = level; this.countryCode = countryCode; this.comments = comments; this.applications = applications; @@ -78,14 +84,6 @@ public void setPassword(String password) { this.password = password; } - public UserLevel getLevel() { - return level; - } - - public void setLevel(UserLevel level) { - this.level = level; - } - public CountryCode getCountryCode() { return countryCode; } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/PipelineTestUtils.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/PipelineTestUtils.java index b31a9de43..d4c8212fb 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/PipelineTestUtils.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/PipelineTestUtils.java @@ -59,6 +59,8 @@ public class PipelineTestUtils { public static final Source sourceParam1, sourceParam2; public static final PipelineParameter pipelineParam1, pipelineParam2; + public static final PipelineParameter resultsDir, fileParam, textParam, optionalTextParamNoValueProvided, optionalTextParam, flagParam; + public static final Entry[] paramPairs; static { @@ -76,6 +78,23 @@ public class PipelineTestUtils { paramPairs = new Entry[] {new SimpleEntry(sourceParam1, pipelineParam1), new SimpleEntry(sourceParam2, pipelineParam2)}; + resultsDir = new PipelineParameter("results-directory", ParameterType.File, + false, false, "/test/vip/Home", "This is the test results directory input"); + + fileParam = new PipelineParameter("testFileInput", ParameterType.File, + false, false, null, "This is a test file input"); + + textParam = new PipelineParameter("testTextInput", ParameterType.String, + false, false, "test text value", "This is a test text input"); + + optionalTextParamNoValueProvided = new PipelineParameter("testOptionalTextInput", ParameterType.String, + true, false, "No_value_provided", "This is a optional test text input"); + + optionalTextParam = new PipelineParameter("testOptionalTextInput", ParameterType.String, + true, false, null, "This is a optional test text input"); + + flagParam = new PipelineParameter("testFlagInput", ParameterType.Boolean, + true, false, "false", "This is a test flag input"); pipelineSuppliers = getPipelineSuppliers(); pipelineParameterSuppliers = getPipelineParameterSuppliers(); @@ -83,7 +102,12 @@ public class PipelineTestUtils { public static Pipeline getPipeline(Application app, AppVersion version) { return new Pipeline(app.getName() + "/" + version.getVersion(), - app.getName(), version.getVersion(), true); + app.getName(), version.getVersion()); + } + + public static Pipeline getPipeline(AppVersion version) { + return new Pipeline(version.getApplicationName() + "/" + version.getVersion(), + version.getApplicationName(), version.getVersion()); } public static Descriptor getDescriptor(String desc, Integer... paramIndexes) { @@ -94,8 +118,8 @@ public static Descriptor getDescriptor(String desc, Integer... paramIndexes) { return new Descriptor(sources, desc); } - public static Pipeline getFullPipeline(Application app, AppVersion version, String desc, Integer... paramIndexes) { - Pipeline pipeline = getPipeline(app, version); + public static Pipeline getFullPipeline(AppVersion version, String desc, Integer... paramIndexes) { + Pipeline pipeline = getPipeline(version); pipeline.setDescription(desc); for (Integer paramIndex : paramIndexes) { pipeline.getParameters().add(paramPairs[paramIndex].getValue()); @@ -103,6 +127,15 @@ public static Pipeline getFullPipeline(Application app, AppVersion version, Stri return pipeline; } + public static Pipeline getFullPipeline(AppVersion version, String desc, PipelineParameter... params) { + Pipeline pipeline = getPipeline(version); + pipeline.setDescription(desc); + for (PipelineParameter param : params) { + pipeline.getParameters().add(param); + } + return pipeline; + } + public static Map getPipelineSuppliers() { return JsonCustomObjectMatcher.formatSuppliers( Arrays.asList("identifier", "name", "version", "description", "canExecute", "parameters"), diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java index a0fc593a0..656ad3c9f 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java @@ -35,9 +35,11 @@ import fr.insalyon.creatis.vip.api.security.apikey.SpringApiPrincipal; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.client.view.user.UserLevel; +import fr.insalyon.creatis.vip.core.client.view.util.CountryCode; import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.test.web.servlet.request.RequestPostProcessor; +import java.util.ArrayList; import java.util.Collections; /** @@ -47,6 +49,8 @@ public class UserTestUtils { static public User baseUser1; static public User baseUser2; + static public User baseUser3; + static public User baseUser4; static public SignUpUserDTO restUser1; @@ -65,9 +69,14 @@ static public void reset() { baseUser2 = new User("base2", "User2", "baseuser2@test.tst", null, UserLevel.Advanced, null); baseUser2.setFolder("user2"); + baseUser3 = new User("base3", "User3", "baseuser3@test.tst", null, + UserLevel.Beginner, null); + baseUser3.setFolder("user3"); + baseUser4 = new User("base4", "User4", "baseuser4@test.tst", null, + UserLevel.Beginner, null); + baseUser4.setFolder("user4"); - restUser1 = new SignUpUserDTO("base3", "User3", "baseuser3@test.tst", "test", baseUser2Password, - UserLevel.Advanced, null, "test comment", Collections.singletonList("test applications")); + restUser1 = new SignUpUserDTO("base3", "User3", "baseuser3@test.tst", "test", baseUser2Password, CountryCode.lc, "test comment", new ArrayList<>()); } public static RequestPostProcessor baseUser1() { @@ -77,4 +86,12 @@ public static RequestPostProcessor baseUser1() { public static RequestPostProcessor baseUser2() { return SecurityMockMvcRequestPostProcessors.user(new SpringApiPrincipal(baseUser2)); } + + public static RequestPostProcessor baseUser3() { + return SecurityMockMvcRequestPostProcessors.user(new SpringApiPrincipal(baseUser3)); + } + + public static RequestPostProcessor baseUser4() { + return SecurityMockMvcRequestPostProcessors.user(new SpringApiPrincipal(baseUser4)); + } } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/config/BaseWebSpringIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/config/BaseWebSpringIT.java index b343cf8a8..e6cd22664 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/config/BaseWebSpringIT.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/config/BaseWebSpringIT.java @@ -31,9 +31,14 @@ */ package fr.insalyon.creatis.vip.api.rest.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.insalyon.creatis.grida.client.GRIDAClient; +import fr.insalyon.creatis.grida.client.GRIDAClientException; import fr.insalyon.creatis.vip.api.rest.mockconfig.DataConfigurator; +import fr.insalyon.creatis.vip.application.client.bean.AppVersion; +import fr.insalyon.creatis.vip.application.integrationtest.BaseApplicationSpringIT; import fr.insalyon.creatis.vip.application.server.business.*; -import fr.insalyon.creatis.vip.core.integrationtest.database.BaseSpringIT; +import fr.insalyon.creatis.vip.core.integrationtest.ServerMockConfig; import fr.insalyon.creatis.vip.core.server.business.BusinessException; import fr.insalyon.creatis.vip.core.server.business.ConfigurationBusiness; import fr.insalyon.creatis.vip.core.server.dao.UserDAO; @@ -42,6 +47,7 @@ import fr.insalyon.creatis.vip.datamanager.server.business.TransferPoolBusiness; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -53,11 +59,9 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Map; /** * Created by abonnet on 7/28/16. @@ -71,10 +75,9 @@ * * login via with httpbasic(user, password) * * use {@link WithMockUser} annotation *

- * The interaction with VIP outside vip-api are mocked (see {@link SpringTestConfig} ) */ @WebAppConfiguration -abstract public class BaseWebSpringIT extends BaseSpringIT { +abstract public class BaseWebSpringIT extends BaseApplicationSpringIT { @Autowired protected WebApplicationContext wac; @@ -86,52 +89,15 @@ abstract public class BaseWebSpringIT extends BaseSpringIT { @Autowired protected ConfigurationBusiness configurationBusiness; @Autowired - protected WorkflowBusiness workflowBusiness; - @Autowired - protected ApplicationBusiness applicationBusiness; - @Autowired - protected ClassBusiness classBusiness; - @Autowired protected TransferPoolBusiness transferPoolBusiness; @Autowired protected SimulationBusiness simulationBusiness; @Autowired - protected EngineBusiness engineBusiness; - @Autowired protected LFCBusiness lfcBusiness; - @Autowired protected LFCPermissionBusiness lfcPermissionBusiness; - - /* hack from : - * https://stackoverflow.com/a/7201825 - */ - public static void setEnv(Map newenv) throws Exception { - try { - Class processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment"); - Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment"); - theEnvironmentField.setAccessible(true); - Map env = (Map) theEnvironmentField.get(null); - env.putAll(newenv); - Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment"); - theCaseInsensitiveEnvironmentField.setAccessible(true); - Map cienv = (Map) theCaseInsensitiveEnvironmentField.get(null); - cienv.putAll(newenv); - } catch (NoSuchFieldException e) { - Class[] classes = Collections.class.getDeclaredClasses(); - Map env = System.getenv(); - for (Class cl : classes) { - if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { - Field field = cl.getDeclaredField("m"); - field.setAccessible(true); - Object obj = field.get(env); - Map map = (Map) obj; - map.clear(); - map.putAll(newenv); - } - } - } - } + @Autowired + protected GRIDAClient gridaClient; @BeforeEach @Override @@ -173,18 +139,6 @@ public ConfigurationBusiness getConfigurationBusiness() { return configurationBusiness; } - public WorkflowBusiness getWorkflowBusiness() { - return workflowBusiness; - } - - public ApplicationBusiness getApplicationBusiness() { - return applicationBusiness; - } - - public ClassBusiness getClassBusiness() { - return classBusiness; - } - public TransferPoolBusiness getTransferPoolBusiness() { return transferPoolBusiness; } @@ -201,15 +155,54 @@ public LFCPermissionBusiness lfcPermissionBusiness() { return lfcPermissionBusiness; } - /* - @BeforeAll - public static void setupEnvVariables() throws Exception { - String fakeHomePath = Paths.get(ClassLoader.getSystemResource("TestHome").toURI()) - .toAbsolutePath().toString(); - setEnv(Collections.singletonMap("HOME", fakeHomePath)); - }*/ - protected void configureDataFS() throws BusinessException { DataConfigurator.configureFS(this); } + + protected static String asJsonString(final Object obj) { + try { + return new ObjectMapper().writeValueAsString(obj); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected AppVersion configureGwendiaTestApp(String appName, String groupName, String className, String versionName) throws BusinessException, GRIDAClientException, IOException { + return configureTestApp(appName, groupName, className, versionName, true); + } + + protected AppVersion configureBoutiquesTestApp(String appName, String groupName, String className, String versionName) throws BusinessException, GRIDAClientException, IOException { + return configureTestApp(appName, groupName, className, versionName, false); + } + + protected File getGwendiaTestFile() throws IOException { + return getResourceFromClasspath("gwendia/basic-gwendia.gwendia").getFile(); + } + + protected File getBoutiquesTestFile() throws IOException { + return getResourceFromClasspath("boutiques/test-boutiques.json").getFile(); + } + + protected AppVersion configureTestApp(String appName, String groupName, String className, String versionName, boolean gwendia) throws BusinessException, GRIDAClientException, IOException { + AppVersion appVersion = configureAnApplication(appName, versionName, groupName, className); + configureVersion(appVersion, + gwendia ? "/vip/testGroup (group)/path/to/test.gwendia" : null, + gwendia ? null : "/vip/testGroup (group)/path/to/desc-boutiques.json"); + + Mockito.when(server.getDataManagerPath()).thenReturn("/test/folder"); + + // localDir is datamanagerpath + "downloads" + groupRoot + dir(path) + File gwendiaFile = getGwendiaTestFile(); + File jsonFile = getBoutiquesTestFile(); + if (gwendia) { + Mockito.when(gridaClient.getRemoteFile( + ServerMockConfig.TEST_GROUP_ROOT + "/testGroup/path/to/test.gwendia", + "/test/folder/downloads"+ ServerMockConfig.TEST_GROUP_ROOT +"/testGroup/path/to")).thenReturn(gwendiaFile.getAbsolutePath()); + } else { + Mockito.when(gridaClient.getRemoteFile( + ServerMockConfig.TEST_GROUP_ROOT + "/testGroup/path/to/desc-boutiques.json", + "/test/folder/downloads"+ ServerMockConfig.TEST_GROUP_ROOT +"/testGroup/path/to")).thenReturn(jsonFile.getAbsolutePath()); + } + return appVersion; + } } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/AuthenticationControllerIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/AuthenticationControllerIT.java index b90fd92ce..51a41970b 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/AuthenticationControllerIT.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/AuthenticationControllerIT.java @@ -31,18 +31,13 @@ */ package fr.insalyon.creatis.vip.api.rest.itest; -import fr.insalyon.creatis.vip.api.data.UserTestUtils; import fr.insalyon.creatis.vip.api.exception.ApiException.ApiError; import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; -import fr.insalyon.creatis.vip.core.server.business.ConfigurationBusiness; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import static fr.insalyon.creatis.vip.api.data.AuthenticationInfoTestUtils.jsonCorrespondsToAuthenticationInfo; import static fr.insalyon.creatis.vip.api.data.CarminAPITestConstants.TEST_APIKEY_HEADER; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -50,20 +45,27 @@ /** * Created by abonnet on 8/21/17. */ -@Disabled public class AuthenticationControllerIT extends BaseWebSpringIT { + @Test + public void badPasswordAuthentication() throws Exception { + createUser(emailUser2); + mockMvc.perform( + post("/rest/authenticate") + .contentType("application/json") + .content(getResourceAsString("jsonObjects/user-credentials.json"))) + .andDo(print()) + .andExpect(status().isUnauthorized()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.errorCode") + .value(ApiError.BAD_CREDENTIALS.getCode()));; + } + @Test public void okAuthentication() throws Exception { - ConfigurationBusiness configBness = getConfigurationBusiness(); - String email = UserTestUtils.baseUser1.getEmail(); - String apikey="plopplop"; - when(configBness.signin(anyString(), anyString())) - .thenThrow(new RuntimeException()); - doReturn(UserTestUtils.baseUser1) - .when(configBness) - .signin(eq(email),eq("coucou")); - when(configBness.getUserApikey(eq(email))).thenReturn(apikey); + createUserWithPassword(emailUser2, "coucou"); + String apikey = getConfigurationBusiness().generateNewUserApikey(emailUser2); + mockMvc.perform( post("/rest/authenticate") .contentType("application/json") @@ -71,12 +73,10 @@ public void okAuthentication() throws Exception { .andDo(print()) .andExpect(jsonPath( "$", - jsonCorrespondsToAuthenticationInfo(TEST_APIKEY_HEADER, apikey) - )) + jsonCorrespondsToAuthenticationInfo(TEST_APIKEY_HEADER, apikey))) .andExpect(status().isOk()); } - @Test public void missingInfoAuthentication() throws Exception { mockMvc.perform( diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/PlatformControllerIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/PlatformControllerIT.java index f1eb24d47..9fe3e7b23 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/PlatformControllerIT.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/PlatformControllerIT.java @@ -58,7 +58,6 @@ * * Test method on platform path */ -@Disabled public class PlatformControllerIT extends BaseWebSpringIT { @Test @@ -99,9 +98,10 @@ public void testPlatformProperties() throws Exception { .andExpect(jsonPath("$.APIErrorCodesAndMessages[*]", hasItems( jsonCorrespondsToErrorCodeAndMessage(ApiError.GENERIC_API_ERROR), - jsonCorrespondsToErrorCodeAndMessage(ApiError.NOT_ALLOWED_TO_USE_APPLICATION), + jsonCorrespondsToErrorCodeAndMessage(ApiError.NOT_ALLOWED_TO_USE_PIPELINE), jsonCorrespondsToErrorCodeAndMessage(ApplicationError.USER_MAX_EXECS), - jsonCorrespondsToErrorCodeAndMessage(8002, "The error message for 'bad credentials' cannot be known in advance")))); + jsonCorrespondsToErrorCodeAndMessage(ApiError.BAD_CREDENTIALS), + jsonCorrespondsToErrorCodeAndMessage(ApiError.INSUFFICIENT_AUTH.getCode(), "The error message for 'insufficient auth' cannot be known in advance")))); } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/RegisterUserControllerIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/RegisterUserControllerIT.java new file mode 100644 index 000000000..d1b582fa7 --- /dev/null +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/RegisterUserControllerIT.java @@ -0,0 +1,86 @@ +package fr.insalyon.creatis.vip.api.rest.itest; + +import fr.insalyon.creatis.vip.api.data.UserTestUtils; +import fr.insalyon.creatis.vip.api.exception.ApiException; +import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; +import fr.insalyon.creatis.vip.application.client.bean.AppClass; +import fr.insalyon.creatis.vip.application.client.bean.Application; +import fr.insalyon.creatis.vip.core.client.bean.Group; +import fr.insalyon.creatis.vip.core.client.bean.User; +import fr.insalyon.creatis.vip.core.client.view.user.UserLevel; +import fr.insalyon.creatis.vip.core.client.view.util.CountryCode; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; + +import java.util.Collections; +import java.util.List; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class RegisterUserControllerIT extends BaseWebSpringIT { + + @BeforeEach + public void reset() { + UserTestUtils.reset(); + } + + @Test + public void registerEndpointOk() throws Exception { + mockMvc.perform( + post("/rest/register"). + content(asJsonString(UserTestUtils.restUser1)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isCreated()); + User u = getConfigurationBusiness().getUserWithGroups(UserTestUtils.restUser1.getEmail()); + Assertions.assertEquals(CountryCode.lc, u.getCountryCode()); + Assertions.assertEquals(UserLevel.Beginner, u.getLevel()); + Assertions.assertTrue(u.getGroups().isEmpty()); + Assertions.assertFalse(u.isConfirmed()); + Assertions.assertFalse(u.isAccountLocked()); + Assertions.assertNotNull(getConfigurationBusiness().signin( + UserTestUtils.restUser1.getEmail(), UserTestUtils.restUser1.getPassword())); + } + + @Test + public void registerEndpointWithAppOk() throws Exception { + String appName = "testApp", groupName = "testGroup", className = "testClass"; + getConfigurationBusiness().addGroup(new Group(groupName, true, true, true)); + getClassBusiness().addClass(new AppClass(className, Collections.emptyList(), List.of(groupName))); + getApplicationBusiness().add(new Application(appName, List.of(className), "test citation")); + UserTestUtils.restUser1.getApplications().add("testApp"); + mockMvc.perform( + post("/rest/register"). + content(asJsonString(UserTestUtils.restUser1)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isCreated()); + User u = getConfigurationBusiness().getUserWithGroups(UserTestUtils.restUser1.getEmail()); + Assertions.assertEquals(1, u.getGroups().size()); + Assertions.assertEquals(groupName, u.getGroups().iterator().next().getName()); + } + + @Test + public void registerEndpointValidationFailed() throws Exception { + UserTestUtils.restUser1.setCountryCode(null); + mockMvc.perform( + post("/rest/register") . + content(asJsonString(UserTestUtils.restUser1)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.errorCode").value(ApiException.ApiError.INPUT_FIELD_NOT_VALID.getCode())) + .andExpect(jsonPath("$.errorMessage").value(Matchers.containsString("'countryCode'"))); + } + + +} \ No newline at end of file diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/RegisterUserControllerTest.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/RegisterUserControllerTest.java deleted file mode 100644 index 922a27f8a..000000000 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/RegisterUserControllerTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.insalyon.creatis.vip.api.rest.itest; - -import com.fasterxml.jackson.databind.ObjectMapper; -import fr.insalyon.creatis.vip.api.data.UserTestUtils; -import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@Disabled -class RegisterUserControllerTest extends BaseWebSpringIT { - - public static String asJsonString(final Object obj) { - try { - return new ObjectMapper().writeValueAsString(obj); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - public void registerEndpointOK() throws Exception { - mockMvc.perform(post("/rest/register") - .content(asJsonString(UserTestUtils.restUser1)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isCreated()); - } - -} \ No newline at end of file diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationIT.java index 9bb89681f..d0deca203 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationIT.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationIT.java @@ -41,7 +41,11 @@ import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; import static fr.insalyon.creatis.vip.api.data.UserTestUtils.baseUser1; import static fr.insalyon.creatis.vip.api.data.UserTestUtils.baseUser1Password; @@ -60,45 +64,26 @@ *

* Use common vip spring test configuration ({@link BaseWebSpringIT} */ -@Disabled public class SpringAuthenticationIT extends BaseWebSpringIT { - @Autowired - @Qualifier("mockUserDAO") - UserDAO userDAO; - - @BeforeEach - public void setUp() throws Exception { - super.setUp(); - Mockito.reset(userDAO); - when(userDAO.getUserByApikey(eq("apikeyvalue"))).thenReturn(baseUser1); - } - @Test public void authenticationOK() throws Exception { + createUserWithPassword(emailUser2, "coucou"); + String apikey = getConfigurationBusiness().generateNewUserApikey(emailUser2); mockMvc.perform(get("/rest/wrongUrl") - .with(ApikeyRequestPostProcessor.apikey("testapikey", "apikeyvalue"))) + .with(ApikeyRequestPostProcessor.apikey("testapikey", apikey))) .andDo(print()) .andExpect(status().isNotFound()); } - @Test - public void authenticationWithCoreKo() throws Exception { - when(userDAO.getUserByApikey("apikeyvalue")) - .thenThrow(new RuntimeException("hey hey")); - mockMvc.perform(get("/rest/wrongUrl") - .with(ApikeyRequestPostProcessor.apikey("testapikey", "apikeyvalue"))) - .andDo(print()) - .andExpect(status().isUnauthorized()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$.errorCode") - .value(ApiError.AUTHENTICATION_ERROR.getCode())); - } - + /** + * Basic is not supported anymore + */ @Test public void authenticationWithBasicShouldBeKo() throws Exception { + createUserWithPassword(emailUser2, "coucou"); mockMvc.perform(get("/rest/wrongUrl") - .with(httpBasic(baseUser1.getEmail(), baseUser1Password))) + .with(httpBasic(emailUser2, "coucou"))) .andDo(print()) .andExpect(status().isUnauthorized()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationWithMockedUserDaoIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationWithMockedUserDaoIT.java new file mode 100644 index 000000000..51e9d89ea --- /dev/null +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/SpringAuthenticationWithMockedUserDaoIT.java @@ -0,0 +1,85 @@ +/* + * Copyright and authors: see LICENSE.txt in base repository. + * + * This software is a web portal for pipeline execution on distributed systems. + * + * This software is governed by the CeCILL-B license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-B + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-B license and that you accept its terms. + */ +package fr.insalyon.creatis.vip.api.rest.itest; + +import fr.insalyon.creatis.vip.api.exception.ApiException.ApiError; +import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; +import fr.insalyon.creatis.vip.api.tools.spring.ApikeyRequestPostProcessor; +import fr.insalyon.creatis.vip.core.server.dao.UserDAO; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; + +import static fr.insalyon.creatis.vip.api.data.UserTestUtils.baseUser1; +import static fr.insalyon.creatis.vip.api.data.UserTestUtils.baseUser1Password; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Created by abonnet on 7/22/16. + * + * These tests check the authentication with the spring test tools. + * It requests a wrong url that should be secured and expects a 404 when OK + *

+ * Use common vip spring test configuration ({@link BaseWebSpringIT} + */ +@ContextConfiguration(classes = SpringAuthenticationWithMockedUserDaoIT.TestContextConfiguration.class) +public class SpringAuthenticationWithMockedUserDaoIT extends BaseWebSpringIT { + + static class TestContextConfiguration { + @Bean + @Primary + public UserDAO mockUser() { + return Mockito.mock(UserDAO.class); + } + } + + @Test + public void authenticationWithCoreKo() throws Exception { + Mockito.when(getUserDAO().getUserByApikey("apikeyvalue")) + .thenThrow(new RuntimeException("hey hey")); + mockMvc.perform(get("/rest/wrongUrl") + .with(ApikeyRequestPostProcessor.apikey("testapikey", "apikeyvalue"))) + .andDo(print()) + .andExpect(status().isUnauthorized()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.errorCode") + .value(ApiError.AUTHENTICATION_ERROR.getCode())); + } +} diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/ExecutionControllerIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/ExecutionControllerIT.java index 4022bf976..b0692d92d 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/ExecutionControllerIT.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/ExecutionControllerIT.java @@ -31,39 +31,47 @@ */ package fr.insalyon.creatis.vip.api.rest.itest.processing; +import fr.insalyon.creatis.grida.common.bean.GridData; import fr.insalyon.creatis.moteur.plugins.workflowsdb.bean.*; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.InputDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.OutputDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.WorkflowDAO; +import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.WorkflowsDBDAOException; import fr.insalyon.creatis.vip.api.exception.ApiException; +import fr.insalyon.creatis.vip.api.model.Execution; +import fr.insalyon.creatis.vip.api.model.ExecutionStatus; import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; import fr.insalyon.creatis.vip.api.rest.config.RestTestUtils; import fr.insalyon.creatis.vip.application.client.bean.AppClass; import fr.insalyon.creatis.vip.application.client.bean.AppVersion; import fr.insalyon.creatis.vip.application.client.bean.Application; import fr.insalyon.creatis.vip.application.client.bean.Engine; +import fr.insalyon.creatis.vip.application.client.view.monitor.SimulationStatus; +import fr.insalyon.creatis.vip.application.server.business.simulation.ParameterSweep; import fr.insalyon.creatis.vip.application.server.business.simulation.WebServiceEngine; -import fr.insalyon.creatis.vip.application.server.dao.ApplicationDAO; import fr.insalyon.creatis.vip.core.client.bean.Group; -import fr.insalyon.creatis.vip.core.server.business.BusinessException; -import fr.insalyon.creatis.vip.core.server.dao.GroupDAO; -import fr.insalyon.creatis.vip.core.server.dao.UsersGroupsDAO; +import fr.insalyon.creatis.vip.core.integrationtest.ServerMockConfig; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.hibernate.jdbc.Work; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; +import org.mockito.MockedConstruction; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.ResultActions; +import java.io.File; +import java.lang.reflect.Parameter; import java.util.*; import static fr.insalyon.creatis.vip.api.data.ExecutionTestUtils.*; import static fr.insalyon.creatis.vip.api.data.UserTestUtils.baseUser1; -import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -77,27 +85,6 @@ */ public class ExecutionControllerIT extends BaseWebSpringIT { - @Autowired - @Qualifier("mockWorkflowDAO") - WorkflowDAO workflowDAO; - @Autowired - @Qualifier("mockOutputDAO") - OutputDAO outputDAO; - @Autowired - @Qualifier("mockInputDAO") - InputDAO inputDAO; - //@Autowired - //@Qualifier("mockUsersGroupsDAO") - UsersGroupsDAO usersGroupsDAO; - //@Autowired - //@Qualifier("mockApplicationDAO") - ApplicationDAO applicationDAO; - @Autowired - @Qualifier("mockWebServiceEngine") - WebServiceEngine webServiceEngine; - //@Autowired - //@Qualifier("mockGroupDAO") - GroupDAO groupDAO; private Workflow w1; private Workflow w2; @@ -105,12 +92,6 @@ public class ExecutionControllerIT extends BaseWebSpringIT { @BeforeEach public void setUp() throws Exception { super.setUp(); - Mockito.reset(workflowDAO); - Mockito.reset(outputDAO); - Mockito.reset(webServiceEngine); - Mockito.reset(inputDAO); - //Mockito.reset(usersGroupsDAO); - //Mockito.reset(applicationDAO); w1 = new Workflow(simulation1.getID(), baseUser1.getFullName(), WorkflowStatus.Completed, new Date(), new Date(), "description", "application", "applicationVersion", "applicationClass", "engine"); w2 = new Workflow(simulation2.getID(), baseUser1.getFullName(), WorkflowStatus.Completed, new Date(), new Date(), "description", "application", "applicationVersion", "applicationClass", "engine"); @@ -120,7 +101,8 @@ public void setUp() throws Exception { public void shouldListExecutions() throws Exception { when(workflowDAO.get(eq(simulation1.getID()))).thenReturn(w1, null); when(workflowDAO.get(eq(simulation2.getID()))).thenReturn(w2, null); - when(workflowDAO.get(eq(baseUser1.getFullName()), ArgumentMatchers.isNull(), ArgumentMatchers.isNull(), ArgumentMatchers.isNull(), ArgumentMatchers.isNull(), ArgumentMatchers.isNull())) + when(workflowDAO.get( + eq(baseUser1.getFullName()), ArgumentMatchers.isNull(), ArgumentMatchers.isNull(), ArgumentMatchers.isNull(), ArgumentMatchers.isNull(), ArgumentMatchers.isNull())) .thenReturn(Arrays.asList(w1, w2), null); // perform a getWorkflows() @@ -129,7 +111,7 @@ public void shouldListExecutions() throws Exception { .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("[*]", hasSize(2))) + .andExpect(jsonPath("$[*]", hasSize(2))) // Check that the returned executions are the good ones .andExpect(jsonPath("$[0].status").value("Finished")) .andExpect(jsonPath("$[0].identifier").value("execId1")) @@ -183,13 +165,19 @@ public void shouldGetExecution2() throws Exception { } @Test - public void shouldGetErrorWhenGettingUnknownExecution() throws Exception { - when(workflowDAO.get(argThat(argument -> !simulation1.getID().equals(argument) && !simulation2.getID().equals(argument)))) - .thenAnswer(invocation -> { - throw new BusinessException("no test execution"); - }); + public void shouldGetErrorOnUnknownExecution() throws Exception { + mockMvc.perform( + get("/rest/executions/WrongExecId").with(baseUser1())) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.errorCode").value(ApiException.ApiError.GENERIC_API_ERROR.getCode())); + } + + @Test + public void shouldGetErrorOnExpectedException() throws Exception { + when(workflowDAO.get(anyString())).thenThrow(new WorkflowsDBDAOException("test exception")); - // perform a getWorkflows() mockMvc.perform( get("/rest/executions/WrongExecId").with(baseUser1())) .andDo(print()) @@ -200,10 +188,7 @@ public void shouldGetErrorWhenGettingUnknownExecution() throws Exception { @Test public void shouldReturnErrorOnUnexpectedException() throws Exception { - when(workflowDAO.get(argThat(argument -> !simulation1.getID().equals(argument) && !simulation2.getID().equals(argument)))) - .thenAnswer(invocation -> { - throw new RuntimeException("TEST RUNTIME EXCEPTION"); - }); + when(workflowDAO.get(anyString())).thenThrow(new RuntimeException("TEST RUNTIME EXCEPTION")); // perform a getWorkflows() mockMvc.perform( @@ -345,25 +330,26 @@ public void testPlayExecutionIsNotImplemented() throws Exception { } @Test - @Disabled public void shouldGetExecution2Results() throws Exception { - String resultPath = simulation2OutData.get(0).getPath(); + String resultPath = "/root/user/user1/path/to/result.res"; + when(workflowDAO.get(eq(simulation2.getID()))).thenReturn(w2, null); Output output = new Output(new OutputID("workflowID", resultPath, "processor"), DataType.URI, "port"); when(outputDAO.get(eq(simulation2.getID()))).thenReturn(Arrays.asList(output), null); - Group group = new Group("group1", true, true, true); - configurationBusiness.addGroup(group); - when(groupDAO.getGroups()).thenReturn(Arrays.asList(group)); + Mockito.when(server.getDataManagerUsersHome()).thenReturn("/root/user"); + Mockito.when(gridaClient.exist(resultPath)).thenReturn(true); + Mockito.when(gridaClient.getFolderData(resultPath, true)).thenReturn(Arrays.asList( + new GridData("result.res", GridData.Type.File, 42, "modifData", "", "", ""))); mockMvc.perform( get("/rest/executions/" + simulation2.getID() + "/results").with(baseUser1())) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$[*]", hasSize(1))); - /*.andExpect(jsonPath("$[0]", - PathTestUtils.jsonCorrespondsToPath(PathTestUtils.testFile1PathProperties)));*/ + .andExpect(jsonPath("$[*]", hasSize(1))) + .andExpect(jsonPath("$[0].path", equalTo("/vip/Home/path/to/result.res"))) + .andExpect(jsonPath("$[0].size", equalTo(42))); } @@ -380,63 +366,158 @@ public void shouldKillExecution2() throws Exception } @Test - @Disabled - public void testInitExecution() throws Exception + public void testInitGwendiaExecution() throws Exception { - // engine test creation - group1 = new Group("group1", true, true, true); - configurationBusiness.addGroup(group1); - List groups = new ArrayList<>(); - groups.add("group1"); - createUserInGroup("test1@test.fr", "suffix1", "group1"); - createUserInGroup("test2@test.fr", "suffix2", "group1"); - - // engine test creation - String engineName = "test engine"; - String engineEndpoint = "test endpoint"; - String engineStatus = "enabled"; - Engine engine = new Engine(engineName, engineEndpoint, engineStatus); - List engines = new ArrayList<>(); - engines.add("test engine"); - engineBusiness.add(engine); - - // appClass test creation - AppClass appClass = new AppClass("class1", engines, groups); - classBusiness.addClass(appClass); - applicationClasses = new ArrayList<>(); - applicationClasses.add("class1"); - - // Application test creation - Application application = new Application("application 1", applicationClasses, "test1@test.fr", "test1", "citation1"); - applicationBusiness.add(application); - - // AppVersion test creation - AppVersion version42 = new AppVersion("application 1", "version 4.2", "lfn", "jsonLfn", true, true); - applicationBusiness.addVersion(version42); - - when(applicationDAO.getApplication("application 1")).thenReturn(application); - - // configure lauch - when(workflowDAO.get(eq(simulation1.getID()))).thenReturn(w1); - when(workflowDAO.getNumberOfRunning(baseUser1.getFullName())).thenReturn(1L); - when(workflowDAO.getRunning()).thenReturn(Arrays.asList(w1)); - when(applicationDAO.getVersion("Application 1", "version 0.0")).thenReturn(version42); - Input input = new Input(new InputID("workflowId", "jsonObjects/execution1.json", "processor"), DataType.URI); - when(inputDAO.get(eq(simulation1.getID()))).thenReturn(Arrays.asList(input)); - //when(testLfcPathsBusiness.parseRealDir(anyString(), eq(baseUser1.getFolder()))).thenReturn("path",null); - Output output = new Output(new OutputID("workflowID", "path", "processor"), DataType.URI, "port"); - when(outputDAO.get(eq(simulation1.getID()))).thenReturn(Arrays.asList(output)); - when(usersGroupsDAO.getUserGroups(eq(baseUser1.getEmail()))).thenReturn(new HashMap<>()); + String appName = "test application", groupName = "testGroup", className = "testClass", versionName = "4.2"; + String engineName = "testEngine", engineEndpoint = "endpoint", worflowId = "test-workflow-id"; + Date startDate = new Date(); + + configureGwendiaTestApp(appName,groupName, className, versionName); + addEngineToClass(className, engineName, engineEndpoint); + + createUserInGroup(baseUser1.getEmail(), groupName); + + ArgumentCaptor workflowFile = ArgumentCaptor.forClass(File.class); + ArgumentCaptor> inputsCaptor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor workflowCaptor = ArgumentCaptor.forClass(Workflow.class); + + Mockito.when(server.getVoName()).thenReturn("test-vo-name"); + Mockito.when(server.getServerProxy("test-vo-name")).thenReturn("/path/to/proxy"); + Mockito.when(getWebServiceEngine().launch("/path/to/proxy", null)).thenReturn("full-test-workflow-id", (String) null); + Mockito.when(getWebServiceEngine().getSimulationId("full-test-workflow-id")).thenReturn(worflowId, (String) null); + Mockito.when(getWebServiceEngine().getStatus(worflowId)).thenReturn(SimulationStatus.Running, (SimulationStatus) null); + Mockito.when(getWebServiceEngine().getAddressWS()).thenReturn(engineEndpoint, (String) null); + + Workflow w = new Workflow(worflowId, baseUser1.getFullName(), WorkflowStatus.Running, startDate, null, "Exec test 1", appName, versionName, className, engineName); + when(workflowDAO.get(worflowId)).thenReturn(w, (Workflow) null); + + Execution expectedExecution = new Execution(worflowId, "Exec test 1", appName + "/" + versionName, 0, ExecutionStatus.RUNNING, null, null, startDate.getTime(), null, null); + expectedExecution.clearReturnedFiles(); mockMvc.perform( - post("/rest/executions").contentType("application/json") - .content(getResourceAsString("jsonObjects/execution1.json")) - .with(baseUser1())) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$", - jsonCorrespondsToExecution(execution1) + post("/rest/executions").contentType("application/json") + .content(getResourceAsString("jsonObjects/execution1.json")) + .with(baseUser1())) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$", + jsonCorrespondsToExecution(expectedExecution) + )); + + // verify workflow path + Mockito.verify(getWebServiceEngine()).setWorkflow(workflowFile.capture()); + Assertions.assertEquals(getGwendiaTestFile().getAbsolutePath(), workflowFile.getValue().getAbsolutePath()); + + // verify inputs + Mockito.verify(getWebServiceEngine()).setInput(inputsCaptor.capture()); + List inputs = inputsCaptor.getValue(); + Assertions.assertEquals(5, inputs.size()); + MatcherAssert.assertThat(inputs, Matchers.containsInAnyOrder( + both(hasProperty("parameterName", is("testFileInput"))). + and(hasProperty("values", Matchers.contains(ServerMockConfig.TEST_USERS_ROOT + "/" + baseUser1.getFolder() + "/path/to/input.in"))), + both(hasProperty("parameterName", is("testTextInput"))). + and(hasProperty("values", Matchers.contains("best test text value"))), + both(hasProperty("parameterName", is("results-directory"))). + and(hasProperty("values", Matchers.contains(ServerMockConfig.TEST_USERS_ROOT + "/" + baseUser1.getFolder()))), + both(hasProperty("parameterName", is("testOptionalTextInput"))). + and(hasProperty("values", Matchers.contains("No_value_provided"))), + both(hasProperty("parameterName", is("testFlagInput"))). + and(hasProperty("values", Matchers.contains("false"))) )); + + // verify created workflow + Mockito.verify(workflowDAO).add(workflowCaptor.capture()); + Workflow workflow = workflowCaptor.getValue(); + Assertions.assertEquals(appName, workflow.getApplication()); + Assertions.assertEquals(versionName, workflow.getApplicationVersion()); + Assertions.assertEquals(className, workflow.getApplicationClass()); + Assertions.assertEquals(worflowId, workflow.getId()); + Assertions.assertEquals(WorkflowStatus.Running, workflow.getStatus()); + Assertions.assertEquals("Exec test 1", workflow.getDescription()); + Assertions.assertEquals(engineEndpoint, workflow.getEngine()); + Assertions.assertEquals(baseUser1.getFullName(), workflow.getUsername()); + Assertions.assertNull(workflow.getFinishedTime()); + MatcherAssert.assertThat(workflow.getStartedTime().getTime(), + is(both(greaterThan(startDate.getTime())).and(lessThan(new Date().getTime())))); + + } + + // the difference (at the moment) is that with moteurLite the optional and absent parameters are not included + @Test + public void testInitBoutiquesExecution() throws Exception + { + String appName = "test application", groupName = "testGroup", className = "testClass", versionName = "4.2"; + String engineName = "testEngine", engineEndpoint = "endpoint", worflowId = "test-workflow-id"; + Date startDate = new Date(); + + configureBoutiquesTestApp(appName,groupName, className, versionName); + addEngineToClass(className, engineName, engineEndpoint); + + createUserInGroup(baseUser1.getEmail(), groupName); + + ArgumentCaptor workflowFile = ArgumentCaptor.forClass(File.class); + ArgumentCaptor> inputsCaptor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor workflowCaptor = ArgumentCaptor.forClass(Workflow.class); + + Mockito.when(server.useMoteurlite()).thenReturn(true); + Mockito.when(server.getVoName()).thenReturn("test-vo-name"); + Mockito.when(server.getServerProxy("test-vo-name")).thenReturn("/path/to/proxy"); + Mockito.when(getWebServiceEngine().launch("/path/to/proxy", null)).thenReturn("full-test-workflow-id", (String) null); + Mockito.when(getWebServiceEngine().getSimulationId("full-test-workflow-id")).thenReturn(worflowId, (String) null); + Mockito.when(getWebServiceEngine().getStatus(worflowId)).thenReturn(SimulationStatus.Running, (SimulationStatus) null); + Mockito.when(getWebServiceEngine().getAddressWS()).thenReturn(engineEndpoint, (String) null); + + Workflow w = new Workflow(worflowId, baseUser1.getFullName(), WorkflowStatus.Running, startDate, null, "Exec test 1", appName, versionName, className, engineName); + when(workflowDAO.get(worflowId)).thenReturn(w, (Workflow) null); + + Execution expectedExecution = new Execution(worflowId, "Exec test 1", appName + "/" + versionName, 0, ExecutionStatus.RUNNING, null, null, startDate.getTime(), null, null); + expectedExecution.clearReturnedFiles(); + + mockMvc.perform( + post("/rest/executions").contentType("application/json") + .content(getResourceAsString("jsonObjects/execution1.json")) + .with(baseUser1())) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$", + jsonCorrespondsToExecution(expectedExecution) + )); + + // verify workflow path + Mockito.verify(getWebServiceEngine()).setWorkflow(workflowFile.capture()); + Assertions.assertEquals(getBoutiquesTestFile().getAbsolutePath(), workflowFile.getValue().getAbsolutePath()); + + // verify inputs + Mockito.verify(getWebServiceEngine()).setInput(inputsCaptor.capture()); + List inputs = inputsCaptor.getValue(); + Assertions.assertEquals(4, inputs.size()); + MatcherAssert.assertThat(inputs, Matchers.containsInAnyOrder( + both(hasProperty("parameterName", is("testFileInput"))). + and(hasProperty("values", Matchers.contains(ServerMockConfig.TEST_USERS_ROOT + "/" + baseUser1.getFolder() + "/path/to/input.in"))), + both(hasProperty("parameterName", is("testTextInput"))). + and(hasProperty("values", Matchers.contains("best test text value"))), + both(hasProperty("parameterName", is("results-directory"))). + and(hasProperty("values", Matchers.contains(ServerMockConfig.TEST_USERS_ROOT + "/" + baseUser1.getFolder()))), + both(hasProperty("parameterName", is("testFlagInput"))). + and(hasProperty("values", Matchers.contains("false"))) + )); + + // verify created workflow + Mockito.verify(workflowDAO).add(workflowCaptor.capture()); + Workflow workflow = workflowCaptor.getValue(); + Assertions.assertEquals(appName, workflow.getApplication()); + Assertions.assertEquals(versionName, workflow.getApplicationVersion()); + Assertions.assertEquals(className, workflow.getApplicationClass()); + Assertions.assertEquals(worflowId, workflow.getId()); + Assertions.assertEquals(WorkflowStatus.Running, workflow.getStatus()); + Assertions.assertEquals("Exec test 1", workflow.getDescription()); + Assertions.assertEquals(engineEndpoint, workflow.getEngine()); + Assertions.assertEquals(baseUser1.getFullName(), workflow.getUsername()); + Assertions.assertNull(workflow.getFinishedTime()); + MatcherAssert.assertThat(workflow.getStartedTime().getTime(), + is(both(greaterThan(startDate.getTime())).and(lessThan(new Date().getTime())))); + } } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/PipelineControllerIT.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/PipelineControllerIT.java index 9f3ce0e14..a47622aee 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/PipelineControllerIT.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/processing/PipelineControllerIT.java @@ -31,75 +31,32 @@ */ package fr.insalyon.creatis.vip.api.rest.itest.processing; -import fr.insalyon.creatis.vip.api.data.ClassesTestUtils; -import fr.insalyon.creatis.vip.api.data.UserTestUtils; +import fr.insalyon.creatis.grida.client.GRIDAClientException; import fr.insalyon.creatis.vip.api.exception.ApiException.ApiError; import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; -import fr.insalyon.creatis.vip.application.client.bean.AppClass; import fr.insalyon.creatis.vip.application.client.bean.AppVersion; -import fr.insalyon.creatis.vip.application.client.bean.Application; -import fr.insalyon.creatis.vip.application.server.dao.ApplicationDAO; -import fr.insalyon.creatis.vip.application.server.dao.ClassDAO; -import fr.insalyon.creatis.vip.core.client.bean.Group; import fr.insalyon.creatis.vip.core.server.business.BusinessException; -import fr.insalyon.creatis.vip.datamanager.server.business.DataManagerBusiness; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.RequestPostProcessor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.io.File; +import java.io.IOException; -import static fr.insalyon.creatis.vip.api.data.AppVersionTestUtils.*; -import static fr.insalyon.creatis.vip.api.data.ApplicationTestUtils.*; import static fr.insalyon.creatis.vip.api.data.PipelineTestUtils.*; -import static fr.insalyon.creatis.vip.api.data.UserTestUtils.baseUser1; -import static fr.insalyon.creatis.vip.api.rest.mockconfig.ApplicationsConfigurator.configureAnApplication; -import static fr.insalyon.creatis.vip.api.rest.mockconfig.ApplicationsConfigurator.configureApplications; +import static fr.insalyon.creatis.vip.api.data.UserTestUtils.*; import static fr.insalyon.creatis.vip.application.client.view.ApplicationException.ApplicationError.WRONG_APPLICATION_DESCRIPTOR; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.hasSize; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.when; +import static org.hamcrest.Matchers.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -/** - * Created by abonnet on 7/20/16. - *

- * Test methods on pipeline path - *

- * Include 2 tests on error handling - */ -@Disabled public class PipelineControllerIT extends BaseWebSpringIT { - @Autowired - @Qualifier("mockClassDAO") - ClassDAO classDAO; - @Autowired - @Qualifier("mockApplicationDAO") - ApplicationDAO applicationDAO; - @Autowired - @Qualifier("mockDataManagerBusiness") - DataManagerBusiness dataManagerBusiness; - @BeforeEach public void setUp() throws Exception { super.setUp(); - Mockito.reset(classDAO); - Mockito.reset(applicationDAO); } @Test @@ -129,13 +86,22 @@ public void shouldReturnErrorOnAPIExceptionInvalidId() throws Exception { @Test public void shouldReturnErrorOnConfiguredVipException() throws Exception { - /*configureApplications(this, baseUser1, Arrays.asList(class1, class2), - app2, version42);*/ + String appName = "testApp", groupName = "testGroup", className = "testClass"; + String versionName = "42-test"; + AppVersion appVersion = configureAnApplication(appName, versionName, groupName, className); + configureVersion(appVersion, + "/vip/testGroup (group)/path/to/test.gwendia", null); + + createUserInGroup(baseUser1.getEmail(), groupName); + + Mockito.when(server.getDataManagerPath()).thenReturn("/test/folder"); + Mockito.when(server.getDataManagerGroupsHome()).thenReturn("/root/group"); + // localDir is datamanagerpath + "downloads" + groupRoot + dir(path) + Mockito.when(gridaClient.getRemoteFile( + "/root/group/testGroup/path/to/test.gwendia", + "/test/folder/downloads/root/group/testGroup/path/to")).thenThrow(new GRIDAClientException("test exception")); - String pipelineId = app2.getName() + "/" + version42.getVersion(); - when(workflowBusiness.getApplicationDescriptor( - eq(baseUser1), eq(app2.getName()), eq(version42.getVersion()))) - .thenThrow(new BusinessException(WRONG_APPLICATION_DESCRIPTOR, pipelineId)); + String pipelineId = appName + "/" + versionName; mockMvc.perform(get("/rest/pipelines/" + pipelineId).with(baseUser1())) .andDo(print()) .andExpect(status().isBadRequest()) @@ -145,74 +111,155 @@ public void shouldReturnErrorOnConfiguredVipException() throws Exception { @Test public void userGetAPipelineWithPathParameterNonEncoded() throws Exception { - /*configureApplications(this, baseUser1, Arrays.asList(class1, class2), - app2, version42);*/ - String pipelineId = configureAnApplication(this, baseUser1, app2, version42, 0, 1); - mockMvc.perform(get("/rest/pipelines/" + pipelineId) - .with(baseUser1())) + String appName = "testGwendiaApp", groupName = "testGroup", className = "testClass", versionName = "42-test"; + AppVersion appVersion = configureGwendiaTestApp(appName, groupName, className, versionName); + String pipelineId = appName + "/" + versionName; + + createUserInGroup(baseUser1.getEmail(), groupName); + + mockMvc.perform(get("/rest/pipelines/" + pipelineId).with(baseUser1())) .andDo(print()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$", jsonCorrespondsToPipeline(getFullPipeline(app2, version42, "desc test", 0, 1)))); + // res-dir should be removed from the description + .andExpect(jsonPath("$", jsonCorrespondsToPipeline( + getFullPipeline(appVersion, "Test tool description. Must be similar to the boutiques one", flagParam, textParam, fileParam, optionalTextParamNoValueProvided)))); } @Test - public void shouldReturnPipelines() throws Exception { + public void userGetAPipelineWithQueryParameter() throws Exception { + String appName = "testGwendiaApp", groupName = "testGroup", className = "testClass", versionName = "42-test"; + AppVersion appVersion = configureGwendiaTestApp(appName, groupName, className, versionName); + String pipelineId = appName + "/" + versionName; + + createUserInGroup(baseUser1.getEmail(), groupName); + + mockMvc.perform(get("/rest/pipelines").param("pipelineId", pipelineId).with(baseUser1())) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + // res-dir should be removed from the description + .andExpect(jsonPath("$", jsonCorrespondsToPipeline( + getFullPipeline(appVersion, "Test tool description. Must be similar to the boutiques one", flagParam, textParam, fileParam, optionalTextParamNoValueProvided)))); + } - AppClass appClass = new AppClass("appClass", new ArrayList<>()); - classBusiness.addClass(appClass); + @Test + public void userGetAPipelineWithBoutiques() throws Exception { - createUser("test1@test.fr"); + String appName = "testBoutiquesApp", groupName = "testGroup", className = "testClass", versionName = "v42"; + AppVersion appVersion = configureBoutiquesTestApp(appName, groupName, className, versionName); + String pipelineId = appName + "/" + versionName; - Application app1 = new Application("app1", Arrays.asList(appClass.getName()), "test1@test.fr", "test1", "citation1"); - Application app2 = new Application("app2", Arrays.asList(appClass.getName()), "test1@test.fr", "test1", "citation1"); - Application app3 = new Application("app3", Arrays.asList(appClass.getName()), "test1@test.fr", "test1", "citation1"); - applicationBusiness.add(app1); - applicationBusiness.add(app2); - applicationBusiness.add(app3); + Mockito.when(server.useMoteurlite()).thenReturn(true); - AppVersion version42App1 = new AppVersion("app1", "version42", "lfn", "jsonLfn", true, true); - applicationBusiness.addVersion(version42App1); + createUserInGroup(baseUser1.getEmail(), groupName); - AppVersion version42App3 = new AppVersion("app3", "version42", "lfn", "jsonLfn", true, true); - applicationBusiness.addVersion(version42App3); + mockMvc.perform(get("/rest/pipelines/" + pipelineId).with(baseUser1())) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + // res-dir should be absent from the description + .andExpect(jsonPath("$.name", equalTo(appName))) + .andExpect(jsonPath("$", jsonCorrespondsToPipeline( + getFullPipeline(appVersion, "Test app from axel. Must be similar to the gwendia test app", flagParam, textParam, fileParam, optionalTextParam)))); - AppVersion version01App2= new AppVersion("app2", "version01", "lfn", "jsonLfn", true, true); - applicationBusiness.addVersion(version01App2); + } - AppVersion version01App3= new AppVersion("app3", "version01", "lfn", "jsonLfn", true, true); - applicationBusiness.addVersion(version01App3); + @Test + public void userGetBoutiquesDescriptor() throws Exception { - AppVersion version43App3= new AppVersion("app3", "version43", "lfn", "jsonLfn", true, true); - applicationBusiness.addVersion(version43App3); + String appName = "testBoutiquesApp", groupName = "testGroup", className = "testClass", versionName = "v42"; + configureBoutiquesTestApp(appName, groupName, className, versionName); + String pipelineId = appName + "/" + versionName; + createUserInGroup(baseUser1.getEmail(), groupName); - ResultActions result = mockMvc.perform(get("/rest/pipelines").with(baseUser1())) + mockMvc.perform(get("/rest/pipelines/" + pipelineId).param("format", "boutiques").with(baseUser1())) .andDo(print()) - .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$[*]", hasSize(5))) - .andExpect(jsonPath("$[*]", containsInAnyOrder( - jsonCorrespondsToPipeline(getPipeline(app1, version42)), - jsonCorrespondsToPipeline(getPipeline(app2, version01)), - jsonCorrespondsToPipeline(getPipeline(app3, version01)), - jsonCorrespondsToPipeline(getPipeline(app3, version42)), - jsonCorrespondsToPipeline(getPipeline(app3, version43))))); - - String content = result.andReturn().getResponse().getContentAsString(); - System.out.println("Results : "+content); + // res-dir should be removed from the description + .andExpect(jsonPath("$.name", equalTo(appName))) + .andExpect(jsonPath("$.tool-version", equalTo(versionName))) + .andExpect(jsonPath("$.schema-version", equalTo("0.5"))) + .andExpect(jsonPath("$.inputs[*]", hasSize(4))); + } @Test - public void userGetAPipelineWithQueryParameter() throws Exception { - /*configureApplications(this, baseUser1, Arrays.asList(class1, class2), - app2, version42);*/ + public void shouldReturnPipelines() throws Exception { + createGroup("group1"); + createGroup("group2"); + createGroup("group3"); - String pipelineId = configureAnApplication(this, baseUser1, app2, version42, 0, 1); - mockMvc.perform(get("/rest/pipelines").param("pipelineId", pipelineId) - .with(baseUser1())) + createClass("class1", "group1"); + createClass("class2", "group2"); + createClass("class3", "group3"); + createAnApplication("app1", "class1"); + createAnApplication("app2", "class2"); + createAnApplication("app3", "class3"); + + AppVersion app11 = createAVersion("app1", "v1", true, null, null); + createAVersion("app1", "v2", false, null, null); + AppVersion app13 = createAVersion("app1", "v3", true, null, null); + AppVersion app2 = createAVersion("app2", "v1.1", true, null, null); + createAVersion("app3", "v4", false, null, null); + + createClass("classA", "group1", "group2"); + createClass("classB", "group2", "group3"); + createClass("classC", "group3"); + + createAnApplication("appAB", "classA", "classB"); + createAnApplication("appBC", "classB", "classC"); + createAnApplication("appC", "classC"); + + AppVersion appAB = createAVersion("appAB", "v1", true, null, null); + AppVersion appBC = createAVersion("appBC", "v1", true, null, null); + AppVersion appC = createAVersion("appC", "v1", true, null, null); + + createUserInGroup(baseUser1.getEmail(), "test1", "group1"); + createUserInGroup(baseUser2.getEmail(), "test2", "group2"); + createUserInGroup(baseUser3.getEmail(), "test3", "group3"); + createUserInGroups(baseUser4.getEmail(), "test4", "group1", "group2"); + + mockMvc.perform(get("/rest/pipelines").with(baseUser1())) .andDo(print()) + .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$", jsonCorrespondsToPipeline(getFullPipeline(app2, version42, "desc test", 0, 1)))); + .andExpect(jsonPath("$[*]", hasSize(3))) + .andExpect(jsonPath("$[*]", containsInAnyOrder( + jsonCorrespondsToPipeline(getPipeline(app11)), + jsonCorrespondsToPipeline(getPipeline(app13)), + jsonCorrespondsToPipeline(getPipeline(appAB))))); + + mockMvc.perform(get("/rest/pipelines").with(baseUser2())) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$[*]", hasSize(3))) + .andExpect(jsonPath("$[*]", containsInAnyOrder( + jsonCorrespondsToPipeline(getPipeline(app2)), + jsonCorrespondsToPipeline(getPipeline(appAB)), + jsonCorrespondsToPipeline(getPipeline(appBC))))); + + mockMvc.perform(get("/rest/pipelines").with(baseUser3())) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$[*]", hasSize(3))) + .andExpect(jsonPath("$[*]", containsInAnyOrder( + jsonCorrespondsToPipeline(getPipeline(appAB)), + jsonCorrespondsToPipeline(getPipeline(appBC)), + jsonCorrespondsToPipeline(getPipeline(appC))))); + + mockMvc.perform(get("/rest/pipelines").with(baseUser4())) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$[*]", hasSize(5))) + .andExpect(jsonPath("$[*]", containsInAnyOrder( + jsonCorrespondsToPipeline(getPipeline(app11)), + jsonCorrespondsToPipeline(getPipeline(app13)), + jsonCorrespondsToPipeline(getPipeline(app2)), + jsonCorrespondsToPipeline(getPipeline(appAB)), + jsonCorrespondsToPipeline(getPipeline(appBC))))); + } } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/mockconfig/ApplicationsConfigurator.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/mockconfig/ApplicationsConfigurator.java deleted file mode 100644 index 4f16fc608..000000000 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/mockconfig/ApplicationsConfigurator.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright and authors: see LICENSE.txt in base repository. - * - * This software is a web portal for pipeline execution on distributed systems. - * - * This software is governed by the CeCILL-B license under French law and - * abiding by the rules of distribution of free software. You can use, - * modify and/ or redistribute the software under the terms of the CeCILL-B - * license as circulated by CEA, CNRS and INRIA at the following URL - * "http://www.cecill.info". - * - * As a counterpart to the access to the source code and rights to copy, - * modify and redistribute granted by the license, users are provided only - * with a limited warranty and the software's author, the holder of the - * economic rights, and the successive licensors have only limited - * liability. - * - * In this respect, the user's attention is drawn to the risks associated - * with loading, using, modifying and/or developing or reproducing the - * software by the user in light of its specific status of free software, - * that may mean that it is complicated to manipulate, and that also - * therefore means that it is reserved for developers and experienced - * professionals having in-depth computer knowledge. Users are therefore - * encouraged to load and test the software's suitability as regards their - * requirements in conditions enabling the security of their systems and/or - * data to be ensured and, more generally, to use and operate it in the - * same conditions as regards security. - * - * The fact that you are presently reading this means that you have had - * knowledge of the CeCILL-B license and that you accept its terms. - */ -package fr.insalyon.creatis.vip.api.rest.mockconfig; - -import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; -import fr.insalyon.creatis.vip.application.client.bean.AppClass; -import fr.insalyon.creatis.vip.application.client.bean.AppVersion; -import fr.insalyon.creatis.vip.application.client.bean.Application; -import fr.insalyon.creatis.vip.application.server.business.ApplicationBusiness; -import fr.insalyon.creatis.vip.application.server.business.ClassBusiness; -import fr.insalyon.creatis.vip.application.server.business.WorkflowBusiness; -import fr.insalyon.creatis.vip.core.client.bean.User; -import fr.insalyon.creatis.vip.core.server.business.BusinessException; - -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static fr.insalyon.creatis.vip.api.data.AppVersionTestUtils.getVersion; -import static fr.insalyon.creatis.vip.api.data.PipelineTestUtils.getDescriptor; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -/** - * Created by abonnet on 10/14/16. - */ -public class ApplicationsConfigurator { - - /** - * Should take only Application and AppVersion classes in the sequence : - * Application AppVersion+ - * (an application followed by one or more version) - */ - public static void configureApplications( - BaseWebSpringIT test, - User user, - List classes, - Object... args) throws BusinessException { - // parse the args to map the application to the versions - Application currentApplication = null; - Map> applicationVersions = new HashMap<>(); - for (Object currentArg : args) { - if (currentArg instanceof Application) { - currentApplication = (Application) currentArg; - applicationVersions.put(currentApplication, new ArrayList<>()); - } else { - applicationVersions.get(currentApplication). - add(getVersion((AppVersion) currentArg, currentApplication)); - } - } - List classNames = - classes.stream().map(AppClass::getName).collect(Collectors.toList()); - // verify the classes given are good - Predicate isAppNotOK = - app -> Collections.disjoint(app.getApplicationClasses(), classNames); - if (applicationVersions.keySet().stream().anyMatch(isAppNotOK)) { - throw new RuntimeException("misconfiguration of test class>app config"); - } - // configure mocks - ClassBusiness classBusiness = test.getClassBusiness(); - ApplicationBusiness applicationBusiness = test.getApplicationBusiness(); - // 1 return user classes - when(classBusiness.getUserClasses(eq(user.getEmail()), eq(false))) - .thenReturn(classes); - when(classBusiness.getUserClassesName( - eq(user.getEmail()), eq(false))) - .thenReturn(classNames); - // 2 return apps for the classes - when(applicationBusiness.getApplications(anyList())). - thenReturn(new ArrayList<>(applicationVersions.keySet())); - // 3 return versions for each app - for (Application app : applicationVersions.keySet()) { - when(applicationBusiness.getVersions(eq(app.getName()))) - .thenReturn(applicationVersions.get(app)); - when(applicationBusiness.getApplication(eq(app.getName()))) - .thenReturn(app); - } - } - - public static String configureAnApplication( - BaseWebSpringIT test, - User user, Application app, - AppVersion version, - Integer... appParamsIndexes) throws BusinessException { - WorkflowBusiness workflowBusiness = test.getWorkflowBusiness(); - when(workflowBusiness.getApplicationDescriptor( - eq(user), eq(app.getName()), eq(version.getVersion()))) - .thenReturn(getDescriptor("desc test", appParamsIndexes)); - return app.getName() + "/" + version.getVersion(); - } -} diff --git a/vip-api/src/test/resources/TestHome/.vip/vip.conf b/vip-api/src/test/resources/TestHome/.vip/vip.conf deleted file mode 100644 index e69de29bb..000000000 diff --git a/vip-api/src/test/resources/boutiques/test-boutiques.json b/vip-api/src/test/resources/boutiques/test-boutiques.json new file mode 100644 index 000000000..e8fafc49f --- /dev/null +++ b/vip-api/src/test/resources/boutiques/test-boutiques.json @@ -0,0 +1,68 @@ +{ + "name": "testBoutiquesApp", + "tool-version": "v42", + "description": "Test app from axel. Must be similar to the gwendia test app", + "schema-version": "0.5", + "command-line": "echo [testFileInput] [testTextInput] [testOptionalTextInput] [testFlagInput]", + "author": "Axel ", + "container-image": { + "index": "docker://", + "image": "test-axel", + "type": "docker", + "container-opts": [ + "-v /tmp:/tmp" + ] + }, + "inputs": [ + { + "id": "testFileInput", + "name": "Test file input", + "type": "File", + "description": "This is a test file input", + "value-key": "[testFileInput]" + }, + { + "id": "testTextInput", + "name": "Test text input", + "type": "String", + "default-value": "test text value", + "description": "This is a test text input", + "value-key": "[testTextInput]" + }, + { + "id": "testOptionalTextInput", + "name": "Test optional text input", + "type": "String", + "optional": true, + "description": "This is a optional test text input", + "value-key": "[testOptionalTextInput]" + }, + { + "id": "testFlagInput", + "name": "Test flag input", + "type": "Flag", + "optional": true, + "default-value": "false", + "description": "This is a test flag input", + "command-line-flag": "--test-flag", + "value-key": "[testFlagInput]" + } + ], + "output-files": [ + { + "id": "UNUSED", + "name": "Output", + "optional": false, + "description": "UNUSED", + "path-template": "UNUSED.tgz" + } + ], "error-codes": [ + { + "description": "Crashed", + "code": 1 + } + ], + "custom": { + "vip:plop": "plop" + } +} diff --git a/vip-api/src/test/resources/gwendia/basic-gwendia.gwendia b/vip-api/src/test/resources/gwendia/basic-gwendia.gwendia new file mode 100644 index 000000000..b347235aa --- /dev/null +++ b/vip-api/src/test/resources/gwendia/basic-gwendia.gwendia @@ -0,0 +1,72 @@ + + + Test tool description. Must be similar to the boutiques one + + + This is the test results directory input + + + This is a test file input + + + This is a test text input + + + This is a optional test text input + + + This is a test flag input + + + + + + + + + /*----------Beginning of Beanshell------------*/ +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +String result = dir.toString(); +if ( result.startsWith("/") || result.startsWith("lfn:") ) { + DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy_HH:mm:ss"); + result = result + "/" + (dateFormat.format(System.currentTimeMillis())); +} +/*------------End of Beanshell------------*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vip-api/src/test/resources/jsonObjects/execution1.json b/vip-api/src/test/resources/jsonObjects/execution1.json index 3439e0d45..657cd07db 100644 --- a/vip-api/src/test/resources/jsonObjects/execution1.json +++ b/vip-api/src/test/resources/jsonObjects/execution1.json @@ -1,8 +1,8 @@ { "name" : "Exec test 1", - "pipelineIdentifier" : "application 1/4.2", + "pipelineIdentifier" : "test application/4.2", "inputValues" : { - "param 1" : "test text", - "param 2" : "/path/test" + "testFileInput" : "/vip/Home/path/to/input.in", + "testTextInput" : "best test text value" } } \ No newline at end of file diff --git a/vip-api/src/test/resources/jsonObjects/user-credentials.json b/vip-api/src/test/resources/jsonObjects/user-credentials.json index 7a5e602ec..bb04fd530 100644 --- a/vip-api/src/test/resources/jsonObjects/user-credentials.json +++ b/vip-api/src/test/resources/jsonObjects/user-credentials.json @@ -1,4 +1,4 @@ { - "username":"baseuser1@test.tst", + "username":"test2@test.fr", "password":"coucou" } \ No newline at end of file diff --git a/vip-application/pom.xml b/vip-application/pom.xml index 0f6a9ca52..99d66c8a7 100644 --- a/vip-application/pom.xml +++ b/vip-application/pom.xml @@ -105,7 +105,7 @@ knowledge of the CeCILL-B license and that you accept its terms. org.jsoup jsoup - 1.7.2 + 1.15.3 diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/Application.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/Application.java index 5260abb36..3808641a7 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/Application.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/Application.java @@ -34,6 +34,7 @@ import com.google.gwt.user.client.rpc.IsSerializable; import org.opensaml.xml.encryption.Public; +import java.util.ArrayList; import java.util.List; /** @@ -53,7 +54,7 @@ public Application() { } public Application(String name, String citation) { - this(name, null, null, null, citation); + this(name, new ArrayList<>(), null, null, citation); } public Application(String name, List applicationClasses, String citation) { diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/SpringApplicationConfig.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/SpringApplicationConfig.java index 2c5f5d9d1..05d1609c5 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/SpringApplicationConfig.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/SpringApplicationConfig.java @@ -1,5 +1,6 @@ package fr.insalyon.creatis.vip.application.server; +import com.fasterxml.jackson.databind.ObjectMapper; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.*; import fr.insalyon.creatis.vip.application.server.dao.SimulationStatsDAO; import fr.insalyon.creatis.vip.application.server.dao.hibernate.SimulationStatsData; @@ -7,6 +8,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; /** * Spring special configuration for vip-application. @@ -55,4 +57,5 @@ public InputDAO getInputDAO() throws WorkflowsDBDAOException { public StatsDAO getStatsDAO() throws WorkflowsDBDAOException { return workflowsDBDAOFactory().getStatsDAO(); } + } diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/BoutiquesBusiness.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/BoutiquesBusiness.java index af8baad1d..1da7addb0 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/BoutiquesBusiness.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/BoutiquesBusiness.java @@ -31,7 +31,9 @@ */ package fr.insalyon.creatis.vip.application.server.business; +import com.fasterxml.jackson.databind.ObjectMapper; import fr.insalyon.creatis.vip.application.client.bean.AppVersion; +import fr.insalyon.creatis.vip.application.server.model.boutiques.BoutiquesDescriptor; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.server.business.BusinessException; import fr.insalyon.creatis.vip.core.server.business.Server; @@ -45,6 +47,7 @@ import org.xml.sax.SAXException; import java.io.*; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Scanner; @@ -63,12 +66,15 @@ public class BoutiquesBusiness { private Server server; private DataManagerBusiness dataManagerBusiness; private ApplicationBusiness applicationBusiness; + private ObjectMapper objectMapper; @Autowired - public BoutiquesBusiness(Server server, DataManagerBusiness dataManagerBusiness, ApplicationBusiness applicationBusiness) { + public BoutiquesBusiness(Server server, DataManagerBusiness dataManagerBusiness, + ApplicationBusiness applicationBusiness, ObjectMapper objectMapper) { this.server = server; this.dataManagerBusiness = dataManagerBusiness; this.applicationBusiness = applicationBusiness; + this.objectMapper = objectMapper; } public String publishVersion(User user, String applicationName, String version) @@ -133,6 +139,15 @@ public String getApplicationDescriptorString( } } + public BoutiquesDescriptor parseBoutiquesFile(File boutiquesFile) throws BusinessException { + try { + return objectMapper.readValue(boutiquesFile, BoutiquesDescriptor.class); + } catch (IOException e) { + logger.error("Error reading {} file for boutiques parsing", boutiquesFile, e); + throw new BusinessException("Error reading boutiques file", e); + } + } + private void saveDoiForVersion( String doi, String applicationName, String applicationVersion) throws BusinessException { diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/WorkflowBusiness.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/WorkflowBusiness.java index 55026d9b8..d192c4b28 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/WorkflowBusiness.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/WorkflowBusiness.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Random; +import fr.insalyon.creatis.vip.application.server.model.boutiques.BoutiquesDescriptor; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/dao/mysql/ApplicationData.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/dao/mysql/ApplicationData.java index ba8fb761a..0c4f0d560 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/dao/mysql/ApplicationData.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/dao/mysql/ApplicationData.java @@ -624,19 +624,19 @@ public AppVersion getVersion(String applicationName, String applicationVersion) ps.setString(2, applicationVersion); ResultSet rs = ps.executeQuery(); - rs.next(); - - AppVersion version = new AppVersion(rs.getString("application"), - rs.getString("version"), - rs.getString("lfn"), - rs.getString("json_lfn"), - rs.getString("doi"), - rs.getBoolean("visible"), - rs.getBoolean("useBoutiquesForm")); - ps.close(); - - return version; + if (rs.first()) { + AppVersion version = new AppVersion(rs.getString("application"), + rs.getString("version"), + rs.getString("lfn"), + rs.getString("json_lfn"), + rs.getString("doi"), + rs.getBoolean("visible"), + rs.getBoolean("useBoutiquesForm")); + ps.close(); + return version; + } + return null; } catch (SQLException ex) { logger.error("Error getting versions for {}/{}", applicationName, applicationVersion, ex); diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Assertions.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Assertions.java new file mode 100644 index 000000000..c896e08e7 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Assertions.java @@ -0,0 +1,75 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "exit-code", + "output-files" +}) +@Generated("jsonschema2pojo") +public class Assertions { + + /** + * Expected code returned by the program. + * + */ + @JsonProperty("exit-code") + @JsonPropertyDescription("Expected code returned by the program.") + private Integer exitCode; + @JsonProperty("output-files") + private List testOutputFiles = new ArrayList(); + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + /** + * Expected code returned by the program. + * + */ + @JsonProperty("exit-code") + public Integer getExitCode() { + return exitCode; + } + + /** + * Expected code returned by the program. + * + */ + @JsonProperty("exit-code") + public void setExitCode(Integer exitCode) { + this.exitCode = exitCode; + } + + @JsonProperty("output-files") + public List getOutputFiles() { + return testOutputFiles; + } + + @JsonProperty("output-files") + public void setOutputFiles(List testOutputFiles) { + this.testOutputFiles = testOutputFiles; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/BoutiquesDescriptor.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/BoutiquesDescriptor.java new file mode 100644 index 000000000..fd20ed071 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/BoutiquesDescriptor.java @@ -0,0 +1,645 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + + +/** + * Tool + *

+ * + * + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "name", + "tool-version", + "description", + "deprecated-by-doi", + "author", + "url", + "descriptor-url", + "doi", + "shell", + "tool-doi", + "command-line", + "container-image", + "schema-version", + "environment-variables", + "groups", + "inputs", + "tests", + "online-platform-urls", + "output-files", + "invocation-schema", + "suggested-resources", + "tags", + "error-codes", + "custom" +}) +@Generated("jsonschema2pojo") +public class BoutiquesDescriptor { + + /** + * Tool name. + * (Required) + * + */ + @JsonProperty("name") + @JsonPropertyDescription("Tool name.") + private String name; + /** + * Tool version. + * (Required) + * + */ + @JsonProperty("tool-version") + @JsonPropertyDescription("Tool version.") + private String toolVersion; + /** + * Tool description. + * (Required) + * + */ + @JsonProperty("description") + @JsonPropertyDescription("Tool description.") + private String description; + /** + * doi of the tool that deprecates the current one. May be set to 'true' if the current tool is deprecated but no specific tool deprecates it. + * + */ + @JsonProperty("deprecated-by-doi") + @JsonPropertyDescription("doi of the tool that deprecates the current one. May be set to 'true' if the current tool is deprecated but no specific tool deprecates it.") + private String deprecatedByDoi; + /** + * Tool author name(s). + * + */ + @JsonProperty("author") + @JsonPropertyDescription("Tool author name(s).") + private String author; + /** + * Tool URL. + * + */ + @JsonProperty("url") + @JsonPropertyDescription("Tool URL.") + private String url; + /** + * Link to the descriptor itself (e.g. the GitHub repo where it is hosted). + * + */ + @JsonProperty("descriptor-url") + @JsonPropertyDescription("Link to the descriptor itself (e.g. the GitHub repo where it is hosted).") + private String descriptorUrl; + /** + * DOI of the descriptor (not of the tool itself). + * + */ + @JsonProperty("doi") + @JsonPropertyDescription("DOI of the descriptor (not of the tool itself).") + private String doi; + /** + * Absolute path of the shell interpreter to use in the container (defaults to /bin/sh). + * + */ + @JsonProperty("shell") + @JsonPropertyDescription("Absolute path of the shell interpreter to use in the container (defaults to /bin/sh).") + private String shell; + /** + * DOI of the tool (not of the descriptor). + * + */ + @JsonProperty("tool-doi") + @JsonPropertyDescription("DOI of the tool (not of the descriptor).") + private String toolDoi; + /** + * A string that describes the tool command line, where input and output values are identified by "keys". At runtime, command-line keys are substituted with flags and values. + * (Required) + * + */ + @JsonProperty("command-line") + @JsonPropertyDescription("A string that describes the tool command line, where input and output values are identified by \"keys\". At runtime, command-line keys are substituted with flags and values.") + private String commandLine; + @JsonProperty("container-image") + private ContainerImage containerImage; + /** + * Version of the schema used. + * (Required) + * + */ + @JsonProperty("schema-version") + @JsonPropertyDescription("Version of the schema used.") + private BoutiquesDescriptor.SchemaVersion schemaVersion; + /** + * An array of key-value pairs specifying environment variable names and their values to be used in the execution environment. + * + */ + @JsonProperty("environment-variables") + @JsonDeserialize(as = java.util.LinkedHashSet.class) + @JsonPropertyDescription("An array of key-value pairs specifying environment variable names and their values to be used in the execution environment.") + private Set environmentVariables = new LinkedHashSet(); + /** + * Sets of identifiers of inputs, each specifying an input group. + * + */ + @JsonProperty("groups") + @JsonDeserialize(as = java.util.LinkedHashSet.class) + @JsonPropertyDescription("Sets of identifiers of inputs, each specifying an input group.") + private Set groups = new LinkedHashSet(); + /** + * + * (Required) + * + */ + @JsonProperty("inputs") + @JsonDeserialize(as = java.util.LinkedHashSet.class) + private Set inputs = new LinkedHashSet(); + @JsonProperty("tests") + private List tests = new ArrayList(); + /** + * Online platform URLs from which the tool can be executed. + * + */ + @JsonProperty("online-platform-urls") + @JsonPropertyDescription("Online platform URLs from which the tool can be executed.") + private List onlinePlatformUrls = new ArrayList(); + @JsonProperty("output-files") + @JsonDeserialize(as = java.util.LinkedHashSet.class) + private Set outputFiles = new LinkedHashSet(); + @JsonProperty("invocation-schema") + private InvocationSchema invocationSchema; + @JsonProperty("suggested-resources") + private SuggestedResources suggestedResources; + /** + * A set of key-value pairs specifying tags describing the pipeline. The tag names are open, they might be more constrained in the future. + * + */ + @JsonProperty("tags") + @JsonPropertyDescription("A set of key-value pairs specifying tags describing the pipeline. The tag names are open, they might be more constrained in the future.") + private Tags tags; + /** + * An array of key-value pairs specifying exit codes and their description. Can be used for tools to specify the meaning of particular exit codes. Exit code 0 is assumed to indicate a successful execution. + * + */ + @JsonProperty("error-codes") + @JsonDeserialize(as = java.util.LinkedHashSet.class) + @JsonPropertyDescription("An array of key-value pairs specifying exit codes and their description. Can be used for tools to specify the meaning of particular exit codes. Exit code 0 is assumed to indicate a successful execution.") + private Set errorCodes = new LinkedHashSet(); + @JsonProperty("custom") + private Custom custom; + + /** + * Tool name. + * (Required) + * + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * Tool name. + * (Required) + * + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * Tool version. + * (Required) + * + */ + @JsonProperty("tool-version") + public String getToolVersion() { + return toolVersion; + } + + /** + * Tool version. + * (Required) + * + */ + @JsonProperty("tool-version") + public void setToolVersion(String toolVersion) { + this.toolVersion = toolVersion; + } + + /** + * Tool description. + * (Required) + * + */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + /** + * Tool description. + * (Required) + * + */ + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + + /** + * doi of the tool that deprecates the current one. May be set to 'true' if the current tool is deprecated but no specific tool deprecates it. + * + */ + @JsonProperty("deprecated-by-doi") + public String getDeprecatedByDoi() { + return deprecatedByDoi; + } + + /** + * doi of the tool that deprecates the current one. May be set to 'true' if the current tool is deprecated but no specific tool deprecates it. + * + */ + @JsonProperty("deprecated-by-doi") + public void setDeprecatedByDoi(String deprecatedByDoi) { + this.deprecatedByDoi = deprecatedByDoi; + } + + /** + * Tool author name(s). + * + */ + @JsonProperty("author") + public String getAuthor() { + return author; + } + + /** + * Tool author name(s). + * + */ + @JsonProperty("author") + public void setAuthor(String author) { + this.author = author; + } + + /** + * Tool URL. + * + */ + @JsonProperty("url") + public String getUrl() { + return url; + } + + /** + * Tool URL. + * + */ + @JsonProperty("url") + public void setUrl(String url) { + this.url = url; + } + + /** + * Link to the descriptor itself (e.g. the GitHub repo where it is hosted). + * + */ + @JsonProperty("descriptor-url") + public String getDescriptorUrl() { + return descriptorUrl; + } + + /** + * Link to the descriptor itself (e.g. the GitHub repo where it is hosted). + * + */ + @JsonProperty("descriptor-url") + public void setDescriptorUrl(String descriptorUrl) { + this.descriptorUrl = descriptorUrl; + } + + /** + * DOI of the descriptor (not of the tool itself). + * + */ + @JsonProperty("doi") + public String getDoi() { + return doi; + } + + /** + * DOI of the descriptor (not of the tool itself). + * + */ + @JsonProperty("doi") + public void setDoi(String doi) { + this.doi = doi; + } + + /** + * Absolute path of the shell interpreter to use in the container (defaults to /bin/sh). + * + */ + @JsonProperty("shell") + public String getShell() { + return shell; + } + + /** + * Absolute path of the shell interpreter to use in the container (defaults to /bin/sh). + * + */ + @JsonProperty("shell") + public void setShell(String shell) { + this.shell = shell; + } + + /** + * DOI of the tool (not of the descriptor). + * + */ + @JsonProperty("tool-doi") + public String getToolDoi() { + return toolDoi; + } + + /** + * DOI of the tool (not of the descriptor). + * + */ + @JsonProperty("tool-doi") + public void setToolDoi(String toolDoi) { + this.toolDoi = toolDoi; + } + + /** + * A string that describes the tool command line, where input and output values are identified by "keys". At runtime, command-line keys are substituted with flags and values. + * (Required) + * + */ + @JsonProperty("command-line") + public String getCommandLine() { + return commandLine; + } + + /** + * A string that describes the tool command line, where input and output values are identified by "keys". At runtime, command-line keys are substituted with flags and values. + * (Required) + * + */ + @JsonProperty("command-line") + public void setCommandLine(String commandLine) { + this.commandLine = commandLine; + } + + @JsonProperty("container-image") + public ContainerImage getContainerImage() { + return containerImage; + } + + @JsonProperty("container-image") + public void setContainerImage(ContainerImage containerImage) { + this.containerImage = containerImage; + } + + /** + * Version of the schema used. + * (Required) + * + */ + @JsonProperty("schema-version") + public BoutiquesDescriptor.SchemaVersion getSchemaVersion() { + return schemaVersion; + } + + /** + * Version of the schema used. + * (Required) + * + */ + @JsonProperty("schema-version") + public void setSchemaVersion(BoutiquesDescriptor.SchemaVersion schemaVersion) { + this.schemaVersion = schemaVersion; + } + + /** + * An array of key-value pairs specifying environment variable names and their values to be used in the execution environment. + * + */ + @JsonProperty("environment-variables") + public Set getEnvironmentVariables() { + return environmentVariables; + } + + /** + * An array of key-value pairs specifying environment variable names and their values to be used in the execution environment. + * + */ + @JsonProperty("environment-variables") + public void setEnvironmentVariables(Set environmentVariables) { + this.environmentVariables = environmentVariables; + } + + /** + * Sets of identifiers of inputs, each specifying an input group. + * + */ + @JsonProperty("groups") + public Set getGroups() { + return groups; + } + + /** + * Sets of identifiers of inputs, each specifying an input group. + * + */ + @JsonProperty("groups") + public void setGroups(Set groups) { + this.groups = groups; + } + + /** + * + * (Required) + * + */ + @JsonProperty("inputs") + public Set getInputs() { + return inputs; + } + + /** + * + * (Required) + * + */ + @JsonProperty("inputs") + public void setInputs(Set inputs) { + this.inputs = inputs; + } + + @JsonProperty("tests") + public List getTests() { + return tests; + } + + @JsonProperty("tests") + public void setTests(List tests) { + this.tests = tests; + } + + /** + * Online platform URLs from which the tool can be executed. + * + */ + @JsonProperty("online-platform-urls") + public List getOnlinePlatformUrls() { + return onlinePlatformUrls; + } + + /** + * Online platform URLs from which the tool can be executed. + * + */ + @JsonProperty("online-platform-urls") + public void setOnlinePlatformUrls(List onlinePlatformUrls) { + this.onlinePlatformUrls = onlinePlatformUrls; + } + + @JsonProperty("output-files") + public Set getOutputFiles() { + return outputFiles; + } + + @JsonProperty("output-files") + public void setOutputFiles(Set outputFiles) { + this.outputFiles = outputFiles; + } + + @JsonProperty("invocation-schema") + public InvocationSchema getInvocationSchema() { + return invocationSchema; + } + + @JsonProperty("invocation-schema") + public void setInvocationSchema(InvocationSchema invocationSchema) { + this.invocationSchema = invocationSchema; + } + + @JsonProperty("suggested-resources") + public SuggestedResources getSuggestedResources() { + return suggestedResources; + } + + @JsonProperty("suggested-resources") + public void setSuggestedResources(SuggestedResources suggestedResources) { + this.suggestedResources = suggestedResources; + } + + /** + * A set of key-value pairs specifying tags describing the pipeline. The tag names are open, they might be more constrained in the future. + * + */ + @JsonProperty("tags") + public Tags getTags() { + return tags; + } + + /** + * A set of key-value pairs specifying tags describing the pipeline. The tag names are open, they might be more constrained in the future. + * + */ + @JsonProperty("tags") + public void setTags(Tags tags) { + this.tags = tags; + } + + /** + * An array of key-value pairs specifying exit codes and their description. Can be used for tools to specify the meaning of particular exit codes. Exit code 0 is assumed to indicate a successful execution. + * + */ + @JsonProperty("error-codes") + public Set getErrorCodes() { + return errorCodes; + } + + /** + * An array of key-value pairs specifying exit codes and their description. Can be used for tools to specify the meaning of particular exit codes. Exit code 0 is assumed to indicate a successful execution. + * + */ + @JsonProperty("error-codes") + public void setErrorCodes(Set errorCodes) { + this.errorCodes = errorCodes; + } + + @JsonProperty("custom") + public Custom getCustom() { + return custom; + } + + @JsonProperty("custom") + public void setCustom(Custom custom) { + this.custom = custom; + } + + + /** + * Version of the schema used. + * + */ + @Generated("jsonschema2pojo") + public enum SchemaVersion { + + _0_5("0.5"); + private final String value; + private final static Map CONSTANTS = new HashMap(); + + static { + for (BoutiquesDescriptor.SchemaVersion c: values()) { + CONSTANTS.put(c.value, c); + } + } + + SchemaVersion(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + @JsonValue + public String value() { + return this.value; + } + + @JsonCreator + public static BoutiquesDescriptor.SchemaVersion fromValue(String value) { + BoutiquesDescriptor.SchemaVersion constant = CONSTANTS.get(value); + if (constant == null) { + throw new IllegalArgumentException(value); + } else { + return constant; + } + } + + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ConditionalPathTemplate.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ConditionalPathTemplate.java new file mode 100644 index 000000000..e0c99b130 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ConditionalPathTemplate.java @@ -0,0 +1,46 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "propertyNames" +}) +@Generated("jsonschema2pojo") +public class ConditionalPathTemplate { + + @JsonProperty("propertyNames") + private Object propertyNames; + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonProperty("propertyNames") + public Object getPropertyNames() { + return propertyNames; + } + + @JsonProperty("propertyNames") + public void setPropertyNames(Object propertyNames) { + this.propertyNames = propertyNames; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ContainerImage.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ContainerImage.java new file mode 100644 index 000000000..3fb20917e --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ContainerImage.java @@ -0,0 +1,267 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.*; +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.*; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "type", + "image", + "entrypoint", + "index", + "container-opts", + "url", + "working-directory", + "container-hash" +}) +@Generated("jsonschema2pojo") +public class ContainerImage { + + /** + * + * (Required) + * + */ + @JsonProperty("type") + private ContainerImage.Type type; + /** + * Name of an image where the tool is installed and configured. Example: bids/mriqc. + * + */ + @JsonProperty("image") + @JsonPropertyDescription("Name of an image where the tool is installed and configured. Example: bids/mriqc.") + private String image; + /** + * Flag indicating whether or not the container uses an entrypoint. + * + */ + @JsonProperty("entrypoint") + @JsonPropertyDescription("Flag indicating whether or not the container uses an entrypoint.") + private Boolean entrypoint; + /** + * Optional index where the image is available, if not the standard location. Example: docker.io + * + */ + @JsonProperty("index") + @JsonPropertyDescription("Optional index where the image is available, if not the standard location. Example: docker.io") + private String index; + /** + * Container-level arguments for the application. Example: --privileged + * + */ + @JsonProperty("container-opts") + @JsonPropertyDescription("Container-level arguments for the application. Example: --privileged") + private List containerOpts = new ArrayList(); + /** + * URL where the image is available. + * + */ + @JsonProperty("url") + @JsonPropertyDescription("URL where the image is available.") + private String url; + /** + * Location from which this task must be launched within the container. + * + */ + @JsonProperty("working-directory") + @JsonPropertyDescription("Location from which this task must be launched within the container.") + private String workingDirectory; + /** + * Hash for the given container. + * + */ + @JsonProperty("container-hash") + @JsonPropertyDescription("Hash for the given container.") + private String containerHash; + + /** + * + * (Required) + * + */ + @JsonProperty("type") + public ContainerImage.Type getType() { + return type; + } + + /** + * + * (Required) + * + */ + @JsonProperty("type") + public void setType(ContainerImage.Type type) { + this.type = type; + } + + /** + * Name of an image where the tool is installed and configured. Example: bids/mriqc. + * + */ + @JsonProperty("image") + public String getImage() { + return image; + } + + /** + * Name of an image where the tool is installed and configured. Example: bids/mriqc. + * + */ + @JsonProperty("image") + public void setImage(String image) { + this.image = image; + } + + /** + * Flag indicating whether or not the container uses an entrypoint. + * + */ + @JsonProperty("entrypoint") + public Boolean getEntrypoint() { + return entrypoint; + } + + /** + * Flag indicating whether or not the container uses an entrypoint. + * + */ + @JsonProperty("entrypoint") + public void setEntrypoint(Boolean entrypoint) { + this.entrypoint = entrypoint; + } + + /** + * Optional index where the image is available, if not the standard location. Example: docker.io + * + */ + @JsonProperty("index") + public String getIndex() { + return index; + } + + /** + * Optional index where the image is available, if not the standard location. Example: docker.io + * + */ + @JsonProperty("index") + public void setIndex(String index) { + this.index = index; + } + + /** + * Container-level arguments for the application. Example: --privileged + * + */ + @JsonProperty("container-opts") + public List getContainerOpts() { + return containerOpts; + } + + /** + * Container-level arguments for the application. Example: --privileged + * + */ + @JsonProperty("container-opts") + public void setContainerOpts(List containerOpts) { + this.containerOpts = containerOpts; + } + + /** + * URL where the image is available. + * + */ + @JsonProperty("url") + public String getUrl() { + return url; + } + + /** + * URL where the image is available. + * + */ + @JsonProperty("url") + public void setUrl(String url) { + this.url = url; + } + + /** + * Location from which this task must be launched within the container. + * + */ + @JsonProperty("working-directory") + public String getWorkingDirectory() { + return workingDirectory; + } + + /** + * Location from which this task must be launched within the container. + * + */ + @JsonProperty("working-directory") + public void setWorkingDirectory(String workingDirectory) { + this.workingDirectory = workingDirectory; + } + + /** + * Hash for the given container. + * + */ + @JsonProperty("container-hash") + public String getContainerHash() { + return containerHash; + } + + /** + * Hash for the given container. + * + */ + @JsonProperty("container-hash") + public void setContainerHash(String containerHash) { + this.containerHash = containerHash; + } + + @Generated("jsonschema2pojo") + public enum Type { + + DOCKER("docker"), + SINGULARITY("singularity"), + ROOTFS("rootfs"); + private final String value; + private final static Map CONSTANTS = new HashMap(); + + static { + for (ContainerImage.Type c: values()) { + CONSTANTS.put(c.value, c); + } + } + + Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + @JsonValue + public String value() { + return this.value; + } + + @JsonCreator + public static ContainerImage.Type fromValue(String value) { + ContainerImage.Type constant = CONSTANTS.get(value); + if (constant == null) { + throw new IllegalArgumentException(value); + } else { + return constant; + } + } + + } + +} \ No newline at end of file diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Custom.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Custom.java new file mode 100644 index 000000000..f0a998f3f --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Custom.java @@ -0,0 +1,33 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + +}) +@Generated("jsonschema2pojo") +public class Custom { + + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/EnvironmentVariable.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/EnvironmentVariable.java new file mode 100644 index 000000000..d8a0eabb2 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/EnvironmentVariable.java @@ -0,0 +1,101 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "name", + "value", + "description" +}) +@Generated("jsonschema2pojo") +public class EnvironmentVariable { + + /** + * The environment variable name (identifier) containing only alphanumeric characters and underscores. Example: "PROGRAM_PATH". + * (Required) + * + */ + @JsonProperty("name") + @JsonPropertyDescription("The environment variable name (identifier) containing only alphanumeric characters and underscores. Example: \"PROGRAM_PATH\".") + private String name; + /** + * The value of the environment variable. + * (Required) + * + */ + @JsonProperty("value") + @JsonPropertyDescription("The value of the environment variable.") + private String value; + /** + * Description of the environment variable. + * + */ + @JsonProperty("description") + @JsonPropertyDescription("Description of the environment variable.") + private String description; + + /** + * The environment variable name (identifier) containing only alphanumeric characters and underscores. Example: "PROGRAM_PATH". + * (Required) + * + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * The environment variable name (identifier) containing only alphanumeric characters and underscores. Example: "PROGRAM_PATH". + * (Required) + * + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * The value of the environment variable. + * (Required) + * + */ + @JsonProperty("value") + public String getValue() { + return value; + } + + /** + * The value of the environment variable. + * (Required) + * + */ + @JsonProperty("value") + public void setValue(String value) { + this.value = value; + } + + /** + * Description of the environment variable. + * + */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + /** + * Description of the environment variable. + * + */ + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ErrorCode.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ErrorCode.java new file mode 100644 index 000000000..8929b1608 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ErrorCode.java @@ -0,0 +1,75 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "code", + "description" +}) +@Generated("jsonschema2pojo") +public class ErrorCode { + + /** + * Value of the exit code + * (Required) + * + */ + @JsonProperty("code") + @JsonPropertyDescription("Value of the exit code") + private Integer code; + /** + * Description of the error code. + * (Required) + * + */ + @JsonProperty("description") + @JsonPropertyDescription("Description of the error code.") + private String description; + + /** + * Value of the exit code + * (Required) + * + */ + @JsonProperty("code") + public Integer getCode() { + return code; + } + + /** + * Value of the exit code + * (Required) + * + */ + @JsonProperty("code") + public void setCode(Integer code) { + this.code = code; + } + + /** + * Description of the error code. + * (Required) + * + */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + /** + * Description of the error code. + * (Required) + * + */ + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Group.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Group.java new file mode 100644 index 000000000..064badeb4 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Group.java @@ -0,0 +1,210 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "id", + "name", + "description", + "members", + "mutually-exclusive", + "one-is-required", + "all-or-none" +}) +@Generated("jsonschema2pojo") +public class Group { + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "outfile_group". + * (Required) + * + */ + @JsonProperty("id") + @JsonPropertyDescription("A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: \"outfile_group\".") + private String id; + /** + * A human-readable name for the input group. + * (Required) + * + */ + @JsonProperty("name") + @JsonPropertyDescription("A human-readable name for the input group.") + private String name; + /** + * Description of the input group. + * + */ + @JsonProperty("description") + @JsonPropertyDescription("Description of the input group.") + private String description; + /** + * IDs of the inputs belonging to this group. + * (Required) + * + */ + @JsonProperty("members") + @JsonPropertyDescription("IDs of the inputs belonging to this group.") + private List members = new ArrayList(); + /** + * True if only one input in the group may be active at runtime. + * + */ + @JsonProperty("mutually-exclusive") + @JsonPropertyDescription("True if only one input in the group may be active at runtime.") + private Boolean mutuallyExclusive; + /** + * True if at least one of the inputs in the group must be active at runtime. + * + */ + @JsonProperty("one-is-required") + @JsonPropertyDescription("True if at least one of the inputs in the group must be active at runtime.") + private Boolean oneIsRequired; + /** + * True if members of the group need to be toggled together + * + */ + @JsonProperty("all-or-none") + @JsonPropertyDescription("True if members of the group need to be toggled together") + private Boolean allOrNone; + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "outfile_group". + * (Required) + * + */ + @JsonProperty("id") + public String getId() { + return id; + } + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "outfile_group". + * (Required) + * + */ + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + /** + * A human-readable name for the input group. + * (Required) + * + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * A human-readable name for the input group. + * (Required) + * + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * Description of the input group. + * + */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + /** + * Description of the input group. + * + */ + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + + /** + * IDs of the inputs belonging to this group. + * (Required) + * + */ + @JsonProperty("members") + public List getMembers() { + return members; + } + + /** + * IDs of the inputs belonging to this group. + * (Required) + * + */ + @JsonProperty("members") + public void setMembers(List members) { + this.members = members; + } + + /** + * True if only one input in the group may be active at runtime. + * + */ + @JsonProperty("mutually-exclusive") + public Boolean getMutuallyExclusive() { + return mutuallyExclusive; + } + + /** + * True if only one input in the group may be active at runtime. + * + */ + @JsonProperty("mutually-exclusive") + public void setMutuallyExclusive(Boolean mutuallyExclusive) { + this.mutuallyExclusive = mutuallyExclusive; + } + + /** + * True if at least one of the inputs in the group must be active at runtime. + * + */ + @JsonProperty("one-is-required") + public Boolean getOneIsRequired() { + return oneIsRequired; + } + + /** + * True if at least one of the inputs in the group must be active at runtime. + * + */ + @JsonProperty("one-is-required") + public void setOneIsRequired(Boolean oneIsRequired) { + this.oneIsRequired = oneIsRequired; + } + + /** + * True if members of the group need to be toggled together + * + */ + @JsonProperty("all-or-none") + public Boolean getAllOrNone() { + return allOrNone; + } + + /** + * True if members of the group need to be toggled together + * + */ + @JsonProperty("all-or-none") + public void setAllOrNone(Boolean allOrNone) { + this.allOrNone = allOrNone; + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Input.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Input.java new file mode 100644 index 000000000..8dc8f878b --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Input.java @@ -0,0 +1,703 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "id", + "name", + "type", + "description", + "value-key", + "list", + "list-separator", + "optional", + "command-line-flag", + "requires-inputs", + "disables-inputs", + "command-line-flag-separator", + "default-value", + "value-choices", + "value-requires", + "value-disables", + "integer", + "minimum", + "maximum", + "exclusive-minimum", + "exclusive-maximum", + "min-list-entries", + "max-list-entries", + "uses-absolute-path" +}) +@Generated("jsonschema2pojo") +public class Input { + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "data_file". + * (Required) + * + */ + @JsonProperty("id") + @JsonPropertyDescription("A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: \"data_file\".") + private String id; + /** + * A human-readable input name. Example: 'Data file'. + * (Required) + * + */ + @JsonProperty("name") + @JsonPropertyDescription("A human-readable input name. Example: 'Data file'.") + private String name; + /** + * Input type. + * (Required) + * + */ + @JsonProperty("type") + @JsonPropertyDescription("Input type.") + private Input.Type type; + /** + * Input description. + * + */ + @JsonProperty("description") + @JsonPropertyDescription("Input description.") + private String description; + /** + * A string contained in command-line, substituted by the input value and/or flag at runtime. + * + */ + @JsonProperty("value-key") + @JsonPropertyDescription("A string contained in command-line, substituted by the input value and/or flag at runtime.") + private String valueKey; + /** + * True if input is a list of value. An input of type "Flag" cannot be a list. + * + */ + @JsonProperty(value = "list") + @JsonPropertyDescription("True if input is a list of value. An input of type \"Flag\" cannot be a list.") + private Boolean list; + /** + * Separator used between list items. Defaults to a single space. + * + */ + @JsonProperty("list-separator") + @JsonPropertyDescription("Separator used between list items. Defaults to a single space.") + private String listSeparator; + /** + * True if input is optional. + * + */ + @JsonProperty("optional") + @JsonPropertyDescription("True if input is optional.") + private Boolean optional; + /** + * Option flag of the input, involved in the value-key substitution. Inputs of type "Flag" have to have a command-line flag. Examples: -v, --force. + * + */ + @JsonProperty("command-line-flag") + @JsonPropertyDescription("Option flag of the input, involved in the value-key substitution. Inputs of type \"Flag\" have to have a command-line flag. Examples: -v, --force.") + private String commandLineFlag; + /** + * Ids of the inputs or ids of groups whose members must be active for this input to be available. + * + */ + @JsonProperty("requires-inputs") + @JsonPropertyDescription("Ids of the inputs or ids of groups whose members must be active for this input to be available.") + private List requiresInputs = new ArrayList(); + /** + * Ids of the inputs that are disabled when this input is active. + * + */ + @JsonProperty("disables-inputs") + @JsonPropertyDescription("Ids of the inputs that are disabled when this input is active.") + private List disablesInputs = new ArrayList(); + /** + * Separator used between flags and their arguments. Defaults to a single space. + * + */ + @JsonProperty("command-line-flag-separator") + @JsonPropertyDescription("Separator used between flags and their arguments. Defaults to a single space.") + private String commandLineFlagSeparator; + /** + * Default value of the input. The default value is set when no value is specified, even when the input is optional. If the desired behavior is to omit the input from the command line when no value is specified, then no default value should be used. In this case, the tool might still use a default value internally, but this will remain undocumented in the Boutiques interface. + * + */ + @JsonProperty("default-value") + @JsonPropertyDescription("Default value of the input. The default value is set when no value is specified, even when the input is optional. If the desired behavior is to omit the input from the command line when no value is specified, then no default value should be used. In this case, the tool might still use a default value internally, but this will remain undocumented in the Boutiques interface.") + private Object defaultValue; + /** + * Permitted choices for input value. May not be used with the Flag type. + * + */ + @JsonProperty("value-choices") + @JsonPropertyDescription("Permitted choices for input value. May not be used with the Flag type.") + private List valueChoices = new ArrayList(); + /** + * Ids of the inputs that are required when the corresponding value choice is selected. + * + */ + @JsonProperty("value-requires") + @JsonPropertyDescription("Ids of the inputs that are required when the corresponding value choice is selected.") + private ValueRequires valueRequires; + /** + * Ids of the inputs that are disabled when the corresponding value choice is selected. + * + */ + @JsonProperty("value-disables") + @JsonPropertyDescription("Ids of the inputs that are disabled when the corresponding value choice is selected.") + private ValueDisables valueDisables; + /** + * Specify whether the input should be an integer. May only be used with Number type inputs. + * + */ + @JsonProperty("integer") + @JsonPropertyDescription("Specify whether the input should be an integer. May only be used with Number type inputs.") + private Boolean integer; + /** + * Specify the minimum value of the input (inclusive). May only be used with Number type inputs. + * + */ + @JsonProperty("minimum") + @JsonPropertyDescription("Specify the minimum value of the input (inclusive). May only be used with Number type inputs.") + private Double minimum; + /** + * Specify the maximum value of the input (inclusive). May only be used with Number type inputs. + * + */ + @JsonProperty("maximum") + @JsonPropertyDescription("Specify the maximum value of the input (inclusive). May only be used with Number type inputs.") + private Double maximum; + /** + * Specify whether the minimum is exclusive or not. May only be used with Number type inputs. + * + */ + @JsonProperty("exclusive-minimum") + @JsonPropertyDescription("Specify whether the minimum is exclusive or not. May only be used with Number type inputs.") + private Boolean exclusiveMinimum; + /** + * Specify whether the maximum is exclusive or not. May only be used with Number type inputs. + * + */ + @JsonProperty("exclusive-maximum") + @JsonPropertyDescription("Specify whether the maximum is exclusive or not. May only be used with Number type inputs.") + private Boolean exclusiveMaximum; + /** + * Specify the minimum number of entries in the list. May only be used with List type inputs. + * + */ + @JsonProperty("min-list-entries") + @JsonPropertyDescription("Specify the minimum number of entries in the list. May only be used with List type inputs.") + private Double minListEntries; + /** + * Specify the maximum number of entries in the list. May only be used with List type inputs. + * + */ + @JsonProperty("max-list-entries") + @JsonPropertyDescription("Specify the maximum number of entries in the list. May only be used with List type inputs.") + private Double maxListEntries; + /** + * Specifies that this input must be given as an absolute path. Only specifiable for File type inputs. + * + */ + @JsonProperty("uses-absolute-path") + @JsonPropertyDescription("Specifies that this input must be given as an absolute path. Only specifiable for File type inputs.") + private Boolean usesAbsolutePath; + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "data_file". + * (Required) + * + */ + @JsonProperty("id") + public String getId() { + return id; + } + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "data_file". + * (Required) + * + */ + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + /** + * A human-readable input name. Example: 'Data file'. + * (Required) + * + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * A human-readable input name. Example: 'Data file'. + * (Required) + * + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * Input type. + * (Required) + * + */ + @JsonProperty("type") + public Input.Type getType() { + return type; + } + + /** + * Input type. + * (Required) + * + */ + @JsonProperty("type") + public void setType(Input.Type type) { + this.type = type; + } + + /** + * Input description. + * + */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + /** + * Input description. + * + */ + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + + /** + * A string contained in command-line, substituted by the input value and/or flag at runtime. + * + */ + @JsonProperty("value-key") + public String getValueKey() { + return valueKey; + } + + /** + * A string contained in command-line, substituted by the input value and/or flag at runtime. + * + */ + @JsonProperty("value-key") + public void setValueKey(String valueKey) { + this.valueKey = valueKey; + } + + /** + * True if input is a list of value. An input of type "Flag" cannot be a list. + * + */ + @JsonProperty("list") + public Boolean getList() { + return list; + } + + /** + * True if input is a list of value. An input of type "Flag" cannot be a list. + * + */ + @JsonProperty("list") + public void setList(Boolean list) { + this.list = list; + } + + /** + * Separator used between list items. Defaults to a single space. + * + */ + @JsonProperty("list-separator") + public String getListSeparator() { + return listSeparator; + } + + /** + * Separator used between list items. Defaults to a single space. + * + */ + @JsonProperty("list-separator") + public void setListSeparator(String listSeparator) { + this.listSeparator = listSeparator; + } + + /** + * True if input is optional. + * + */ + @JsonProperty("optional") + public Boolean getOptional() { + return optional; + } + + /** + * True if input is optional. + * + */ + @JsonProperty("optional") + public void setOptional(Boolean optional) { + this.optional = optional; + } + + /** + * Option flag of the input, involved in the value-key substitution. Inputs of type "Flag" have to have a command-line flag. Examples: -v, --force. + * + */ + @JsonProperty("command-line-flag") + public String getCommandLineFlag() { + return commandLineFlag; + } + + /** + * Option flag of the input, involved in the value-key substitution. Inputs of type "Flag" have to have a command-line flag. Examples: -v, --force. + * + */ + @JsonProperty("command-line-flag") + public void setCommandLineFlag(String commandLineFlag) { + this.commandLineFlag = commandLineFlag; + } + + /** + * Ids of the inputs or ids of groups whose members must be active for this input to be available. + * + */ + @JsonProperty("requires-inputs") + public List getRequiresInputs() { + return requiresInputs; + } + + /** + * Ids of the inputs or ids of groups whose members must be active for this input to be available. + * + */ + @JsonProperty("requires-inputs") + public void setRequiresInputs(List requiresInputs) { + this.requiresInputs = requiresInputs; + } + + /** + * Ids of the inputs that are disabled when this input is active. + * + */ + @JsonProperty("disables-inputs") + public List getDisablesInputs() { + return disablesInputs; + } + + /** + * Ids of the inputs that are disabled when this input is active. + * + */ + @JsonProperty("disables-inputs") + public void setDisablesInputs(List disablesInputs) { + this.disablesInputs = disablesInputs; + } + + /** + * Separator used between flags and their arguments. Defaults to a single space. + * + */ + @JsonProperty("command-line-flag-separator") + public String getCommandLineFlagSeparator() { + return commandLineFlagSeparator; + } + + /** + * Separator used between flags and their arguments. Defaults to a single space. + * + */ + @JsonProperty("command-line-flag-separator") + public void setCommandLineFlagSeparator(String commandLineFlagSeparator) { + this.commandLineFlagSeparator = commandLineFlagSeparator; + } + + /** + * Default value of the input. The default value is set when no value is specified, even when the input is optional. If the desired behavior is to omit the input from the command line when no value is specified, then no default value should be used. In this case, the tool might still use a default value internally, but this will remain undocumented in the Boutiques interface. + * + */ + @JsonProperty("default-value") + public Object getDefaultValue() { + return defaultValue; + } + + /** + * Default value of the input. The default value is set when no value is specified, even when the input is optional. If the desired behavior is to omit the input from the command line when no value is specified, then no default value should be used. In this case, the tool might still use a default value internally, but this will remain undocumented in the Boutiques interface. + * + */ + @JsonProperty("default-value") + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * Permitted choices for input value. May not be used with the Flag type. + * + */ + @JsonProperty("value-choices") + public List getValueChoices() { + return valueChoices; + } + + /** + * Permitted choices for input value. May not be used with the Flag type. + * + */ + @JsonProperty("value-choices") + public void setValueChoices(List valueChoices) { + this.valueChoices = valueChoices; + } + + /** + * Ids of the inputs that are required when the corresponding value choice is selected. + * + */ + @JsonProperty("value-requires") + public ValueRequires getValueRequires() { + return valueRequires; + } + + /** + * Ids of the inputs that are required when the corresponding value choice is selected. + * + */ + @JsonProperty("value-requires") + public void setValueRequires(ValueRequires valueRequires) { + this.valueRequires = valueRequires; + } + + /** + * Ids of the inputs that are disabled when the corresponding value choice is selected. + * + */ + @JsonProperty("value-disables") + public ValueDisables getValueDisables() { + return valueDisables; + } + + /** + * Ids of the inputs that are disabled when the corresponding value choice is selected. + * + */ + @JsonProperty("value-disables") + public void setValueDisables(ValueDisables valueDisables) { + this.valueDisables = valueDisables; + } + + /** + * Specify whether the input should be an integer. May only be used with Number type inputs. + * + */ + @JsonProperty("integer") + public Boolean getInteger() { + return integer; + } + + /** + * Specify whether the input should be an integer. May only be used with Number type inputs. + * + */ + @JsonProperty("integer") + public void setInteger(Boolean integer) { + this.integer = integer; + } + + /** + * Specify the minimum value of the input (inclusive). May only be used with Number type inputs. + * + */ + @JsonProperty("minimum") + public Double getMinimum() { + return minimum; + } + + /** + * Specify the minimum value of the input (inclusive). May only be used with Number type inputs. + * + */ + @JsonProperty("minimum") + public void setMinimum(Double minimum) { + this.minimum = minimum; + } + + /** + * Specify the maximum value of the input (inclusive). May only be used with Number type inputs. + * + */ + @JsonProperty("maximum") + public Double getMaximum() { + return maximum; + } + + /** + * Specify the maximum value of the input (inclusive). May only be used with Number type inputs. + * + */ + @JsonProperty("maximum") + public void setMaximum(Double maximum) { + this.maximum = maximum; + } + + /** + * Specify whether the minimum is exclusive or not. May only be used with Number type inputs. + * + */ + @JsonProperty("exclusive-minimum") + public Boolean getExclusiveMinimum() { + return exclusiveMinimum; + } + + /** + * Specify whether the minimum is exclusive or not. May only be used with Number type inputs. + * + */ + @JsonProperty("exclusive-minimum") + public void setExclusiveMinimum(Boolean exclusiveMinimum) { + this.exclusiveMinimum = exclusiveMinimum; + } + + /** + * Specify whether the maximum is exclusive or not. May only be used with Number type inputs. + * + */ + @JsonProperty("exclusive-maximum") + public Boolean getExclusiveMaximum() { + return exclusiveMaximum; + } + + /** + * Specify whether the maximum is exclusive or not. May only be used with Number type inputs. + * + */ + @JsonProperty("exclusive-maximum") + public void setExclusiveMaximum(Boolean exclusiveMaximum) { + this.exclusiveMaximum = exclusiveMaximum; + } + + /** + * Specify the minimum number of entries in the list. May only be used with List type inputs. + * + */ + @JsonProperty("min-list-entries") + public Double getMinListEntries() { + return minListEntries; + } + + /** + * Specify the minimum number of entries in the list. May only be used with List type inputs. + * + */ + @JsonProperty("min-list-entries") + public void setMinListEntries(Double minListEntries) { + this.minListEntries = minListEntries; + } + + /** + * Specify the maximum number of entries in the list. May only be used with List type inputs. + * + */ + @JsonProperty("max-list-entries") + public Double getMaxListEntries() { + return maxListEntries; + } + + /** + * Specify the maximum number of entries in the list. May only be used with List type inputs. + * + */ + @JsonProperty("max-list-entries") + public void setMaxListEntries(Double maxListEntries) { + this.maxListEntries = maxListEntries; + } + + /** + * Specifies that this input must be given as an absolute path. Only specifiable for File type inputs. + * + */ + @JsonProperty("uses-absolute-path") + public Boolean getUsesAbsolutePath() { + return usesAbsolutePath; + } + + /** + * Specifies that this input must be given as an absolute path. Only specifiable for File type inputs. + * + */ + @JsonProperty("uses-absolute-path") + public void setUsesAbsolutePath(Boolean usesAbsolutePath) { + this.usesAbsolutePath = usesAbsolutePath; + } + + + /** + * Input type. + * + */ + @Generated("jsonschema2pojo") + public enum Type { + + STRING("String"), + FILE("File"), + FLAG("Flag"), + NUMBER("Number"); + private final String value; + private final static Map CONSTANTS = new HashMap(); + + static { + for (Input.Type c: values()) { + CONSTANTS.put(c.value, c); + } + } + + Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + @JsonValue + public String value() { + return this.value; + } + + @JsonCreator + public static Input.Type fromValue(String value) { + Input.Type constant = CONSTANTS.get(value); + if (constant == null) { + throw new IllegalArgumentException(value); + } else { + return constant; + } + } + + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Invocation.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Invocation.java new file mode 100644 index 000000000..5c0024e33 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Invocation.java @@ -0,0 +1,33 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + +}) +@Generated("jsonschema2pojo") +public class Invocation { + + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/InvocationSchema.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/InvocationSchema.java new file mode 100644 index 000000000..0da3e5dbb --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/InvocationSchema.java @@ -0,0 +1,33 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + +}) +@Generated("jsonschema2pojo") +public class InvocationSchema { + + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/OutputFile.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/OutputFile.java new file mode 100644 index 000000000..4fd886522 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/OutputFile.java @@ -0,0 +1,363 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "id", + "name", + "description", + "value-key", + "path-template", + "conditional-path-template", + "path-template-stripped-extensions", + "list", + "optional", + "command-line-flag", + "command-line-flag-separator", + "uses-absolute-path", + "file-template" +}) +@Generated("jsonschema2pojo") +public class OutputFile { + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "data_file" + * (Required) + * + */ + @JsonProperty("id") + @JsonPropertyDescription("A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: \"data_file\"") + private String id; + /** + * A human-readable output name. Example: 'Data file' + * (Required) + * + */ + @JsonProperty("name") + @JsonPropertyDescription("A human-readable output name. Example: 'Data file'") + private String name; + /** + * Output description. + * + */ + @JsonProperty("description") + @JsonPropertyDescription("Output description.") + private String description; + /** + * A string contained in command-line, substituted by the output value and/or flag at runtime. + * + */ + @JsonProperty("value-key") + @JsonPropertyDescription("A string contained in command-line, substituted by the output value and/or flag at runtime.") + private String valueKey; + /** + * Describes the output file path relatively to the execution directory. May contain input value keys and wildcards. Example: "results/[INPUT1]_brain*.mnc". + * + */ + @JsonProperty("path-template") + @JsonPropertyDescription("Describes the output file path relatively to the execution directory. May contain input value keys and wildcards. Example: \"results/[INPUT1]_brain*.mnc\".") + private String pathTemplate; + /** + * List of objects containing boolean statement (Limited python syntax: ==, !=, <, >, <=, >=, and, or) and output file paths relative to the execution directory, assign path of first true boolean statement. May contain input value keys, "default" object required if "optional" set to True . Example list: "[{"[PARAM1] > 8": "outputs/[INPUT1].txt"}, {"default": "outputs/default.txt"}]". + * + */ + @JsonProperty("conditional-path-template") + @JsonPropertyDescription("List of objects containing boolean statement (Limited python syntax: ==, !=, <, >, <=, >=, and, or) and output file paths relative to the execution directory, assign path of first true boolean statement. May contain input value keys, \"default\" object required if \"optional\" set to True . Example list: \"[{\"[PARAM1] > 8\": \"outputs/[INPUT1].txt\"}, {\"default\": \"outputs/default.txt\"}]\".") + private List conditionalPathTemplate = new ArrayList(); + /** + * List of file extensions that will be stripped from the input values before being substituted in the path template. Example: [".nii",".nii.gz"]. + * + */ + @JsonProperty("path-template-stripped-extensions") + @JsonPropertyDescription("List of file extensions that will be stripped from the input values before being substituted in the path template. Example: [\".nii\",\".nii.gz\"].") + private List pathTemplateStrippedExtensions = new ArrayList(); + /** + * True if output is a list of value. + * + */ + @JsonProperty("list") + @JsonPropertyDescription("True if output is a list of value.") + private Boolean list; + /** + * True if output may not be produced by the tool. + * + */ + @JsonProperty("optional") + @JsonPropertyDescription("True if output may not be produced by the tool.") + private Boolean optional; + /** + * Option flag of the output, involved in the value-key substitution. Examples: -o, --output + * + */ + @JsonProperty("command-line-flag") + @JsonPropertyDescription("Option flag of the output, involved in the value-key substitution. Examples: -o, --output") + private String commandLineFlag; + /** + * Separator used between flags and their arguments. Defaults to a single space. + * + */ + @JsonProperty("command-line-flag-separator") + @JsonPropertyDescription("Separator used between flags and their arguments. Defaults to a single space.") + private String commandLineFlagSeparator; + /** + * Specifies that this output filepath will be given as an absolute path. + * + */ + @JsonProperty("uses-absolute-path") + @JsonPropertyDescription("Specifies that this output filepath will be given as an absolute path.") + private Boolean usesAbsolutePath; + /** + * An array of strings that may contain value keys. Each item will be a line in the configuration file. + * + */ + @JsonProperty("file-template") + @JsonPropertyDescription("An array of strings that may contain value keys. Each item will be a line in the configuration file.") + private List fileTemplate = new ArrayList(); + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "data_file" + * (Required) + * + */ + @JsonProperty("id") + public String getId() { + return id; + } + + /** + * A short, unique, informative identifier containing only alphanumeric characters and underscores. Typically used to generate variable names. Example: "data_file" + * (Required) + * + */ + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + /** + * A human-readable output name. Example: 'Data file' + * (Required) + * + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * A human-readable output name. Example: 'Data file' + * (Required) + * + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * Output description. + * + */ + @JsonProperty("description") + public String getDescription() { + return description; + } + + /** + * Output description. + * + */ + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + + /** + * A string contained in command-line, substituted by the output value and/or flag at runtime. + * + */ + @JsonProperty("value-key") + public String getValueKey() { + return valueKey; + } + + /** + * A string contained in command-line, substituted by the output value and/or flag at runtime. + * + */ + @JsonProperty("value-key") + public void setValueKey(String valueKey) { + this.valueKey = valueKey; + } + + /** + * Describes the output file path relatively to the execution directory. May contain input value keys and wildcards. Example: "results/[INPUT1]_brain*.mnc". + * + */ + @JsonProperty("path-template") + public String getPathTemplate() { + return pathTemplate; + } + + /** + * Describes the output file path relatively to the execution directory. May contain input value keys and wildcards. Example: "results/[INPUT1]_brain*.mnc". + * + */ + @JsonProperty("path-template") + public void setPathTemplate(String pathTemplate) { + this.pathTemplate = pathTemplate; + } + + /** + * List of objects containing boolean statement (Limited python syntax: ==, !=, <, >, <=, >=, and, or) and output file paths relative to the execution directory, assign path of first true boolean statement. May contain input value keys, "default" object required if "optional" set to True . Example list: "[{"[PARAM1] > 8": "outputs/[INPUT1].txt"}, {"default": "outputs/default.txt"}]". + * + */ + @JsonProperty("conditional-path-template") + public List getConditionalPathTemplate() { + return conditionalPathTemplate; + } + + /** + * List of objects containing boolean statement (Limited python syntax: ==, !=, <, >, <=, >=, and, or) and output file paths relative to the execution directory, assign path of first true boolean statement. May contain input value keys, "default" object required if "optional" set to True . Example list: "[{"[PARAM1] > 8": "outputs/[INPUT1].txt"}, {"default": "outputs/default.txt"}]". + * + */ + @JsonProperty("conditional-path-template") + public void setConditionalPathTemplate(List conditionalPathTemplate) { + this.conditionalPathTemplate = conditionalPathTemplate; + } + + /** + * List of file extensions that will be stripped from the input values before being substituted in the path template. Example: [".nii",".nii.gz"]. + * + */ + @JsonProperty("path-template-stripped-extensions") + public List getPathTemplateStrippedExtensions() { + return pathTemplateStrippedExtensions; + } + + /** + * List of file extensions that will be stripped from the input values before being substituted in the path template. Example: [".nii",".nii.gz"]. + * + */ + @JsonProperty("path-template-stripped-extensions") + public void setPathTemplateStrippedExtensions(List pathTemplateStrippedExtensions) { + this.pathTemplateStrippedExtensions = pathTemplateStrippedExtensions; + } + + /** + * True if output is a list of value. + * + */ + @JsonProperty("list") + public Boolean getList() { + return list; + } + + /** + * True if output is a list of value. + * + */ + @JsonProperty("list") + public void setList(Boolean list) { + this.list = list; + } + + /** + * True if output may not be produced by the tool. + * + */ + @JsonProperty("optional") + public Boolean getOptional() { + return optional; + } + + /** + * True if output may not be produced by the tool. + * + */ + @JsonProperty("optional") + public void setOptional(Boolean optional) { + this.optional = optional; + } + + /** + * Option flag of the output, involved in the value-key substitution. Examples: -o, --output + * + */ + @JsonProperty("command-line-flag") + public String getCommandLineFlag() { + return commandLineFlag; + } + + /** + * Option flag of the output, involved in the value-key substitution. Examples: -o, --output + * + */ + @JsonProperty("command-line-flag") + public void setCommandLineFlag(String commandLineFlag) { + this.commandLineFlag = commandLineFlag; + } + + /** + * Separator used between flags and their arguments. Defaults to a single space. + * + */ + @JsonProperty("command-line-flag-separator") + public String getCommandLineFlagSeparator() { + return commandLineFlagSeparator; + } + + /** + * Separator used between flags and their arguments. Defaults to a single space. + * + */ + @JsonProperty("command-line-flag-separator") + public void setCommandLineFlagSeparator(String commandLineFlagSeparator) { + this.commandLineFlagSeparator = commandLineFlagSeparator; + } + + /** + * Specifies that this output filepath will be given as an absolute path. + * + */ + @JsonProperty("uses-absolute-path") + public Boolean getUsesAbsolutePath() { + return usesAbsolutePath; + } + + /** + * Specifies that this output filepath will be given as an absolute path. + * + */ + @JsonProperty("uses-absolute-path") + public void setUsesAbsolutePath(Boolean usesAbsolutePath) { + this.usesAbsolutePath = usesAbsolutePath; + } + + /** + * An array of strings that may contain value keys. Each item will be a line in the configuration file. + * + */ + @JsonProperty("file-template") + public List getFileTemplate() { + return fileTemplate; + } + + /** + * An array of strings that may contain value keys. Each item will be a line in the configuration file. + * + */ + @JsonProperty("file-template") + public void setFileTemplate(List fileTemplate) { + this.fileTemplate = fileTemplate; + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/SuggestedResources.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/SuggestedResources.java new file mode 100644 index 000000000..f3de56b67 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/SuggestedResources.java @@ -0,0 +1,164 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "cpu-cores", + "ram", + "disk-space", + "nodes", + "walltime-estimate" +}) +@Generated("jsonschema2pojo") +public class SuggestedResources { + + /** + * The requested number of cpu cores to run the described application + * + */ + @JsonProperty("cpu-cores") + @JsonPropertyDescription("The requested number of cpu cores to run the described application") + private Integer cpuCores; + /** + * The requested number of GB RAM to run the described application + * + */ + @JsonProperty("ram") + @JsonPropertyDescription("The requested number of GB RAM to run the described application") + private Double ram; + /** + * The requested number of GB of storage to run the described application + * + */ + @JsonProperty("disk-space") + @JsonPropertyDescription("The requested number of GB of storage to run the described application") + private Double diskSpace; + /** + * The requested number of nodes to spread the described application across + * + */ + @JsonProperty("nodes") + @JsonPropertyDescription("The requested number of nodes to spread the described application across") + private Integer nodes; + /** + * Estimated wall time of a task in seconds. + * + */ + @JsonProperty("walltime-estimate") + @JsonPropertyDescription("Estimated wall time of a task in seconds.") + private Double walltimeEstimate; + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + /** + * The requested number of cpu cores to run the described application + * + */ + @JsonProperty("cpu-cores") + public Integer getCpuCores() { + return cpuCores; + } + + /** + * The requested number of cpu cores to run the described application + * + */ + @JsonProperty("cpu-cores") + public void setCpuCores(Integer cpuCores) { + this.cpuCores = cpuCores; + } + + /** + * The requested number of GB RAM to run the described application + * + */ + @JsonProperty("ram") + public Double getRam() { + return ram; + } + + /** + * The requested number of GB RAM to run the described application + * + */ + @JsonProperty("ram") + public void setRam(Double ram) { + this.ram = ram; + } + + /** + * The requested number of GB of storage to run the described application + * + */ + @JsonProperty("disk-space") + public Double getDiskSpace() { + return diskSpace; + } + + /** + * The requested number of GB of storage to run the described application + * + */ + @JsonProperty("disk-space") + public void setDiskSpace(Double diskSpace) { + this.diskSpace = diskSpace; + } + + /** + * The requested number of nodes to spread the described application across + * + */ + @JsonProperty("nodes") + public Integer getNodes() { + return nodes; + } + + /** + * The requested number of nodes to spread the described application across + * + */ + @JsonProperty("nodes") + public void setNodes(Integer nodes) { + this.nodes = nodes; + } + + /** + * Estimated wall time of a task in seconds. + * + */ + @JsonProperty("walltime-estimate") + public Double getWalltimeEstimate() { + return walltimeEstimate; + } + + /** + * Estimated wall time of a task in seconds. + * + */ + @JsonProperty("walltime-estimate") + public void setWalltimeEstimate(Double walltimeEstimate) { + this.walltimeEstimate = walltimeEstimate; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Tags.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Tags.java new file mode 100644 index 000000000..d1fb45dc6 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Tags.java @@ -0,0 +1,38 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +/** + * A set of key-value pairs specifying tags describing the pipeline. The tag names are open, they might be more constrained in the future. + * + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + +}) +@Generated("jsonschema2pojo") +public class Tags { + + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, String value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Test.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Test.java new file mode 100644 index 000000000..763141302 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/Test.java @@ -0,0 +1,119 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "name", + "invocation", + "assertions" +}) +@Generated("jsonschema2pojo") +public class Test { + + /** + * Name of the test-case + * (Required) + * + */ + @JsonProperty("name") + @JsonPropertyDescription("Name of the test-case") + private String name; + /** + * + * (Required) + * + */ + @JsonProperty("invocation") + private Invocation invocation; + /** + * + * (Required) + * + */ + @JsonProperty("assertions") + private Assertions assertions; + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + /** + * Name of the test-case + * (Required) + * + */ + @JsonProperty("name") + public String getName() { + return name; + } + + /** + * Name of the test-case + * (Required) + * + */ + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + /** + * + * (Required) + * + */ + @JsonProperty("invocation") + public Invocation getInvocation() { + return invocation; + } + + /** + * + * (Required) + * + */ + @JsonProperty("invocation") + public void setInvocation(Invocation invocation) { + this.invocation = invocation; + } + + /** + * + * (Required) + * + */ + @JsonProperty("assertions") + public Assertions getAssertions() { + return assertions; + } + + /** + * + * (Required) + * + */ + @JsonProperty("assertions") + public void setAssertions(Assertions assertions) { + this.assertions = assertions; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/TestOutputFile.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/TestOutputFile.java new file mode 100644 index 000000000..efb607352 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/TestOutputFile.java @@ -0,0 +1,89 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + "id", + "md5-reference" +}) +@Generated("jsonschema2pojo") +public class TestOutputFile { + + /** + * Id referring to an output-file + * (Required) + * + */ + @JsonProperty("id") + @JsonPropertyDescription("Id referring to an output-file") + private String id; + /** + * MD5 checksum string to match against the MD5 checksum of the output-file specified by the id object + * + */ + @JsonProperty("md5-reference") + @JsonPropertyDescription("MD5 checksum string to match against the MD5 checksum of the output-file specified by the id object") + private String md5Reference; + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + /** + * Id referring to an output-file + * (Required) + * + */ + @JsonProperty("id") + public String getId() { + return id; + } + + /** + * Id referring to an output-file + * (Required) + * + */ + @JsonProperty("id") + public void setId(String id) { + this.id = id; + } + + /** + * MD5 checksum string to match against the MD5 checksum of the output-file specified by the id object + * + */ + @JsonProperty("md5-reference") + public String getMd5Reference() { + return md5Reference; + } + + /** + * MD5 checksum string to match against the MD5 checksum of the output-file specified by the id object + * + */ + @JsonProperty("md5-reference") + public void setMd5Reference(String md5Reference) { + this.md5Reference = md5Reference; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ValueDisables.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ValueDisables.java new file mode 100644 index 000000000..545e251c8 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ValueDisables.java @@ -0,0 +1,38 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +/** + * Ids of the inputs that are disabled when the corresponding value choice is selected. + * + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + +}) +@Generated("jsonschema2pojo") +public class ValueDisables { + + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ValueRequires.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ValueRequires.java new file mode 100644 index 000000000..439e7d590 --- /dev/null +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/model/boutiques/ValueRequires.java @@ -0,0 +1,38 @@ + +package fr.insalyon.creatis.vip.application.server.model.boutiques; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +/** + * Ids of the inputs that are required when the corresponding value choice is selected. + * + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ + +}) +@Generated("jsonschema2pojo") +public class ValueRequires { + + @JsonIgnore + private Map additionalProperties = new LinkedHashMap(); + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + +} diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/rpc/ApplicationServiceImpl.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/rpc/ApplicationServiceImpl.java index f724781d0..63e7a82d9 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/rpc/ApplicationServiceImpl.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/rpc/ApplicationServiceImpl.java @@ -69,13 +69,28 @@ public class ApplicationServiceImpl extends AbstractRemoteServiceServlet impleme @Override public void init() throws ServletException { super.init(); - engineBusiness = getBean(EngineBusiness.class); - classBusiness = getBean(ClassBusiness.class); - applicationBusiness = getBean(ApplicationBusiness.class); - boutiquesBusiness = getBean(BoutiquesBusiness.class); - configurationBusiness = getBean(ConfigurationBusiness.class); - workflowBusiness = getBean(WorkflowBusiness.class); - simulationBusiness = getBean(SimulationBusiness.class); + setBeans( + getBean(ClassBusiness.class), + getBean(ApplicationBusiness.class), + getBean(EngineBusiness.class), + getBean(BoutiquesBusiness.class), + getBean(ConfigurationBusiness.class), + getBean(WorkflowBusiness.class), + getBean(SimulationBusiness.class) + ); + } + + public void setBeans( + ClassBusiness classBusiness, ApplicationBusiness applicationBusiness, EngineBusiness engineBusiness, + BoutiquesBusiness boutiquesBusiness, ConfigurationBusiness configurationBusiness, + WorkflowBusiness workflowBusiness, SimulationBusiness simulationBusiness) { + this.classBusiness = classBusiness; + this.applicationBusiness = applicationBusiness; + this.engineBusiness = engineBusiness; + this.boutiquesBusiness = boutiquesBusiness; + this.configurationBusiness = configurationBusiness; + this.workflowBusiness = workflowBusiness; + this.simulationBusiness = simulationBusiness; } @Override @@ -347,16 +362,14 @@ public ApplicationStatus getApplicationStatus() throws ApplicationException { @Override public String getCitation(String applicationName) throws ApplicationException { + // I think this is meant to nullify empty citation like "
" try { - String citationWithoutHtml = Jsoup - .parse(applicationBusiness.getCitation( - applicationName)) - .text(); - if (citationWithoutHtml.isEmpty() || citationWithoutHtml == null) { + String citation = applicationBusiness.getCitation(applicationName); + String citationWithoutHtml = Jsoup.parse(citation).text(); + if (citationWithoutHtml.isEmpty()) { return null; } else { - return applicationBusiness.getCitation( - applicationName); + return citation; } } catch (BusinessException ex) { throw new ApplicationException(ex); diff --git a/vip-application/src/test/java/fr/insalyon/creatis/vip/application/JsoupIntegrationTest.java b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/JsoupIntegrationTest.java new file mode 100644 index 000000000..e3a508f2e --- /dev/null +++ b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/JsoupIntegrationTest.java @@ -0,0 +1,35 @@ +package fr.insalyon.creatis.vip.application; + +import fr.insalyon.creatis.vip.application.client.rpc.ApplicationService; +import fr.insalyon.creatis.vip.application.client.view.ApplicationException; +import fr.insalyon.creatis.vip.application.server.business.ApplicationBusiness; +import fr.insalyon.creatis.vip.application.server.rpc.ApplicationServiceImpl; +import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import org.jsoup.Jsoup; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.List; + + +public class JsoupIntegrationTest { + + @Test + public void testJsoup() throws ApplicationException, BusinessException { + String citationOk = "  S. Camarasu-Pop, T. Glatard, R. Ferreira da Silva, P. Gueth, D. Sarrut, and H. Benoit-Cattin, \"Monte-Carlo Simulation on Heterogeneous Distributed Systems: a Computing Framework with Parallel Merging and Checkpointing Strategies\", Future Generation Computer Systems, vol. 29, no. 3, pp. 728--738, 03/2013
"; + String emptyCitation = "
"; + + ApplicationServiceImpl applicationService = new ApplicationServiceImpl(); + ApplicationBusiness applicationBusiness = Mockito.mock(ApplicationBusiness.class); + Mockito.when(applicationBusiness.getCitation(ArgumentMatchers.anyString())).thenReturn(citationOk, emptyCitation); + applicationService.setBeans(null, applicationBusiness, null, null, null, null, null); + Assertions.assertEquals( + citationOk, + applicationService.getCitation("firstcall")); + Assertions.assertNull(applicationService.getCitation("secondcall")); + } + +} diff --git a/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/BaseApplicationSpringIT.java b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/BaseApplicationSpringIT.java new file mode 100644 index 000000000..e7c3a7c8e --- /dev/null +++ b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/BaseApplicationSpringIT.java @@ -0,0 +1,105 @@ +package fr.insalyon.creatis.vip.application.integrationtest; + +import fr.insalyon.creatis.grida.client.GRIDAClientException; +import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.InputDAO; +import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.OutputDAO; +import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.WorkflowDAO; +import fr.insalyon.creatis.vip.application.client.bean.AppClass; +import fr.insalyon.creatis.vip.application.client.bean.AppVersion; +import fr.insalyon.creatis.vip.application.client.bean.Application; +import fr.insalyon.creatis.vip.application.client.bean.Engine; +import fr.insalyon.creatis.vip.application.server.business.ApplicationBusiness; +import fr.insalyon.creatis.vip.application.server.business.ClassBusiness; +import fr.insalyon.creatis.vip.application.server.business.EngineBusiness; +import fr.insalyon.creatis.vip.application.server.business.WorkflowBusiness; +import fr.insalyon.creatis.vip.application.server.business.simulation.WebServiceEngine; +import fr.insalyon.creatis.vip.core.integrationtest.database.BaseSpringIT; +import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class BaseApplicationSpringIT extends BaseSpringIT { + + @Autowired + protected WorkflowDAO workflowDAO; + @Autowired + protected OutputDAO outputDAO; + @Autowired + protected InputDAO inputDAO; + @Autowired + protected WebServiceEngine webServiceEngine; + + @Autowired + protected ApplicationBusiness applicationBusiness; + @Autowired + protected ClassBusiness classBusiness; + @Autowired + protected EngineBusiness engineBusiness; + + @BeforeEach + protected void setUp() throws Exception { + super.setUp(); + Mockito.reset(workflowDAO); + Mockito.reset(outputDAO); + Mockito.reset(webServiceEngine); + Mockito.reset(inputDAO); + } + + protected ApplicationBusiness getApplicationBusiness() { + return applicationBusiness; + } + + protected ClassBusiness getClassBusiness() { + return classBusiness; + } + + protected EngineBusiness getEngineBusiness() { + return engineBusiness; + } + + public WebServiceEngine getWebServiceEngine() { + return webServiceEngine; + } + + protected void createClass(String className, String... groupNames) throws BusinessException { + getClassBusiness().addClass(new AppClass(className, Collections.emptyList(), List.of(groupNames))); + } + + protected void createAnApplication(String appName, String... classNames) throws BusinessException { + getApplicationBusiness().add(new Application(appName, Arrays.asList(classNames), "test citation")); + } + + protected AppVersion createAVersion(String appName, String versionName, boolean visible, String gwendiaPath, String jsonPath) throws BusinessException { + AppVersion appVersion = new AppVersion(appName, versionName, gwendiaPath, jsonPath, visible, true); + getApplicationBusiness().addVersion(appVersion); + return appVersion; + } + + protected AppVersion configureAnApplication(String appName, String versionName, String groupName, String className) throws BusinessException { + createGroup(groupName); + createClass(className, groupName); + createAnApplication(appName, className); + return createAVersion(appName, versionName, true, null, null); + } + + protected void configureVersion(AppVersion appVersion, String gwendiaPath, String jsonPath) throws BusinessException { + appVersion = new AppVersion( + appVersion.getApplicationName(), appVersion.getVersion(), gwendiaPath, jsonPath, + appVersion.isVisible(), appVersion.isBoutiquesForm()); + getApplicationBusiness().updateVersion(appVersion); + } + + protected void addEngineToClass(String className, String engineName, String endpoint) throws BusinessException { + AppClass appClass = getClassBusiness().getClass(className); + getEngineBusiness().add(new Engine(engineName, endpoint, "enabled")); + appClass.getEngines().add(engineName); + getClassBusiness().updateClass(appClass); + } +} diff --git a/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/BoutiquesParsingIT.java b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/BoutiquesParsingIT.java new file mode 100644 index 000000000..7e31121f9 --- /dev/null +++ b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/BoutiquesParsingIT.java @@ -0,0 +1,68 @@ +package fr.insalyon.creatis.vip.application.integrationtest; + +import fr.insalyon.creatis.vip.application.server.business.BoutiquesBusiness; +import fr.insalyon.creatis.vip.application.server.model.boutiques.BoutiquesDescriptor; +import fr.insalyon.creatis.vip.application.server.model.boutiques.ContainerImage; +import fr.insalyon.creatis.vip.application.server.model.boutiques.Input; +import fr.insalyon.creatis.vip.core.integrationtest.database.BaseSpringIT; +import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Optional; + +public class BoutiquesParsingIT extends BaseSpringIT { + + @Autowired + BoutiquesBusiness boutiquesBusiness; + + @Value("classpath:FreeSurfer-Recon-all_v731.json") + Resource resourceFile; + + @Test + public void testFreesurferParsing() throws BusinessException, IOException { + BoutiquesDescriptor desc = boutiquesBusiness.parseBoutiquesFile(resourceFile.getFile()); + + // general stuff + Assertions.assertEquals("FreeSurfer-Recon-all", desc.getName()); + Assertions.assertEquals("v7.3.1", desc.getToolVersion()); + Assertions.assertTrue(desc.getCommandLine().contains("recon-all -subjid [SUBJID] [NIFTI] [DIRECTIVES]")); + Assertions.assertEquals(1, desc.getOutputFiles().size()); + Assertions.assertEquals(2, desc.getCustom().getAdditionalProperties().size()); + Assertions.assertEquals("Natacha Beck ", desc.getCustom().getAdditionalProperties().get("cbrain:author")); + Assertions.assertEquals(true, desc.getCustom().getAdditionalProperties().get("cbrain:readonly-input-files")); + + + // container + Assertions.assertEquals(ContainerImage.Type.DOCKER, desc.getContainerImage().getType()); + Assertions.assertEquals(1, desc.getContainerImage().getContainerOpts().size()); + Assertions.assertEquals("-v /tmp:/tmp", desc.getContainerImage().getContainerOpts().get(0)); + + // inputs + Assertions.assertEquals(13, desc.getInputs().size()); + Optional licenseInput = desc.getInputs().stream().filter(i -> "license".equals(i.getId())).findAny(); + Assertions.assertTrue(licenseInput.isPresent()); + Assertions.assertFalse(licenseInput.get().getOptional()); + Assertions.assertEquals(Input.Type.FILE, licenseInput.get().getType()); + Assertions.assertEquals("[LICENSE_FILE]", licenseInput.get().getValueKey()); + + Optional directivesInput = desc.getInputs().stream().filter(i -> "directives".equals(i.getId())).findAny(); + Assertions.assertTrue(directivesInput.isPresent()); + Assertions.assertEquals(Input.Type.STRING, directivesInput.get().getType()); + Assertions.assertTrue(directivesInput.get().getValueChoices().containsAll(Arrays.asList("-all", "-autorecon2", "-autorecon2-perhemi"))); + + // outputs + Assertions.assertEquals(1, desc.getOutputFiles().size()); + Assertions.assertEquals("Output", desc.getOutputFiles().iterator().next().getName()); + Assertions.assertEquals("[SUBJID].tgz", desc.getOutputFiles().iterator().next().getPathTemplate()); + Assertions.assertEquals("[RESULTS]", desc.getOutputFiles().iterator().next().getValueKey()); + + } + + +} diff --git a/vip-application/src/test/resources/FreeSurfer-Recon-all_v731.json b/vip-application/src/test/resources/FreeSurfer-Recon-all_v731.json new file mode 100644 index 000000000..827a18fef --- /dev/null +++ b/vip-application/src/test/resources/FreeSurfer-Recon-all_v731.json @@ -0,0 +1,166 @@ +{ + "suggested-resources": { + "ram": 10240, + "walltime-estimate": 960, + "cpu-cores": 1 + }, + "schema-version": "0.5", + "output-files": [ + { + "name": "Output", + "optional": false, + "description": "The subject data upon which to operate ", + "id": "subjid_output", + "path-template": "[SUBJID].tgz", + "value-key":"[RESULTS]" + } + ], + "name": "FreeSurfer-Recon-all", + "container-image": { + "index": "docker://", + "image": "cont_freesurfer_731", + "type": "docker", + "container-opts": [ + "-v /tmp:/tmp" + ] + }, + "tool-version": "v7.3.1", + "command-line": "export SUBJECTS_DIR=`pwd`; export FS_LICENSE=$PWD/[LICENSE_FILE]; recon-all -subjid [SUBJID] [NIFTI] [DIRECTIVES] [QCACHE] [MPRAGE] [3T] [CW256] [NOTAL-CHECK] [HYPPOCAMPAL-SUBFIELDS] [BRAINSTEM-STRUCTURES] [NO-WSGCAATLAS] [NO-SKULLSTRIP]; tar -czvf [RESULTS] [SUBJID]", + "author": "Laboratory for Computational Neuroimaging ", + "error-codes": [ + { + "description": "Crashed", + "code": 1 + } + ], + "inputs": [ + { + "name": "License file", + "value-key": "[LICENSE_FILE]", + "optional": false, + "description": "Valid license file needed to run FreeSurfer.", + "id": "license", + "type": "File" + }, + { + "name": "Output name", + "optional": false, + "value-key": "[SUBJID]", + "type": "String", + "id": "subjid" + }, + { + "name": "NIFTI file", + "id": "nifti", + "optional": false, + "value-key": "[NIFTI]", + "description": "Single NIFTI file from series.", + "command-line-flag": "-i", + "type": "File" + }, + { + "name": "Directive", + "default-value": "-all", + "value-key": "[DIRECTIVES]", + "optional": false, + "type": "String", + "id": "directives", + "value-choices": [ + "-all", + "-autorecon1", + "-autorecon2", + "-autorecon2-cp", + "-autorecon2-wm", + "-autorecon2-inflate1", + "-autorecon2-perhemi", + "-autorecon3" + ] + }, + { + "name": "qcache", + "id": "qcache_flag", + "optional": true, + "value-key": "[QCACHE]", + "description": "Produce the pre-cached files required by the Qdec utility, allowing rapid analysis of group data.", + "command-line-flag": "-qcache", + "type": "Flag" + }, + { + "name": "mprage", + "id": "mprage_flag", + "optional": true, + "value-key": "[MPRAGE]", + "description": "Assume scan parameters are MGH MP-RAGE protocol.", + "command-line-flag": "-mprage", + "type": "Flag" + }, + { + "name": "3T", + "id": "3T_flag", + "optional": true, + "value-key": "[3T]", + "description": "The -3T flag enables two specific options in recon-all for images acquired with a 3T scanner: 3T-specific NU intensity correction parameters are used in the Non-Uniform normalization stage, and the Schwartz 3T atlas is used for Talairach alignment", + "command-line-flag": "-3T", + "type": "Flag" + }, + { + "name": "cw256", + "id": "cw256_flag", + "optional": true, + "value-key": "[CW256]", + "description": "Include this flag after -autorecon1 if images have a FOV > 256.", + "command-line-flag": "-cw256", + "type": "Flag" + }, + { + "name": "Notal check", + "id": "notal_flag", + "optional": true, + "value-key": "[NOTAL-CHECK]", + "description": "Skip the automatic failure detection of Talairach alignment.", + "command-line-flag": "-notal-check", + "type": "Flag" + }, + { + "name": "Hippocampal-subfileds-T1", + "id": "hippocampal_subfields_T1_flag", + "optional": true, + "value-key": "[HYPPOCAMPAL-SUBFIELDS]", + "description": "Segmentation of hippocampal subfields using input T1 scan.", + "command-line-flag": "-hippocampal-subfields-T1", + "type": "Flag" + }, + { + "name": "Brainstem Structures", + "id": "brainstem_structures_flag", + "optional": true, + "value-key": "[BRAINSTEM-STRUCTURES]", + "description": "Segmentation of brainstem structures.", + "command-line-flag": "-brainstem-structures", + "type": "Flag" + }, + { + "name": "No wsgcaatlas", + "id": "no_wsgcaatlas_flag", + "optional": true, + "value-key": "[NO-WSGCAATLAS]", + "description": "Do not use GCA atlas when skull stripping.", + "command-line-flag": "-no-wsgcaatlas", + "type": "Flag" + }, + { + "name": "No skull strip", + "id": "noskullstrip_flag", + "optional": true, + "value-key": "[NO-SKULLSTRIP]", + "description": "Exclude skull strip step.", + "command-line-flag": "-noskullstrip", + "type": "Flag" + } + ], + "custom": { + "cbrain:author": "Natacha Beck ", + "cbrain:readonly-input-files": true + }, + "description": "Performs all, or any part of, the FreeSurfer cortical reconstruction process (https://surfer.nmr.mgh.harvard.edu/fswiki/recon-all)." +} diff --git a/vip-core/pom.xml b/vip-core/pom.xml index 388a50d47..af3401d28 100644 --- a/vip-core/pom.xml +++ b/vip-core/pom.xml @@ -158,6 +158,18 @@ knowledge of the CeCILL-B license and that you accept its terms. ${spring-framework.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + diff --git a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/VipException.java b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/VipException.java index 10ecc3994..1df521a1b 100644 --- a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/VipException.java +++ b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/VipException.java @@ -94,9 +94,12 @@ private static String format(String format, Object... args) { return sb.toString(); } - private Integer vipErrorCode = null; + private VipError vipError = null; + protected Optional getVipError() { + return Optional.ofNullable(vipError); + } public Optional getVipErrorCode() { - return Optional.ofNullable(vipErrorCode); + return getVipError().map(VipError::getCode); } // Allow all exception constructors to be used @@ -120,17 +123,17 @@ public VipException(Throwable cause) { public VipException(VipError vipError, Object ...params) { super(formatMessage(vipError, params)); - this.vipErrorCode = vipError.getCode(); + this.vipError = vipError; } public VipException(VipError vipError, Throwable cause, Object ...params) { super(formatMessage(vipError, params), cause); - this.vipErrorCode = vipError.getCode(); + this.vipError = vipError; } public VipException(String message, VipError vipError) { super(message); - this.vipErrorCode = vipError.getCode(); + this.vipError = vipError; } } diff --git a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/SpringCoreConfig.java b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/SpringCoreConfig.java index 2e19d3853..f4cc0de5e 100644 --- a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/SpringCoreConfig.java +++ b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/SpringCoreConfig.java @@ -1,5 +1,6 @@ package fr.insalyon.creatis.vip.core.server; +import com.fasterxml.jackson.databind.ObjectMapper; import fr.insalyon.creatis.grida.client.GRIDACacheClient; import fr.insalyon.creatis.grida.client.GRIDAClient; import fr.insalyon.creatis.grida.client.GRIDAPoolClient; @@ -20,6 +21,7 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePropertySource; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; @@ -121,6 +123,11 @@ public SMAClient smaClient(Server server) { return new SMAClient(server.getSMAHost(), server.getSMAPort()); } + @Bean + public ObjectMapper objectMapper() { + return Jackson2ObjectMapperBuilder.json().build(); + } + // to verify the @Value injection existence @Bean public static PropertySourcesPlaceholderConfigurer properties(){ diff --git a/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/ServerMockConfig.java b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/ServerMockConfig.java index 65929ad07..c9091b4d8 100644 --- a/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/ServerMockConfig.java +++ b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/ServerMockConfig.java @@ -2,6 +2,7 @@ import fr.insalyon.creatis.vip.core.server.business.Server; import org.mockito.Mockito; +import org.mockito.quality.Strictness; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -9,8 +10,7 @@ import java.io.IOException; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; /** * Spring configuration class for tests. @@ -34,6 +34,10 @@ public class ServerMockConfig { public static final String MAX_NUMBER_EXECUTIONS = "5"; public static final String TEST_CAS_URL = "testCasURL"; + // paths stuff + public static final String TEST_USERS_ROOT = "/test/prefix/vip/data/test_users"; + public static final String TEST_GROUP_ROOT = "/test/prefix/vip/data/test_groups"; + public static void reset(Server server) { Mockito.reset(server); Mockito.when(server.getAdminFirstName()).thenReturn(TEST_ADMIN_FIRST_NAME); @@ -45,15 +49,15 @@ public static void reset(Server server) { Mockito.when(server.getTruststoreFile()).thenReturn(LAB_TRUSTSTORE_FILE); Mockito.when(server.getTruststorePass()).thenReturn(LAB_TRUSTSTORE_PASS); when(server.getMaxPlatformRunningSimulations()).thenReturn(Integer.valueOf(MAX_NUMBER_EXECUTIONS)); - when(server.getDataManagerUsersHome()).thenReturn("/test/prefix/vip/data/test_users"); - when(server.getDataManagerGroupsHome()).thenReturn("/test/prefix/vip/data/test_groups"); + when(server.getDataManagerUsersHome()).thenReturn(TEST_USERS_ROOT); + when(server.getDataManagerGroupsHome()).thenReturn(TEST_GROUP_ROOT); when(server.getVoRoot()).thenReturn("/vo_test/root"); } @Bean @Primary public Server testServer() throws IOException { - Server server = mock(Server.class); + Server server = mock(Server.class, withSettings().strictness(Strictness.STRICT_STUBS)); reset(server); return server; } diff --git a/vip-core/src/test/java/UsersAndGroupsIT.java b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/UsersAndGroupsIT.java similarity index 99% rename from vip-core/src/test/java/UsersAndGroupsIT.java rename to vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/UsersAndGroupsIT.java index d6189837e..3e75544eb 100644 --- a/vip-core/src/test/java/UsersAndGroupsIT.java +++ b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/UsersAndGroupsIT.java @@ -1,3 +1,5 @@ +package fr.insalyon.creatis.vip.core.integrationtest; + import fr.insalyon.creatis.grida.client.GRIDAClientException; import fr.insalyon.creatis.vip.core.client.bean.Group; import fr.insalyon.creatis.vip.core.client.bean.User; diff --git a/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/BaseSpringIT.java b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/BaseSpringIT.java index f31af0609..0083f2d4d 100644 --- a/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/BaseSpringIT.java +++ b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/BaseSpringIT.java @@ -13,6 +13,8 @@ import fr.insalyon.creatis.vip.core.server.business.Server; import org.junit.jupiter.api.BeforeEach; import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; @@ -25,6 +27,7 @@ import javax.sql.DataSource; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -90,6 +93,7 @@ public abstract class BaseSpringIT { @BeforeEach protected void setUp() throws Exception { ServerMockConfig.reset(server); + Mockito.reset(gridaClient); } protected void assertRowsNbInTable(String tableName, int expectedNb) { @@ -102,27 +106,46 @@ protected void createUser(String testEmail) throws GRIDAClientException, Busines createUser(testEmail, ""); } + protected void createUserWithPassword(String testEmail, String password) throws GRIDAClientException, BusinessException { + createUser(testEmail, "", password); + } + protected void createUser(String testEmail, String nameSuffix) throws GRIDAClientException, BusinessException { + createUser(testEmail, nameSuffix, "testPassword"); + } + + protected void createUser(String testEmail, String nameSuffix, String password) throws GRIDAClientException, BusinessException { User newUser = new User("test firstName " + nameSuffix, "test lastName " + nameSuffix, testEmail, "test institution", - "testPassword", CountryCode.fr, + password, CountryCode.fr, null); Mockito.when(gridaClient.exist(anyString())).thenReturn(true, false); configurationBusiness.signup(newUser, "", (Group) null); } + protected void createUserInGroup(String userEmail, String groupName) throws BusinessException, GRIDAClientException { + createUserInGroup(userEmail, "", groupName); + } + protected void createUserInGroup(String userEmail, String nameSuffix, String groupName) throws BusinessException, GRIDAClientException { + createUserInGroups(userEmail, nameSuffix, groupName); + } + + public void createGroup(String groupName) throws BusinessException { + configurationBusiness.addGroup(new Group(groupName, true, true, true)); + } + + protected void createUserInGroups(String userEmail, String nameSuffix, String... groupNames) throws BusinessException, GRIDAClientException { User newUser = new User("test firstName " + nameSuffix, "test lastName " + nameSuffix, userEmail, "test institution", "testPassword", CountryCode.fr, null); Mockito.when(gridaClient.exist(anyString())).thenReturn(true, false); - Group group = configurationBusiness.getGroup(groupName); - configurationBusiness.signup(newUser, "", false, true, group); - } - - protected void signInUser() throws BusinessException { - configurationBusiness.signin("test1@test.fr", "testPassword"); + List groups = new ArrayList<>(); + for (String groupName : groupNames) { + groups.add(configurationBusiness.getGroup(groupName)); + } + configurationBusiness.signup(newUser, "", false, true, groups); } protected Date getNextSecondDate() { diff --git a/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/SpringJndiIT.java b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/SpringJndiIT.java index c1570a45e..a107acffc 100644 --- a/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/SpringJndiIT.java +++ b/vip-core/src/test/java/fr/insalyon/creatis/vip/core/integrationtest/database/SpringJndiIT.java @@ -2,6 +2,7 @@ import fr.insalyon.creatis.grida.client.GRIDAClient; import fr.insalyon.creatis.grida.client.GRIDAClientException; +import fr.insalyon.creatis.vip.core.client.bean.Account; import fr.insalyon.creatis.vip.core.client.bean.Group; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.client.view.util.CountryCode; @@ -19,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @@ -61,7 +63,6 @@ @TestPropertySource(properties = "db.tableEngine=") // to disable the default mysql/innodb engine on database init @TestMethodOrder(OrderAnnotation.class) @ActiveProfiles({"jndi-db", "test"}) // to use default jndi datasource but avoid default server config -@Disabled public class SpringJndiIT { @Autowired @@ -112,39 +113,39 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } /* - Add an account + Add a group (there is already one after init) + */ @Test @Order(2) - public void addNewAccount() throws BusinessException { - List accounts = configurationBusiness.getAccounts(); - assertEquals(0, accounts.size()); - configurationBusiness.addAccount("test Account", Collections.emptyList()); - accounts = configurationBusiness.getAccounts(); - assertEquals(1, accounts.size()); + public void addNewGroup() throws BusinessException { + List groups = configurationBusiness.getGroups(); + assertEquals(1, groups.size()); + configurationBusiness.addGroup(new Group("test group", true, true, true)); + groups = configurationBusiness.getGroups(); + assertEquals(2, groups.size()); } - */ /* - Verify the account is still there + Verify the group is still there + */ @Test @Order(3) - public void isAccountStillThere() throws BusinessException { - List accounts = configurationBusiness.getAccounts(); - assertEquals(1, accounts.size()); + public void isGroupStillThere() throws BusinessException { + List groups = configurationBusiness.getGroups(); + assertEquals(2, groups.size()); } - */ /* - Restart spring, account should still be there + Restart spring, group should still be there + */ @Test @Order(4) - @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD) // to restart spring - public void isAccountStillThereAfterRestart() throws BusinessException { - List accounts = configurationBusiness.getAccounts(); - assertEquals(1, accounts.size()); + @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) // to restart spring + public void isGroupStillThereAfterRestart() throws BusinessException { + List groups = configurationBusiness.getGroups(); + assertEquals(2, groups.size()); } - */ @Test @Order(5) diff --git a/vip-core/src/test/resources/jndi.properties b/vip-core/src/test/resources/jndi.properties index 2ad299a7c..b832aefa3 100644 --- a/vip-core/src/test/resources/jndi.properties +++ b/vip-core/src/test/resources/jndi.properties @@ -1,5 +1,5 @@ -java.naming.factory.initial=org.osjava.sj.SimpleContextFactory -org.osjava.sj.root=/$VIP_PROJECT_HOME/VIP-portal/vip-core/src/test/resources/jndi +java.naming.factory.initial = org.osjava.sj.SimpleContextFactory +org.osjava.sj.root=src/test/resources/simple-jndi-config org.osjava.sj.space=java:comp/env org.osjava.sj.jndi.shared=true org.osjava.sj.delimiter=. diff --git a/vip-core/src/test/resources/jndi/jdbc/vip.properties b/vip-core/src/test/resources/simple-jndi-config/jdbc/vip.properties similarity index 100% rename from vip-core/src/test/resources/jndi/jdbc/vip.properties rename to vip-core/src/test/resources/simple-jndi-config/jdbc/vip.properties diff --git a/vip-portal/pom.xml b/vip-portal/pom.xml index 2a158c285..365981430 100644 --- a/vip-portal/pom.xml +++ b/vip-portal/pom.xml @@ -222,6 +222,12 @@ knowledge of the CeCILL-B license and that you accept its terms. com.google.gwt gwt-dev provided + + + org.eclipse.jetty + * + + diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/DefaultSpringConfigurationIT.java b/vip-portal/src/test/java/fr/insalyon/creatis/vip/integrationtest/DefaultSpringConfigurationIT.java similarity index 65% rename from vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/DefaultSpringConfigurationIT.java rename to vip-portal/src/test/java/fr/insalyon/creatis/vip/integrationtest/DefaultSpringConfigurationIT.java index 02c3054d7..9d5009930 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/rest/itest/DefaultSpringConfigurationIT.java +++ b/vip-portal/src/test/java/fr/insalyon/creatis/vip/integrationtest/DefaultSpringConfigurationIT.java @@ -29,48 +29,37 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. */ -package fr.insalyon.creatis.vip.api.rest.itest; +package fr.insalyon.creatis.vip.integrationtest; -import fr.insalyon.creatis.vip.api.business.VipConfigurer; -import fr.insalyon.creatis.vip.api.controller.EgiController; import fr.insalyon.creatis.vip.api.controller.PlatformController; import fr.insalyon.creatis.vip.api.exception.ApiException; -import fr.insalyon.creatis.vip.api.rest.config.BaseWebSpringIT; -import fr.insalyon.creatis.vip.application.server.business.WorkflowBusiness; +import fr.insalyon.creatis.vip.core.server.SpringCoreConfig; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; import org.springframework.util.Assert; import java.nio.file.Paths; -import java.util.Collections; - -import static org.mockito.ArgumentMatchers.any; /** * Created by abonnet on 7/21/16. * - * Test the the global spring configuration + * Test the the global spring configuration, almost nothing is mocked * - * The less mock should be used to be as close as possible to the production - * environment. */ -@Disabled +@SpringJUnitWebConfig(SpringCoreConfig.class) public class DefaultSpringConfigurationIT { @Autowired private PlatformController platformController; - @Autowired - private EgiController egiController; + @BeforeAll - public static void setup() throws Exception { + static void configureHomePath() throws Exception { String fakeHomePath = Paths.get(ClassLoader.getSystemResource("TestHome").toURI()) .toAbsolutePath().toString(); - BaseWebSpringIT.setEnv(Collections.singletonMap("HOME", fakeHomePath)); + System.setProperty("user.home", fakeHomePath); } @Test @@ -79,20 +68,4 @@ public void propertiesShouldBePresent() throws ApiException { Assert.notNull(platformController.getPlatformProperties(), "platform properties should be present"); } - // Need to override vipConfigurer that operate on the database - //@Configuration - //@Import(SpringWebConfig.class) - static class TestConfig { - @Bean - public VipConfigurer vipConfigurer() { - VipConfigurer mock = Mockito.mock(VipConfigurer.class); - Mockito.when(mock.preHandle(any(), any(), any())).thenReturn(true); - return mock; - } - - @Bean - public WorkflowBusiness workflowBusiness() { - return Mockito.mock(WorkflowBusiness.class); - } - } } diff --git a/vip-portal/src/test/resources/TestHome/.moteur2/moteur2plugins.conf b/vip-portal/src/test/resources/TestHome/.moteur2/moteur2plugins.conf new file mode 100644 index 000000000..2c2c126ff --- /dev/null +++ b/vip-portal/src/test/resources/TestHome/.moteur2/moteur2plugins.conf @@ -0,0 +1,6 @@ +moteur2.plugins.workflowsdb.schema = workflowsdb +moteur2.plugins.workflowsdb.connection.username = sa +moteur2.plugins.workflowsdb.connection.password = +moteur2.plugins.workflowsdb.dialect = org.hibernate.dialect.H2Dialect +moteur2.plugins.workflowsdb.connection.driver_class = org.h2.Driver +moteur2.plugins.workflowsdb.connection.url = jdbc:h2:mem:viptestwithjndi;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false diff --git a/vip-api/src/test/resources/TestHome/.vip/vip-api.conf b/vip-portal/src/test/resources/TestHome/.vip/vip-api.conf similarity index 88% rename from vip-api/src/test/resources/TestHome/.vip/vip-api.conf rename to vip-portal/src/test/resources/TestHome/.vip/vip-api.conf index 32969756c..ae4b0ff15 100644 --- a/vip-api/src/test/resources/TestHome/.vip/vip-api.conf +++ b/vip-portal/src/test/resources/TestHome/.vip/vip-api.conf @@ -32,7 +32,7 @@ # comma separated list of authorized domains # domain example : http://brain-perfusion.creatis.insa-lyon.fr -cors.autorized-domains= +cors.autorized-domains=plop.plp # General info stuff carmin.platform.name=VIP @@ -43,13 +43,6 @@ carmin.platform.default_limit_list_execution=500 carmin.platform.unsupported_methods=playExecution carmin.platform.supported_API_Version=0.3 carmin.platform.email=vip-support@creatis.insa-lyon.fr -carmin.platform.error_codes_and_message=\ - 40001:An error has been encountered on the API,\ - 40002:Unfortunately this method is not implemented,\ - 40101:Bad credentials,\ - 40102:Insufficient authntication,\ - 40103:Authentication Error,\ - 50001:An unexpected error has been encountered # Authentication stuff carmin.authentication.apikey.header.name=apikey diff --git a/vip-portal/src/test/resources/TestHome/.vip/vip.conf b/vip-portal/src/test/resources/TestHome/.vip/vip.conf new file mode 100644 index 000000000..5ef9903e1 --- /dev/null +++ b/vip-portal/src/test/resources/TestHome/.vip/vip.conf @@ -0,0 +1,74 @@ +# Admin information +admin.first.name = Administrator +admin.last.name = +admin.email = admin@vip.creatis.insa-lyon.fr +admin.institution = +admin.pass = TOCHANGE + +# VIP internal config +simulation.max.beginner = 1 +simulation.max.platfrom = 35 +account.undesiredEmailDomains = +account.undesiredCountries = +last.publication.update = 6 +ssh.publickey = TOCHANGE + +# Gatelab Application config +appletGatelab.classes = GateLab +appletGatelabTest.classes = GateLab Test + +# SAML config +#saml.trustedcertificate.ISSUERTOCHANGE = PATH_TO_CERT +#saml.accounttype = TOCHANGE + +# Boutiques config for import and publication +boutiques.upload.repository = /tmp/boutiques-cache +boutiques.application.rootFolder = /biomed/user/c/creatis/vip/data/groups/Applications +boutiques.application.requirements = +publication.system-command = bosh publish --no-int $FILE + +# External Storage : Girder +girder.token.duration-in-days = 1.0 + +# VO config +vo.name = biomed +vo.root = /biomed + +# Grida / DFC config +grida.server.host = localhost +grida.server.port = 9006 +datamanager.path = /tmp +datamanager.users.home = /users +datamanager.users.home.alternative = +datamanager.groups.home = /groups +datamanager.groups.home.alternative = + +# MyProxy config +myproxy.enabled = false + + +# Mail config +sma.host = localhost +sma.port = 8084 + +# Simulation runtime information +workflows.directory = /SHARED_DIRECTORY/workflows +workflows.db.host = localhost + +# Truststore file +truststore.file = /TOMCAT_HOME/conf/truststore.jks +truststore.password = TOCHANGE + +# Other Config (seems unused) +cas.url = https://ng-cas.maatg.fr/pandora-gateway-sl-cas +apache.host = localhost +apache.ssl.port = 80 + +# EGI OIDC info +oidc.egi.client_id=CLIENT_ID +oidc.egi.client_secret=CLIENT_SECRET +oidc.egi.redirect_uri=http://localhost/login/oauth2/code/egi +oidc.egi.authorization_uri=https://EGI_URL/oidc/authorize +oidc.egi.token_uri=https://EGI_URL/oidc/token +oidc.egi.user_info_uri=https://EGI_URL/oidc/userinfo +oidc.egi.jwk_set_uri=https://EGI_URL/oidc/jwk \ No newline at end of file diff --git a/vip-portal/src/test/resources/jndi.properties b/vip-portal/src/test/resources/jndi.properties new file mode 100644 index 000000000..b832aefa3 --- /dev/null +++ b/vip-portal/src/test/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.osjava.sj.SimpleContextFactory +org.osjava.sj.root=src/test/resources/simple-jndi-config +org.osjava.sj.space=java:comp/env +org.osjava.sj.jndi.shared=true +org.osjava.sj.delimiter=. +jndi.syntax.separator=/ \ No newline at end of file diff --git a/vip-portal/src/test/resources/simple-jndi-config/jdbc/vip.properties b/vip-portal/src/test/resources/simple-jndi-config/jdbc/vip.properties new file mode 100644 index 000000000..2ce7a1be1 --- /dev/null +++ b/vip-portal/src/test/resources/simple-jndi-config/jdbc/vip.properties @@ -0,0 +1,5 @@ +type=javax.sql.DataSource +driver=org.h2.Driver +url=jdbc:h2:mem:viptestwithjndi;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false +user=sa +password= \ No newline at end of file