From e0437a4237c99a16955d5ec56ff5fe9996c76b57 Mon Sep 17 00:00:00 2001 From: Remigiusz Janeczek Date: Tue, 16 Mar 2021 16:00:26 +0100 Subject: Add helm validator sources Issue-ID: SDC-3185 Signed-off-by: Remigiusz Janeczek Change-Id: I32dea3b4294a90c4dfc75864fb4200f044e7a0b6 --- .../helmvalidator/HelmValidatorApplication.java | 33 +++ .../api/SupportedVersionsController.java | 52 ++++ .../helmvalidator/api/ValidationController.java | 68 +++++ .../errorhandling/ValidationErrorHandler.java | 129 +++++++++ .../errorhandling/ValidationErrorResponse.java | 34 +++ .../helm/validation/BashExecutor.java | 69 +++++ .../helmvalidator/helm/validation/FileManager.java | 72 +++++ .../helm/validation/ValidationService.java | 221 +++++++++++++++ .../exception/BashExecutionException.java | 28 ++ .../exception/NotSupportedVersionException.java | 28 ++ .../validation/exception/SaveFileException.java | 28 ++ .../helm/validation/model/BashOutput.java | 43 +++ .../validation/model/LintValidationResult.java | 55 ++++ .../validation/model/TemplateValidationResult.java | 48 ++++ .../helm/validation/model/ValidationResult.java | 98 +++++++ .../helm/versions/ApiVersionsReader.java | 80 ++++++ .../helm/versions/ChartBasedVersionProvider.java | 57 ++++ .../helm/versions/SupportedVersionsProvider.java | 65 +++++ .../helm/versions/SystemEnvVersionsReader.java | 47 +++ .../exception/ApiVersionNotFoundException.java | 29 ++ .../exception/NotSupportedApiVersionException.java | 28 ++ .../helm/versions/exception/ReadFileException.java | 28 ++ src/main/resources/application.properties | 4 + .../HelmValidatorApplicationTests.java | 33 +++ .../api/SupportedVersionsControllerTest.java | 67 +++++ .../api/ValidationControllerTest.java | 195 +++++++++++++ .../errorhandling/ValidationErrorHandlerTest.java | 125 ++++++++ .../helm/validation/BashExecutorTest.java | 43 +++ .../helm/validation/FileManagerTest.java | 100 +++++++ .../helm/validation/ValidationServiceTest.java | 314 +++++++++++++++++++++ .../helm/versions/ApiVersionsReaderTest.java | 128 +++++++++ .../versions/ChartBasedVersionProviderTest.java | 73 +++++ .../versions/SupportedVersionsProviderTest.java | 72 +++++ .../helm/versions/SystemEnvVersionsReaderTest.java | 69 +++++ 34 files changed, 2563 insertions(+) create mode 100644 src/main/java/org/onap/sdc/helmvalidator/HelmValidatorApplication.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/api/SupportedVersionsController.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/api/ValidationController.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandler.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorResponse.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutor.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/FileManager.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/ValidationService.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/BashExecutionException.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/NotSupportedVersionException.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/SaveFileException.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/BashOutput.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/LintValidationResult.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/TemplateValidationResult.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/ValidationResult.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReader.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProvider.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProvider.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReader.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ApiVersionNotFoundException.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/NotSupportedApiVersionException.java create mode 100644 src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ReadFileException.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/org/onap/sdc/helmvalidator/HelmValidatorApplicationTests.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/api/SupportedVersionsControllerTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/api/ValidationControllerTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandlerTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutorTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/validation/FileManagerTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/validation/ValidationServiceTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReaderTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProviderTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProviderTest.java create mode 100644 src/test/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReaderTest.java (limited to 'src') diff --git a/src/main/java/org/onap/sdc/helmvalidator/HelmValidatorApplication.java b/src/main/java/org/onap/sdc/helmvalidator/HelmValidatorApplication.java new file mode 100644 index 0000000..b8bed69 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/HelmValidatorApplication.java @@ -0,0 +1,33 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HelmValidatorApplication { + + public static void main(String[] args) { + SpringApplication.run(HelmValidatorApplication.class, args); + } + +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/api/SupportedVersionsController.java b/src/main/java/org/onap/sdc/helmvalidator/api/SupportedVersionsController.java new file mode 100644 index 0000000..1a92624 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/api/SupportedVersionsController.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.api; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.onap.sdc.helmvalidator.helm.versions.SupportedVersionsProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SupportedVersionsController { + + private final SupportedVersionsProvider versionsProvider; + + @Autowired + public SupportedVersionsController(SupportedVersionsProvider provider) { + this.versionsProvider = provider; + } + + @GetMapping("/versions") + public ResponseEntity>> supportedVersions() { + return mapVersionsToResponseEntity(versionsProvider.getVersions()); + } + + private ResponseEntity>> mapVersionsToResponseEntity(List versions) { + + return new ResponseEntity<>(Collections.singletonMap("versions", versions), HttpStatus.OK); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/api/ValidationController.java b/src/main/java/org/onap/sdc/helmvalidator/api/ValidationController.java new file mode 100644 index 0000000..a4e476c --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/api/ValidationController.java @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.api; + +import org.onap.sdc.helmvalidator.helm.validation.ValidationService; +import org.onap.sdc.helmvalidator.helm.validation.model.ValidationResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController +public class ValidationController { + + private static final Logger LOGGER = LoggerFactory.getLogger(ValidationController.class); + + private final ValidationService validationService; + + @Autowired + public ValidationController(ValidationService validationService) { + this.validationService = validationService; + } + + /** + * Validates Helm chart. + * + * @param version requested version of Helm client to be used + * @param file packaged Helm chart file + * @param isLinted flag deciding if chart should be linted + * @param isStrictLinted flag deciding if chart should be linted with strict option turned on + * @return Response with result of validation + */ + @PostMapping("/validate") + public ResponseEntity validate( + @RequestParam(value = "versionDesired", required = false) String version, + @RequestParam("file") MultipartFile file, + @RequestParam(value = "isLinted", required = false, defaultValue = "false") boolean isLinted, + @RequestParam(value = "isStrictLinted", required = false, defaultValue = "false") boolean isStrictLinted) { + LOGGER.debug("Received file: {}, size: {}, helm version: {}", + file.getOriginalFilename(), file.getSize(), version); + ValidationResult result = validationService + .process(version, file, isLinted, isStrictLinted); + return new ResponseEntity<>(result, HttpStatus.OK); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandler.java b/src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandler.java new file mode 100644 index 0000000..332a923 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandler.java @@ -0,0 +1,129 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.errorhandling; + +import org.onap.sdc.helmvalidator.api.ValidationController; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.NotSupportedVersionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.SaveFileException; +import org.onap.sdc.helmvalidator.helm.versions.exception.ApiVersionNotFoundException; +import org.onap.sdc.helmvalidator.helm.versions.exception.NotSupportedApiVersionException; +import org.onap.sdc.helmvalidator.helm.versions.exception.ReadFileException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice(assignableTypes = ValidationController.class) +public class ValidationErrorHandler { + + /** + * BashExecutionException handler. + * + * @param exception Exception that occurs during execution of bash command + * @return ResponseEntity with ValidationErrorResponse created from given exception + */ + @ExceptionHandler(value = BashExecutionException.class) + public ResponseEntity handle(BashExecutionException exception) { + return getErrorResponseEntity( + exception.getMessage(), + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + + /** + * SaveFileException handler. + * + * @param exception Exception that occurs during file saving + * @return ResponseEntity with ValidationErrorResponse created from given exception + */ + @ExceptionHandler(value = SaveFileException.class) + public ResponseEntity handle(SaveFileException exception) { + return getErrorResponseEntity( + exception.getMessage(), + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + + /** + * NotSupportedVersionException handler. + * + * @param exception Exception that occurs when not supported Helm version is requested for validation + * @return ResponseEntity with ValidationErrorResponse created from given exception + */ + @ExceptionHandler(value = NotSupportedVersionException.class) + public ResponseEntity handle(NotSupportedVersionException exception) { + return getErrorResponseEntity( + exception.getMessage(), + HttpStatus.BAD_REQUEST + ); + } + + /** + * ApiVersionNotFoundException handler. + * + * @param exception Exception that occurs when API version cannot be derived from Helm chart + * @return ResponseEntity with ValidationErrorResponse created from given exception + */ + @ExceptionHandler(value = ApiVersionNotFoundException.class) + public ResponseEntity handle(ApiVersionNotFoundException exception) { + return getErrorResponseEntity( + exception.getMessage(), + HttpStatus.BAD_REQUEST + ); + } + + /** + * NotSupportedApiVersionException handler. + * + * @param exception Exception that occurs when API version from Helm chart is not supported + * @return ResponseEntity with ValidationErrorResponse created from given exception + */ + @ExceptionHandler(value = NotSupportedApiVersionException.class) + public ResponseEntity handle(NotSupportedApiVersionException exception) { + return getErrorResponseEntity( + exception.getMessage(), + HttpStatus.BAD_REQUEST + ); + } + + /** + * ReadFileException handler. + * + * @param exception Exception that occurs during reading of Helm chart + * @return ResponseEntity with ValidationErrorResponse created from given exception + */ + @ExceptionHandler(value = ReadFileException.class) + public ResponseEntity handle(ReadFileException exception) { + return getErrorResponseEntity( + exception.getMessage(), + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + + private ResponseEntity getErrorResponseEntity(String errorMessage, HttpStatus status) { + ValidationErrorResponse errorResponse = new ValidationErrorResponse(errorMessage); + return new ResponseEntity<>( + errorResponse, + status + ); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorResponse.java b/src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorResponse.java new file mode 100644 index 0000000..0f1fded --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorResponse.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.errorhandling; + +class ValidationErrorResponse { + + private final String message; + + ValidationErrorResponse(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutor.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutor.java new file mode 100644 index 0000000..0bebc0a --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutor.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.stream.Collectors; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.model.BashOutput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class BashExecutor { + + private static final Logger LOGGER = LoggerFactory.getLogger( + ValidationService.class); + + BashOutput execute(String helmCommand) { + + try { + ProcessBuilder pb = new ProcessBuilder("bash", "-c", helmCommand); + pb.redirectErrorStream(true); + LOGGER.debug("Start process"); + Process process = pb.start(); + + List processOutput = readOutputAndCloseProcess(process); + return new BashOutput(process.exitValue(), processOutput); + } catch (IOException | InterruptedException e) { + throw new BashExecutionException("Error during bash execution: ", e); + } + } + + private List readOutputAndCloseProcess(Process process) throws IOException, InterruptedException { + + final InputStream inputStream = process.getInputStream(); + final List lines = new BufferedReader(new InputStreamReader(inputStream)) + .lines().collect(Collectors.toList()); + + // For compatibility with Helm2 and Helm3 + process.waitFor(); + inputStream.close(); + process.destroy(); + + return lines; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/FileManager.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/FileManager.java new file mode 100644 index 0000000..3617df7 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/FileManager.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.time.Instant; +import org.onap.sdc.helmvalidator.helm.validation.exception.SaveFileException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public class FileManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(FileManager.class); + private final String basePath; + + @Autowired + FileManager(@Value("${app.config.charts-base-path}") String basePath) { + this.basePath = basePath; + } + + String saveFile(MultipartFile file) { + LOGGER.debug("Base PATH: {}", basePath); + try { + String filePath = basePath + File.separator + generateFileName(file.getOriginalFilename()); + LOGGER.info("Attempt to save file : {}", filePath); + Files.copy(file.getInputStream(), Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING); + return filePath; + } catch (IOException e) { + throw new SaveFileException("Cannot save file: " + file.getOriginalFilename(), e); + } + } + + void removeFile(String path) { + try { + LOGGER.debug("Attempt to delete file : {}", path); + Files.deleteIfExists(Paths.get(path)); + } catch (IOException e) { + LOGGER.warn("Cannot delete file: {}, Exception: {}", path, e.getStackTrace()); + } + } + + private String generateFileName(String fileName) { + return Instant.now().toEpochMilli() + "_" + fileName; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/ValidationService.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/ValidationService.java new file mode 100644 index 0000000..1e6cedb --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/ValidationService.java @@ -0,0 +1,221 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.NotSupportedVersionException; +import org.onap.sdc.helmvalidator.helm.validation.model.BashOutput; +import org.onap.sdc.helmvalidator.helm.validation.model.LintValidationResult; +import org.onap.sdc.helmvalidator.helm.validation.model.TemplateValidationResult; +import org.onap.sdc.helmvalidator.helm.validation.model.ValidationResult; +import org.onap.sdc.helmvalidator.helm.versions.ChartBasedVersionProvider; +import org.onap.sdc.helmvalidator.helm.versions.SupportedVersionsProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public class ValidationService { + + private static final Logger LOGGER = LoggerFactory.getLogger(ValidationService.class); + private static final String TEMPLATE_OPTION = "template"; + private static final String LINT_OPTION = "lint"; + private static final String HELM_SUMMARY_MESSAGE_PATTERN = + "Error: \\d* chart\\(s\\) linted, \\d* chart\\(s\\) failed"; + private static final boolean INVALID_RESULT = false; + + private final FileManager fileManager; + + private final BashExecutor executor; + + private final SupportedVersionsProvider supportedVersionsProvider; + + private final ChartBasedVersionProvider chartBasedVersionProvider; + + + /** + * Constructor for ValidationService. + * + * @param fileManager object responsible for file manging + * @param executor object responsible for running shell commands + * @param supportedVersionsProvider object providing supported versions of Helm + * @param chartBasedVersionProvider object allowing to derive Helm version from a chart + */ + @Autowired + public ValidationService( + FileManager fileManager, BashExecutor executor, + SupportedVersionsProvider supportedVersionsProvider, + ChartBasedVersionProvider chartBasedVersionProvider) { + this.fileManager = fileManager; + this.executor = executor; + this.supportedVersionsProvider = supportedVersionsProvider; + this.chartBasedVersionProvider = chartBasedVersionProvider; + } + + /** + * Process Helm chart package with given options. + * + * @param desiredVersion requested version of Helm client to be used + * @param file packaged Helm chart file + * @param isLinted flag deciding if chart should be linted + * @param isStrictLinted flag deciding if chart should be linted with strict option turned on + * @return Result of Helm chart validation + */ + public ValidationResult process(String desiredVersion, MultipartFile file, boolean isLinted, + boolean isStrictLinted) { + String chartPath = fileManager.saveFile(file); + try { + String helmVersion = getSupportedHelmVersion(desiredVersion, chartPath); + return validateChart(helmVersion, file, isLinted, isStrictLinted, chartPath); + } finally { + LOGGER.info("File process finished"); + fileManager.removeFile(chartPath); + } + } + + private String getSupportedHelmVersion(String desiredVersion, String chartPath) { + String helmVersion = getHelmVersion(desiredVersion, chartPath); + + if (isNotSupportedVersion(helmVersion)) { + throw new NotSupportedVersionException(helmVersion); + } + + return helmVersion; + } + + private String getHelmVersion(String desiredVersion, String chartPath) { + if (desiredVersion == null) { + return chartBasedVersionProvider.getVersion(chartPath); + } + + if (desiredVersion.startsWith("v")) { + String helmMajorVersion = desiredVersion.substring(1); + return supportedVersionsProvider.getLatestVersion(helmMajorVersion); + } + + return desiredVersion; + } + + private ValidationResult validateChart(String version, MultipartFile file, boolean isLinted, boolean isStrictLinted, + String chartPath) { + LOGGER.info("Start validation of file: {}, with helm version: {}", + file.getOriginalFilename(), version); + + TemplateValidationResult templateValidationResult = runHelmTemplate( + buildHelmTemplateCommand(version, chartPath)); + LOGGER.info("Helm template finished"); + + if (isLinted) { + LOGGER.info("Start helm lint, strict: {}", isStrictLinted); + LintValidationResult lintValidationResult = runHelmLint( + buildHelmLintCommand(version, chartPath, isStrictLinted)); + LOGGER.info("Helm lint finished"); + return new ValidationResult(templateValidationResult, lintValidationResult, version); + } + + return new ValidationResult(templateValidationResult, version); + } + + private boolean isNotSupportedVersion(String version) { + return !supportedVersionsProvider.getVersions().contains(version); + } + + + private String buildHelmTemplateCommand(String version, String chartPath) { + return "helm-v" + version + " " + TEMPLATE_OPTION + " " + chartPath; + } + + private TemplateValidationResult runHelmTemplate(String helmCommand) + throws BashExecutionException { + + LOGGER.debug("Command executions: {} ", helmCommand); + BashOutput chartTemplateResult = executor.execute(helmCommand); + LOGGER.debug("Status code: " + chartTemplateResult.getExitValue()); + if (chartTemplateResult.getExitValue() != 0) { + List renderingErrors = parseTemplateError(chartTemplateResult.getOutputLines()); + return new TemplateValidationResult(false, renderingErrors); + } + return new TemplateValidationResult(true, Collections.emptyList()); + } + + private String buildHelmLintCommand(String version, String chartPath, boolean isStrictLint) { + String command = "helm-v" + version + " " + LINT_OPTION + " " + chartPath; + if (isStrictLint) { + return command + " --strict"; + } + return command; + } + + private LintValidationResult runHelmLint(String helmCommand) { + BashOutput chartLintResult = executor.execute(helmCommand); + + List lintErrors = parseLintError(chartLintResult.getOutputLines()); + List lintWarnings = parseWarningError(chartLintResult.getOutputLines()); + + boolean isSuccessExitStatus = isSuccessExitStatus(chartLintResult.getExitValue()); + + if (isInvalidWithoutStandardError(isSuccessExitStatus, lintErrors, lintWarnings)) { + return new LintValidationResult(INVALID_RESULT, chartLintResult.getOutputLines(), new ArrayList<>()); + } + + return new LintValidationResult(isSuccessExitStatus, lintErrors, lintWarnings); + } + + private boolean isInvalidWithoutStandardError(boolean isValid, List lintErrors, List lintWarnings) { + return !isValid && lintErrors.isEmpty() && lintWarnings.isEmpty(); + } + + private boolean isSuccessExitStatus(int exitValue) { + return exitValue == 0; + } + + private List parseTemplateError(List outputLines) { + + return outputLines.stream() + .filter(s -> s.startsWith("Error:")) + .collect(Collectors.toList()); + } + + private List parseWarningError(List outputLines) { + return outputLines.stream() + .filter(s -> s.startsWith("[WARNING]")) + .collect(Collectors.toList()); + } + + private List parseLintError(List outputLines) { + return outputLines.stream() + .filter(s -> s.startsWith("[ERROR]") || s.startsWith("Error")) + .filter(this::isNotHelmSummaryMessage) + .collect(Collectors.toList()); + } + + private boolean isNotHelmSummaryMessage(String line) { + Pattern pattern = Pattern.compile(HELM_SUMMARY_MESSAGE_PATTERN); + return !pattern.matcher(line).matches(); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/BashExecutionException.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/BashExecutionException.java new file mode 100644 index 0000000..2d70d39 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/BashExecutionException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.exception; + +public class BashExecutionException extends RuntimeException { + + public BashExecutionException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/NotSupportedVersionException.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/NotSupportedVersionException.java new file mode 100644 index 0000000..753a08d --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/NotSupportedVersionException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.exception; + +public class NotSupportedVersionException extends RuntimeException { + + public NotSupportedVersionException(String version) { + super("Version: " + version + " is not supported"); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/SaveFileException.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/SaveFileException.java new file mode 100644 index 0000000..cdb9079 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/exception/SaveFileException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.exception; + +public class SaveFileException extends RuntimeException { + + public SaveFileException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/BashOutput.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/BashOutput.java new file mode 100644 index 0000000..88942e5 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/BashOutput.java @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.model; + +import java.util.List; + +public class BashOutput { + + private final int exitValue; + + private final List outputLines; + + public BashOutput(int exitValue, List outputLines) { + this.exitValue = exitValue; + this.outputLines = outputLines; + } + + public int getExitValue() { + return exitValue; + } + + public List getOutputLines() { + return outputLines; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/LintValidationResult.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/LintValidationResult.java new file mode 100644 index 0000000..09cbe36 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/LintValidationResult.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.model; + +import java.util.List; + +public class LintValidationResult { + + private final boolean isValid; + + private final List lintErrors; + private final List lintWarnings; + + /** + * Validation result of linting a Helm chart. + * @param isValid flag indicating if chart is valid + * @param lintErrors list of errors occurred during linting + * @param lintWarnings list of warning occurred during linting + */ + public LintValidationResult(boolean isValid, List lintErrors, List lintWarnings) { + this.isValid = isValid; + this.lintErrors = lintErrors; + this.lintWarnings = lintWarnings; + } + + boolean isValid() { + return isValid; + } + + List getLintErrors() { + return lintErrors; + } + + List getLintWarnings() { + return lintWarnings; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/TemplateValidationResult.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/TemplateValidationResult.java new file mode 100644 index 0000000..1ba20f9 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/TemplateValidationResult.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.model; + +import java.util.List; + +public class TemplateValidationResult { + + private final boolean isDeployable; + + private final List renderErrors; + + /** + * Validation result of templating a Helm chart. + * @param isDeployable flag indicating if chart can be templated + * @param renderErrors list of errors occurred during templating + */ + public TemplateValidationResult(boolean isDeployable, List renderErrors) { + this.isDeployable = isDeployable; + this.renderErrors = renderErrors; + } + + boolean isDeployable() { + return isDeployable; + } + + List getRenderErrors() { + return renderErrors; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/ValidationResult.java b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/ValidationResult.java new file mode 100644 index 0000000..bb4fccc --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/validation/model/ValidationResult.java @@ -0,0 +1,98 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation.model; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +public class ValidationResult { + + private final Boolean isDeployable; + private final List renderErrors; + private final Boolean isValid; + private final List lintWarning; + private final List lintError; + private final String versionUsed; + + + /** + * ValidationResult constructor when linting is enabled. + * @param templateValidationResult result of helm chart templating + * @param lintValidationResult result of helm chart linting + * @param versionUsed version of helm client used + */ + public ValidationResult( + TemplateValidationResult templateValidationResult, + LintValidationResult lintValidationResult, + String versionUsed) { + this.isDeployable = templateValidationResult.isDeployable(); + this.renderErrors = templateValidationResult.getRenderErrors(); + + this.isValid = lintValidationResult.isValid(); + this.lintWarning = lintValidationResult.getLintWarnings(); + this.lintError = lintValidationResult.getLintErrors(); + this.versionUsed = versionUsed; + } + + /** + * ValidationResult constructor when linting is disabled. + * @param templateValidationResult result of helm chart templating + * @param versionUsed version of helm client used + */ + public ValidationResult( + TemplateValidationResult templateValidationResult, String versionUsed) { + this.isDeployable = templateValidationResult.isDeployable(); + this.renderErrors = templateValidationResult.getRenderErrors(); + + this.isValid = null; + this.lintWarning = null; + this.lintError = null; + this.versionUsed = versionUsed; + } + + public Boolean isDeployable() { + return isDeployable; + } + + public List getRenderErrors() { + return Optional.ofNullable(renderErrors) + .map(Collections::unmodifiableList).orElse(null); + } + + public Boolean isValid() { + return isValid; + } + + public List getLintWarning() { + return Optional.ofNullable(lintWarning) + .map(Collections::unmodifiableList).orElse(null); + } + + public List getLintError() { + return Optional.ofNullable(lintError) + .map(Collections::unmodifiableList).orElse(null); + } + + public String getVersionUsed() { + return versionUsed; + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReader.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReader.java new file mode 100644 index 0000000..e5c1a2e --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReader.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Path; +import java.util.Optional; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.onap.sdc.helmvalidator.helm.versions.exception.ApiVersionNotFoundException; +import org.onap.sdc.helmvalidator.helm.versions.exception.ReadFileException; +import org.springframework.stereotype.Service; + +@Service +public class ApiVersionsReader { + + private static final int MAIN_CHART_DIR_DEPTH = 2; + private static final String API_VERSION_PREFIX = "apiVersion:"; + private static final Path CHART_FILE_NAME = Path.of("Chart.yaml"); + + String readVersion(String chartPath) { + return tryReadVersionFromChart(chartPath) + .orElseThrow(ApiVersionNotFoundException::new); + } + + private Optional tryReadVersionFromChart(String chartPath) { + try (TarArchiveInputStream tarInput = new TarArchiveInputStream( + new GzipCompressorInputStream(new FileInputStream(chartPath)))) { + return readVersionFromChart(tarInput); + } catch (IOException e) { + throw new ReadFileException("Cannot read tar from path: " + chartPath, e); + } + } + + private Optional readVersionFromChart(TarArchiveInputStream tarInput) throws IOException { + TarArchiveEntry currentEntry; + while ((currentEntry = tarInput.getNextTarEntry()) != null) { + if (isMainChartYaml(currentEntry)) { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(tarInput)); + return bufferedReader.lines() + .filter(chartLine -> chartLine.contains(API_VERSION_PREFIX)) + .map(apiVersionLine -> apiVersionLine.replaceAll(API_VERSION_PREFIX, "")) + .map(String::trim) + .findFirst(); + } + } + return Optional.empty(); + } + + private boolean isMainChartYaml(TarArchiveEntry currentEntry) { + Path entryPath = Path.of(currentEntry.getName()); + return currentEntry.isFile() + && CHART_FILE_NAME.equals(entryPath.getFileName()) + && (entryPath.getNameCount() == MAIN_CHART_DIR_DEPTH); + } + + +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProvider.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProvider.java new file mode 100644 index 0000000..b892a33 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProvider.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import org.onap.sdc.helmvalidator.helm.versions.exception.NotSupportedApiVersionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ChartBasedVersionProvider { + + private final SupportedVersionsProvider supportedVersionsProvider; + private final ApiVersionsReader apiVersionsReader; + + @Autowired + public ChartBasedVersionProvider( + SupportedVersionsProvider supportedVersionsProvider, + ApiVersionsReader apiVersionsReader) { + this.supportedVersionsProvider = supportedVersionsProvider; + this.apiVersionsReader = apiVersionsReader; + } + + public String getVersion(String chartPath) { + String apiVersion = apiVersionsReader.readVersion(chartPath); + return mapToChartVersion(apiVersion); + } + + private String mapToChartVersion(String apiVersion) { + switch (apiVersion) { + case "v1": + return supportedVersionsProvider.getLatestVersion("2"); + case "v2": + return supportedVersionsProvider.getLatestVersion("3"); + default: + throw new NotSupportedApiVersionException("Cannot obtain Helm version from API version: " + apiVersion); + } + } + +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProvider.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProvider.java new file mode 100644 index 0000000..ff1cdde --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProvider.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import java.util.Comparator; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.onap.sdc.helmvalidator.helm.validation.exception.NotSupportedVersionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SupportedVersionsProvider { + + private final SystemEnvVersionsReader versionsReader; + + @Autowired + public SupportedVersionsProvider(SystemEnvVersionsReader versionsReader) { + this.versionsReader = versionsReader; + } + + /** + * Retrieves list of available Helm client versions. + * + * @return list of available Helm client versions + */ + public List getVersions() { + return versionsReader.readVersions().stream() + .filter(Predicate.not(String::isBlank)) + .sorted(Comparator.reverseOrder()) + .collect(Collectors.toList()); + } + + /** + * Retrieves latest available Helm client with given major version. + * + * @param helmMajorVersion major version of Helm client + * @return latest available Helm client with given major version + */ + public String getLatestVersion(String helmMajorVersion) { + return getVersions().stream() + .filter(supportedVersion -> supportedVersion.startsWith(helmMajorVersion + ".")) + .findFirst() + .orElseThrow(() -> new NotSupportedVersionException(helmMajorVersion)); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReader.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReader.java new file mode 100644 index 0000000..8cccd2b --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReader.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.springframework.stereotype.Service; + +@Service +public class SystemEnvVersionsReader { + + private static final String HELM_SUPPORTED_VERSIONS = "HELM_SUPPORTED_VERSIONS"; + private static final String DELIMITER = ","; + + List readVersions() { + return Arrays.stream(getSupportedVersionsFromEnv() + .split(DELIMITER)) + .filter(Predicate.not(String::isBlank)) + .collect(Collectors.toList()); + } + + String getSupportedVersionsFromEnv() { + return Optional.ofNullable(System.getenv(HELM_SUPPORTED_VERSIONS)) + .orElse(""); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ApiVersionNotFoundException.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ApiVersionNotFoundException.java new file mode 100644 index 0000000..fadcc2a --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ApiVersionNotFoundException.java @@ -0,0 +1,29 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions.exception; + +public class ApiVersionNotFoundException extends RuntimeException { + + public ApiVersionNotFoundException() { + super("Cannot find apiVersion value in a main chart"); + } + +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/NotSupportedApiVersionException.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/NotSupportedApiVersionException.java new file mode 100644 index 0000000..368f9f1 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/NotSupportedApiVersionException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions.exception; + +public class NotSupportedApiVersionException extends RuntimeException { + + public NotSupportedApiVersionException(String message) { + super(message); + } +} diff --git a/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ReadFileException.java b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ReadFileException.java new file mode 100644 index 0000000..a6a1ec4 --- /dev/null +++ b/src/main/java/org/onap/sdc/helmvalidator/helm/versions/exception/ReadFileException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions.exception; + +public class ReadFileException extends RuntimeException { + + public ReadFileException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..3fef31f --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,4 @@ +logging.level.web="ERROR" +spring.mvc.log-request-details=false +app.config.charts-base-path=/charts +spring.jackson.default-property-inclusion=NON_NULL diff --git a/src/test/java/org/onap/sdc/helmvalidator/HelmValidatorApplicationTests.java b/src/test/java/org/onap/sdc/helmvalidator/HelmValidatorApplicationTests.java new file mode 100644 index 0000000..5b81936 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/HelmValidatorApplicationTests.java @@ -0,0 +1,33 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class HelmValidatorApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/api/SupportedVersionsControllerTest.java b/src/test/java/org/onap/sdc/helmvalidator/api/SupportedVersionsControllerTest.java new file mode 100644 index 0000000..ef93a90 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/api/SupportedVersionsControllerTest.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.api; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.sdc.helmvalidator.helm.versions.SupportedVersionsProvider; +import org.springframework.http.ResponseEntity; + +@ExtendWith(MockitoExtension.class) +class SupportedVersionsControllerTest { + + private static final String SAMPLE_VERSION1 = "3.4.1"; + private static final String SAMPLE_VERSION2 = "3.3.4"; + private static final String SAMPLE_VERSION3 = "2.17.0"; + private static final String VERSIONS = "versions"; + private static final int EXPECTED_SIZE = 3; + + private SupportedVersionsController supportedVersionsController; + + @Mock + private SupportedVersionsProvider versionsProvider; + + @BeforeEach + void setUp() { + supportedVersionsController = new SupportedVersionsController(versionsProvider); + } + + @Test + void shouldReturnVersions() { + when(versionsProvider.getVersions()).thenReturn(List.of(SAMPLE_VERSION1, SAMPLE_VERSION2, SAMPLE_VERSION3)); + + ResponseEntity>> supportedVersionsResponse = supportedVersionsController + .supportedVersions(); + List supportedVersions = supportedVersionsResponse.getBody().get(VERSIONS); + + assertThat(supportedVersions).isNotNull(); + assertThat(supportedVersions).hasSize(EXPECTED_SIZE); + assertThat(supportedVersions).contains(SAMPLE_VERSION1, SAMPLE_VERSION2, SAMPLE_VERSION3); + } +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/api/ValidationControllerTest.java b/src/test/java/org/onap/sdc/helmvalidator/api/ValidationControllerTest.java new file mode 100644 index 0000000..03f976a --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/api/ValidationControllerTest.java @@ -0,0 +1,195 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.api; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; + +import java.util.ArrayList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.sdc.helmvalidator.helm.validation.ValidationService; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.NotSupportedVersionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.SaveFileException; +import org.onap.sdc.helmvalidator.helm.validation.model.LintValidationResult; +import org.onap.sdc.helmvalidator.helm.validation.model.TemplateValidationResult; +import org.onap.sdc.helmvalidator.helm.validation.model.ValidationResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.web.multipart.MultipartFile; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@AutoConfigureMockMvc +@ExtendWith(SpringExtension.class) +@ExtendWith(MockitoExtension.class) +class ValidationControllerTest { + + private static final String SAMPLE_VERSION = "3.3.4"; + private static final String VERSION_PARAM = "versionDesired"; + private static final String IS_LINTED_PARAM = "isLinted"; + private static final String IS_STRICT_LINTED_PARAM = "isStrictLinted"; + private static final String VALID = "valid"; + private static final String DEPLOYABLE = "deployable"; + private static final String RENDER_ERRORS = "renderErrors"; + private static final String LINT_WARNING = "lintWarning"; + private static final String LINT_ERROR = "lintError"; + private static final String SAMPLE_ORIGINAL_FILENAME = "sampleChart.tar.gz"; + private static final String FILE_KEY = "file"; + private static final String VALIDATION_ENDPOINT = "/validate"; + private static final String VERSION_USED = "versionUsed"; + + private ValidationController validationController; + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ValidationService validationService; + + @Mock + private MultipartFile multipartFile; + + @BeforeEach + void setUp() { + validationController = new ValidationController(validationService); + } + + @Test + void shouldReturnValidResponseForMockedFile() { + TemplateValidationResult templateValidationResult = new TemplateValidationResult(true, new ArrayList<>()); + LintValidationResult lintValidationResult = new LintValidationResult(true, new ArrayList<>(), + new ArrayList<>()); + + when(validationService.process(SAMPLE_VERSION, multipartFile, true, true)) + .thenReturn(new ValidationResult(templateValidationResult, lintValidationResult, SAMPLE_VERSION)); + + ResponseEntity result = validationController + .validate(SAMPLE_VERSION, multipartFile, true, true); + + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(result.getBody().isDeployable()).isTrue(); + assertThat(result.getBody().isValid()).isTrue(); + assertThat(result.getBody().getRenderErrors()).isEmpty(); + assertThat(result.getBody().getLintError()).isEmpty(); + assertThat(result.getBody().getLintWarning()).isEmpty(); + assertThat(result.getBody().getVersionUsed()).isEqualTo(SAMPLE_VERSION); + + } + + @Test + void shouldThrowExceptionWhenCannotSaveFile() { + when(validationService.process(SAMPLE_VERSION, multipartFile, true, true)).thenThrow(SaveFileException.class); + + assertThatExceptionOfType(SaveFileException.class) + .isThrownBy(() -> validationController.validate(SAMPLE_VERSION, multipartFile, true, true)); + } + + @Test + void shouldThrowExceptionIfErrorOccursDuringBashExecution() { + when(validationService.process(SAMPLE_VERSION, multipartFile, true, true)) + .thenThrow(BashExecutionException.class); + + assertThatExceptionOfType(BashExecutionException.class) + .isThrownBy(() -> validationController.validate(SAMPLE_VERSION, multipartFile, true, true)); + } + + @Test + void shouldThrowExceptionWhenProvidedVersionIsNotSupported() { + when(validationService.process(SAMPLE_VERSION, multipartFile, true, true)).thenThrow( + NotSupportedVersionException.class); + + assertThatExceptionOfType(NotSupportedVersionException.class) + .isThrownBy(() -> validationController.validate(SAMPLE_VERSION, multipartFile, true, true)); + } + + @Test + void shouldContainDeployAndValidParametersInResponseBodyIfLintedIsTrue() throws Exception { + + TemplateValidationResult templateValidationResult = new TemplateValidationResult(true, new ArrayList<>()); + LintValidationResult lintValidationResult = new LintValidationResult(true, new ArrayList<>(), + new ArrayList<>()); + MockMultipartFile file = new MockMultipartFile(FILE_KEY, SAMPLE_ORIGINAL_FILENAME, + MediaType.MULTIPART_FORM_DATA_VALUE, "test".getBytes()); + + when(validationService.process(SAMPLE_VERSION, file, true, true)) + .thenReturn(new ValidationResult(templateValidationResult, lintValidationResult, SAMPLE_VERSION)); + + MvcResult mvcResult = mockMvc.perform( + multipart(VALIDATION_ENDPOINT) + .file(file) + .param(VERSION_PARAM, SAMPLE_VERSION) + .param(IS_LINTED_PARAM, "true") + .param(IS_STRICT_LINTED_PARAM, "true")) + .andReturn(); + String contentAsString = mvcResult.getResponse().getContentAsString(); + + assertThat(contentAsString).contains(VALID); + assertThat(contentAsString).contains(DEPLOYABLE); + assertThat(contentAsString).contains(RENDER_ERRORS); + assertThat(contentAsString).contains(LINT_WARNING); + assertThat(contentAsString).contains(LINT_ERROR); + assertThat(contentAsString).contains(VERSION_USED); + assertThat(mvcResult.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()); + } + + @Test + void shouldNotContainValidParametersInResponseBodyIfLintedIsFalse() throws Exception { + + TemplateValidationResult templateValidationResult = new TemplateValidationResult(true, new ArrayList<>()); + MockMultipartFile file = new MockMultipartFile(FILE_KEY, SAMPLE_ORIGINAL_FILENAME, + MediaType.MULTIPART_FORM_DATA_VALUE, "test".getBytes()); + + when(validationService.process(SAMPLE_VERSION, file, false, false)) + .thenReturn(new ValidationResult(templateValidationResult, SAMPLE_VERSION)); + + MvcResult mvcResult = mockMvc.perform( + multipart(VALIDATION_ENDPOINT) + .file(file) + .param(VERSION_PARAM, SAMPLE_VERSION) + .param(IS_LINTED_PARAM, "false") + .param(IS_STRICT_LINTED_PARAM, "false")) + .andReturn(); + String contentAsString = mvcResult.getResponse().getContentAsString(); + + assertThat(contentAsString).doesNotContain(VALID); + assertThat(contentAsString).contains(DEPLOYABLE); + assertThat(contentAsString).contains(RENDER_ERRORS); + assertThat(contentAsString).doesNotContain(LINT_WARNING); + assertThat(contentAsString).doesNotContain(LINT_ERROR); + assertThat(contentAsString).contains(VERSION_USED); + assertThat(mvcResult.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()); + } +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandlerTest.java b/src/test/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandlerTest.java new file mode 100644 index 0000000..5fbad30 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/errorhandling/ValidationErrorHandlerTest.java @@ -0,0 +1,125 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.errorhandling; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.NotSupportedVersionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.SaveFileException; +import org.onap.sdc.helmvalidator.helm.versions.exception.ApiVersionNotFoundException; +import org.onap.sdc.helmvalidator.helm.versions.exception.NotSupportedApiVersionException; +import org.onap.sdc.helmvalidator.helm.versions.exception.ReadFileException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +@ExtendWith(MockitoExtension.class) +class ValidationErrorHandlerTest { + + private ValidationErrorHandler errorHandler; + + @Mock + private Throwable cause; + + @BeforeEach + void setUp() { + errorHandler = new ValidationErrorHandler(); + } + + @Test + void shouldReturnResponseEntityWithMessageWhenCannotSaveFile() { + String expectedMessage = "Cannot save file test-chart.tar.gz"; + SaveFileException saveFileException = new SaveFileException(expectedMessage, cause); + + ResponseEntity responseEntity = errorHandler.handle(saveFileException); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + assertThat(responseEntity.getBody().getMessage()).isEqualTo(expectedMessage); + } + + @Test + void shouldReturnResponseEntityWithMessageWhenProvidedVersionIsNotSupported() { + String version = "3.3.3"; + String expectedMessage = "Version: " + version + " is not supported"; + + NotSupportedVersionException notSupportedVersionException = new NotSupportedVersionException(version); + + ResponseEntity responseEntity = errorHandler.handle(notSupportedVersionException); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(responseEntity.getBody().getMessage()).isEqualTo(expectedMessage); + } + + @Test + void shouldReturnResponseEntityWithMessageWhenErrorOccursDuringBashExecution() { + String expectedMessage = "Error in bash executions"; + BashExecutionException bashExecutionException = new BashExecutionException(expectedMessage, cause); + + ResponseEntity responseEntity = errorHandler.handle(bashExecutionException); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + assertThat(responseEntity.getBody().getMessage()).isEqualTo(expectedMessage); + + } + + @Test + void shouldReturnResponseEntityWithMessageWhenHelmApiVersionNotFoundInChart() { + String expectedMessage = "Cannot find apiVersion value in a main chart"; + ApiVersionNotFoundException apiVersionNotFoundException = new ApiVersionNotFoundException(); + + ResponseEntity responseEntity = errorHandler.handle(apiVersionNotFoundException); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(responseEntity.getBody().getMessage()).isEqualTo(expectedMessage); + + } + + @Test + void shouldReturnResponseEntityWithMessageWhenHelmApiVersionIsNotSupported() { + String expectedMessage = "Cannot obtain Helm version from API version"; + NotSupportedApiVersionException notSupportedApiVersionException = new NotSupportedApiVersionException( + expectedMessage); + + ResponseEntity responseEntity = errorHandler.handle(notSupportedApiVersionException); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + assertThat(responseEntity.getBody().getMessage()).isEqualTo(expectedMessage); + + } + + @Test + void shouldReturnResponseEntityWithMessageWhenCannotReadChartFile() { + String expectedMessage = "Cannot read tar file from path"; + ReadFileException readFileException = new ReadFileException(expectedMessage, cause); + + ResponseEntity responseEntity = errorHandler.handle(readFileException); + + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + assertThat(responseEntity.getBody().getMessage()).isEqualTo(expectedMessage); + + } + +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutorTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutorTest.java new file mode 100644 index 0000000..5f76b83 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/validation/BashExecutorTest.java @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.model.BashOutput; + +class BashExecutorTest { + + + @Test + @Disabled("Disabled due to Operating System dependency - allowed on Linux OS") + void testExecution() throws BashExecutionException { + + BashExecutor executor = new BashExecutor(); + + BashOutput output = executor.execute("ls -al"); + + assertThat(output.getOutputLines()).isNotEmpty(); + } +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/validation/FileManagerTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/validation/FileManagerTest.java new file mode 100644 index 0000000..2d05cd9 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/validation/FileManagerTest.java @@ -0,0 +1,100 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Comparator; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.web.multipart.MultipartFile; + +@ExtendWith(MockitoExtension.class) +class FileManagerTest { + + private static final String TEST_RESOURCES_TMP = "src/test/resources/tmp"; + private static final File TEST_RESOURCES_DIR = new File(TEST_RESOURCES_TMP); + private static final ByteArrayInputStream TEST_INPUT_STREAM = new ByteArrayInputStream("test".getBytes()); + private static final String SAMPLE_FILE_NAME = "sample_file"; + + private FileManager fileManager; + + @Mock + private MultipartFile multipartFile; + + @BeforeAll + static void createTmpDir() { + TEST_RESOURCES_DIR.mkdirs(); + } + + @AfterAll + static void cleanTmpDir() throws IOException { + Files.walk(Paths.get(TEST_RESOURCES_TMP)) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .filter(File::isFile) + .forEach(File::delete); + TEST_RESOURCES_DIR.delete(); + } + + @BeforeEach + void setUp() { + fileManager = new FileManager(TEST_RESOURCES_TMP); + } + + @Test + void saveMultipartFileAndReturnFilePath() throws IOException { + mockMultipartFile(); + + String filePath = fileManager.saveFile(multipartFile); + + assertThat(filePath).isNotBlank(); + assertThat(Files.exists(Paths.get(filePath))).isTrue(); + } + + + @Test + void removeFileByPath() throws IOException { + mockMultipartFile(); + + String filePath = fileManager.saveFile(multipartFile); + fileManager.removeFile(filePath); + + assertThat(Files.exists(Paths.get(filePath))).isFalse(); + } + + private void mockMultipartFile() throws IOException { + when(multipartFile.getOriginalFilename()).thenReturn(SAMPLE_FILE_NAME); + when(multipartFile.getInputStream()).thenReturn(TEST_INPUT_STREAM); + } +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/validation/ValidationServiceTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/validation/ValidationServiceTest.java new file mode 100644 index 0000000..c3c4093 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/validation/ValidationServiceTest.java @@ -0,0 +1,314 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.validation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.sdc.helmvalidator.helm.validation.exception.BashExecutionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.NotSupportedVersionException; +import org.onap.sdc.helmvalidator.helm.validation.exception.SaveFileException; +import org.onap.sdc.helmvalidator.helm.validation.model.BashOutput; +import org.onap.sdc.helmvalidator.helm.validation.model.ValidationResult; +import org.onap.sdc.helmvalidator.helm.versions.ChartBasedVersionProvider; +import org.onap.sdc.helmvalidator.helm.versions.SupportedVersionsProvider; +import org.springframework.web.multipart.MultipartFile; + +@ExtendWith(MockitoExtension.class) +class ValidationServiceTest { + + private static final String HELM_ERROR_ON_TEMPLATE = + "Error: parse error at (sample/templates/fail.yaml:1): function \"deliberateSyntaxError\" not defined"; + private static final String HELM_ERROR_ON_LINT = + "[ERROR] templates/: parse error at (sample/templates/fail.yaml:1): function \"deliberateSyntaxError\" " + + "not defined\n"; + private static final String HELM_WARNING_ON_LINT = + "[WARNING] templates/: directory not found\n"; + private static final String HELM_WITHOUT_STANDARD_ERROR_ON_LINT = + "unable to check Chart.yaml file in chart: stat /charts/1610528407457_apiv2.tar.gz/Chart.yaml: not a directory"; + private static final String HELM_LINT_ERROR_SUMMARY_MESSAGE = "Error: 0 chart(s) linted, 1 chart(s) failed"; + private static final String HELM_EMPTY_OUTPUT = ""; + + private static final boolean LINTED = true; + private static final boolean NOT_LINTED = false; + private static final boolean STRICT_LINTED = true; + private static final boolean NOT_STRICT_LINTED = false; + private static final int SUCCESS_HELM_EXIT_CODE = 0; + private static final int UNSUCCESSFUL_HELM_EXIT_CODE = 1; + + private static final String SAMPLE_VERSION = "3.3.3"; + private static final List SAMPLE_VERSIONS = List.of("3.3.4", "3.3.3", "2.3.1", "2.1.4", "2.3.4"); + private static final String NOT_SUPPORTED_VERSION = "not supported version"; + + private static final String SAMPLE_PATH = "samplePath"; + private static final String HELM_TEMPLATE = "helm-v3.3.3 template samplePath"; + private static final String HELM_LINT = "helm-v3.3.3 lint samplePath"; + private static final String HELM_LINT_STRICT = "helm-v3.3.3 lint samplePath --strict"; + private static final int EXPECTED_ONE = 1; + + private ValidationService validationService; + + @Mock + private FileManager fileManager; + + @Mock + private SupportedVersionsProvider versionsProvider; + + @Mock + private ChartBasedVersionProvider chartBasedProvider; + + @Mock + private MultipartFile multipartFile; + + @Mock + private BashExecutor bashExecutor; + + @BeforeEach + void setUp() { + when(fileManager.saveFile(multipartFile)).thenReturn(SAMPLE_PATH); + lenient().when(versionsProvider.getVersions()).thenReturn(SAMPLE_VERSIONS); + this.validationService = new ValidationService(fileManager, bashExecutor, versionsProvider, chartBasedProvider); + } + + @Test + void shouldThrowExceptionWhenCannotSaveFile() { + when(fileManager.saveFile(multipartFile)).thenThrow(SaveFileException.class); + + assertThatExceptionOfType(SaveFileException.class) + .isThrownBy( + () -> validationService.process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED)); + } + + @Test + void shouldThrowExceptionWhenVersionsIsNotSupported() { + + assertThatExceptionOfType(NotSupportedVersionException.class) + .isThrownBy( + () -> validationService.process(NOT_SUPPORTED_VERSION, multipartFile, LINTED, STRICT_LINTED)); + } + + @Test + void shouldBeValidAndDeployableForNoErrorsAndNoWarning() { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isTrue(); + assertThat(validationResult.isValid()).isTrue(); + assertThat(validationResult.getRenderErrors()).isEmpty(); + assertThat(validationResult.getLintError()).isEmpty(); + assertThat(validationResult.getLintWarning()).isEmpty(); + } + + @ParameterizedTest + @CsvSource({"v2", "v3"}) + void shouldBeDeployableForLatestHelmVersion(String desiredVersion) { + final String majorVersion = desiredVersion.substring(1); + final String helmVersion = getLatestSampleHelmVersion(majorVersion); + final String helmTemplate = String.format("helm-v%s template samplePath", helmVersion); + when(versionsProvider.getLatestVersion(Mockito.anyString())).thenReturn(helmVersion); + mockBashCommand(helmTemplate, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + + ValidationResult validationResult = validationService + .process(desiredVersion, multipartFile, NOT_LINTED, NOT_STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isTrue(); + assertThat(validationResult.getRenderErrors()).isEmpty(); + verify(versionsProvider).getLatestVersion(majorVersion); + } + + @Test + void shouldBeValidAndDeployableForVersionTakenFromChart() { + when(chartBasedProvider.getVersion(Mockito.anyString())).thenReturn(SAMPLE_VERSION); + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + + ValidationResult validationResult = validationService + .process(null, multipartFile, LINTED, STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isTrue(); + assertThat(validationResult.isValid()).isTrue(); + assertThat(validationResult.getRenderErrors()).isEmpty(); + assertThat(validationResult.getLintError()).isEmpty(); + assertThat(validationResult.getLintWarning()).isEmpty(); + verify(chartBasedProvider).getVersion(SAMPLE_PATH); + } + + @Test + void shouldBeUndeployableForRenderErrorsWithMessages() { + mockBashCommand(HELM_TEMPLATE, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_ERROR_ON_TEMPLATE); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, NOT_LINTED, NOT_STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isFalse(); + assertThat(validationResult.getRenderErrors()).isNotEmpty(); + } + + @Test + void shouldBeUndeployableAndValidWhenRenderFailAndLintSuccessfulWithMessages() + throws BashExecutionException, SaveFileException { + mockBashCommand(HELM_TEMPLATE, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_ERROR_ON_TEMPLATE); + mockBashCommand(HELM_LINT_STRICT, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isFalse(); + assertThat(validationResult.isValid()).isTrue(); + assertThat(validationResult.getRenderErrors()).isNotEmpty(); + assertThat(validationResult.getLintError()).isEmpty(); + assertThat(validationResult.getLintWarning()).isEmpty(); + } + + @Test + void shouldBeDeployableAndInvalidForErrorOnLintWithMessages() { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_ERROR_ON_LINT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, NOT_STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isTrue(); + assertThat(validationResult.isValid()).isFalse(); + assertThat(validationResult.getRenderErrors()).isEmpty(); + assertThat(validationResult.getLintError()).isNotEmpty(); + assertThat(validationResult.getLintWarning()).isEmpty(); + } + + @Test + void shouldBeDeployableAndInvalidForWarningOnLintAndStrictLintWithMessages() + throws BashExecutionException, SaveFileException { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_WARNING_ON_LINT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isTrue(); + assertThat(validationResult.isValid()).isFalse(); + assertThat(validationResult.getRenderErrors()).isEmpty(); + assertThat(validationResult.getLintError()).isEmpty(); + assertThat(validationResult.getLintWarning()).isNotEmpty(); + } + + @Test + void shouldBeUndeployableAndInvalidForErrorOnTemplateAndErrorOnLintWithMessages() + throws BashExecutionException, SaveFileException { + mockBashCommand(HELM_TEMPLATE, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_ERROR_ON_TEMPLATE); + mockBashCommand(HELM_LINT_STRICT, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_WARNING_ON_LINT, HELM_ERROR_ON_LINT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + + assertThat(validationResult.isDeployable()).isFalse(); + assertThat(validationResult.isValid()).isFalse(); + assertThat(validationResult.getRenderErrors()).isNotEmpty(); + assertThat(validationResult.getLintError()).isNotEmpty(); + assertThat(validationResult.getLintWarning()).isNotEmpty(); + } + + @Test + void shouldBeInvalidForWarningOnStrictLintWithMessages() throws BashExecutionException, SaveFileException { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_WARNING_ON_LINT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + + assertThat(validationResult.isValid()).isFalse(); + assertThat(validationResult.getLintError()).isEmpty(); + assertThat(validationResult.getLintWarning()).isNotEmpty(); + } + + @Test + void shouldAddUsedVersionToValidationResultOnLinted() { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + assertThat(validationResult.getVersionUsed()).isEqualTo(SAMPLE_VERSION); + } + + @Test + void shouldAddUsedVersionToValidationResultOnNotLinted() { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, NOT_LINTED, NOT_STRICT_LINTED); + assertThat(validationResult.getVersionUsed()).isEqualTo(SAMPLE_VERSION); + } + + @Test + void shouldAddBashOutputToResultWhenHelmReturnNonStandardError() { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_WITHOUT_STANDARD_ERROR_ON_LINT); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + assertThat(validationResult.getLintError()).isNotEmpty(); + } + + @Test + void shouldNotAddSummaryMessageToLintErrors() { + mockBashCommand(HELM_TEMPLATE, SUCCESS_HELM_EXIT_CODE, HELM_EMPTY_OUTPUT); + mockBashCommand(HELM_LINT_STRICT, UNSUCCESSFUL_HELM_EXIT_CODE, HELM_ERROR_ON_LINT, + HELM_LINT_ERROR_SUMMARY_MESSAGE); + + ValidationResult validationResult = validationService + .process(SAMPLE_VERSION, multipartFile, LINTED, STRICT_LINTED); + assertThat(validationResult.getLintError()).isNotEmpty(); + assertThat(validationResult.getLintError()).hasSize(EXPECTED_ONE); + } + + private String getLatestSampleHelmVersion(String majorVersion) { + return SAMPLE_VERSIONS.stream() + .filter(version -> version.startsWith(majorVersion)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Not supported version")); + } + + private void mockBashCommand(String command, int exitValue, String... consoleOutput) { + when(bashExecutor.execute(command)) + .thenReturn(new BashOutput(exitValue, mockBashConsoleLog(consoleOutput))); + } + + private List mockBashConsoleLog(String... args) { + return Arrays.stream(args).collect(Collectors.toList()); + } +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReaderTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReaderTest.java new file mode 100644 index 0000000..7343e59 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/ApiVersionsReaderTest.java @@ -0,0 +1,128 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.onap.sdc.helmvalidator.helm.versions.exception.ApiVersionNotFoundException; +import org.onap.sdc.helmvalidator.helm.versions.exception.ReadFileException; + +class ApiVersionsReaderTest { + + private static final String TEST_RESOURCES_TMP = "src/test/resources/tmp"; + private static final Path TEST_CHART_PATH = Path.of(TEST_RESOURCES_TMP).resolve(Path.of("Chart.yaml")); + + private static final Path TEST_TAR_PATH = Path.of(TEST_RESOURCES_TMP, "test.tar"); + + private ApiVersionsReader apiVersionsReader; + + @BeforeEach + void setUp() { + apiVersionsReader = new ApiVersionsReader(); + } + + @ParameterizedTest + @ValueSource(strings = {"v1", "v2"}) + void shouldCorrectlyReadApiVersionFromTar(String apiVersion) throws IOException { + prepareTestTar(apiVersion); + + String helmVersion = apiVersionsReader.readVersion(TEST_TAR_PATH.toString()); + + assertThat(helmVersion).isEqualTo(apiVersion); + } + + @Test + void shouldThrowExceptionWhenApiVersionIsNotProvided() throws IOException { + prepareTestTar(null); + + Exception exception = assertThrows(ApiVersionNotFoundException.class, + () -> apiVersionsReader.readVersion(TEST_TAR_PATH.toString())); + + assertThat(exception).hasMessageContaining("Cannot find apiVersion value in a main chart"); + } + + @Test + void shouldThrowExceptionForNotExistingPath() { + String notExistingChartPath = "not/exiting/chart/path"; + + Exception exception = assertThrows(ReadFileException.class, + () -> apiVersionsReader.readVersion(notExistingChartPath)); + + assertThat(exception).hasMessageContaining("Cannot read tar from path: " + notExistingChartPath); + } + + @AfterEach + void cleanTmpDir() throws IOException { + Files.walk(Paths.get(TEST_RESOURCES_TMP)) + .map(Path::toFile) + .filter(File::isFile) + .forEach(File::delete); + } + + private void prepareTestTar(String apiVersion) throws IOException { + createTestChart(apiVersion); + createTestTar(); + } + + private void createTestTar() throws IOException { + TarArchiveOutputStream tarOutput = null; + try { + tarOutput = new TarArchiveOutputStream( + new GzipCompressorOutputStream(new FileOutputStream(String.valueOf(TEST_TAR_PATH)))); + + final String tarChartPath = "test/Chart.yaml"; + TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(TEST_CHART_PATH.toFile(), tarChartPath); + tarOutput.putArchiveEntry(tarArchiveEntry); + + Files.copy(TEST_CHART_PATH, tarOutput); + } finally { + if (tarOutput != null) { + tarOutput.closeArchiveEntry(); + tarOutput.close(); + } + } + } + + private void createTestChart(String apiVersion) throws IOException { + String apiVersionLine = apiVersion != null ? "apiVersion: " + apiVersion : ""; + + Files.createDirectories(TEST_CHART_PATH.getParent()); + Files.createFile(TEST_CHART_PATH); + Files.write(TEST_CHART_PATH, List.of("appVersion: 1.0", apiVersionLine, "name: test-chart")); + } + +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProviderTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProviderTest.java new file mode 100644 index 0000000..64daf2d --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/ChartBasedVersionProviderTest.java @@ -0,0 +1,73 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.sdc.helmvalidator.helm.versions.exception.NotSupportedApiVersionException; + +@ExtendWith(MockitoExtension.class) +class ChartBasedVersionProviderTest { + + private final String testChartPath = "test/path"; + @Mock + private SupportedVersionsProvider versionsProvider; + @Mock + private ApiVersionsReader apiVersionsReader; + private ChartBasedVersionProvider chartBasedVersionProvider; + + @BeforeEach + void setUp() { + chartBasedVersionProvider = new ChartBasedVersionProvider(versionsProvider, apiVersionsReader); + } + + @ParameterizedTest + @CsvSource({"v1,2.18", "v2,3.11"}) + void shouldGetLatestHelmVersionBasedOnApiVersion(String apiVersion, String expectedHelmVersion) { + when(apiVersionsReader.readVersion(testChartPath)).thenReturn(apiVersion); + when(versionsProvider.getLatestVersion(Mockito.anyString())).thenReturn(expectedHelmVersion); + + String helmVersion = chartBasedVersionProvider.getVersion(testChartPath); + + assertThat(helmVersion).isEqualTo(expectedHelmVersion); + } + + @Test + void shouldThrowExceptionWhenApiVersionIsNotSupported() { + when(apiVersionsReader.readVersion(testChartPath)).thenReturn("v3"); + + Exception exception = assertThrows(NotSupportedApiVersionException.class, + () -> chartBasedVersionProvider.getVersion(testChartPath)); + + assertThat(exception).hasMessageContaining("Cannot obtain Helm version from API version: v3"); + } + +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProviderTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProviderTest.java new file mode 100644 index 0000000..c28d339 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/SupportedVersionsProviderTest.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class SupportedVersionsProviderTest { + + private static final List UNSORTED_VERSIONS = List.of("1.0.0", "2.2.1", "2.0.0", "3.0.0"); + private static final List SORTED_VERSIONS = List.of("3.0.0", "2.2.1", "2.0.0", "1.0.0"); + private static final List SUPPORTED_VERSIONS = List.of("4.2.0", "3.11.3", "3.1.0", "3.0.4", "2.18.2", + "2.1.5", "1.5.6"); + + private SupportedVersionsProvider versionsProvider; + + @Mock + private SystemEnvVersionsReader versionsReader; + + @BeforeEach + void setUp() { + versionsProvider = new SupportedVersionsProvider(versionsReader); + } + + @Test + void shouldReturnSortedVersionsInRevertOrder() { + + when(versionsReader.readVersions()).thenReturn(UNSORTED_VERSIONS); + + List versions = versionsProvider.getVersions(); + + assertThat(versions).isEqualTo(SORTED_VERSIONS); + } + + @ParameterizedTest + @CsvSource({"2,2.18.2", "3,3.11.3"}) + void shouldGetLatestHelmVersionBasedOnDesiredMajorVersion(String desiredMajorVersion, String expectedHelmVersion) { + when(versionsProvider.getVersions()).thenReturn(SUPPORTED_VERSIONS); + + String helmVersion = versionsProvider.getLatestVersion(desiredMajorVersion); + + assertThat(helmVersion).isEqualTo(expectedHelmVersion); + } +} diff --git a/src/test/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReaderTest.java b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReaderTest.java new file mode 100644 index 0000000..7748355 --- /dev/null +++ b/src/test/java/org/onap/sdc/helmvalidator/helm/versions/SystemEnvVersionsReaderTest.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * SDC-HELM-VALIDATOR + * ================================================================================ + * Copyright (C) 2021 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.sdc.helmvalidator.helm.versions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class SystemEnvVersionsReaderTest { + + private static final String SINGLE_VERSION_VALUE = "3.2.1"; + private static final String MULTIPLE_VERSIONS_VALUE = "3.2.1,2.0.0,1.0.0"; + private static final int EXPECTED_SIZE_ONE = 1; + private static final int EXPECTED_SIZE_THREE = 3; + + @Spy + private SystemEnvVersionsReader versionsReader; + + @Test + void canReadSingleValue() { + when(versionsReader.getSupportedVersionsFromEnv()).thenReturn(SINGLE_VERSION_VALUE); + + List versions = versionsReader.readVersions(); + + assertThat(versions).hasSize(EXPECTED_SIZE_ONE); + } + + @Test + void canReadMultipleValues() { + when(versionsReader.getSupportedVersionsFromEnv()).thenReturn(MULTIPLE_VERSIONS_VALUE); + + List versions = versionsReader.readVersions(); + + assertThat(versions).hasSize(EXPECTED_SIZE_THREE); + } + + @Test + void returnEmptyListWhenVariableIsNotPresent() { + when(versionsReader.getSupportedVersionsFromEnv()).thenReturn(""); + + List versions = versionsReader.readVersions(); + + assertThat(versions).isEmpty(); + } +} -- cgit 1.2.3-korg