From c3b798b7a358a2469415ce1ea1099f11bd9a578f Mon Sep 17 00:00:00 2001 From: Margaret Black Date: Thu, 26 Sep 2024 15:19:01 -0500 Subject: [PATCH] #379 Add unit tests to check pyproject.toml velocity template Python version updates --- .../generator/PyprojectGenerationSteps.java | 119 ++++++++++++++++++ .../pyproject-generation.feature | 36 ++++++ 2 files changed, 155 insertions(+) create mode 100644 foundation/foundation-mda/src/test/java/com/boozallen/aiops/mda/generator/PyprojectGenerationSteps.java create mode 100644 foundation/foundation-mda/src/test/resources/specifications/pyproject-generation.feature diff --git a/foundation/foundation-mda/src/test/java/com/boozallen/aiops/mda/generator/PyprojectGenerationSteps.java b/foundation/foundation-mda/src/test/java/com/boozallen/aiops/mda/generator/PyprojectGenerationSteps.java new file mode 100644 index 000000000..ae34db396 --- /dev/null +++ b/foundation/foundation-mda/src/test/java/com/boozallen/aiops/mda/generator/PyprojectGenerationSteps.java @@ -0,0 +1,119 @@ +package com.boozallen.aiops.mda.generator;/*- + * #%L + * aiSSEMBLE::Foundation::MDA + * %% + * Copyright (C) 2021 Booz Allen + * %% + * This software package is licensed under the Booz Allen Public License. All Rights Reserved. + * #L% + */ + +import com.boozallen.aiops.mda.generator.util.PipelineUtils; + +import com.boozallen.aiops.mda.metamodel.element.*; +import com.boozallen.aiops.mda.metamodel.element.StepElement; +import com.boozallen.aiops.mda.metamodel.element.RecordElement; +import io.cucumber.java.Before; +import io.cucumber.java.Scenario; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.technologybrewery.fermenter.mda.GenerateSourcesHelper; +import org.technologybrewery.fermenter.mda.element.ExpandedProfile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class PyprojectGenerationSteps extends AbstractModelInstanceSteps { + private static final Logger logger = LoggerFactory.getLogger(PyprojectGenerationSteps.class); + private RecordElement record; + + @Before("@pyproject-generation") + public void setup(Scenario scenario) throws IOException { + this.scenario = scenario.getName(); + FileUtils.deleteDirectory(GENERATED_METADATA_DIRECTORY); + } + + @Given("a project with the name {string}") + public void a_project_with_the_name(String projectName) throws IOException { + createProject(projectName, "shared"); + } + + @Given("a {string} pipeline using the {string} implementation") + public void a_pipeline_using_the_implementation(String pipelineType, String pipelineImplementation) throws IOException { + String pipelineName = pipelineType + "-pipeline"; + createAndSavePipeline(pipelineName, pipelineType, pipelineImplementation); + } + + @Given("a {string} pipeline with step type {string} using the {string} implementation") + public void a_pipeline_with_step_type_using_the_implementation(String pipelineType, String pipelineStepType, String pipelineImplementation) throws IOException { + String pipelineName = pipelineType + "-pipeline"; + String pipelineStepName = pipelineStepType + "-step"; + + createAndSavePipeline(pipelineName, pipelineType, pipelineImplementation, pipeline -> { + try { + StepElement pipelineStep = createPipelineStep(pipelineStepName, pipelineStepType); + pipeline.addStep(pipelineStep); + } catch (Exception e) { + logger.error("Failed to add new step to test pipeline", e); + }; + + }); + } + + @Given("a record model with a corresponding dictionary type defined") + public void a_record_model_with_a_corresponding_dictionary_type_defined() throws Exception { + createSampleDictionaryType(); + record = new RecordElement(); + record.setName("TestRecord"); + record.setPackage(BOOZ_ALLEN_PACKAGE); + saveRecordToFile(record); + } + + @When("the {string} profile {string} is generated") + public void the_profile_is_generated(String profileType, String profile) throws Exception { + readMetadata(projectName); + Map profiles = loadProfiles(); + GenerateSourcesHelper.performSourceGeneration(profile, profiles, this::createGenerationContext, (missingProfile, foundProfiles) -> { + throw new RuntimeException("Missing profile: " + missingProfile); + }, new Slf4jDelegate(logger), projectDir.toFile()); + } + + @Then("the {string} is generated with the minimum Python version, {string}") + public void the_is_generated_with_the_minimum_Python_version(String outputFile, String minPythonVersion) throws IOException { + File fullFilepath = new File(projectDir.toString(), outputFile); + + assertTrue("The " + outputFile + " file was not generated!", fullFilepath.exists()); + + AtomicBoolean minPythonVersionFound = fileInspector(fullFilepath, "python = \"" + minPythonVersion+ "\""); + + assertTrue("The minimum Python version " + minPythonVersion + " was NOT found in " + fullFilepath + ".", minPythonVersionFound.get()); + } + + private AtomicBoolean fileInspector(File filepath, String patternToFind) throws IOException { + AtomicBoolean patternFound = new AtomicBoolean(false); + Files.lines(Paths.get(filepath.getAbsolutePath())).forEach(line -> { + if(line.contains(patternToFind)) { + patternFound.set(true); + } + }); + return patternFound; + } + + private static StepElement createPipelineStep(String stepName, String stepType) throws IOException { + StepElement step = new StepElement(); + step.setName(stepName); + step.setType(stepType); + return step; + } +} diff --git a/foundation/foundation-mda/src/test/resources/specifications/pyproject-generation.feature b/foundation/foundation-mda/src/test/resources/specifications/pyproject-generation.feature new file mode 100644 index 000000000..ddc277abd --- /dev/null +++ b/foundation/foundation-mda/src/test/resources/specifications/pyproject-generation.feature @@ -0,0 +1,36 @@ +@pyproject-generation +Feature: Minimum Python version can be set in the pyproject.toml.vm files. + + @pipeline-generation @code-generation + Scenario: The data-flow pipeline generates the correct pyproject.toml + Given a project with the name "example" + And a "data-flow" pipeline using the "data-delivery-pyspark" implementation + When the "pipeline" profile "data-delivery-pyspark-pipeline" is generated + Then the "pyproject.toml" is generated with the minimum Python version, ">=3.8" + + @pipeline-generation @code-generation + Scenario Outline: The record metamodel with profile "" generates the correct pyproject.toml + Given a project with the name "example" + And a record model with a corresponding dictionary type defined + When the "metadata" profile "" is generated + Then the "pyproject.toml" is generated with the minimum Python version, ">=3.8" + + Examples: + | profile | + | data-delivery-combined-data-records-python | + | data-delivery-data-records-core-python | + | data-delivery-data-pyspark | + + + @pipeline-generation @code-generation + Scenario Outline: The machine-learning pipeline with the "" step generates the correct pyproject.toml + Given a project with the name "example" + And a "machine-learning" pipeline with step type "" using the "machine-learning-mlflow" implementation + When the "pipeline" profile "" is generated + Then the "pyproject.toml" is generated with the minimum Python version, ">=3.8" + + Examples: + | pipelineStepType | profile | + | training | machine-learning-training | + | sagemaker-training | machine-learning-sagemaker-training | + | inference | machine-learning-inference |