-
Notifications
You must be signed in to change notification settings - Fork 4
SED-4429 initial draft of mapping fragments to plans #594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
58e52f0
d14ca08
fbad6b5
0a7306a
12349f4
7911b28
99c2105
364d3b4
9ee49db
b9ace31
6b3ad60
289beaa
177b99d
9caa1f5
12b840a
3b47d4c
a0507b4
5a19c9b
3169fc0
9db55ab
c07d009
7ced285
d89021f
483ea4a
26ca44e
d2a178e
4fcde11
360247b
fead30f
54b63d5
3e70101
e3200c3
1d0de2c
fbaf665
d007114
1a591b3
dc93ae4
62b6f6e
6fda7fe
7fcd655
2893c14
ff3ed7f
2110d89
a98fd6f
e6e9c0a
210507a
7949029
5449983
0562593
4569c0a
0d90a60
30d01cf
76aefd7
eef60b7
5a82afb
2dbd927
7b5746c
9c0d7ae
f2f8efc
75751c4
9b25e37
a6e8039
86110d9
cccb72e
6bf39b0
6ac6f24
f9a39bd
72affeb
cfeb124
dc2884b
6ef962b
c41364e
8745ce2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>ch.exense.step</groupId> | ||
| <artifactId>step-automation-packages</artifactId> | ||
| <version>0.0.0-SNAPSHOT</version> | ||
| </parent> | ||
|
|
||
| <artifactId>step-automation-packages-ide</artifactId> | ||
|
|
||
| <properties> | ||
| <groupId>ch.exense.step</groupId> | ||
| <maven.compiler.source>21</maven.compiler.source> | ||
| <maven.compiler.target>21</maven.compiler.target> | ||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| </properties> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>ch.exense.step</groupId> | ||
| <artifactId>step-ide</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>ch.exense.step</groupId> | ||
| <artifactId>step-automation-packages-controller</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>ch.exense.step</groupId> | ||
| <artifactId>step-plans-base-artefacts</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>ch.exense.step</groupId> | ||
| <artifactId>step-automation-packages-yaml</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>ch.exense.step</groupId> | ||
| <artifactId>step-controller-backend</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-core</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-all</artifactId> | ||
| <version>1.9.5</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /******************************************************************************* | ||
| * Copyright (C) 2026, exense GmbH | ||
| * | ||
| * This file is part of STEP | ||
| * | ||
| * STEP is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * STEP is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU Affero General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Affero General Public License | ||
| * along with STEP. If not, see <http://www.gnu.org/licenses/>. | ||
| ******************************************************************************/ | ||
| package step.core.collections; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.Properties; | ||
|
|
||
| import step.automation.packages.yaml.AutomationPackageYamlFragmentManager; | ||
| import step.core.collections.inmemory.InMemoryCollectionFactory; | ||
| import step.core.plans.Plan; | ||
|
|
||
| public class AutomationPackageCollectionFactory implements CollectionFactory { | ||
|
|
||
| private final InMemoryCollectionFactory baseFactory; | ||
| private final AutomationPackageYamlFragmentManager fragmentManager; | ||
|
|
||
| public AutomationPackageCollectionFactory(Properties properties, AutomationPackageYamlFragmentManager fragmentManager) { | ||
| this.fragmentManager = fragmentManager; | ||
| this.baseFactory = new InMemoryCollectionFactory(properties); | ||
| } | ||
|
|
||
| @Override | ||
| public <T> Collection<T> getCollection(String name, Class<T> entityClass) { | ||
|
|
||
| if (entityClass == Plan.class) { | ||
| return (Collection<T>) new AutomationPackagePlanCollection(fragmentManager); | ||
| } | ||
|
|
||
| return baseFactory.getCollection(name, entityClass); | ||
| } | ||
|
|
||
| @Override | ||
| public Collection<EntityVersion> getVersionedCollection(String name) { | ||
| Collection<EntityVersion> baseCollection = baseFactory.getCollection(name, EntityVersion.class); | ||
| return baseCollection; | ||
| } | ||
|
|
||
| @Override | ||
| public void close() throws IOException { | ||
| baseFactory.close(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||
| /******************************************************************************* | ||||||
| * Copyright (C) 2026, exense GmbH | ||||||
| * | ||||||
| * This file is part of STEP | ||||||
| * | ||||||
| * STEP is free software: you can redistribute it and/or modify | ||||||
| * it under the terms of the GNU Affero General Public License as published by | ||||||
| * the Free Software Foundation, either version 3 of the License, or | ||||||
| * (at your option) any later version. | ||||||
| * | ||||||
| * STEP is distributed in the hope that it will be useful, | ||||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
| * GNU Affero General Public License for more details. | ||||||
| * | ||||||
| * You should have received a copy of the GNU Affero General Public License | ||||||
| * along with STEP. If not, see <http://www.gnu.org/licenses/>. | ||||||
| ******************************************************************************/ | ||||||
| package step.core.collections; | ||||||
|
|
||||||
| import step.automation.packages.yaml.AutomationPackageYamlFragmentManager; | ||||||
| import step.core.collections.inmemory.InMemoryCollection; | ||||||
| import step.core.plans.Plan; | ||||||
|
|
||||||
| public class AutomationPackagePlanCollection extends InMemoryCollection<Plan> implements Collection<Plan> { | ||||||
|
|
||||||
|
|
||||||
| private final AutomationPackageYamlFragmentManager fragmentManager; | ||||||
|
|
||||||
| public AutomationPackagePlanCollection(AutomationPackageYamlFragmentManager fragmentManager) { | ||||||
| super(true, "plan"); | ||||||
| this.fragmentManager = fragmentManager; | ||||||
| super.save(fragmentManager.getPlans()); | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public Plan save(Plan p){ | ||||||
| return super.save(fragmentManager.savePlan(p)); | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void save(Iterable<Plan> iterable) { | ||||||
| for (Plan p : iterable) { | ||||||
| save(p); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| @Override | ||||||
| public void remove(Filter filter) { | ||||||
| find(filter, null, null, null, 100).forEach(fragmentManager::removePlan); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||
| super.remove(filter); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| /******************************************************************************* | ||
| * Copyright (C) 2026, exense GmbH | ||
| * | ||
| * This file is part of STEP | ||
| * | ||
| * STEP is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * STEP is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU Affero General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Affero General Public License | ||
| * along with STEP. If not, see <http://www.gnu.org/licenses/>. | ||
| ******************************************************************************/ | ||
| package step.core.collections; | ||
|
|
||
| import ch.exense.commons.app.Configuration; | ||
| import org.apache.commons.io.FileUtils; | ||
| import org.junit.After; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
| import org.mockito.Mockito; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import step.artefacts.Echo; | ||
| import step.automation.packages.AutomationPackageHookRegistry; | ||
| import step.automation.packages.AutomationPackageReadingException; | ||
| import step.automation.packages.JavaAutomationPackageReader; | ||
| import step.automation.packages.deserialization.AutomationPackageSerializationRegistry; | ||
| import step.automation.packages.scheduler.AutomationPackageSchedulerHook; | ||
| import step.automation.packages.yaml.AutomationPackageYamlFragmentManager; | ||
| import step.automation.packages.yaml.YamlAutomationPackageVersions; | ||
| import step.core.dynamicbeans.DynamicValue; | ||
| import step.core.plans.Plan; | ||
| import step.core.scheduler.ExecutionScheduler; | ||
| import step.core.scheduler.automation.AutomationPackageSchedule; | ||
| import step.core.scheduler.automation.AutomationPackageScheduleRegistration; | ||
| import step.parameter.ParameterManager; | ||
| import step.parameter.automation.AutomationPackageParametersRegistration; | ||
|
|
||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import java.util.Properties; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static org.junit.Assert.*; | ||
|
|
||
| public class AutomationPackageCollectionTest { | ||
|
|
||
|
|
||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(AutomationPackageCollectionTest.class); | ||
|
|
||
| private final JavaAutomationPackageReader reader; | ||
|
|
||
| private final File sourceDirectory = new File("src/test/resources/samples/step-automation-packages-sample1");; | ||
| private File destinationDirectory; | ||
| private Collection<Plan> planCollection; | ||
| private final Path expectedFilesPath = sourceDirectory.toPath().resolve("expected"); | ||
|
|
||
| public AutomationPackageCollectionTest() throws AutomationPackageReadingException { | ||
| AutomationPackageSerializationRegistry serializationRegistry = new AutomationPackageSerializationRegistry(); | ||
| AutomationPackageHookRegistry hookRegistry = new AutomationPackageHookRegistry(); | ||
|
|
||
| AutomationPackageScheduleRegistration.registerSerialization(serializationRegistry); | ||
|
|
||
| hookRegistry.register(AutomationPackageSchedule.FIELD_NAME_IN_AP, new AutomationPackageSchedulerHook(Mockito.mock(ExecutionScheduler.class))); | ||
|
|
||
| // accessor is not required in this test - we only read the yaml and don't store the result anywhere | ||
| AutomationPackageParametersRegistration.registerParametersHooks(hookRegistry, serializationRegistry, Mockito.mock(ParameterManager.class)); | ||
|
|
||
| this.reader = new JavaAutomationPackageReader(YamlAutomationPackageVersions.ACTUAL_JSON_SCHEMA_PATH, hookRegistry, serializationRegistry, new Configuration()); | ||
| } | ||
|
|
||
| @Before | ||
| public void setUp() throws IOException, AutomationPackageReadingException { | ||
| Properties properties = new Properties(); | ||
| destinationDirectory = Files.createTempDirectory("automationPackageCollectionTest").toFile(); | ||
| FileUtils.copyDirectory(sourceDirectory, destinationDirectory); | ||
|
|
||
| AutomationPackageYamlFragmentManager fragmentManager = reader.provideAutomationPackageYamlFragmentManager(destinationDirectory); | ||
| AutomationPackageCollectionFactory collectionFactory = new AutomationPackageCollectionFactory(properties, fragmentManager); | ||
| planCollection = collectionFactory.getCollection("plan", Plan.class); | ||
| } | ||
|
|
||
| @After | ||
| public void tearDown() throws IOException { | ||
| FileUtils.deleteDirectory(destinationDirectory); | ||
| } | ||
|
|
||
| @Test | ||
| public void testReadAllPlans() { | ||
| long count = planCollection.count(Filters.empty(), 100); | ||
| List<Plan> plans = planCollection.find(Filters.empty(), null, null, null, 100).collect(Collectors.toList()); | ||
|
|
||
| assertEquals(2, count); | ||
| Set<String> names = plans.stream().map(p -> p.getAttributes().get("name")).collect(Collectors.toUnmodifiableSet()); | ||
|
|
||
| assertEquals(2, names.size()); | ||
|
|
||
| assertTrue(names.contains("Test Plan")); | ||
| assertTrue(names.contains("Test Plan with Composite")); | ||
| } | ||
|
|
||
| @Test | ||
| public void testPlanModify() throws IOException { | ||
| Optional<Plan> optionalPlan = planCollection.find(Filters.equals("attributes.name", "Test Plan"), null, null, null, 100).findFirst(); | ||
|
|
||
| assertTrue(optionalPlan.isPresent()); | ||
|
|
||
| Plan plan = optionalPlan.get(); | ||
|
|
||
| Echo firstEcho = (Echo) plan.getRoot().getChildren().get(0); | ||
| DynamicValue<Object> text = firstEcho.getText(); | ||
| text.setDynamic(true); | ||
| text.setExpression("new Date().toString();"); | ||
|
|
||
| planCollection.save(plan); | ||
|
|
||
| assertFilesEqual(expectedFilesPath.resolve("plan1AfterModification.yml"), destinationDirectory.toPath().resolve("plans").resolve("plan1.yml")); | ||
| } | ||
|
|
||
|
|
||
| @Test | ||
| public void testPlanRenameExisting() throws IOException { | ||
| Optional<Plan> optionalPlan = planCollection.find(Filters.equals("attributes.name", "Test Plan"), null, null, null, 100).findFirst(); | ||
|
|
||
| assertTrue(optionalPlan.isPresent()); | ||
|
|
||
| Plan plan = optionalPlan.get(); | ||
|
|
||
| plan.getAttributes().put("name", "New Plan Name"); | ||
|
|
||
| planCollection.save(plan); | ||
|
|
||
| assertFilesEqual(expectedFilesPath.resolve("plan1AfterRename.yml"), destinationDirectory.toPath().resolve("plans").resolve("plan1.yml")); | ||
| } | ||
|
|
||
|
|
||
| @Test | ||
| public void testPlanRemoveExisting() throws IOException { | ||
| planCollection.remove(Filters.equals("attributes.name", "Test Plan")); | ||
|
|
||
| assertFilesEqual(expectedFilesPath.resolve("plan1AfterRemove.yml"), destinationDirectory.toPath().resolve("plans").resolve("plan1.yml")); | ||
| } | ||
|
|
||
| private void assertFilesEqual(Path expected, Path actual) throws IOException { | ||
| List<String> expectedLines = Files.readAllLines(expected); | ||
| List<String> actualLines = Files.readAllLines(actual); | ||
|
|
||
| assertEquals(expectedLines, actualLines); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| /ignored | ||
| /ignoredFile.yml |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| schemaVersion: 1.0.0 | ||
| name: "My package" | ||
| fragments: | ||
| - "keywords.yml" | ||
| - "plans/*.yml" | ||
| - "schedules.yml" | ||
| - "parameters.yml" | ||
| - "parameters2.yml" | ||
| - "unknown.yml" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --- | ||
| fragments: [] | ||
| keywords: [] | ||
| plans: | ||
| - version: "1.2.0" | ||
| name: "Test Plan" | ||
| root: | ||
| testCase: | ||
| nodeName: "Test Plan" | ||
| children: | ||
| - echo: | ||
| text: | ||
| expression: "new Date().toString();" | ||
| - echo: | ||
| text: | ||
| expression: "mySimpleKey" | ||
| - callKeyword: | ||
| nodeName: "CallMyKeyword2" | ||
| inputs: | ||
| - myInput: "myValue" | ||
| keyword: "MyKeyword2" | ||
| agents: null | ||
| categories: | ||
| - "Yaml Plan" | ||
| plansPlainText: | ||
| - name: "Plain text plan" | ||
| rootType: "Sequence" | ||
| categories: | ||
| - "PlainTextPlan" | ||
| file: "plans/plan2.plan" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
mockito-alldependency is used with a very old version1.9.5(from 2012). This artifact is deprecated and can cause dependency conflicts as it bundles other libraries. The project already includesmockito-core(lines 47-50), which is the recommended approach. Please remove themockito-alldependency to avoid potential issues and keep the dependencies clean.