diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index fc60fc6f6fddbb9b18a85ed1f472a444e0ed4cea..4acb2ba79d5cde699cf9dd4d379bf17c3c93e068 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -239,7 +239,7 @@ GEM
       jekyll-seo-tag (~> 2.1)
     minitest (5.15.0)
     multipart-post (2.1.1)
-    nokogiri (1.13.4-x86_64-linux)
+    nokogiri (1.13.6-x86_64-linux)
       racc (~> 1.4)
     octokit (4.22.0)
       faraday (>= 0.9)
diff --git a/docs/api-reference/crds.md b/docs/api-reference/crds.md
index fb3f02ac941870dd085d06027d972e6003c7aadb..f0962d47400dfb85f8f9a2b695fec49cc45fe6e8 100644
--- a/docs/api-reference/crds.md
+++ b/docs/api-reference/crds.md
@@ -114,6 +114,13 @@ Resource Types:
           A list of resource types that can be scaled for this `benchmark` resource. For each resource type the concrete values are defined in the `execution` object.<br/>
         </td>
         <td>true</td>
+      </tr><tr>
+        <td><b><a href="#benchmarkspecslosindex">slos</a></b></td>
+        <td>[]object</td>
+        <td>
+          List of resource values for the specified resource type.<br/>
+        </td>
+        <td>true</td>
       </tr><tr>
         <td><b><a href="#benchmarkspecsut">sut</a></b></td>
         <td>object</td>
@@ -146,6 +153,15 @@ Resource Types:
             <i>Default</i>: <br/>
         </td>
         <td>false</td>
+      </tr><tr>
+        <td><b>waitForResourcesEnabled</b></td>
+        <td>boolean</td>
+        <td>
+          If true, Theodolite waits to create the resource for the SUT until the infrastructure resources are ready, and analogously, Theodolite waits to create the load-gen resource until the resources of the SUT are ready.<br/>
+          <br/>
+            <i>Default</i>: false<br/>
+        </td>
+        <td>false</td>
       </tr></tbody>
 </table>
 
@@ -727,6 +743,63 @@ The fileSystem resourceSet loads the Kubernetes manifests from the filesystem.
 </table>
 
 
+### benchmark.spec.slos[index]
+<sup><sup>[↩ Parent](#benchmarkspec)</sup></sup>
+
+
+
+
+
+<table>
+    <thead>
+        <tr>
+            <th>Name</th>
+            <th>Type</th>
+            <th>Description</th>
+            <th>Required</th>
+        </tr>
+    </thead>
+    <tbody><tr>
+        <td><b>name</b></td>
+        <td>string</td>
+        <td>
+          The name of the SLO.<br/>
+        </td>
+        <td>true</td>
+      </tr><tr>
+        <td><b>offset</b></td>
+        <td>integer</td>
+        <td>
+          Hours by which the start and end timestamp will be shifted (for different timezones).<br/>
+        </td>
+        <td>true</td>
+      </tr><tr>
+        <td><b>prometheusUrl</b></td>
+        <td>string</td>
+        <td>
+          Connection string for Promehteus.<br/>
+        </td>
+        <td>true</td>
+      </tr><tr>
+        <td><b>sloType</b></td>
+        <td>string</td>
+        <td>
+          The type of the SLO. It must match 'lag trend'.<br/>
+        </td>
+        <td>true</td>
+      </tr><tr>
+        <td><b>properties</b></td>
+        <td>map[string]string</td>
+        <td>
+          (Optional) SLO specific additional arguments.<br/>
+          <br/>
+            <i>Default</i>: map[]<br/>
+        </td>
+        <td>false</td>
+      </tr></tbody>
+</table>
+
+
 ### benchmark.spec.sut
 <sup><sup>[↩ Parent](#benchmarkspec)</sup></sup>
 
@@ -1765,7 +1838,7 @@ Contains the Kafka configuration.
         </td>
         <td>true</td>
       </tr><tr>
-        <td><b><a href="#executionspecload">load</a></b></td>
+        <td><b><a href="#executionspecloads">loads</a></b></td>
         <td>object</td>
         <td>
           Specifies the load values that are benchmarked.<br/>
@@ -1778,13 +1851,6 @@ Contains the Kafka configuration.
           Specifies the scaling resource that is benchmarked.<br/>
         </td>
         <td>true</td>
-      </tr><tr>
-        <td><b><a href="#executionspecslosindex">slos</a></b></td>
-        <td>[]object</td>
-        <td>
-          List of resource values for the specified resource type.<br/>
-        </td>
-        <td>true</td>
       </tr><tr>
         <td><b>name</b></td>
         <td>string</td>
@@ -1794,6 +1860,13 @@ Contains the Kafka configuration.
             <i>Default</i>: <br/>
         </td>
         <td>false</td>
+      </tr><tr>
+        <td><b><a href="#executionspecslosindex">slos</a></b></td>
+        <td>[]object</td>
+        <td>
+          List of SLOs with their properties, which differ from the benchmark definition.<br/>
+        </td>
+        <td>false</td>
       </tr></tbody>
 </table>
 
@@ -1906,35 +1979,83 @@ Defines the overall parameter for the execution.
         <td><b>repetitions</b></td>
         <td>integer</td>
         <td>
-          Numper of repititions for each experiments.<br/>
+          Number of repititions for each experiment.<br/>
         </td>
         <td>true</td>
       </tr><tr>
-        <td><b>restrictions</b></td>
-        <td>[]string</td>
+        <td><b><a href="#executionspecexecutionstrategy">strategy</a></b></td>
+        <td>object</td>
         <td>
-          List of restriction strategys used to delimit the search space.<br/>
+          Defines the used strategy for the execution, either 'LinearSearch', 'BinarySearch' or 'InitialGuessSearch'.<br/>
         </td>
         <td>true</td>
       </tr><tr>
-        <td><b>strategy</b></td>
+        <td><b>loadGenerationDelay</b></td>
+        <td>integer</td>
+        <td>
+          Seconds to wait between the start of the SUT and the load generator.<br/>
+        </td>
+        <td>false</td>
+      </tr><tr>
+        <td><b>metric</b></td>
+        <td>string</td>
+        <td>
+          <br/>
+        </td>
+        <td>false</td>
+      </tr></tbody>
+</table>
+
+
+### execution.spec.execution.strategy
+<sup><sup>[↩ Parent](#executionspecexecution)</sup></sup>
+
+
+
+Defines the used strategy for the execution, either 'LinearSearch', 'BinarySearch' or 'InitialGuessSearch'.
+
+<table>
+    <thead>
+        <tr>
+            <th>Name</th>
+            <th>Type</th>
+            <th>Description</th>
+            <th>Required</th>
+        </tr>
+    </thead>
+    <tbody><tr>
+        <td><b>name</b></td>
         <td>string</td>
         <td>
-          Defines the used strategy for the execution, either 'LinearSearch' or 'BinarySearch'<br/>
+          <br/>
         </td>
         <td>true</td>
       </tr><tr>
-        <td><b>loadGenerationDelay</b></td>
-        <td>integer</td>
+        <td><b>guessStrategy</b></td>
+        <td>string</td>
         <td>
-          Seconds to wait between the start of the SUT and the load generator.<br/>
+          <br/>
+        </td>
+        <td>false</td>
+      </tr><tr>
+        <td><b>restrictions</b></td>
+        <td>[]string</td>
+        <td>
+          List of restriction strategies used to delimit the search space.<br/>
+        </td>
+        <td>false</td>
+      </tr><tr>
+        <td><b>searchStrategy</b></td>
+        <td>string</td>
+        <td>
+          <br/>
         </td>
         <td>false</td>
       </tr></tbody>
 </table>
 
 
-### execution.spec.load
+### execution.spec.loads
 <sup><sup>[↩ Parent](#executionspec)</sup></sup>
 
 
@@ -2019,24 +2140,10 @@ Specifies the scaling resource that is benchmarked.
         </tr>
     </thead>
     <tbody><tr>
-        <td><b>offset</b></td>
-        <td>integer</td>
-        <td>
-          Hours by which the start and end timestamp will be shifted (for different timezones).<br/>
-        </td>
-        <td>true</td>
-      </tr><tr>
-        <td><b>prometheusUrl</b></td>
-        <td>string</td>
-        <td>
-          Connection string for Promehteus.<br/>
-        </td>
-        <td>true</td>
-      </tr><tr>
-        <td><b>sloType</b></td>
+        <td><b>name</b></td>
         <td>string</td>
         <td>
-          The type of the SLO. It must match 'lag trend'.<br/>
+          The name of the SLO. It must match a SLO specified in the Benchmark.<br/>
         </td>
         <td>true</td>
       </tr><tr>
@@ -2047,7 +2154,7 @@ Specifies the scaling resource that is benchmarked.
           <br/>
             <i>Default</i>: map[]<br/>
         </td>
-        <td>false</td>
+        <td>true</td>
       </tr></tbody>
 </table>
 
diff --git a/docs/index.yaml b/docs/index.yaml
index c6cf4f6dcbeaf4b4ede37bca925025db950a2a77..956bb83b19ebbae4cddc4da6f07a0d937cf3dc2d 100644
--- a/docs/index.yaml
+++ b/docs/index.yaml
@@ -1,41 +1,6 @@
 apiVersion: v1
 entries:
   theodolite:
-  - apiVersion: v2
-    appVersion: 0.7.0
-    created: "2022-05-11T13:49:02.457130925+02:00"
-    dependencies:
-    - condition: grafana.enabled
-      name: grafana
-      repository: https://grafana.github.io/helm-charts
-      version: 6.17.5
-    - condition: kube-prometheus-stack.enabled
-      name: kube-prometheus-stack
-      repository: https://prometheus-community.github.io/helm-charts
-      version: 20.0.1
-    - condition: cp-helm-charts.enabled
-      name: cp-helm-charts
-      repository: https://soerenhenning.github.io/cp-helm-charts
-      version: 0.6.0
-    - condition: strimzi.enabled
-      name: strimzi-kafka-operator
-      repository: https://strimzi.io/charts/
-      version: 0.28.0
-    description: Theodolite is a framework for benchmarking the horizontal and vertical
-      scalability of cloud-native applications.
-    digest: af10134baa30bb07423f78240fe1c609381e1c616585883cf5d3aded2d86a2b1
-    home: https://www.theodolite.rocks
-    maintainers:
-    - email: soeren.henning@email.uni-kiel.de
-      name: Sören Henning
-      url: https://www.se.informatik.uni-kiel.de/en/team/soeren-henning-m-sc
-    name: theodolite
-    sources:
-    - https://github.com/cau-se/theodolite
-    type: application
-    urls:
-    - https://github.com/cau-se/theodolite/releases/download/v0.7.0/theodolite-0.7.0%20copy.tgz
-    version: 0.7.0
   - apiVersion: v2
     appVersion: 0.7.0
     created: "2022-05-11T13:49:02.491041789+02:00"
diff --git a/theodolite/crd/crd-benchmark.yaml b/theodolite/crd/crd-benchmark.yaml
index c901e61360c05b2f1cf2b1767a20f624eb262231..d73ec0105c7f97d0e425307fc4f21fd84d1e9b46 100644
--- a/theodolite/crd/crd-benchmark.yaml
+++ b/theodolite/crd/crd-benchmark.yaml
@@ -20,12 +20,16 @@ spec:
         properties:
           spec:
             type: object
-            required: ["sut", "loadGenerator", "resourceTypes", "loadTypes"]
+            required: ["sut", "loadGenerator", "resourceTypes", "loadTypes", "slos"]
             properties:
               name:
                 description: This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten.
                 type: string
                 default: ""
+              waitForResourcesEnabled:
+                description: If true, Theodolite waits to create the resource for the SUT until the infrastructure resources are ready, and analogously, Theodolite waits to create the load-gen resource until the resources of the SUT are ready.
+                type: boolean
+                default: false
               infrastructure:
                 description: (Optional) A list of file names that reference Kubernetes resources that are deployed on the cluster to create the required infrastructure.
                 type: object
@@ -425,6 +429,31 @@ spec:
                             additionalProperties: true
                             x-kubernetes-map-type: "granular"
                             default: {}
+              slos: # def of service level objectives
+                description: List of resource values for the specified resource type.
+                type: array
+                items:
+                  type: object
+                  required: ["name", "sloType", "prometheusUrl", "offset"]
+                  properties:
+                    name:
+                      description: The name of the SLO.
+                      type: string
+                    sloType:
+                      description: The type of the SLO. It must match 'lag trend'.
+                      type: string
+                    prometheusUrl:
+                      description: Connection string for Promehteus.
+                      type: string
+                    offset:
+                      description: Hours by which the start and end timestamp will be shifted (for different timezones).
+                      type: integer
+                    properties:
+                      description: (Optional) SLO specific additional arguments.
+                      type: object
+                      additionalProperties: true
+                      x-kubernetes-map-type: "granular"
+                      default: { }
               kafkaConfig:
                 description: Contains the Kafka configuration.
                 type: object
diff --git a/theodolite/crd/crd-execution.yaml b/theodolite/crd/crd-execution.yaml
index 92a8ca18d87009143620097caf2abfe8da202c82..0db251864bac3e6f2541534eec8895297b21cf39 100644
--- a/theodolite/crd/crd-execution.yaml
+++ b/theodolite/crd/crd-execution.yaml
@@ -20,7 +20,7 @@ spec:
         properties:
           spec:
             type: object
-            required: ["benchmark", "load", "resources", "slos", "execution", "configOverrides"]
+            required: ["benchmark", "loads", "resources", "execution", "configOverrides"]
             properties:
               name:
                 description: This field exists only for technical reasons and should not be set by the user. The value of the field will be overwritten.
@@ -29,7 +29,7 @@ spec:
               benchmark:
                 description: The name of the benchmark this execution is referring to.
                 type: string
-              load: # definition of the load dimension
+              loads: # definition of the load dimension
                 description: Specifies the load values that are benchmarked.
                 type: object
                 required: ["loadType", "loadValues"]
@@ -56,21 +56,15 @@ spec:
                     items:
                       type: integer
               slos: # def of service level objectives
-                description:  List of resource values for the specified resource type.
+                description:  List of SLOs with their properties, which differ from the benchmark definition.
                 type: array
                 items:
                   type: object
-                  required: ["sloType", "prometheusUrl", "offset"]
+                  required: ["name", "properties"]
                   properties:
-                    sloType:
-                      description: The type of the SLO. It must match 'lag trend'.
+                    name:
+                      description: The name of the SLO. It must match a SLO specified in the Benchmark.
                       type: string
-                    prometheusUrl:
-                      description: Connection string for Promehteus.
-                      type: string
-                    offset:
-                      description: Hours by which the start and end timestamp will be shifted (for different timezones).
-                      type: integer
                     properties:
                         description: (Optional) SLO specific additional arguments.
                         type: object
@@ -80,25 +74,35 @@ spec:
               execution: # def execution config
                 description: Defines the overall parameter for the execution.
                 type: object
-                required: ["strategy", "duration", "repetitions", "restrictions"]
+                required: ["strategy", "duration", "repetitions"]
                 properties:
-                  strategy:
-                    description: Defines the used strategy for the execution, either 'LinearSearch' or 'BinarySearch'
+                  metric:
                     type: string
+                  strategy:
+                    description: Defines the used strategy for the execution, either 'LinearSearch', 'BinarySearch' or 'InitialGuessSearch'.
+                    type: object
+                    required: ["name"]
+                    properties:
+                      name:
+                        type: string
+                      restrictions:
+                        description: List of restriction strategies used to delimit the search space.
+                        type: array
+                        items:
+                          type: string
+                      guessStrategy:
+                        type: string
+                      searchStrategy:
+                        type: string
                   duration:
                     description: Defines the duration of each experiment in seconds.
                     type: integer
                   repetitions:
-                    description: Numper of repititions for each experiments.
+                    description: Number of repititions for each experiment.
                     type: integer
                   loadGenerationDelay:
                     description: Seconds to wait between the start of the SUT and the load generator.
                     type: integer
-                  restrictions:
-                    description: List of restriction strategys used to delimit the search space.
-                    type: array
-                    items:
-                      type: string
               configOverrides:
                 description:  List of patchers that are used to override existing configurations.
                 type: array
diff --git a/theodolite/examples/operator/example-benchmark.yaml b/theodolite/examples/operator/example-benchmark.yaml
index 62920091e831ff914fb67e85a67cd3f1d98995ab..be7116c46f8222eeba0f3bffd086f7cc2b6ee227 100644
--- a/theodolite/examples/operator/example-benchmark.yaml
+++ b/theodolite/examples/operator/example-benchmark.yaml
@@ -33,6 +33,15 @@ spec:
           resource: "uc1-load-generator-deployment.yaml"
           properties:
             loadGenMaxRecords: "150000"
+  slos:
+    - name: "lag trend"
+      sloType: "lag trend"
+      prometheusUrl: "http://prometheus-operated:9090"
+      offset: 0
+      properties:
+        threshold: 3000
+        externalSloUrl: "http://localhost:80/evaluate-slope"
+        warmup: 60 # in seconds
   kafkaConfig:
     bootstrapServer: "theodolite-kafka-kafka-bootstrap:9092"
     topics:
diff --git a/theodolite/examples/operator/example-execution.yaml b/theodolite/examples/operator/example-execution.yaml
index 576a74b90dfc38483de79502ac14d42f6bedfb49..87e6275a8409177394dd313f2f1f0436e2162577 100644
--- a/theodolite/examples/operator/example-execution.yaml
+++ b/theodolite/examples/operator/example-execution.yaml
@@ -4,27 +4,25 @@ metadata:
   name: theodolite-example-execution
 spec:
   benchmark: "example-benchmark"
-  load:
+  loads:
     loadType: "NumSensors"
     loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
   resources:
     resourceType: "Instances"
     resourceValues: [1, 2, 3, 4, 5]
   slos:
-    - sloType: "lag trend"
-      prometheusUrl: "http://prometheus-operated:9090"
-      offset: 0
+    - name: "lag trend"
       properties:
         threshold: 2000
-        externalSloUrl: "http://localhost:80/evaluate-slope"
-        warmup: 60 # in seconds
   execution:
-    strategy: "LinearSearch"
+    strategy:
+      name: "RestrictionSearch"
+      restrictions:
+        - "LowerBound"
+      searchStrategy: "LinearSearch"
     duration: 300 # in seconds
     repetitions: 1
     loadGenerationDelay: 30 # in seconds
-    restrictions:
-      - "LowerBound"
   configOverrides: []
   # - patcher:
   #     type: "NodeSelectorPatcher"
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt
index cf2fac7337d79c1c5daf2b0fac070200cf27f9a5..f2b587cba90151af199da4b76a9cb8ad407f80ef 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/Benchmark.kt
@@ -2,13 +2,12 @@ package theodolite.benchmark
 
 import io.quarkus.runtime.annotations.RegisterForReflection
 import theodolite.util.ConfigurationOverride
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
+import theodolite.util.PatcherDefinition
 
 /**
  * A Benchmark contains:
- * - The [Resource]s that can be scaled for the benchmark.
- * - The [LoadDimension]s that can be scaled the benchmark.
+ * - The Resource that can be scaled for the benchmark.
+ * - The Load that can be scaled the benchmark.
  * - additional [ConfigurationOverride]s.
  */
 @RegisterForReflection
@@ -22,10 +21,12 @@ interface Benchmark {
      * @return a BenchmarkDeployment.
      */
     fun buildDeployment(
-        load: LoadDimension,
-        res: Resource,
-        configurationOverrides: List<ConfigurationOverride?>,
-        loadGenerationDelay: Long,
-        afterTeardownDelay: Long
+            load: Int,
+            loadPatcherDefinitions: List<PatcherDefinition>,
+            resource: Int,
+            resourcePatcherDefinitions: List<PatcherDefinition>,
+            configurationOverrides: List<ConfigurationOverride?>,
+            loadGenerationDelay: Long,
+            afterTeardownDelay: Long
     ): BenchmarkDeployment
 }
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
index f2dda487d390c5f771e4f47c0f9c7ebf2cf971e7..13c98d7013fc3c6f24066419604d42c576db2c94 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/BenchmarkExecution.kt
@@ -12,9 +12,9 @@ import kotlin.properties.Delegates
  * A BenchmarkExecution consists of:
  *  - A [name].
  *  - The [benchmark] that should be executed.
- *  - The [load] that should be checked in the benchmark.
+ *  - The [loads]s that should be checked in the benchmark.
  *  - The [resources] that should be checked in the benchmark.
- *  - A list of [slos] that are used for the evaluation of the experiments.
+ *  - The [slos] further restrict the Benchmark SLOs for the evaluation of the experiments.
  *  - An [execution] that encapsulates: the strategy, the duration, and the restrictions
  *  for the execution of the benchmark.
  *  - [configOverrides] additional configurations.
@@ -28,48 +28,55 @@ class BenchmarkExecution : KubernetesResource {
     var executionId: Int = 0
     lateinit var name: String
     lateinit var benchmark: String
-    lateinit var load: LoadDefinition
+    lateinit var loads: LoadDefinition
     lateinit var resources: ResourceDefinition
-    lateinit var slos: List<Slo>
+    lateinit var slos: List<SloConfiguration>
     lateinit var execution: Execution
     lateinit var configOverrides: MutableList<ConfigurationOverride?>
 
     /**
-     * This execution encapsulates the [strategy], the [duration], the [repetitions], and the [restrictions]
+     * This execution encapsulates the [strategy], the [duration], and the [repetitions],
      *  which are used for the concrete benchmark experiments.
      */
     @JsonDeserialize
     @RegisterForReflection
     class Execution : KubernetesResource {
-        lateinit var strategy: String
+        var metric = "demand"
+        lateinit var strategy: Strategy
         var duration by Delegates.notNull<Long>()
         var repetitions by Delegates.notNull<Int>()
-        lateinit var restrictions: List<String>
         var loadGenerationDelay = 0L
         var afterTeardownDelay = 5L
     }
 
     /**
-     * Measurable metric.
-     * [sloType] determines the type of the metric.
-     * It is evaluated using the [theodolite.evaluation.ExternalSloChecker] by data measured by Prometheus.
-     * The evaluation checks if a [threshold] is reached or not.
-     * [offset] determines the shift in hours by which the start and end timestamps should be shifted.
-     * The [warmup] determines after which time the metric should be evaluated to avoid starting interferences.
-     * The [warmup] time unit depends on the Slo: for the lag trend it is in seconds.
+     * This Strategy encapsulates the [restrictions], [guessStrategy] and [searchStrategy],
+     * which are used for restricting the resources, the guess Strategy for the
+     * [theodolite.strategies.searchstrategy.InitialGuessSearchStrategy] and the name of the actual
+     * [theodolite.strategies.searchstrategy.SearchStrategy] which is used.
      */
     @JsonDeserialize
     @RegisterForReflection
-    class Slo : KubernetesResource {
-        lateinit var sloType: String
-        lateinit var prometheusUrl: String
-        var offset by Delegates.notNull<Int>()
-        lateinit var properties: MutableMap<String, String>
+    class Strategy : KubernetesResource {
+        lateinit var name: String
+        var restrictions = emptyList<String>()
+        var guessStrategy = ""
+        var searchStrategy = ""
     }
 
     /**
-     * Represents a Load that should be created and checked.
-     * It can be set to [loadValues].
+     * Further SLO configurations for the SLOs specified in the Benchmark.
+     */
+    @JsonDeserialize
+    @RegisterForReflection
+    class SloConfiguration : KubernetesResource {
+        lateinit var name: String
+        var properties: MutableMap<String, String>? = null
+    }
+
+    /**
+     * Represents the Loads that should be created and checked if the demand metric is in use or
+     * represents a Load that can be scaled to [loadValues] if the capacity metric is in use.
      */
     @JsonDeserialize
     @RegisterForReflection
@@ -79,7 +86,8 @@ class BenchmarkExecution : KubernetesResource {
     }
 
     /**
-     * Represents a resource that can be scaled to [resourceValues].
+     * Represents a resource that can be scaled to [resourceValues] if the demand metric is in use or
+     * represents the Resources that should be created and checked if the capacity metric is in use.
      */
     @JsonDeserialize
     @RegisterForReflection
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
index 6857b9bf8918593dbe5085f40eb28fd8bd809d85..d40d91961266098702171c7c3d040db87b2c6f9f 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmark.kt
@@ -8,8 +8,10 @@ import io.fabric8.kubernetes.client.NamespacedKubernetesClient
 import io.quarkus.runtime.annotations.RegisterForReflection
 import mu.KotlinLogging
 import theodolite.k8s.K8sManager
+import theodolite.patcher.PatchHandler
 import theodolite.patcher.PatcherFactory
 import theodolite.util.*
+import kotlin.properties.Delegates
 
 
 private val logger = KotlinLogging.logger {}
@@ -21,13 +23,13 @@ private var DEFAULT_THEODOLITE_APP_RESOURCES = "./benchmark-resources"
  * Represents a benchmark in Kubernetes. An example for this is the BenchmarkType.yaml
  * Contains a of:
  * - [name] of the benchmark,
- * - [appResource] list of the resources that have to be deployed for the benchmark,
- * - [loadGenResource] resource that generates the load,
+ * - [infrastructure] resources that have to be deployed for the benchmark infrastructure
+ * - [sut] list of the resources that have to be deployed for the benchmark,
+ * - [loadGenerator] resource that generates the load,
  * - [resourceTypes] types of scaling resources,
  * - [loadTypes] types of loads that can be scaled for the benchmark,
  * - [kafkaConfig] for the [theodolite.k8s.TopicManager],
  * - [namespace] for the client,
- * - [path] under which the resource yamls can be found.
  *
  *  This class is used for the parsing(in the [theodolite.execution.TheodoliteStandalone]) and
  *  for the deserializing in the [theodolite.execution.operator.TheodoliteOperator].
@@ -37,8 +39,10 @@ private var DEFAULT_THEODOLITE_APP_RESOURCES = "./benchmark-resources"
 @RegisterForReflection
 class KubernetesBenchmark : KubernetesResource, Benchmark {
     lateinit var name: String
+    var waitForResourcesEnabled = false
     lateinit var resourceTypes: List<TypeName>
     lateinit var loadTypes: List<TypeName>
+    lateinit var slos: MutableList<Slo>
     var kafkaConfig: KafkaConfig? = null
     lateinit var infrastructure: Resources
     lateinit var sut: Resources
@@ -64,14 +68,13 @@ class KubernetesBenchmark : KubernetesResource, Benchmark {
 
     override fun setupInfrastructure() {
         this.infrastructure.beforeActions.forEach { it.exec(client = client) }
-        val kubernetesManager = K8sManager(this.client)
-        loadResources(this.infrastructure.resources)
-            .map { it.second }
-            .forEach { kubernetesManager.deploy(it) }
+        RolloutManager(waitForResourcesEnabled, this.client)
+            .rollout(loadResources(this.infrastructure.resources).map { it.second })
     }
 
     override fun teardownInfrastructure() {
         val kubernetesManager = K8sManager(this.client)
+
         loadResources(this.infrastructure.resources)
             .map { it.second }
             .forEach { kubernetesManager.remove(it) }
@@ -80,39 +83,48 @@ class KubernetesBenchmark : KubernetesResource, Benchmark {
 
     /**
      * Builds a deployment.
-     * First loads all required resources and then patches them to the concrete load and resources for the experiment.
-     * Afterwards patches additional configurations(cluster depending) into the resources.
-     * @param load concrete load that will be benchmarked in this experiment.
-     * @param res concrete resource that will be scaled for this experiment.
+     * First loads all required resources and then patches them to the concrete load and resources for the experiment for the demand metric
+     * or loads all loads and then patches them to the concrete load and resources for the experiment.
+     * Afterwards patches additional configurations(cluster depending) into the resources (or loads).
+     * @param load concrete load that will be benchmarked in this experiment (demand metric), or scaled (capacity metric).
+     * @param resource concrete resource that will be scaled for this experiment (demand metric), or benchmarked (capacity metric).
      * @param configurationOverrides
      * @return a [BenchmarkDeployment]
      */
     override fun buildDeployment(
-        load: LoadDimension,
-        res: Resource,
+        load: Int,
+        loadPatcherDefinitions: List<PatcherDefinition>,
+        resource: Int,
+        resourcePatcherDefinitions: List<PatcherDefinition>,
         configurationOverrides: List<ConfigurationOverride?>,
         loadGenerationDelay: Long,
         afterTeardownDelay: Long
     ): BenchmarkDeployment {
         logger.info { "Using $namespace as namespace." }
 
-        val appResources = loadResources(this.sut.resources)
-        val loadGenResources = loadResources(this.loadGenerator.resources)
 
-        val patcherFactory = PatcherFactory()
+        val appResources = loadResources(this.sut.resources).toResourceMap()
+        val loadGenResources = loadResources(this.loadGenerator.resources).toResourceMap()
 
         // patch the load dimension the resources
-        load.getType().forEach { patcherDefinition ->
-            patcherFactory.createPatcher(patcherDefinition, loadGenResources).patch(load.get().toString())
+        loadPatcherDefinitions.forEach { patcherDefinition ->
+            loadGenResources[patcherDefinition.resource] =
+                PatchHandler.patchResource(loadGenResources, patcherDefinition, load.toString())
         }
-        res.getType().forEach { patcherDefinition ->
-            patcherFactory.createPatcher(patcherDefinition, appResources).patch(res.get().toString())
+        resourcePatcherDefinitions.forEach { patcherDefinition ->
+            appResources[patcherDefinition.resource] =
+                PatchHandler.patchResource(appResources, patcherDefinition, resource.toString())
         }
 
-        // Patch the given overrides
         configurationOverrides.forEach { override ->
             override?.let {
-                patcherFactory.createPatcher(it.patcher, appResources + loadGenResources).patch(override.value)
+                if (appResources.keys.contains(it.patcher.resource)) {
+                    appResources[it.patcher.resource] =
+                        PatchHandler.patchResource(appResources, override.patcher, override.value)
+                } else {
+                    loadGenResources[it.patcher.resource] =
+                        PatchHandler.patchResource(loadGenResources, override.patcher, override.value)
+                }
             }
         }
 
@@ -123,13 +135,15 @@ class KubernetesBenchmark : KubernetesResource, Benchmark {
             sutAfterActions = sut.afterActions,
             loadGenBeforeActions = loadGenerator.beforeActions,
             loadGenAfterActions = loadGenerator.afterActions,
-            appResources = appResources.map { it.second },
-            loadGenResources = loadGenResources.map { it.second },
+            appResources = appResources.toList().flatMap { it.second },
+            loadGenResources = loadGenResources.toList().flatMap { it.second },
             loadGenerationDelay = loadGenerationDelay,
             afterTeardownDelay = afterTeardownDelay,
             kafkaConfig = if (kafkaConfig != null) mapOf("bootstrap.servers" to kafkaConfig.bootstrapServer) else mapOf(),
             topics = kafkaConfig?.topics ?: listOf(),
-            client = this.client
+            client = this.client,
+            rolloutMode = waitForResourcesEnabled
+
         )
     }
 
@@ -142,3 +156,11 @@ class KubernetesBenchmark : KubernetesResource, Benchmark {
         this.client = client
     }
 }
+
+private fun Collection<Pair<String, HasMetadata>>.toResourceMap(): MutableMap<String, List<HasMetadata>> {
+    return this.toMap()
+        .toMutableMap()
+        .map { Pair(it.key, listOf(it.value)) }
+        .toMap()
+        .toMutableMap()
+}
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
index b30032c524b1e421301e0e9d1ffe83772b43d900..1d7b22233c084625cf16ca7194c76c14601bbaad 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/KubernetesBenchmarkDeployment.kt
@@ -28,6 +28,7 @@ class KubernetesBenchmarkDeployment(
     private val sutAfterActions: List<Action>,
     private val loadGenBeforeActions: List<Action>,
     private val loadGenAfterActions: List<Action>,
+    private val rolloutMode: Boolean,
     val appResources: List<HasMetadata>,
     val loadGenResources: List<HasMetadata>,
     private val loadGenerationDelay: Long,
@@ -47,19 +48,20 @@ class KubernetesBenchmarkDeployment(
      *  - Deploy the needed resources.
      */
     override fun setup() {
+        val rolloutManager = RolloutManager(rolloutMode, client)
         if (this.topics.isNotEmpty()) {
             val kafkaTopics = this.topics
                 .filter { !it.removeOnly }
                 .map { NewTopic(it.name, it.numPartitions, it.replicationFactor) }
             kafkaController.createTopics(kafkaTopics)
         }
+
         sutBeforeActions.forEach { it.exec(client = client) }
-        appResources.forEach { kubernetesManager.deploy(it) }
+        rolloutManager.rollout(appResources)
         logger.info { "Wait ${this.loadGenerationDelay} seconds before starting the load generator." }
         Thread.sleep(Duration.ofSeconds(this.loadGenerationDelay).toMillis())
         loadGenBeforeActions.forEach { it.exec(client = client) }
-        loadGenResources.forEach { kubernetesManager.deploy(it) }
-
+        rolloutManager.rollout(loadGenResources)
     }
 
     /**
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt b/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt
index 0626a6e24369348d50b60fbb555665c58dd17281..2ee8d8cf5c0e8590728bc253fd452fe8aa1d9d96 100644
--- a/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/ResourceSets.kt
@@ -11,7 +11,7 @@ import theodolite.util.DeploymentFailedException
 
 @JsonDeserialize
 @RegisterForReflection
-class ResourceSets: KubernetesResource {
+class ResourceSets : KubernetesResource {
     @JsonProperty("configMap")
     @JsonInclude(JsonInclude.Include.NON_NULL)
     var configMap: ConfigMapResourceSet? = null
@@ -21,13 +21,13 @@ class ResourceSets: KubernetesResource {
     var fileSystem: FileSystemResourceSet? = null
 
     fun loadResourceSet(client: NamespacedKubernetesClient): Collection<Pair<String, HasMetadata>> {
-        // TODO Find out whether field access (::configMap) is really what we want to do here (see #362)
-        return if (::configMap != null) {
-                configMap?.getResourceSet(client= client) !!
-            } else if (::fileSystem != null) {
-                fileSystem?.getResourceSet(client= client ) !!
-            } else {
-                throw DeploymentFailedException("Could not load resourceSet.")
-            }
+
+        return if (this.configMap != null) {
+            configMap?.getResourceSet(client = client)!!
+        } else if (this.fileSystem != null) {
+            fileSystem?.getResourceSet(client = client)!!
+        } else {
+            throw DeploymentFailedException("Could not load resourceSet.")
+        }
     }
 }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/RolloutManager.kt b/theodolite/src/main/kotlin/theodolite/benchmark/RolloutManager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f282fb27971218754a0e35801342efc83837b64b
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/RolloutManager.kt
@@ -0,0 +1,42 @@
+package theodolite.benchmark
+
+import io.fabric8.kubernetes.api.model.HasMetadata
+import io.fabric8.kubernetes.api.model.Pod
+import io.fabric8.kubernetes.api.model.apps.DaemonSet
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.ReplicaSet
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+import io.fabric8.kubernetes.api.model.batch.v1.Job
+import io.fabric8.kubernetes.client.NamespacedKubernetesClient
+import theodolite.k8s.K8sManager
+
+private var SLEEP_TIME_MS = 500L
+
+
+class RolloutManager(private val blockUntilResourcesReady: Boolean, private val client: NamespacedKubernetesClient) {
+
+    fun rollout(resources: List<HasMetadata>) {
+        resources
+            .forEach { K8sManager(client).deploy(it) }
+
+        if (blockUntilResourcesReady) {
+            resources
+                .forEach {
+                    when (it) {
+                        is Deployment -> waitFor { client.apps().deployments().withName(it.metadata.name).isReady }
+                        is StatefulSet -> waitFor { client.apps().statefulSets().withName(it.metadata.name).isReady }
+                        is DaemonSet -> waitFor { client.apps().daemonSets().withName(it.metadata.name).isReady }
+                        is ReplicaSet -> waitFor { client.apps().replicaSets().withName(it.metadata.name).isReady }
+                        is Job -> waitFor { client.batch().v1().cronjobs().withName(it.metadata.name).isReady }
+                    }
+                }
+        }
+    }
+
+    private fun waitFor(isResourceReady: () -> Boolean) {
+        while (!isResourceReady()) {
+            Thread.sleep(SLEEP_TIME_MS)
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/benchmark/Slo.kt b/theodolite/src/main/kotlin/theodolite/benchmark/Slo.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c9aac4a1b68692669f0db577003856b964ade4ec
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/benchmark/Slo.kt
@@ -0,0 +1,25 @@
+package theodolite.benchmark
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.quarkus.runtime.annotations.RegisterForReflection
+import kotlin.properties.Delegates
+
+/**
+ * Measurable metric.
+ * [sloType] determines the type of the metric.
+ * It is evaluated using the [theodolite.evaluation.ExternalSloChecker] by data measured by Prometheus.
+ * The evaluation checks if a [threshold] is reached or not.
+ * [offset] determines the shift in hours by which the start and end timestamps should be shifted.
+ * The [warmup] determines after which time the metric should be evaluated to avoid starting interferences.
+ * The [warmup] time unit depends on the Slo: for the lag trend it is in seconds.
+ */
+@JsonDeserialize
+@RegisterForReflection
+class Slo : KubernetesResource {
+    lateinit var name: String
+    lateinit var sloType: String
+    lateinit var prometheusUrl: String
+    var offset by Delegates.notNull<Int>()
+    lateinit var properties: MutableMap<String, String>
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
index b3cc174d2945bf13bc1cc29d4e60d8c9bfbaf7eb..7948058f0716a29712c360b5f90362dcedce2d7f 100644
--- a/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
+++ b/theodolite/src/main/kotlin/theodolite/evaluation/AnalysisExecutor.kt
@@ -1,10 +1,9 @@
 package theodolite.evaluation
 
-import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.Slo
+import theodolite.strategies.Metric
 import theodolite.util.EvaluationFailedException
 import theodolite.util.IOHandler
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 import java.text.Normalizer
 import java.time.Duration
 import java.time.Instant
@@ -16,8 +15,8 @@ import java.util.regex.Pattern
  * @param slo Slo that is used for the analysis.
  */
 class AnalysisExecutor(
-    private val slo: BenchmarkExecution.Slo,
-    private val executionId: Int
+        private val slo: Slo,
+        private val executionId: Int
 ) {
 
     private val fetcher = MetricFetcher(
@@ -29,17 +28,17 @@ class AnalysisExecutor(
      *  Analyses an experiment via prometheus data.
      *  First fetches data from prometheus, then documents them and afterwards evaluate it via a [slo].
      *  @param load of the experiment.
-     *  @param res of the experiment.
+     *  @param resource of the experiment.
      *  @param executionIntervals list of start and end points of experiments
      *  @return true if the experiment succeeded.
      */
-    fun analyze(load: LoadDimension, res: Resource, executionIntervals: List<Pair<Instant, Instant>>): Boolean {
+    fun analyze(load: Int, resource: Int, executionIntervals: List<Pair<Instant, Instant>>, metric: Metric): Boolean {
         var repetitionCounter = 1
 
         try {
             val ioHandler = IOHandler()
             val resultsFolder = ioHandler.getResultFolderURL()
-            val fileURL = "${resultsFolder}exp${executionId}_${load.get()}_${res.get()}_${slo.sloType.toSlug()}"
+            val fileURL = "${resultsFolder}exp${executionId}_${load}_${resource}_${slo.sloType.toSlug()}"
 
             val prometheusData = executionIntervals
                 .map { interval ->
@@ -61,13 +60,15 @@ class AnalysisExecutor(
             val sloChecker = SloCheckerFactory().create(
                 sloType = slo.sloType,
                 properties = slo.properties,
-                load = load
+                load = load,
+                resource = resource,
+                metric = metric
             )
 
             return sloChecker.evaluate(prometheusData)
 
         } catch (e: Exception) {
-            throw EvaluationFailedException("Evaluation failed for resource '${res.get()}' and load '${load.get()}", e)
+            throw EvaluationFailedException("Evaluation failed for resource '$resource' and load '$load ", e)
         }
     }
 
diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt
index f57cebfcb13d0e86919ec15a0a479d1258e318a6..7ab6a0255f6c078f0f365289baa1eb0300a3244a 100644
--- a/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt
+++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloCheckerFactory.kt
@@ -1,6 +1,7 @@
 package theodolite.evaluation
 
-import theodolite.util.LoadDimension
+import theodolite.strategies.Metric
+
 
 /**
  * Factory used to potentially create different [SloChecker]s.
@@ -41,7 +42,9 @@ class SloCheckerFactory {
     fun create(
         sloType: String,
         properties: MutableMap<String, String>,
-        load: LoadDimension
+        load: Int,
+        resource: Int,
+        metric: Metric
     ): SloChecker {
         return when (SloTypes.from(sloType)) {
             SloTypes.GENERIC -> ExternalSloChecker(
@@ -76,7 +79,7 @@ class SloCheckerFactory {
                     throw IllegalArgumentException("Threshold ratio needs to be an Double greater or equal 0.0")
                 }
                 // cast to int, as rounding is not really necessary
-                val threshold = (load.get() * thresholdRatio).toInt()
+                val threshold = (load * thresholdRatio).toInt()
 
                 ExternalSloChecker(
                     externalSlopeURL = properties["externalSloUrl"]
diff --git a/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt b/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt
index 089f40dc6b5ef7d8ac4b063cae68e5e9621d1f50..ee892109dc1fc03a9c270151944c6d90fbacf45e 100644
--- a/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt
+++ b/theodolite/src/main/kotlin/theodolite/evaluation/SloConfigHandler.kt
@@ -1,6 +1,6 @@
 package theodolite.evaluation
 
-import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.Slo
 import theodolite.util.InvalidPatcherConfigurationException
 import javax.enterprise.context.ApplicationScoped
 
@@ -11,7 +11,7 @@ private const val DEFAULT_DROPPED_RECORDS_QUERY = "sum by(job) (kafka_streams_st
 @ApplicationScoped
 class SloConfigHandler {
     companion object {
-        fun getQueryString(slo: BenchmarkExecution.Slo): String {
+        fun getQueryString(slo: Slo): String {
             return when (slo.sloType.lowercase()) {
                 SloTypes.GENERIC.value -> slo.properties["promQLQuery"] ?: throw IllegalArgumentException("promQLQuery expected")
                 SloTypes.LAG_TREND.value, SloTypes.LAG_TREND_RATIO.value -> slo.properties["promQLQuery"] ?:
diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt
index 3238f447be06ce6486bb7f6ca1758700f36ba558..9ae267f42ca3f8420dbd507b0b92e92bf49a31f5 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutor.kt
@@ -2,10 +2,9 @@ package theodolite.execution
 
 import mu.KotlinLogging
 import theodolite.benchmark.Benchmark
-import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.Slo
 import theodolite.util.ConfigurationOverride
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
+import theodolite.util.PatcherDefinition
 import theodolite.util.Results
 import java.time.Duration
 import java.util.concurrent.atomic.AtomicBoolean
@@ -25,12 +24,14 @@ abstract class BenchmarkExecutor(
     val results: Results,
     val executionDuration: Duration,
     val configurationOverrides: List<ConfigurationOverride?>,
-    val slos: List<BenchmarkExecution.Slo>,
+    val slos: List<Slo>,
     val repetitions: Int,
     val executionId: Int,
     val loadGenerationDelay: Long,
     val afterTeardownDelay: Long,
-    val executionName: String
+    val executionName: String,
+    val loadPatcherDefinitions: List<PatcherDefinition>,
+    val resourcePatcherDefinitions: List<PatcherDefinition>
 ) {
 
     var run: AtomicBoolean = AtomicBoolean(true)
@@ -39,12 +40,14 @@ abstract class BenchmarkExecutor(
      * Run a experiment for the given parametrization, evaluate the
      * experiment and save the result.
      *
-     * @param load load to be tested.
-     * @param res resources to be tested.
+     * @param load to be tested.
+     * @param resource to be tested.
      * @return True, if the number of resources are suitable for the
-     *     given load, false otherwise.
+     *     given load, false otherwise (demand metric), or
+     *     True, if there is a load suitable for the
+     *     given resource, false otherwise.
      */
-    abstract fun runExperiment(load: LoadDimension, res: Resource): Boolean
+    abstract fun runExperiment(load: Int, resource: Int): Boolean
 
     /**
      * Wait while the benchmark is running and log the number of minutes executed every 1 minute.
diff --git a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
index 2e938be3a6e503a5e7e3f94c18a9454e173db5b0..790e796e0792acb2542a69db7c1f626aa7c0ee67 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/BenchmarkExecutorImpl.kt
@@ -3,7 +3,7 @@ package theodolite.execution
 import io.quarkus.runtime.annotations.RegisterForReflection
 import mu.KotlinLogging
 import theodolite.benchmark.Benchmark
-import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.Slo
 import theodolite.evaluation.AnalysisExecutor
 import theodolite.execution.operator.EventCreator
 import theodolite.util.*
@@ -18,12 +18,14 @@ class BenchmarkExecutorImpl(
     results: Results,
     executionDuration: Duration,
     configurationOverrides: List<ConfigurationOverride?>,
-    slos: List<BenchmarkExecution.Slo>,
+    slos: List<Slo>,
     repetitions: Int,
     executionId: Int,
     loadGenerationDelay: Long,
     afterTeardownDelay: Long,
-    executionName: String
+    executionName: String,
+    loadPatcherDefinitions: List<PatcherDefinition>,
+    resourcePatcherDefinitions: List<PatcherDefinition>
 ) : BenchmarkExecutor(
     benchmark,
     results,
@@ -34,24 +36,26 @@ class BenchmarkExecutorImpl(
     executionId,
     loadGenerationDelay,
     afterTeardownDelay,
-    executionName
+    executionName,
+    loadPatcherDefinitions,
+    resourcePatcherDefinitions
 ) {
     private val eventCreator = EventCreator()
     private val mode = Configuration.EXECUTION_MODE
 
-    override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
+    override fun runExperiment(load: Int, resource: Int): Boolean {
         var result = false
         val executionIntervals: MutableList<Pair<Instant, Instant>> = ArrayList()
 
         for (i in 1.rangeTo(repetitions)) {
             if (this.run.get()) {
                 logger.info { "Run repetition $i/$repetitions" }
-                executionIntervals.add(runSingleExperiment(load, res))
+                executionIntervals.add(runSingleExperiment(
+                        load, resource))
             } else {
                 break
             }
         }
-
         /**
          * Analyse the experiment, if [run] is true, otherwise the experiment was canceled by the user.
          */
@@ -60,41 +64,43 @@ class BenchmarkExecutorImpl(
                 AnalysisExecutor(slo = it, executionId = executionId)
                     .analyze(
                         load = load,
-                        res = res,
-                        executionIntervals = executionIntervals
+                        resource = resource,
+                        executionIntervals = executionIntervals,
+                        metric = this.results.metric
                     )
             }
 
             result = (false !in experimentResults)
-            this.results.setResult(Pair(load, res), result)
-        }
-
-        if(!this.run.get()) {
+            this.results.setResult(Pair(load, resource), result)
+        } else {
             throw ExecutionFailedException("The execution was interrupted")
         }
-
         return result
     }
 
-    private fun runSingleExperiment(load: LoadDimension, res: Resource): Pair<Instant, Instant> {
+    private fun runSingleExperiment(load: Int, resource: Int): Pair<Instant, Instant> {
         val benchmarkDeployment = benchmark.buildDeployment(
             load,
-            res,
+            this.loadPatcherDefinitions,
+            resource,
+            this.resourcePatcherDefinitions,
             this.configurationOverrides,
             this.loadGenerationDelay,
             this.afterTeardownDelay
         )
-        val from = Instant.now()
+        val from: Instant
 
         try {
             benchmarkDeployment.setup()
+            from = Instant.now()
+
             this.waitAndLog()
             if (mode == ExecutionModes.OPERATOR.value) {
                 eventCreator.createEvent(
                     executionName = executionName,
                     type = "NORMAL",
                     reason = "Start experiment",
-                    message = "load: ${load.get()}, resources: ${res.get()}")
+                    message = "load: $load, resources: $resource")
             }
         } catch (e: Exception) {
             this.run.set(false)
@@ -104,7 +110,7 @@ class BenchmarkExecutorImpl(
                     executionName = executionName,
                     type = "WARNING",
                     reason = "Start experiment failed",
-                    message = "load: ${load.get()}, resources: ${res.get()}")
+                    message = "load: $load, resources: $resource")
             }
             throw ExecutionFailedException("Error during setup the experiment", e)
         }
diff --git a/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt b/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt
index 29ac39c122f68636e08c6c5ecd5a6c01751edafb..cdfe68e7a93d64f2385bded31f94f77ab7b3be0e 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/Shutdown.kt
@@ -3,8 +3,6 @@ package theodolite.execution
 import mu.KotlinLogging
 import theodolite.benchmark.BenchmarkExecution
 import theodolite.benchmark.KubernetesBenchmark
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 
 private val logger = KotlinLogging.logger {}
 
@@ -26,8 +24,10 @@ class Shutdown(private val benchmarkExecution: BenchmarkExecution, private val b
             logger.info { "Received shutdown signal -> Shutting down" }
             val deployment =
                 benchmark.buildDeployment(
-                    load = LoadDimension(0, emptyList()),
-                    res = Resource(0, emptyList()),
+                    load = 0,
+                    loadPatcherDefinitions = emptyList(),
+                    resource = 0,
+                    resourcePatcherDefinitions = emptyList(),
                     configurationOverrides = benchmarkExecution.configOverrides,
                     loadGenerationDelay = 0L,
                     afterTeardownDelay = 5L
diff --git a/theodolite/src/main/kotlin/theodolite/execution/SloFactory.kt b/theodolite/src/main/kotlin/theodolite/execution/SloFactory.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b990828fa1db09532767b9f9255aa53e9c9e894a
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/execution/SloFactory.kt
@@ -0,0 +1,24 @@
+package theodolite.execution
+
+import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.KubernetesBenchmark
+import theodolite.benchmark.Slo
+
+class SloFactory {
+
+    fun createSlos(execution: BenchmarkExecution, benchmark: KubernetesBenchmark): List<Slo> {
+        var benchmarkSlos = benchmark.slos
+        var executionSlos = execution.slos
+
+        for(executionSlo in executionSlos) {
+            for(i in 0 until benchmarkSlos.size) {
+                if(executionSlo.name == benchmarkSlos[i].name && executionSlo.properties != null) {
+                    for (executionProperty in executionSlo.properties!!) {
+                        benchmarkSlos[i].properties[executionProperty.key] = executionProperty.value
+                    }
+                }
+            }
+        }
+        return benchmarkSlos
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
index 8596576e0a7984c32b6dabf90c6bbf06961d2bb1..82b406264fe7a07da1759936f4f2667150a7dee1 100644
--- a/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
+++ b/theodolite/src/main/kotlin/theodolite/execution/TheodoliteExecutor.kt
@@ -4,8 +4,8 @@ import mu.KotlinLogging
 import theodolite.benchmark.BenchmarkExecution
 import theodolite.benchmark.KubernetesBenchmark
 import theodolite.patcher.PatcherDefinitionFactory
+import theodolite.strategies.Metric
 import theodolite.strategies.StrategyFactory
-import theodolite.strategies.searchstrategy.CompositeStrategy
 import theodolite.util.*
 import java.io.File
 import java.time.Duration
@@ -16,12 +16,12 @@ private val logger = KotlinLogging.logger {}
 /**
  * The Theodolite executor runs all the experiments defined with the given execution and benchmark configuration.
  *
- * @property config Configuration of a execution
+ * @property benchmarkExecution Configuration of a execution
  * @property kubernetesBenchmark Configuration of a benchmark
  * @constructor Create empty Theodolite executor
  */
 class TheodoliteExecutor(
-    private val config: BenchmarkExecution,
+    private val benchmarkExecution: BenchmarkExecution,
     private val kubernetesBenchmark: KubernetesBenchmark
 ) {
     /**
@@ -33,79 +33,74 @@ class TheodoliteExecutor(
     /**
      * Creates all required components to start Theodolite.
      *
-     * @return a [Config], that contains a list of [LoadDimension]s,
-     *          a list of [Resource]s , and the [CompositeStrategy].
-     * The [CompositeStrategy] is configured and able to find the minimum required resource for the given load.
+     * @return a [Config], that contains a list of LoadDimension s,
+     *          a list of Resource s , and the [restrictionSearch].
+     * The [searchStrategy] is configured and able to find the minimum required resource for the given load.
      */
     private fun buildConfig(): Config {
-        val results = Results()
+        val results = Results(Metric.from(benchmarkExecution.execution.metric))
         val strategyFactory = StrategyFactory()
 
-        val executionDuration = Duration.ofSeconds(config.execution.duration)
+        val executionDuration = Duration.ofSeconds(benchmarkExecution.execution.duration)
 
         val resourcePatcherDefinition =
             PatcherDefinitionFactory().createPatcherDefinition(
-                config.resources.resourceType,
+                benchmarkExecution.resources.resourceType,
                 this.kubernetesBenchmark.resourceTypes
             )
 
         val loadDimensionPatcherDefinition =
             PatcherDefinitionFactory().createPatcherDefinition(
-                config.load.loadType,
+                benchmarkExecution.loads.loadType,
                 this.kubernetesBenchmark.loadTypes
             )
 
+        val slos = SloFactory().createSlos(this.benchmarkExecution, this.kubernetesBenchmark)
+
         executor =
             BenchmarkExecutorImpl(
                 benchmark = kubernetesBenchmark,
                 results = results,
                 executionDuration = executionDuration,
-                configurationOverrides = config.configOverrides,
-                slos = config.slos,
-                repetitions = config.execution.repetitions,
-                executionId = config.executionId,
-                loadGenerationDelay = config.execution.loadGenerationDelay,
-                afterTeardownDelay = config.execution.afterTeardownDelay,
-                executionName = config.name
+                configurationOverrides = benchmarkExecution.configOverrides,
+                slos = slos,
+                repetitions = benchmarkExecution.execution.repetitions,
+                executionId = benchmarkExecution.executionId,
+                loadGenerationDelay = benchmarkExecution.execution.loadGenerationDelay,
+                afterTeardownDelay = benchmarkExecution.execution.afterTeardownDelay,
+                executionName = benchmarkExecution.name,
+                loadPatcherDefinitions = loadDimensionPatcherDefinition,
+                resourcePatcherDefinitions = resourcePatcherDefinition
             )
 
-        if (config.load.loadValues != config.load.loadValues.sorted()) {
-            config.load.loadValues = config.load.loadValues.sorted()
+        if (benchmarkExecution.loads.loadValues != benchmarkExecution.loads.loadValues.sorted()) {
+            benchmarkExecution.loads.loadValues = benchmarkExecution.loads.loadValues.sorted()
             logger.info {
-                "Load values are not sorted correctly, Theodolite sorts them in ascending order." +
-                        "New order is: ${config.load.loadValues}"
+                "Load values are not sorted correctly. Theodolite sorts them in ascending order." +
+                        "New order is: ${benchmarkExecution.loads.loadValues}."
             }
         }
 
-        if (config.resources.resourceValues != config.resources.resourceValues.sorted()) {
-            config.resources.resourceValues = config.resources.resourceValues.sorted()
+        if (benchmarkExecution.resources.resourceValues != benchmarkExecution.resources.resourceValues.sorted()) {
+            benchmarkExecution.resources.resourceValues = benchmarkExecution.resources.resourceValues.sorted()
             logger.info {
-                "Load values are not sorted correctly, Theodolite sorts them in ascending order." +
-                        "New order is: ${config.resources.resourceValues}"
+                "Load values are not sorted correctly. Theodolite sorts them in ascending order." +
+                        "New order is: ${benchmarkExecution.resources.resourceValues}."
             }
         }
 
         return Config(
-            loads = config.load.loadValues.map { load -> LoadDimension(load, loadDimensionPatcherDefinition) },
-            resources = config.resources.resourceValues.map { resource ->
-                Resource(
-                    resource,
-                    resourcePatcherDefinition
-                )
-            },
-            compositeStrategy = CompositeStrategy(
-                benchmarkExecutor = executor,
-                searchStrategy = strategyFactory.createSearchStrategy(executor, config.execution.strategy),
-                restrictionStrategies = strategyFactory.createRestrictionStrategy(
-                    results,
-                    config.execution.restrictions
-                )
-            )
+            loads = benchmarkExecution.loads.loadValues,
+            loadPatcherDefinitions = loadDimensionPatcherDefinition,
+            resources = benchmarkExecution.resources.resourceValues,
+            resourcePatcherDefinitions = resourcePatcherDefinition,
+            searchStrategy = strategyFactory.createSearchStrategy(executor, benchmarkExecution.execution.strategy, results),
+            metric = Metric.from(benchmarkExecution.execution.metric)
         )
     }
 
     fun getExecution(): BenchmarkExecution {
-        return this.config
+        return this.benchmarkExecution
     }
 
     /**
@@ -117,32 +112,39 @@ class TheodoliteExecutor(
 
         val ioHandler = IOHandler()
         val resultsFolder = ioHandler.getResultFolderURL()
-        this.config.executionId = getAndIncrementExecutionID(resultsFolder + "expID.txt")
-        ioHandler.writeToJSONFile(this.config, "${resultsFolder}exp${this.config.executionId}-execution-configuration")
+        this.benchmarkExecution.executionId = getAndIncrementExecutionID(resultsFolder + "expID.txt")
+        ioHandler.writeToJSONFile(this.benchmarkExecution, "${resultsFolder}exp${this.benchmarkExecution.executionId}-execution-configuration")
         ioHandler.writeToJSONFile(
             kubernetesBenchmark,
-            "${resultsFolder}exp${this.config.executionId}-benchmark-configuration"
+            "${resultsFolder}exp${this.benchmarkExecution.executionId}-benchmark-configuration"
         )
 
         val config = buildConfig()
-        // execute benchmarks for each load
+
+        //execute benchmarks for each load for the demand metric, or for each resource amount for capacity metric
         try {
-            for (load in config.loads) {
-                if (executor.run.get()) {
-                    config.compositeStrategy.findSuitableResource(load, config.resources)
-                }
-            }
+            config.searchStrategy.applySearchStrategyByMetric(config.loads, config.resources, config.metric)
+
         } finally {
             ioHandler.writeToJSONFile(
-                config.compositeStrategy.benchmarkExecutor.results,
-                "${resultsFolder}exp${this.config.executionId}-result"
-            )
-            // Create expXYZ_demand.csv file
-            ioHandler.writeToCSVFile(
-                "${resultsFolder}exp${this.config.executionId}_demand",
-                calculateDemandMetric(config.loads, config.compositeStrategy.benchmarkExecutor.results),
-                listOf("load","resources")
+                config.searchStrategy.benchmarkExecutor.results,
+                "${resultsFolder}exp${this.benchmarkExecution.executionId}-result"
             )
+            // Create expXYZ_demand.csv file or expXYZ_capacity.csv depending on metric
+            when(config.metric) {
+                Metric.DEMAND ->
+                    ioHandler.writeToCSVFile(
+                        "${resultsFolder}exp${this.benchmarkExecution.executionId}_demand",
+                        calculateMetric(config.loads, config.searchStrategy.benchmarkExecutor.results),
+                        listOf("load","resources")
+                    )
+                Metric.CAPACITY ->
+                    ioHandler.writeToCSVFile(
+                        "${resultsFolder}exp${this.benchmarkExecution.executionId}_capacity",
+                        calculateMetric(config.resources, config.searchStrategy.benchmarkExecutor.results),
+                        listOf("resource", "loads")
+                    )
+            }
         }
         kubernetesBenchmark.teardownInfrastructure()
     }
@@ -157,8 +159,8 @@ class TheodoliteExecutor(
         return executionID
     }
 
-    private fun calculateDemandMetric(loadDimensions: List<LoadDimension>, results: Results): List<List<String>> {
-        return loadDimensions.map { listOf(it.get().toString(), results.getMinRequiredInstances(it).get().toString()) }
+    private fun calculateMetric(xValues: List<Int>, results: Results): List<List<String>> {
+        return xValues.map { listOf(it.toString(), results.getOptYDimensionValue(it).toString()) }
     }
 
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
index df80e9cbd2503685a7dbed35db5319920dfc42cb..fbbb7fa1d2ea9fd67732ea5b84f29012c5708136 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/AbstractPatcher.kt
@@ -1,15 +1,13 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
+import io.fabric8.kubernetes.client.utils.Serialization
 
 /**
  * A Patcher is able to modify values of a Kubernetes resource, see [Patcher].
  *
  * An AbstractPatcher is created with up to three parameters.
  *
- * @param k8sResource The Kubernetes resource to be patched.
- * @param container *(optional)* The name of the container to be patched
- * @param variableName *(optional)* The variable name to be patched
  *
  *
  * **For example** to patch the load dimension of a load generator, the patcher should be created as follow:
@@ -19,6 +17,14 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
  * variableName: `NUM_SENSORS`
  *
  */
-abstract class AbstractPatcher(
-    k8sResource: KubernetesResource
-) : Patcher
+abstract class AbstractPatcher : Patcher {
+
+    override fun patch(resources: List<HasMetadata>, value: String) : List<HasMetadata> {
+        return resources
+            .map { Serialization.clone(it)}
+            .map { patchSingleResource(it, value) }
+    }
+
+    abstract fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata
+
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcher.kt
index bdc107910edc8ddfb41e7757c775977086a25a26..db019282fd14c8a7aaa6eba7cd3969ba42da8023 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcher.kt
@@ -1,6 +1,6 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 
 /**
  * The DataVolumeLoadGeneratorReplicaPatcher takes the total load that should be generated
@@ -10,29 +10,29 @@ import io.fabric8.kubernetes.api.model.KubernetesResource
  * The number of instances are set for the load generator and the given variable is set to the
  * load per instance.
  *
- * @property k8sResource Kubernetes resource to be patched.
  * @property maxVolume per load generator instance
  * @property container Container to be patched.
  * @property variableName Name of the environment variable to be patched.
  */
 class DataVolumeLoadGeneratorReplicaPatcher(
-    k8sResource: KubernetesResource,
     private val maxVolume: Int,
-    container: String,
-    variableName: String
-) : AbstractPatcher(k8sResource) {
+    private val container: String,
+    private val variableName: String
+) : Patcher {
 
-    private val replicaPatcher = ReplicaPatcher(k8sResource)
-    private val envVarPatcher = EnvVarPatcher(k8sResource, container, variableName)
+    override fun patch(resources: List<HasMetadata>, value: String) : List<HasMetadata> {
+        return resources.flatMap { patchSingeResource(it, value)}
+    }
 
-    override fun <T> patch(value: T) {
+    fun patchSingeResource(k8sResource: HasMetadata, value: String): List<HasMetadata> {
+        var resource = k8sResource
         // calculate number of load generator instances and load per instance
-        val load = Integer.parseInt(value.toString())
+        val load = Integer.parseInt(value)
         val loadGenInstances = (load + maxVolume - 1) / maxVolume
         val loadPerInstance = load / loadGenInstances
 
         // Patch instance values and load value of generators
-        replicaPatcher.patch(loadGenInstances.toString())
-        envVarPatcher.patch(loadPerInstance.toString())
+        val resourceList = ReplicaPatcher().patch(listOf(resource), loadGenInstances.toString())
+        return EnvVarPatcher(this.container, this.variableName).patch(resourceList, loadPerInstance.toString())
     }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
index 416aec74a3af9b74594f5e6cd018682bf91cbf63..ee95871211145e740a64e711996b85af98ee2151 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/EnvVarPatcher.kt
@@ -2,29 +2,30 @@ package theodolite.patcher
 
 import io.fabric8.kubernetes.api.model.Container
 import io.fabric8.kubernetes.api.model.EnvVar
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
 /**
  * The EnvVarPatcher allows to modify the value of an environment variable
  *
- * @property k8sResource Kubernetes resource to be patched.
  * @property container Container to be patched.
  * @property variableName Name of the environment variable to be patched.
  */
 class EnvVarPatcher(
-    private val k8sResource: KubernetesResource,
     private val container: String,
     private val variableName: String
-) : AbstractPatcher(k8sResource) {
+) : AbstractPatcher() {
 
-    override fun <String> patch(value: String) {
-        if (k8sResource is Deployment) {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
             this.setEnv(
-                k8sResource, this.container,
-                mapOf(this.variableName to value) as Map<kotlin.String, kotlin.String>
+                resource, this.container,
+                mapOf(this.variableName to value)
             )
+            return resource
         }
+        return resource
     }
 
     /**
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ImagePatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
index 8f6753372076c119324dc962112928253633b6b0..2918c825931eb0bb4ca8ad176224e79815272b67 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ImagePatcher.kt
@@ -1,27 +1,37 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
+import io.fabric8.kubernetes.client.utils.Serialization
 
 /**
  * The Image patcher allows to change the image of a container.
  *
- * @param k8sResource Kubernetes resource to be patched.
  * @param container Container to be patched.
  */
-class ImagePatcher(private val k8sResource: KubernetesResource, private val container: String) :
-    AbstractPatcher(k8sResource) {
+class ImagePatcher(
+    private val container: String) :
+    AbstractPatcher() {
 
-    override fun <String> patch(imagePath: String) {
-        if (k8sResource is Deployment) {
-            k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
-                it.image = imagePath as kotlin.String
+    override fun patch(resources: List<HasMetadata>, value: String) : List<HasMetadata> {
+        return resources
+            .map { Serialization.clone(it) }
+            .map { patchSingleResource(it, value as kotlin.String) }
+    }
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            (resource).spec.template.spec.containers.filter { it.name == container }.forEach {
+                it.image = value
             }
-        } else if (k8sResource is StatefulSet) {
-            k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
-                it.image = imagePath as kotlin.String
+            return resource
+        } else if (resource is StatefulSet) {
+            (resource).spec.template.spec.containers.filter { it.name == container }.forEach {
+                it.image = value
             }
+            return resource
         }
+        return resource
     }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
index 2f8c703afa9e826a79f0785abef493d2d448ac74..9a98f9689e28d77d3e7eea5974eff29ab4bbe0f8 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/LabelPatcher.kt
@@ -1,49 +1,50 @@
 package theodolite.patcher
 
 import io.fabric8.kubernetes.api.model.ConfigMap
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.GenericKubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.Service
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
-import io.fabric8.kubernetes.client.CustomResource
 
-class LabelPatcher(private val k8sResource: KubernetesResource, val variableName: String) :
-    AbstractPatcher(k8sResource) {
+class LabelPatcher(
+    val variableName: String) :
+    AbstractPatcher() {
 
-    override fun <String> patch(labelValue: String) {
-        if (labelValue is kotlin.String) {
-            when (k8sResource) {
-                is Deployment -> {
-                    if (k8sResource.metadata.labels == null) {
-                        k8sResource.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.metadata.labels[this.variableName] = labelValue
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        when (resource) {
+            is Deployment -> {
+                if (resource.metadata.labels == null) {
+                    resource.metadata.labels = mutableMapOf()
                 }
-                is StatefulSet -> {
-                    if (k8sResource.metadata.labels == null) {
-                        k8sResource.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.metadata.labels[this.variableName] = labelValue
+                resource.metadata.labels[this.variableName] = value
+            }
+            is StatefulSet -> {
+                if (resource.metadata.labels == null) {
+                    resource.metadata.labels = mutableMapOf()
                 }
-                is Service -> {
-                    if (k8sResource.metadata.labels == null) {
-                        k8sResource.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.metadata.labels[this.variableName] = labelValue
+                resource.metadata.labels[this.variableName] = value
+            }
+            is Service -> {
+                if (resource.metadata.labels == null) {
+                    resource.metadata.labels = mutableMapOf()
                 }
-                is ConfigMap -> {
-                    if (k8sResource.metadata.labels == null) {
-                        k8sResource.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.metadata.labels[this.variableName] = labelValue
+                resource.metadata.labels[this.variableName] = value
+
+            }
+            is ConfigMap -> {
+                if (resource.metadata.labels == null) {
+                    resource.metadata.labels = mutableMapOf()
                 }
-                is CustomResource<*, *> -> {
-                    if (k8sResource.metadata.labels == null) {
-                        k8sResource.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.metadata.labels[this.variableName] = labelValue
+                resource.metadata.labels[this.variableName] = value
+            }
+            is GenericKubernetesResource -> {
+                if (resource.metadata.labels == null) {
+                    resource.metadata.labels = mutableMapOf()
                 }
+                resource.metadata.labels[this.variableName] = value
             }
         }
+        return resource
     }
 }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/MatchLabelPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/MatchLabelPatcher.kt
index 30ff73b5da3b551119ad085adbc982180e4fc066..693d751f275d3666b5e360766eb449b8f6b639c3 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/MatchLabelPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/MatchLabelPatcher.kt
@@ -1,34 +1,33 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
 
 /**
  * This patcher is able to set the `spec.selector.matchLabels` for a `Deployment` or `StatefulSet` Kubernetes resource.
  *
- * @property k8sResource The Kubernetes manifests to patch
  * @property variableName The matchLabel which should be set
  */
-class MatchLabelPatcher(private val k8sResource: KubernetesResource, val variableName: String) :
-    AbstractPatcher(k8sResource) {
+class MatchLabelPatcher(
+    val variableName: String) :
+    AbstractPatcher() {
 
-    override fun <String> patch(labelValue: String) {
-        if (labelValue is kotlin.String) {
-            when (k8sResource) {
-                is Deployment -> {
-                    if (k8sResource.spec.selector.matchLabels == null) {
-                        k8sResource.spec.selector.matchLabels = mutableMapOf()
-                    }
-                    k8sResource.spec.selector.matchLabels[this.variableName] = labelValue
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        when (resource) {
+            is Deployment -> {
+                if (resource.spec.selector.matchLabels == null) {
+                    resource.spec.selector.matchLabels = mutableMapOf()
                 }
-                is StatefulSet -> {
-                    if (k8sResource.spec.selector.matchLabels == null) {
-                        k8sResource.spec.selector.matchLabels = mutableMapOf()
-                    }
-                    k8sResource.spec.selector.matchLabels[this.variableName] = labelValue
+                resource.spec.selector.matchLabels[this.variableName] = value
+            }
+            is StatefulSet -> {
+                if (resource.spec.selector.matchLabels == null) {
+                    resource.spec.selector.matchLabels = mutableMapOf()
                 }
+                resource.spec.selector.matchLabels[this.variableName] = value
             }
         }
+        return resource
     }
 }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/NamePatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/NamePatcher.kt
new file mode 100644
index 0000000000000000000000000000000000000000..74fae390145a10d487b9c39628e67965999593e4
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/patcher/NamePatcher.kt
@@ -0,0 +1,35 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.ConfigMap
+import io.fabric8.kubernetes.api.model.GenericKubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
+import io.fabric8.kubernetes.api.model.Service
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+
+class NamePatcher : AbstractPatcher() {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        when (resource) {
+            is Deployment -> {
+                resource.metadata.name = value
+            }
+            is StatefulSet -> {
+                resource.metadata.name = value
+            }
+            is Service -> {
+                resource.metadata.name = value
+            }
+            is ConfigMap -> {
+                resource.metadata.name = value
+            }
+            is io.fabric8.kubernetes.api.model.networking.v1.Ingress -> {
+                resource.metadata.name = value
+            }
+            is GenericKubernetesResource -> {
+                resource.metadata.name = value
+            }
+        }
+        return resource
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
index 0e8cd553a6c6a9ed6fa2c8cc1b84e4cfebe79d73..b608d3b10440a19998f81776642562d337a4642a 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/NodeSelectorPatcher.kt
@@ -1,19 +1,22 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
 /**
  * The Node selector patcher make it possible to set the NodeSelector of a Kubernetes deployment.
  *
- * @param k8sResource Kubernetes resource to be patched.
  * @param variableName The `label-key` of the node for which the `label-value` is to be patched.
  */
-class NodeSelectorPatcher(private val k8sResource: KubernetesResource, private val variableName: String) :
-    AbstractPatcher(k8sResource) {
-    override fun <String> patch(value: String) {
-        if (k8sResource is Deployment) {
-            k8sResource.spec.template.spec.nodeSelector = mapOf(variableName to value as kotlin.String)
+class NodeSelectorPatcher(
+    private val variableName: String) :
+    AbstractPatcher() {
+
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            resource.spec.template.spec.nodeSelector = mapOf(variableName to value)
         }
+        return resource
     }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
index c617917e6894c3a30779dd4257a96365ded35481..deee1b6efebe98f52e2d19c5cbe2e4c68174ed8f 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcher.kt
@@ -1,23 +1,23 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import kotlin.math.pow
 
 class NumNestedGroupsLoadGeneratorReplicaPatcher(
-    private val k8sResource: KubernetesResource,
     private val numSensors: String,
-    private val loadGenMaxRecords: String
-) :
-    AbstractPatcher(k8sResource) {
-    override fun <String> patch(value: String) {
-        if (k8sResource is Deployment) {
-            if (value is kotlin.String) {
-                val approxNumSensors = numSensors.toDouble().pow(Integer.parseInt(value).toDouble())
-                val loadGenInstances =
-                    (approxNumSensors + loadGenMaxRecords.toDouble() - 1) / loadGenMaxRecords.toDouble()
-                this.k8sResource.spec.replicas = loadGenInstances.toInt()
-            }
+    private val loadGenMaxRecords: String,
+) : AbstractPatcher() {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            val approxNumSensors = numSensors.toDouble().pow(Integer.parseInt(value).toDouble())
+            val loadGenInstances =
+                (approxNumSensors + loadGenMaxRecords.toDouble() - 1) / loadGenMaxRecords.toDouble()
+            resource.spec.replicas = loadGenInstances.toInt()
+
         }
+        return resource
     }
 }
+
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
index 86bb37db3cb9fd0d3bca1690d5eb4e622329a9bc..8463d672687aa9594e2ef168d53e6d7551bc0d4a 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcher.kt
@@ -1,21 +1,21 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
 
 class NumSensorsLoadGeneratorReplicaPatcher(
-    private val k8sResource: KubernetesResource,
-    private val loadGenMaxRecords: String
-) :
-    AbstractPatcher(k8sResource) {
-    override fun <String> patch(value: String) {
-        if (k8sResource is Deployment) {
-            if (value is kotlin.String) {
-                val loadGenInstances =
-                    (Integer.parseInt(value) + loadGenMaxRecords.toInt() - 1) / loadGenMaxRecords.toInt()
-                this.k8sResource.spec.replicas = loadGenInstances
-            }
+    private val loadGenMaxRecords: String,
+) : AbstractPatcher() {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            val loadGenInstances =
+                (Integer.parseInt(value) + loadGenMaxRecords.toInt() - 1) / loadGenMaxRecords.toInt()
+            resource.spec.replicas = loadGenInstances
+
         }
+        return resource
     }
+
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/PatchHandler.kt b/theodolite/src/main/kotlin/theodolite/patcher/PatchHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..73f2f2435b42c59a1b0a294c67bbd0c726ffc209
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/patcher/PatchHandler.kt
@@ -0,0 +1,26 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.HasMetadata
+import theodolite.util.InvalidPatcherConfigurationException
+import theodolite.util.PatcherDefinition
+
+class PatchHandler {
+
+    companion object {
+
+        private fun getResourcesToPatch(resources: MutableMap<String, List<HasMetadata>>, patcherDefinition: PatcherDefinition): List<HasMetadata> {
+            return resources[patcherDefinition.resource]
+                ?: throw InvalidPatcherConfigurationException("Could not find resource ${patcherDefinition.resource}")
+
+        }
+
+        fun patchResource(
+            resources: MutableMap<String, List<HasMetadata>>,
+            patcherDefinition: PatcherDefinition,
+            value: String,
+        ): List<HasMetadata> {
+            val resToPatch = getResourcesToPatch(resources, patcherDefinition)
+            return PatcherFactory.createPatcher(patcherDefinition).patch(resToPatch,value)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/Patcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/Patcher.kt
index 84b886cb4f06b3e667eb8b8aeaa622e1ee54852e..72fe6a1f02e7f1767176fd965740c80f1437f6c1 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/Patcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/Patcher.kt
@@ -1,5 +1,6 @@
 package theodolite.patcher
 
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.quarkus.runtime.annotations.RegisterForReflection
 
 /**
@@ -13,8 +14,7 @@ interface Patcher {
      * The patch method modifies a value in the definition of a
      * Kubernetes resource.
      *
-     * @param T The type of value
      * @param value The value to be used.
      */
-    fun <T> patch(value: T)
+    fun patch(resources: List<HasMetadata>, value: String) : List<HasMetadata>
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt b/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
index e92de4dba7de298c9df76600f2c6785f5878103e..85848a48450637863363a366a1a1767c2c5af565 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/PatcherFactory.kt
@@ -1,6 +1,5 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
 import theodolite.util.InvalidPatcherConfigurationException
 import theodolite.util.PatcherDefinition
 
@@ -10,94 +9,84 @@ import theodolite.util.PatcherDefinition
  * @constructor Creates an empty PatcherFactory.
  */
 class PatcherFactory {
-    /**
-     * Create patcher based on the given [PatcherDefinition] and
-     * the list of KubernetesResources.
-     *
-     * @param patcherDefinition The [PatcherDefinition] for which are
-     *     [Patcher] should be created.
-     * @param k8sResources List of all available Kubernetes resources.
-     *     This is a list of pairs<String, KubernetesResource>:
-     *     The frist corresponds to the filename where the resource is defined.
-     *     The second corresponds to the concrete [KubernetesResource] that should be patched.
-     * @return The created [Patcher].
-     * @throws IllegalArgumentException if no patcher can be created.
-     */
-    fun createPatcher(
-        patcherDefinition: PatcherDefinition,
-        k8sResources: Collection<Pair<String, KubernetesResource>>
-    ): Patcher {
-        val resource =
-            k8sResources.filter { it.first == patcherDefinition.resource }
-                .map { resource -> resource.second }
-                .firstOrNull()
-                ?: throw InvalidPatcherConfigurationException("Could not find resource ${patcherDefinition.resource}")
 
-        return try {
-            when (patcherDefinition.type) {
-                "ReplicaPatcher" -> ReplicaPatcher(
-                    k8sResource = resource
-                )
-                "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(
-                    k8sResource = resource,
-                    loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"]!!,
-                    numSensors = patcherDefinition.properties["numSensors"]!!
-                )
-                "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(
-                    k8sResource = resource,
-                    loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"]!!
-                )
-                "DataVolumeLoadGeneratorReplicaPatcher" -> DataVolumeLoadGeneratorReplicaPatcher(
-                    k8sResource = resource,
-                    maxVolume = patcherDefinition.properties["maxVolume"]!!.toInt(),
-                    container = patcherDefinition.properties["container"]!!,
-                    variableName = patcherDefinition.properties["variableName"]!!
-                )
-                "EnvVarPatcher" -> EnvVarPatcher(
-                    k8sResource = resource,
-                    container = patcherDefinition.properties["container"]!!,
-                    variableName = patcherDefinition.properties["variableName"]!!
-                )
-                "NodeSelectorPatcher" -> NodeSelectorPatcher(
-                    k8sResource = resource,
-                    variableName = patcherDefinition.properties["variableName"]!!
-                )
-                "ResourceLimitPatcher" -> ResourceLimitPatcher(
-                    k8sResource = resource,
-                    container = patcherDefinition.properties["container"]!!,
-                    limitedResource = patcherDefinition.properties["limitedResource"]!!
-                )
-                "ResourceRequestPatcher" -> ResourceRequestPatcher(
-                    k8sResource = resource,
-                    container = patcherDefinition.properties["container"]!!,
-                    requestedResource = patcherDefinition.properties["requestedResource"]!!
-                )
-                "SchedulerNamePatcher" -> SchedulerNamePatcher(
-                    k8sResource = resource
-                )
-                "LabelPatcher" -> LabelPatcher(
-                    k8sResource = resource,
-                    variableName = patcherDefinition.properties["variableName"]!!
-                )
-                "MatchLabelPatcher" -> MatchLabelPatcher(
-                    k8sResource = resource,
-                    variableName = patcherDefinition.properties["variableName"]!!
-                )
-                "TemplateLabelPatcher" -> TemplateLabelPatcher(
-                    k8sResource = resource,
-                    variableName = patcherDefinition.properties["variableName"]!!
-                )
-                "ImagePatcher" -> ImagePatcher(
-                    k8sResource = resource,
-                    container = patcherDefinition.properties["container"]!!
+    companion object {
+        /**
+         * Create patcher based on the given [PatcherDefinition] and
+         * the list of KubernetesResources.
+         *
+         * @param patcherDefinition The [PatcherDefinition] for which are
+         *     [Patcher] should be created.
+         * @param k8sResources List of all available Kubernetes resources.
+         *     This is a list of pairs<String, KubernetesResource>:
+         *     The frist corresponds to the filename where the resource is defined.
+         *     The second corresponds to the concrete [KubernetesResource] that should be patched.
+         * @return The created [Patcher].
+         * @throws IllegalArgumentException if no patcher can be created.
+         */
+        fun createPatcher(
+            patcherDefinition: PatcherDefinition,
+        ): Patcher {
+
+            return try {
+                when (patcherDefinition.type) {
+                    "ReplicaPatcher" -> ReplicaPatcher(
+                    )
+                    "NumNestedGroupsLoadGeneratorReplicaPatcher" -> NumNestedGroupsLoadGeneratorReplicaPatcher(
+                        loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"]!!,
+                        numSensors = patcherDefinition.properties["numSensors"]!!
+                    )
+                    "NumSensorsLoadGeneratorReplicaPatcher" -> NumSensorsLoadGeneratorReplicaPatcher(
+                        loadGenMaxRecords = patcherDefinition.properties["loadGenMaxRecords"]!!
+                    )
+                    "DataVolumeLoadGeneratorReplicaPatcher" -> DataVolumeLoadGeneratorReplicaPatcher(
+                        maxVolume = patcherDefinition.properties["maxVolume"]!!.toInt(),
+                        container = patcherDefinition.properties["container"]!!,
+                        variableName = patcherDefinition.properties["variableName"]!!
+                    )
+                    "EnvVarPatcher" -> EnvVarPatcher(
+                        container = patcherDefinition.properties["container"]!!,
+                        variableName = patcherDefinition.properties["variableName"]!!
+                    )
+                    "NodeSelectorPatcher" -> NodeSelectorPatcher(
+                        variableName = patcherDefinition.properties["variableName"]!!
+                    )
+                    "ResourceLimitPatcher" -> ResourceLimitPatcher(
+                        container = patcherDefinition.properties["container"]!!,
+                        limitedResource = patcherDefinition.properties["limitedResource"]!!
+                    )
+                    "ResourceRequestPatcher" -> ResourceRequestPatcher(
+                        container = patcherDefinition.properties["container"]!!,
+                        requestedResource = patcherDefinition.properties["requestedResource"]!!
+                    )
+                    "SchedulerNamePatcher" -> SchedulerNamePatcher()
+                    "LabelPatcher" -> LabelPatcher(
+                        variableName = patcherDefinition.properties["variableName"]!!
+                    )
+                    "MatchLabelPatcher" -> MatchLabelPatcher(
+                        variableName = patcherDefinition.properties["variableName"]!!
+                    )
+                    "TemplateLabelPatcher" -> TemplateLabelPatcher(
+                        variableName = patcherDefinition.properties["variableName"]!!
+                    )
+                    "ImagePatcher" -> ImagePatcher(
+                        container = patcherDefinition.properties["container"]!!
+                    )
+                    "NamePatcher" -> NamePatcher()
+                    "ServiceSelectorPatcher" -> ServiceSelectorPatcher(
+                        variableName = patcherDefinition.properties["label"]!!
+                    )
+                    "theodolite.patcher.VolumesConfigMapPatcher" -> VolumesConfigMapPatcher(
+                        volumeName = patcherDefinition.properties["volumeName"]!!
+                    )
+                    else -> throw InvalidPatcherConfigurationException("Patcher type ${patcherDefinition.type} not found.")
+                }
+            } catch (e: NullPointerException) {
+                throw InvalidPatcherConfigurationException(
+                    "Could not create patcher with type ${patcherDefinition.type}" +
+                            " Probably a required patcher argument was not specified.", e
                 )
-                else -> throw InvalidPatcherConfigurationException("Patcher type ${patcherDefinition.type} not found.")
             }
-        } catch (e: NullPointerException) {
-            throw InvalidPatcherConfigurationException(
-                "Could not create patcher with type ${patcherDefinition.type}" +
-                        " Probably a required patcher argument was not specified.", e
-            )
         }
     }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ReplicaPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ReplicaPatcher.kt
index 4cc35f2ed74f9e366c266c3f98f1b3d36d4ba1b8..837bebf9da968d9afd7da6846575c9f1f457a3e3 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/ReplicaPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ReplicaPatcher.kt
@@ -1,19 +1,18 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
 /**
  * The Replica [Patcher] modifies the number of replicas for the given Kubernetes deployment.
  *
- * @param k8sResource  Kubernetes resource to be patched.
  */
-class ReplicaPatcher(private val k8sResource: KubernetesResource) : AbstractPatcher(k8sResource) {
-    override fun <String> patch(value: String) {
-        if (k8sResource is Deployment) {
-            if (value is kotlin.String) {
-                this.k8sResource.spec.replicas = Integer.parseInt(value)
-            }
+class ReplicaPatcher : AbstractPatcher() {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            resource.spec.replicas = Integer.parseInt(value)
         }
+        return resource
     }
-}
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
index 9dcdffa0407dd4fdaf2d9b0a898bcdf6cebe5a8b..8b75d43bfc5b589c8c65a1016058a5b850ac9063 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ResourceLimitPatcher.kt
@@ -1,9 +1,6 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.Container
-import io.fabric8.kubernetes.api.model.KubernetesResource
-import io.fabric8.kubernetes.api.model.Quantity
-import io.fabric8.kubernetes.api.model.ResourceRequirements
+import io.fabric8.kubernetes.api.model.*
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
 import theodolite.util.InvalidPatcherConfigurationException
@@ -16,30 +13,31 @@ import theodolite.util.InvalidPatcherConfigurationException
  * @param limitedResource The resource to be limited (e.g. **cpu or memory**)
  */
 class ResourceLimitPatcher(
-    private val k8sResource: KubernetesResource,
     private val container: String,
     private val limitedResource: String
-) : AbstractPatcher(k8sResource) {
+) : AbstractPatcher() {
 
-    override fun <String> patch(value: String) {
-        when (k8sResource) {
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        when (resource) {
             is Deployment -> {
-                k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
-                    setLimits(it, value as kotlin.String)
+                resource.spec.template.spec.containers.filter { it.name == container }.forEach {
+                    setLimits(it, value)
                 }
             }
             is StatefulSet -> {
-                k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
-                    setLimits(it, value as kotlin.String)
+                resource.spec.template.spec.containers.filter { it.name == container }.forEach {
+                    setLimits(it, value)
                 }
             }
             else -> {
-                throw InvalidPatcherConfigurationException("ResourceLimitPatcher not applicable for $k8sResource")
+                throw InvalidPatcherConfigurationException("ResourceLimitPatcher is not applicable for $resource")
             }
         }
+        return resource
     }
 
-    private fun setLimits(container: Container, value: String) {
+
+        private fun setLimits(container: Container, value: String) {
         when {
             container.resources == null -> {
                 val resource = ResourceRequirements()
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
index 24cdde40f7f78bd67d115b2dc44f47e180f51ee2..f63386e5565d053bf276ccada628c3a1676c7c68 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ResourceRequestPatcher.kt
@@ -1,9 +1,6 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.Container
-import io.fabric8.kubernetes.api.model.KubernetesResource
-import io.fabric8.kubernetes.api.model.Quantity
-import io.fabric8.kubernetes.api.model.ResourceRequirements
+import io.fabric8.kubernetes.api.model.*
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
 import theodolite.util.InvalidPatcherConfigurationException
@@ -11,34 +8,33 @@ import theodolite.util.InvalidPatcherConfigurationException
 /**
  * The Resource request [Patcher] set resource limits for deployments and statefulSets.
  *
- * @param k8sResource Kubernetes resource to be patched.
  * @param container Container to be patched.
  * @param requestedResource The resource to be requested (e.g. **cpu or memory**)
  */
 class ResourceRequestPatcher(
-    private val k8sResource: KubernetesResource,
     private val container: String,
     private val requestedResource: String
-) : AbstractPatcher(k8sResource) {
+) : AbstractPatcher() {
 
-    override fun <String> patch(value: String) {
-        when (k8sResource) {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        when (resource) {
             is Deployment -> {
-                k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
-                    setRequests(it, value as kotlin.String)
+                resource.spec.template.spec.containers.filter { it.name == container }.forEach {
+                    setRequests(it, value)
                 }
             }
             is StatefulSet -> {
-                k8sResource.spec.template.spec.containers.filter { it.name == container }.forEach {
-                    setRequests(it, value as kotlin.String)
+                resource.spec.template.spec.containers.filter { it.name == container }.forEach {
+                    setRequests(it, value)
                 }
             }
             else -> {
-                throw InvalidPatcherConfigurationException("ResourceRequestPatcher not applicable for $k8sResource")
+                throw InvalidPatcherConfigurationException("ResourceRequestPatcher is not applicable for $resource")
             }
         }
+        return resource
     }
-
     private fun setRequests(container: Container, value: String) {
         when {
             container.resources == null -> {
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt
index 348f0c50090a34c91221d3e099c3532375a578da..fc6a2864b1cc9495336a2e4756da97b2bd498dc3 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/SchedulerNamePatcher.kt
@@ -1,6 +1,6 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 
 /**
@@ -8,10 +8,13 @@ import io.fabric8.kubernetes.api.model.apps.Deployment
  * be used to deploy the given deployment.
  * @param k8sResource Kubernetes resource to be patched.
  */
-class SchedulerNamePatcher(private val k8sResource: KubernetesResource) : Patcher {
-    override fun <String> patch(value: String) {
-        if (k8sResource is Deployment) {
-            k8sResource.spec.template.spec.schedulerName = value as kotlin.String
+class SchedulerNamePatcher : AbstractPatcher() {
+
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            resource.spec.template.spec.schedulerName = value
         }
+        return resource
     }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/ServiceSelectorPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/ServiceSelectorPatcher.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3d94e283902b9879225ca4b8730730697ebe02a7
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/patcher/ServiceSelectorPatcher.kt
@@ -0,0 +1,19 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.HasMetadata
+import io.fabric8.kubernetes.api.model.Service
+
+class ServiceSelectorPatcher(
+    private var variableName: String
+    ) : AbstractPatcher() {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Service) {
+            if (resource.spec.selector == null) {
+                resource.spec.selector = mutableMapOf()
+            }
+            resource.spec.selector[this.variableName] = value
+        }
+        return resource
+    }
+    }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/TemplateLabelPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/TemplateLabelPatcher.kt
index a524e5c40f90ccf98dc95003cc33dcfceb6f8598..2707d98e046ce9aef01285d9febc7ab3b6d4c45d 100644
--- a/theodolite/src/main/kotlin/theodolite/patcher/TemplateLabelPatcher.kt
+++ b/theodolite/src/main/kotlin/theodolite/patcher/TemplateLabelPatcher.kt
@@ -1,34 +1,34 @@
 package theodolite.patcher
 
-import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.api.model.apps.Deployment
 import io.fabric8.kubernetes.api.model.apps.StatefulSet
 
 /**
  * This patcher is able to set the field `spec.template.metadata.labels` for a `Deployment` or `StatefulSet` Kubernetes resource.
  *
- * @property k8sResource The Kubernetes manifests to patch
  * @property variableName The label which should be set
  */
-class TemplateLabelPatcher(private val k8sResource: KubernetesResource, val variableName: String) :
-    AbstractPatcher(k8sResource) {
+class TemplateLabelPatcher(
+    val variableName: String) :
+    AbstractPatcher() {
 
-    override fun <String> patch(labelValue: String) {
-        if (labelValue is kotlin.String) {
-            when (k8sResource) {
-                is Deployment -> {
-                    if (k8sResource.spec.template.metadata.labels == null) {
-                        k8sResource.spec.template.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.spec.template.metadata.labels[this.variableName] = labelValue
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        when (resource) {
+            is Deployment -> {
+                if (resource.spec.template.metadata.labels == null) {
+                    resource.spec.template.metadata.labels = mutableMapOf()
                 }
-                is StatefulSet -> {
-                    if (k8sResource.spec.template.metadata.labels == null) {
-                        k8sResource.spec.template.metadata.labels = mutableMapOf()
-                    }
-                    k8sResource.spec.template.metadata.labels[this.variableName] = labelValue
+                resource.spec.template.metadata.labels[this.variableName] = value
+            }
+            is StatefulSet -> {
+                if (resource.spec.template.metadata.labels == null) {
+                    resource.spec.template.metadata.labels = mutableMapOf()
                 }
+                resource.spec.template.metadata.labels[this.variableName] = value
             }
         }
+        return resource
     }
 }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/patcher/VolumesConfigMapPatcher.kt b/theodolite/src/main/kotlin/theodolite/patcher/VolumesConfigMapPatcher.kt
new file mode 100644
index 0000000000000000000000000000000000000000..17068c7e7f206b1bbed4530c2008b60d3aaf593e
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/patcher/VolumesConfigMapPatcher.kt
@@ -0,0 +1,44 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.HasMetadata
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+
+class VolumesConfigMapPatcher(private var volumeName: String
+) : AbstractPatcher() {
+
+    override fun patchSingleResource(resource: HasMetadata, value: String): HasMetadata {
+        if (resource is Deployment) {
+            if (resource.spec.template.spec.volumes == null) {
+                resource.spec.template.spec.volumes = mutableListOf()
+            }
+            val volumeMounts = resource.spec.template.spec.volumes
+
+            for (mount in volumeMounts) {
+                try {
+                    if (mount.configMap.name == volumeName) {
+                        mount.configMap.name = value
+                    }
+                } catch (_: NullPointerException) {
+                }
+            }
+        }
+        if (resource is StatefulSet) {
+            if (resource.spec.template.spec.volumes == null) {
+                resource.spec.template.spec.volumes = mutableListOf()
+            }
+            val volumeMounts = resource.spec.template.spec.volumes
+
+            for (mount in volumeMounts) {
+                try {
+                    if (mount.configMap.name == volumeName) {
+                        mount.configMap.name = value
+                    }
+                } catch (_: NullPointerException) {
+                }
+            }
+        }
+
+        return resource
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/Metric.kt b/theodolite/src/main/kotlin/theodolite/strategies/Metric.kt
new file mode 100644
index 0000000000000000000000000000000000000000..05383ca913a460641a6e632211787a2aec17e9d0
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/strategies/Metric.kt
@@ -0,0 +1,11 @@
+package theodolite.strategies
+
+enum class Metric(val value: String) {
+    DEMAND("demand"),
+    CAPACITY("capacity");
+
+    companion object {
+        fun from(metric: String): Metric =
+                values().find { it.value == metric } ?: throw IllegalArgumentException("Requested Metric does not exist")
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/StrategyFactory.kt b/theodolite/src/main/kotlin/theodolite/strategies/StrategyFactory.kt
index 829370e8ce1c181c1a4cb9fdd8ccf0ecefd48d3d..505681716966016548416bf40cefc2c9ad15d805 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/StrategyFactory.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/StrategyFactory.kt
@@ -1,12 +1,10 @@
 package theodolite.strategies
 
+import theodolite.benchmark.BenchmarkExecution
 import theodolite.execution.BenchmarkExecutor
 import theodolite.strategies.restriction.LowerBoundRestriction
 import theodolite.strategies.restriction.RestrictionStrategy
-import theodolite.strategies.searchstrategy.BinarySearch
-import theodolite.strategies.searchstrategy.FullSearch
-import theodolite.strategies.searchstrategy.LinearSearch
-import theodolite.strategies.searchstrategy.SearchStrategy
+import theodolite.strategies.searchstrategy.*
 import theodolite.util.Results
 
 /**
@@ -18,18 +16,37 @@ class StrategyFactory {
      * Create a [SearchStrategy].
      *
      * @param executor The [theodolite.execution.BenchmarkExecutor] that executes individual experiments.
-     * @param searchStrategyString Specifies the [SearchStrategy]. Must either be the string 'LinearSearch',
-     * or 'BinarySearch'.
+     * @param searchStrategyObject Specifies the [SearchStrategy]. Must either be an object with name 'FullSearch',
+     * 'LinearSearch', 'BinarySearch', 'RestrictionSearch' or 'InitialGuessSearch'.
+     * @param results The [Results] saves the state of the Theodolite benchmark run.
      *
      * @throws IllegalArgumentException if the [SearchStrategy] was not one of the allowed options.
      */
-    fun createSearchStrategy(executor: BenchmarkExecutor, searchStrategyString: String): SearchStrategy {
-        return when (searchStrategyString) {
+    fun createSearchStrategy(executor: BenchmarkExecutor, searchStrategyObject: BenchmarkExecution.Strategy,
+                             results: Results): SearchStrategy {
+
+        var strategy : SearchStrategy = when (searchStrategyObject.name) {
             "FullSearch" -> FullSearch(executor)
             "LinearSearch" -> LinearSearch(executor)
             "BinarySearch" -> BinarySearch(executor)
-            else -> throw IllegalArgumentException("Search Strategy $searchStrategyString not found")
+            "RestrictionSearch" -> when (searchStrategyObject.searchStrategy){
+                "FullSearch" -> composeSearchRestrictionStrategy(executor, FullSearch(executor), results,
+                        searchStrategyObject.restrictions)
+                "LinearSearch" -> composeSearchRestrictionStrategy(executor, LinearSearch(executor), results,
+                        searchStrategyObject.restrictions)
+                "BinarySearch" -> composeSearchRestrictionStrategy(executor, BinarySearch(executor), results,
+                        searchStrategyObject.restrictions)
+                else -> throw IllegalArgumentException(
+                        "Search Strategy ${searchStrategyObject.searchStrategy} for RestrictionSearch not found")
+            }
+            "InitialGuessSearch" -> when (searchStrategyObject.guessStrategy){
+                "PrevResourceMinGuess" -> InitialGuessSearchStrategy(executor,PrevInstanceOptGuess(), results)
+                else -> throw IllegalArgumentException("Guess Strategy ${searchStrategyObject.guessStrategy} not found")
+            }
+            else -> throw IllegalArgumentException("Search Strategy $searchStrategyObject not found")
         }
+
+        return strategy
     }
 
     /**
@@ -37,12 +54,12 @@ class StrategyFactory {
      *
      * @param results The [Results] saves the state of the Theodolite benchmark run.
      * @param restrictionStrings Specifies the list of [RestrictionStrategy] that are used to restrict the amount
-     * of [theodolite.util.Resource] for a fixed LoadDimension. Must equal the string
-     * 'LowerBound'.
+     * of Resource for a fixed load or resource (depending on the metric).
+     * Must equal the string 'LowerBound'.
      *
      * @throws IllegalArgumentException if param searchStrategyString was not one of the allowed options.
      */
-    fun createRestrictionStrategy(results: Results, restrictionStrings: List<String>): Set<RestrictionStrategy> {
+    private fun createRestrictionStrategy(results: Results, restrictionStrings: List<String>): Set<RestrictionStrategy> {
         return restrictionStrings
             .map { restriction ->
                 when (restriction) {
@@ -51,4 +68,21 @@ class StrategyFactory {
                 }
             }.toSet()
     }
+
+    /**
+     * Create a RestrictionSearch, if the provided restriction list is not empty. Otherwise just return the given
+     * searchStrategy.
+     *
+     * @param executor The [theodolite.execution.BenchmarkExecutor] that executes individual experiments.
+     * @param searchStrategy The [SearchStrategy] to use.
+     * @param results The [Results] saves the state of the Theodolite benchmark run.
+     * @param restrictions The [RestrictionStrategy]'s to use.
+     */
+    private fun composeSearchRestrictionStrategy(executor: BenchmarkExecutor, searchStrategy: SearchStrategy,
+                                                 results: Results, restrictions: List<String>): SearchStrategy {
+        if(restrictions.isNotEmpty()){
+            return RestrictionSearch(executor,searchStrategy,createRestrictionStrategy(results, restrictions))
+        }
+        return searchStrategy
+    }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/restriction/LowerBoundRestriction.kt b/theodolite/src/main/kotlin/theodolite/strategies/restriction/LowerBoundRestriction.kt
index 13bfedfe055f2bd428137f89b2986f3967ec797c..1203d7293e3790aac2af653c9ceccd0c2ef544bd 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/restriction/LowerBoundRestriction.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/restriction/LowerBoundRestriction.kt
@@ -1,24 +1,24 @@
 package theodolite.strategies.restriction
 
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 import theodolite.util.Results
 
 /**
- * The [LowerBoundRestriction] sets the lower bound of the resources to be examined to the value
- * needed to successfully execute the next smaller load.
+ * The [LowerBoundRestriction] sets the lower bound of the resources to be examined in the experiment to the value
+ * needed to successfully execute the previous smaller load (demand metric), or sets the lower bound of the loads
+ * to be examined in the experiment to the largest value, which still successfully executed the previous smaller
+ * resource (capacity metric).
  *
  * @param results [Result] object used as a basis to restrict the resources.
  */
 class LowerBoundRestriction(results: Results) : RestrictionStrategy(results) {
 
-    override fun apply(load: LoadDimension, resources: List<Resource>): List<Resource> {
-        val maxLoad: LoadDimension? = this.results.getMaxBenchmarkedLoad(load)
-        var lowerBound: Resource? = this.results.getMinRequiredInstances(maxLoad)
+    override fun apply(xValue: Int, yValues: List<Int>): List<Int> {
+        val maxXValue: Int? = this.results.getMaxBenchmarkedXDimensionValue(xValue)
+        var lowerBound: Int? = this.results.getOptYDimensionValue(maxXValue)
         if (lowerBound == null) {
-            lowerBound = resources[0]
+            lowerBound = yValues[0]
         }
-        return resources.filter { x -> x.get() >= lowerBound.get() }
+        return yValues.filter { x -> x >= lowerBound }
     }
 
 }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/restriction/RestrictionStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/restriction/RestrictionStrategy.kt
index 1ab7302d7898daad729b1c94c32d97138b5cdcf4..1ac9d201c734c84db4ec8837c8a242f2be8531b9 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/restriction/RestrictionStrategy.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/restriction/RestrictionStrategy.kt
@@ -1,12 +1,10 @@
 package theodolite.strategies.restriction
 
 import io.quarkus.runtime.annotations.RegisterForReflection
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 import theodolite.util.Results
 
 /**
- * A 'Restriction Strategy' restricts a list of resources based on the current
+ * A 'Restriction Strategy' restricts a list of resources or loads depending on the metric based on the current
  * results of all previously performed benchmarks.
  *
  * @param results the [Results] object
@@ -14,12 +12,13 @@ import theodolite.util.Results
 @RegisterForReflection
 abstract class RestrictionStrategy(val results: Results) {
     /**
-     * Apply the restriction of the given resource list for the given load based on the results object.
+     * Apply the restriction of the given resource list for the given load based on the results object (demand metric),
+     * or apply the restriction of the given load list for the given resource based on the results object (capacity metric).
      *
-     * @param load [LoadDimension] for which a subset of resources are required.
-     * @param resources List of [Resource]s to be restricted.
+     * @param xValue The value to be examined in the experiment, can be load (demand metric) or resource (capacity metric).
+     * @param yValues List of values to be restricted, can be resources (demand metric) or loads (capacity metric).
      * @return Returns a list containing only elements that have not been filtered out by the
      * restriction (possibly empty).
      */
-    abstract fun apply(load: LoadDimension, resources: List<Resource>): List<Resource>
+    abstract fun apply(xValue: Int, yValues: List<Int>): List<Int>
 }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/BinarySearch.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/BinarySearch.kt
index 28e8194c699cd074026c8cb7e6f3ce4ec347023b..6e56c3b36c6e2889e4714c890a424e4f6765386e 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/BinarySearch.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/BinarySearch.kt
@@ -2,8 +2,6 @@ package theodolite.strategies.searchstrategy
 
 import mu.KotlinLogging
 import theodolite.execution.BenchmarkExecutor
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 
 private val logger = KotlinLogging.logger {}
 
@@ -13,48 +11,97 @@ private val logger = KotlinLogging.logger {}
  * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
  */
 class BinarySearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
-    override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
-        val result = binarySearch(load, resources, 0, resources.size - 1)
+    override fun findSuitableResource(load: Int, resources: List<Int>): Int? {
+        val result = binarySearchDemand(load, resources, 0, resources.size - 1)
         if (result == -1) {
             return null
         }
         return resources[result]
     }
 
+    override fun findSuitableLoad(resource: Int, loads: List<Int>): Int? {
+        val result = binarySearchCapacity(resource, loads, 0, loads.size - 1)
+        if (result == -1) {
+            return null
+        }
+        return loads[result]
+    }
+
     /**
-     * Apply binary search.
+     * Apply binary search for the demand metric.
      *
-     * @param load the load dimension to perform experiments for
-     * @param resources the list in which binary search is performed
-     * @param lower lower bound for binary search (inclusive)
-     * @param upper upper bound for binary search (inclusive)
+     * @param load the load to perform experiments for.
+     * @param resources the list of resources in which binary search is performed.
+     * @param lower lower bound for binary search (inclusive).
+     * @param upper upper bound for binary search (inclusive).
      */
-    private fun binarySearch(load: LoadDimension, resources: List<Resource>, lower: Int, upper: Int): Int {
+    private fun binarySearchDemand(load: Int, resources: List<Int>, lower: Int, upper: Int): Int {
         if (lower > upper) {
             throw IllegalArgumentException()
         }
-        // special case:  length == 1 or 2
+        // special case:  length == 1, so lower and upper bounds are the same
         if (lower == upper) {
             val res = resources[lower]
-            logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
-            if (this.benchmarkExecutor.runExperiment(load, resources[lower])) return lower
+            logger.info { "Running experiment with load '$load' and resource '$res'" }
+            if (this.benchmarkExecutor.runExperiment(load, res)) return lower
             else {
                 if (lower + 1 == resources.size) return -1
                 return lower + 1
             }
         } else {
             // apply binary search for a list with
-            // length > 2 and adjust upper and lower depending on the result for `resources[mid]`
+            // length >= 2 and adjust upper and lower depending on the result for `resources[mid]`
             val mid = (upper + lower) / 2
             val res = resources[mid]
-            logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
-            if (this.benchmarkExecutor.runExperiment(load, resources[mid])) {
+            logger.info { "Running experiment with load '$load' and resource '$res'" }
+            if (this.benchmarkExecutor.runExperiment(load, res)) {
+                // case length = 2
                 if (mid == lower) {
                     return lower
                 }
-                return binarySearch(load, resources, lower, mid - 1)
+                return binarySearchDemand(load, resources, lower, mid - 1)
+            } else {
+                return binarySearchDemand(load, resources, mid + 1, upper)
+            }
+        }
+    }
+
+
+    /**
+     * Apply binary search for the capacity metric.
+     *
+     * @param resource the resource to perform experiments for.
+     * @param loads the list of loads in which binary search is performed.
+     * @param lower lower bound for binary search (inclusive).
+     * @param upper upper bound for binary search (inclusive).
+     */
+    private fun binarySearchCapacity(resource: Int, loads: List<Int>, lower: Int, upper: Int): Int {
+        if (lower > upper) {
+            throw IllegalArgumentException()
+        }
+        // length = 1, so lower and upper bounds are the same
+        if (lower == upper) {
+            val load = loads[lower]
+            logger.info { "Running experiment with load '$load' and resource '$resource'" }
+            if (this.benchmarkExecutor.runExperiment(load, resource)) return lower
+            else {
+                if (lower + 1 == loads.size) return -1
+                return lower - 1
+            }
+        } else {
+            // apply binary search for a list with
+            // length > 2 and adjust upper and lower depending on the result for `resources[mid]`
+            val mid = (upper + lower + 1) / 2 //round to next int
+            val load = loads[mid]
+            logger.info { "Running experiment with load '$load' and resource '$resource'" }
+            if (this.benchmarkExecutor.runExperiment(load, resource)) {
+                // length = 2, so since we round down mid is equal to lower
+                if (mid == upper) {
+                    return upper
+                }
+                return binarySearchCapacity(resource, loads, mid + 1, upper)
             } else {
-                return binarySearch(load, resources, mid + 1, upper)
+                return binarySearchCapacity(resource, loads, lower, mid - 1)
             }
         }
     }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt
deleted file mode 100644
index d6ace6f564239e73a0d59f8eb7900f50018482c5..0000000000000000000000000000000000000000
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/CompositeStrategy.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package theodolite.strategies.searchstrategy
-
-import io.quarkus.runtime.annotations.RegisterForReflection
-import theodolite.execution.BenchmarkExecutor
-import theodolite.strategies.restriction.RestrictionStrategy
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
-
-/**
- *  Composite strategy that combines a SearchStrategy and a set of RestrictionStrategy.
- *
- * @param searchStrategy the [SearchStrategy] that is executed as part of this [CompositeStrategy].
- * @param restrictionStrategies the set of [RestrictionStrategy] that are connected conjunctive to restrict the [Resource]
- * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
- */
-@RegisterForReflection
-class CompositeStrategy(
-    benchmarkExecutor: BenchmarkExecutor,
-    private val searchStrategy: SearchStrategy,
-    val restrictionStrategies: Set<RestrictionStrategy>
-) : SearchStrategy(benchmarkExecutor) {
-
-    override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
-        var restrictedResources = resources.toList()
-        for (strategy in this.restrictionStrategies) {
-            restrictedResources = restrictedResources.intersect(strategy.apply(load, resources).toSet()).toList()
-        }
-        return this.searchStrategy.findSuitableResource(load, restrictedResources)
-    }
-}
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt
index 83c4abbdf44f1a1c2f3a27714d796580feedee49..6af6aa1602d18a089b9450f6e1eb84bca8edafa3 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/FullSearch.kt
@@ -2,25 +2,24 @@ package theodolite.strategies.searchstrategy
 
 import mu.KotlinLogging
 import theodolite.execution.BenchmarkExecutor
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 
 private val logger = KotlinLogging.logger {}
 
 /**
- * [SearchStrategy] that executes experiment for provides resources in a linear-search-like fashion, but **without
- * stopping** once a suitable resource amount is found.
+ * [SearchStrategy] that executes an experiment for a load and a resource list (demand metric) or for a resource and a
+ * load list (capacity metric) in a linear-search-like fashion, but **without stopping** once the desired
+ * resource (demand) or load (capacity) is found.
  *
- * @see LinearSearch for a SearchStrategy that stops once a suitable resource amount is found.
+ * @see LinearSearch for a SearchStrategy that stops once the desired resource (demand) or load (capacity) is found.
  *
  * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
  */
 class FullSearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
 
-    override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
-        var minimalSuitableResources: Resource? = null
+    override fun findSuitableResource(load: Int, resources: List<Int>): Int? {
+        var minimalSuitableResources: Int? = null
         for (res in resources) {
-            logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
+            logger.info { "Running experiment with load '$load' and resources '$res'" }
             val result = this.benchmarkExecutor.runExperiment(load, res)
             if (result && minimalSuitableResources == null) {
                 minimalSuitableResources = res
@@ -28,4 +27,13 @@ class FullSearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmar
         }
         return minimalSuitableResources
     }
+
+    override fun findSuitableLoad(resource: Int, loads: List<Int>): Int? {
+        var maxSuitableLoad: Int? = null
+        for (load in loads) {
+            logger.info { "Running experiment with resources '$resource' and load '$load'" }
+            if (this.benchmarkExecutor.runExperiment(load, resource)) maxSuitableLoad = load
+        }
+        return maxSuitableLoad
+    }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt
index 786a3baf159e94841c1f76c696f030718e8f768f..f243b8e4076d0cf0d2ef23bdd6b02b5da2d34152 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt
@@ -1,22 +1,22 @@
 package theodolite.strategies.searchstrategy
 
 import io.quarkus.runtime.annotations.RegisterForReflection
-import theodolite.util.Resource
 
 /**
  * Base class for the implementation of Guess strategies. Guess strategies are strategies to determine the resource
- * demand we start with in our initial guess search strategy.
+ * demand (demand metric) or load (capacity metric) we start with in our initial guess search strategy.
  */
 
 @RegisterForReflection
 abstract class GuessStrategy {
     /**
-     * Computing the resource demand for the initial guess search strategy to start with.
+     * Computing the resource demand (demand metric) or load (capacity metric) for the initial guess search strategy
+     * to start with.
      *
-     * @param resources List of all possible [Resource]s.
-     * @param lastLowestResource Previous resource demand needed for the given load.
+     * @param valuesToCheck List of all possible resources/loads.
+     * @param lastOptValue Previous minimal/maximal resource/load value for the given load/resource.
      *
-     * @return Returns the resource demand to start the initial guess search strategy with or null
+     * @return the resource/load to start the initial guess search strategy with or null
      */
-    abstract fun firstGuess(resources: List<Resource>, lastLowestResource: Resource?): Resource?
+    abstract fun firstGuess(valuesToCheck: List<Int>, lastOptValue: Int?): Int?
 }
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt
index d97fb62cc9d37dd50122199e5d089c491784e511..447d810942be74f0cdbee865e3f0bb5d58e61603 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt
@@ -2,8 +2,6 @@ package theodolite.strategies.searchstrategy
 
 import mu.KotlinLogging
 import theodolite.execution.BenchmarkExecutor
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 import theodolite.util.Results
 
 private val logger = KotlinLogging.logger {}
@@ -16,42 +14,28 @@ private val logger = KotlinLogging.logger {}
  * @param guessStrategy Strategy that provides us with a guess for the first resource amount.
  * @param results current results of all previously performed benchmarks.
  */
-class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStrategy: GuessStrategy, results: Results) :
-        SearchStrategy(benchmarkExecutor, guessStrategy, results) {
+class InitialGuessSearchStrategy(
+        benchmarkExecutor: BenchmarkExecutor,
+        private val guessStrategy: GuessStrategy,
+        private var results: Results
+) : SearchStrategy(benchmarkExecutor) {
 
-    override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
-
-        if(resources.isEmpty()) {
-            logger.info { "You need to specify resources to be checked for the InitialGuessSearchStrategy to work." }
-            return null
-        }
-
-        if(guessStrategy == null){
-            logger.info { "Your InitialGuessSearchStrategy doesn't have a GuessStrategy. This is not supported." }
-            return null
-        }
-
-        if(results == null){
-            logger.info { "The results need to be initialized." }
-            return null
-        }
+    override fun findSuitableResource(load: Int, resources: List<Int>): Int? {
 
-
-        var lastLowestResource : Resource? = null
+        var lastLowestResource : Int? = null
 
         // Getting the lastLowestResource from results and calling firstGuess() with it
         if (!results.isEmpty()) {
-            val maxLoad: LoadDimension? = this.results.getMaxBenchmarkedLoad(load)
-            lastLowestResource = this.results.getMinRequiredInstances(maxLoad)
-            if (lastLowestResource.get() == Int.MAX_VALUE) lastLowestResource = null
+            val maxLoad: Int? = this.results.getMaxBenchmarkedXDimensionValue(load)
+            lastLowestResource = this.results.getOptYDimensionValue(maxLoad)
         }
         lastLowestResource = this.guessStrategy.firstGuess(resources, lastLowestResource)
 
         if (lastLowestResource != null) {
-            val resourcesToCheck: List<Resource>
+            val resourcesToCheck: List<Int>
             val startIndex: Int = resources.indexOf(lastLowestResource)
 
-            logger.info { "Running experiment with load '${load.get()}' and resources '${lastLowestResource.get()}'" }
+            logger.info { "Running experiment with load '$load' and resources '$lastLowestResource'" }
 
             // If the first experiment passes, starting downward linear search
             // otherwise starting upward linear search
@@ -60,10 +44,10 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStra
                 resourcesToCheck = resources.subList(0, startIndex).reversed()
                 if (resourcesToCheck.isEmpty()) return lastLowestResource
 
-                var currentMin: Resource = lastLowestResource
+                var currentMin: Int = lastLowestResource
                 for (res in resourcesToCheck) {
 
-                    logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
+                    logger.info { "Running experiment with load '$load' and resources '$res'" }
                     if (this.benchmarkExecutor.runExperiment(load, res)) {
                         currentMin = res
                     }
@@ -79,14 +63,69 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStra
 
                 for (res in resourcesToCheck) {
 
-                    logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
+                    logger.info { "Running experiment with load '$load' and resources '$res'" }
                     if (this.benchmarkExecutor.runExperiment(load, res)) return res
                 }
             }
         }
         else {
-            logger.info { "InitialGuessSearchStrategy called without lastLowestResource value, which is needed as a " +
-                    "starting point!" }
+            logger.info { "lastLowestResource was null." }
+        }
+        return null
+    }
+
+    override fun findSuitableLoad(resource: Int, loads: List<Int>): Int?{
+
+        var lastMaxLoad : Int? = null
+
+        // Getting the lastLowestLoad from results and calling firstGuess() with it
+        if (!results.isEmpty()) {
+            val maxResource: Int? = this.results.getMaxBenchmarkedXDimensionValue(resource)
+            lastMaxLoad = this.results.getOptYDimensionValue(maxResource)
+        }
+        lastMaxLoad = this.guessStrategy.firstGuess(loads, lastMaxLoad)
+
+        if (lastMaxLoad != null) {
+            val loadsToCheck: List<Int>
+            val startIndex: Int = loads.indexOf(lastMaxLoad)
+
+            logger.info { "Running experiment with resource '$resource' and load '$lastMaxLoad'" }
+
+            // If the first experiment passes, starting upwards linear search
+            // otherwise starting downward linear search
+            if (!this.benchmarkExecutor.runExperiment(lastMaxLoad, resource)) {
+                // downward search
+
+                loadsToCheck = loads.subList(0, startIndex).reversed()
+                if (loadsToCheck.isNotEmpty()) {
+                    for (load in loadsToCheck) {
+
+                        logger.info { "Running experiment with resource '$resource' and load '$load'" }
+                        if (this.benchmarkExecutor.runExperiment(load, resource)) {
+                            return load
+                        }
+                    }
+                }
+            }
+            else {
+                // upward search
+                if (loads.size <= startIndex + 1) {
+                    return lastMaxLoad
+                }
+                loadsToCheck = loads.subList(startIndex + 1, loads.size)
+
+                var currentMax: Int = lastMaxLoad
+                for (load in loadsToCheck) {
+                    logger.info { "Running experiment with resource '$resource' and load '$load'" }
+                    if (this.benchmarkExecutor.runExperiment(load, resource)) {
+                        currentMax = load
+                    }
+                }
+                return currentMax
+            }
+        }
+        else {
+            logger.info { "lastMaxLoad was null." }
         }
         return null
     }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/LinearSearch.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/LinearSearch.kt
index 85deaf6fa75437199bfc560404eb5b40bb4a986a..1991431a970e44bf70eccf834a2ecb0221502a71 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/LinearSearch.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/LinearSearch.kt
@@ -2,24 +2,33 @@ package theodolite.strategies.searchstrategy
 
 import mu.KotlinLogging
 import theodolite.execution.BenchmarkExecutor
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 
 private val logger = KotlinLogging.logger {}
 
 /**
- *  Linear-search-like implementation for determining the smallest suitable number of instances.
+ *  Linear-search-like implementation for determining the smallest/biggest suitable number of resources/loads,
+ *  depending on the metric.
  *
  * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
  */
 class LinearSearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
 
-    override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
+    override fun findSuitableResource(load: Int, resources: List<Int>): Int? {
         for (res in resources) {
-
-            logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
+            logger.info { "Running experiment with load '$load' and resources '$res'" }
             if (this.benchmarkExecutor.runExperiment(load, res)) return res
         }
         return null
     }
+
+    override fun findSuitableLoad(resource: Int, loads: List<Int>): Int? {
+        var maxSuitableLoad: Int? = null
+        for (load in loads) {
+            logger.info { "Running experiment with resources '$resource' and load '$load'" }
+            if (this.benchmarkExecutor.runExperiment(load, resource)) {
+                maxSuitableLoad = load
+            } else break
+        }
+        return maxSuitableLoad
+    }
 }
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevInstanceOptGuess.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevInstanceOptGuess.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c919b475995a6a5366371336041d9633f0aa1993
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevInstanceOptGuess.kt
@@ -0,0 +1,28 @@
+package theodolite.strategies.searchstrategy
+
+
+/**
+ * [PrevInstanceOptGuess] is a [GuessStrategy] that implements the function [firstGuess],
+ * where it returns the optimal result of the previous run.
+ */
+
+class PrevInstanceOptGuess() : GuessStrategy(){
+
+    /**
+     * If the metric is
+     *
+     * - "demand", [valuesToCheck] is a List of resources and [lastOptValue] a resource value.
+     * - "capacity", [valuesToCheck] is a List of loads and [lastOptValue] a load value.
+     *
+     * @param valuesToCheck List of all possible resources/loads.
+     * @param lastOptValue Previous minimal/maximal resource/load value for the given load/resource.
+     *
+     * @return the value of [lastOptValue] if given otherwise the first element of the [valuesToCheck] list or null
+     */
+    override fun firstGuess(valuesToCheck: List<Int>, lastOptValue: Int?): Int? {
+
+        if (lastOptValue != null) return lastOptValue
+        else if(valuesToCheck.isNotEmpty()) return valuesToCheck[0]
+        else return null
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt
deleted file mode 100644
index 413eecea27279cd79bad155fbb7d5d18b674a12e..0000000000000000000000000000000000000000
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package theodolite.strategies.searchstrategy
-
-import theodolite.util.Resource
-
-/**
- * This Guess strategy takes the minimal resource demand of the previous load, which is given as an argument for the
- * firstGuess function.
- */
-
-class PrevResourceMinGuess() : GuessStrategy(){
-
-    /**
-     * @param resources List of all possible [Resource]s.
-     * @param lastLowestResource Previous resource demand needed for the given load.
-     *
-     * @return the value of lastLowestResource if given otherwise the first element of the resource list or null
-     */
-    override fun firstGuess(resources: List<Resource>, lastLowestResource: Resource?): Resource? {
-
-        if (lastLowestResource != null) return lastLowestResource
-        else if(resources.isNotEmpty()) return resources[0]
-        else return null
-    }
-}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/RestrictionSearch.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/RestrictionSearch.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0a136d6ff43e6f62fc5ebe34c392816da3592bf1
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/RestrictionSearch.kt
@@ -0,0 +1,43 @@
+package theodolite.strategies.searchstrategy
+
+import io.quarkus.runtime.annotations.RegisterForReflection
+import theodolite.execution.BenchmarkExecutor
+import theodolite.strategies.restriction.RestrictionStrategy
+
+/**
+ *  Strategy that combines a SearchStrategy and a set of RestrictionStrategy.
+ *
+ * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
+ * @param searchStrategy the [SearchStrategy] that is executed as part of this [RestrictionSearch].
+ * @param restrictionStrategies the set of [RestrictionStrategy] that are connected conjunctive to restrict the Resource.
+ *
+ */
+@RegisterForReflection
+class RestrictionSearch(
+    benchmarkExecutor: BenchmarkExecutor,
+    private val searchStrategy: SearchStrategy,
+    private val restrictionStrategies: Set<RestrictionStrategy>
+) : SearchStrategy(benchmarkExecutor) {
+
+    /**
+     * Restricting the possible resources and calling findSuitableResource of the given [SearchStrategy].
+     */
+    override fun findSuitableResource(load: Int, resources: List<Int>): Int? {
+        var restrictedResources = resources
+        for (strategy in this.restrictionStrategies) {
+            restrictedResources = restrictedResources.intersect(strategy.apply(load, resources).toSet()).toList()
+        }
+        return this.searchStrategy.findSuitableResource(load, restrictedResources)
+    }
+
+    /**
+     * Restricting the possible loads and calling findSuitableLoad of the given [SearchStrategy].
+     */
+    override fun findSuitableLoad(resource: Int, loads: List<Int>): Int? {
+        var restrictedLoads = loads
+        for (strategy in this.restrictionStrategies) {
+            restrictedLoads = restrictedLoads.intersect(strategy.apply(resource, loads).toSet()).toList()
+        }
+        return this.searchStrategy.findSuitableLoad(resource, restrictedLoads)
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt
index 97c723f2cfe459081cbb327f6860e48319c8f4f1..962504c7d85fa5e28d73fe0cb9d844ed2be66a99 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt
@@ -2,27 +2,63 @@ package theodolite.strategies.searchstrategy
 
 import io.quarkus.runtime.annotations.RegisterForReflection
 import theodolite.execution.BenchmarkExecutor
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
+import theodolite.strategies.Metric
 import theodolite.util.Results
 
 /**
- *  Base class for the implementation for SearchStrategies. SearchStrategies determine the smallest suitable number of instances.
+ *  Base class for the implementation for SearchStrategies. SearchStrategies determine the smallest suitable number
+ *  of resources/loads for a load/resource (depending on the metric).
  *
  * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
  * @param guessStrategy Guess strategy for the initial resource amount in case the InitialGuessStrategy is selected.
  * @param results the [Results] object.
  */
 @RegisterForReflection
-abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor, val guessStrategy: GuessStrategy? = null,
-                              val results: Results? = null) {
+abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor) {
+
+
+    /**
+     * Calling findSuitableResource or findSuitableLoad for each load/resource depending on the chosen metric.
+     *
+     * @param loads List of possible loads for the experiments.
+     * @param resources List of possible resources for the experiments.
+     * @param metric The [Metric] for the experiments, either "demand" or "capacity".
+     */
+    fun applySearchStrategyByMetric(loads: List<Int>, resources: List<Int>, metric: Metric) {
+
+        when(metric) {
+            Metric.DEMAND ->
+                for (load in loads) {
+                    if (benchmarkExecutor.run.get()) {
+                        this.findSuitableResource(load, resources)
+                    }
+                }
+            Metric.CAPACITY ->
+                for (resource in resources) {
+                    if (benchmarkExecutor.run.get()) {
+                        this.findSuitableLoad(resource, loads)
+                    }
+                }
+        }
+    }
+
     /**
-     * Find smallest suitable resource from the specified resource list for the given load.
+     * Find the smallest suitable resource from the specified resource list for the given load.
      *
-     * @param load the [LoadDimension] to be tested.
-     * @param resources List of all possible [Resource]s.
+     * @param load the load to be tested.
+     * @param resources List of all possible resources.
      *
      * @return suitable resource for the specified load, or null if no suitable resource exists.
      */
-    abstract fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource?
+    abstract fun findSuitableResource(load: Int, resources: List<Int>): Int?
+
+    /**
+     * Find the biggest suitable load from the specified load list for the given resource amount.
+     *
+     * @param resource the resource to be tested.
+     * @param loads List of all possible loads.
+     *
+     * @return suitable load for the specified resource amount, or null if no suitable load exists.
+     */
+    abstract fun findSuitableLoad(resource: Int, loads: List<Int>) : Int?
 }
diff --git a/theodolite/src/main/kotlin/theodolite/util/Config.kt b/theodolite/src/main/kotlin/theodolite/util/Config.kt
index afbf784e9d6d72939615e367b54891ecd95a3608..675caea5fbd3b8e8c699019e10f43c36b9fbaebe 100644
--- a/theodolite/src/main/kotlin/theodolite/util/Config.kt
+++ b/theodolite/src/main/kotlin/theodolite/util/Config.kt
@@ -1,18 +1,23 @@
 package theodolite.util
 
 import io.quarkus.runtime.annotations.RegisterForReflection
-import theodolite.strategies.searchstrategy.CompositeStrategy
+import theodolite.strategies.Metric
+import theodolite.strategies.searchstrategy.SearchStrategy
 
 /**
  * Config class that represents a configuration of a theodolite run.
  *
- * @param loads the [LoadDimension] of the execution
- * @param resources the [Resource] of the execution
- * @param compositeStrategy the [CompositeStrategy] of the execution
+ * @param loads the possible loads of the execution
+ * @param resources the possible resources of the execution
+ * @param searchStrategy the [SearchStrategy] of the execution
+ * @param metric the Metric of the execution
  */
 @RegisterForReflection
 data class Config(
-    val loads: List<LoadDimension>,
-    val resources: List<Resource>,
-    val compositeStrategy: CompositeStrategy
+        val loads: List<Int>,
+        val loadPatcherDefinitions : List<PatcherDefinition>,
+        val resources: List<Int>,
+        val resourcePatcherDefinitions : List<PatcherDefinition>,
+        val searchStrategy: SearchStrategy,
+        val metric: Metric
 )
diff --git a/theodolite/src/main/kotlin/theodolite/util/LoadDimension.kt b/theodolite/src/main/kotlin/theodolite/util/LoadDimension.kt
deleted file mode 100644
index cf26da979b05f0a2bd82289ce371715ea0d67c93..0000000000000000000000000000000000000000
--- a/theodolite/src/main/kotlin/theodolite/util/LoadDimension.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package theodolite.util
-
-import io.quarkus.runtime.annotations.RegisterForReflection
-
-/**
- * Representation of the load dimensions for a execution of theodolite.
- *
- * @param number the value of this [LoadDimension]
- * @param type [PatcherDefinition] of this [LoadDimension]
- */
-@RegisterForReflection
-data class LoadDimension(private val number: Int, private val type: List<PatcherDefinition>) {
-    /**
-     * @return the value of this load dimension.
-     */
-    fun get(): Int {
-        return this.number
-    }
-
-    /**
-     * @return the list of [PatcherDefinition]
-     */
-    fun getType(): List<PatcherDefinition> {
-        return this.type
-    }
-}
diff --git a/theodolite/src/main/kotlin/theodolite/util/Resource.kt b/theodolite/src/main/kotlin/theodolite/util/Resource.kt
deleted file mode 100644
index 1d6410aa4288e19817e3ba48bfd1bc0d85d006a2..0000000000000000000000000000000000000000
--- a/theodolite/src/main/kotlin/theodolite/util/Resource.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package theodolite.util
-
-import io.quarkus.runtime.annotations.RegisterForReflection
-
-/**
- * Representation of the resources for an execution of Theodolite.
- */
-@RegisterForReflection
-data class Resource(private val number: Int, private val type: List<PatcherDefinition>) {
-
-    /**
-     * @return the value of this resource.
-     */
-    fun get(): Int {
-        return this.number
-    }
-
-    /**
-     * @return the list of [PatcherDefinition]
-     */
-    fun getType(): List<PatcherDefinition> {
-        return this.type
-    }
-}
diff --git a/theodolite/src/main/kotlin/theodolite/util/Results.kt b/theodolite/src/main/kotlin/theodolite/util/Results.kt
index 2221c2e64f6dbc1776122f20793aa8d04d621d9d..418ac50f285996affd7db1c15fc44a22f1677d29 100644
--- a/theodolite/src/main/kotlin/theodolite/util/Results.kt
+++ b/theodolite/src/main/kotlin/theodolite/util/Results.kt
@@ -1,6 +1,7 @@
 package theodolite.util
 
 import io.quarkus.runtime.annotations.RegisterForReflection
+import theodolite.strategies.Metric
 
 /**
  * Central class that saves the state of an execution of Theodolite. For an execution, it is used to save the result of
@@ -8,80 +9,111 @@ import io.quarkus.runtime.annotations.RegisterForReflection
  * perform the [theodolite.strategies.restriction.RestrictionStrategy].
  */
 @RegisterForReflection
-class Results {
-    private val results: MutableMap<Pair<LoadDimension, Resource>, Boolean> = mutableMapOf()
+class Results (val metric: Metric) {
+    // (load, resource) -> Boolean map
+    private val results: MutableMap<Pair<Int, Int>, Boolean> = mutableMapOf()
+
+    // if metric is "demand"  : load     -> resource
+    // if metric is "capacity": resource -> load
+    private var optInstances: MutableMap<Int, Int> = mutableMapOf()
+
 
     /**
-     * Set the result for an experiment.
+     * Set the result for an experiment and update the [optInstances] list accordingly.
      *
-     * @param experiment A pair that identifies the experiment by the [LoadDimension] and [Resource].
+     * @param experiment A pair that identifies the experiment by the Load and Resource.
      * @param successful the result of the experiment. Successful == true and Unsuccessful == false.
      */
-    fun setResult(experiment: Pair<LoadDimension, Resource>, successful: Boolean) {
+    fun setResult(experiment: Pair<Int, Int>, successful: Boolean) {
         this.results[experiment] = successful
+
+        when (metric) {
+            Metric.DEMAND ->
+                if (successful) {
+                    if (optInstances.containsKey(experiment.first)) {
+                        if (optInstances[experiment.first]!! > experiment.second) {
+                            optInstances[experiment.first] = experiment.second
+                        }
+                    } else {
+                        optInstances[experiment.first] = experiment.second
+                    }
+                } else if (!optInstances.containsKey(experiment.first)) {
+                    optInstances[experiment.first] = Int.MAX_VALUE
+                }
+            Metric.CAPACITY ->
+                if (successful) {
+                    if (optInstances.containsKey(experiment.second)) {
+                        if (optInstances[experiment.second]!! < experiment.first) {
+                            optInstances[experiment.second] = experiment.first
+                        }
+                    } else {
+                        optInstances[experiment.second] = experiment.first
+                    }
+                } else if (!optInstances.containsKey(experiment.second)) {
+                    optInstances[experiment.second] = Int.MIN_VALUE
+                }
+        }
     }
 
     /**
      * Get the result for an experiment.
      *
-     * @param experiment A pair that identifies the experiment by the [LoadDimension] and [Resource].
+     * @param experiment A pair that identifies the experiment by the Load and Resource.
      * @return true if the experiment was successful and false otherwise. If the result has not been reported so far,
      * null is returned.
      *
-     * @see Resource
      */
-    fun getResult(experiment: Pair<LoadDimension, Resource>): Boolean? {
+    fun getResult(experiment: Pair<Int, Int>): Boolean? {
         return this.results[experiment]
     }
 
     /**
-     * Get the smallest suitable number of instances for a specified [LoadDimension].
+     * Get the smallest suitable number of instances for a specified x-Value.
+     * The x-Value corresponds to the...
+     * - load, if the metric is "demand".
+     * - resource, if the metric is "capacity".
      *
-     * @param load the [LoadDimension]
+     * @param xValue the Value of the x-dimension of the current metric
      *
-     * @return the smallest suitable number of resources. If the experiment was not executed yet,
-     * a @see Resource with the constant Int.MAX_VALUE as value is returned.
-     * If no experiments have been marked as either successful or unsuccessful
-     * yet, a Resource with the constant value Int.MIN_VALUE is returned.
+     * @return the smallest suitable number of resources/loads (depending on metric).
+     * If there is no experiment that has been executed yet, there is no experiment
+     * for the given [xValue] or there is none marked successful yet, null is returned.
      */
-    fun getMinRequiredInstances(load: LoadDimension?): Resource {
-        if (this.results.isEmpty()) {
-            return Resource(Int.MIN_VALUE, emptyList())
-        }
-
-        var minRequiredInstances = Resource(Int.MAX_VALUE, emptyList())
-        for (experiment in results) {
-            // Get all successful experiments for requested load
-            if (experiment.key.first == load && experiment.value) {
-                if (experiment.key.second.get() < minRequiredInstances.get()) {
-                    // Found new smallest resources
-                    minRequiredInstances = experiment.key.second
-                }
+    fun getOptYDimensionValue(xValue: Int?): Int? {
+        if (xValue != null) {
+            val res = optInstances[xValue]
+            if (res != Int.MAX_VALUE && res != Int.MIN_VALUE) {
+                return res
             }
         }
-        return minRequiredInstances
+        return null
     }
 
     /**
-     * Get the largest [LoadDimension] that has been reported executed successfully (or unsuccessfully) so far, for a
-     * [LoadDimension] and is smaller than the given [LoadDimension].
+     * Get the largest x-Value that has been tested and reported so far (successful or unsuccessful),
+     * which is smaller than the specified x-Value.
+     *
+     * The x-Value corresponds to the...
+     * - load, if the metric is "demand".
+     * - resource, if the metric is "capacity".
      *
-     * @param load the [LoadDimension]
+     * @param xValue the Value of the x-dimension of the current metric
      *
-     * @return the largest [LoadDimension] or null, if there is none for this [LoadDimension]
+     * @return the largest tested x-Value or null, if there wasn't any tested which is smaller than the [xValue].
      */
-    fun getMaxBenchmarkedLoad(load: LoadDimension): LoadDimension? {
-        var maxBenchmarkedLoad: LoadDimension? = null
-        for (experiment in results) {
-            if (experiment.key.first.get() <= load.get()) {
-                if (maxBenchmarkedLoad == null) {
-                    maxBenchmarkedLoad = experiment.key.first
-                } else if (maxBenchmarkedLoad.get() < experiment.key.first.get()) {
-                    maxBenchmarkedLoad = experiment.key.first
+    fun getMaxBenchmarkedXDimensionValue(xValue: Int): Int? {
+        var maxBenchmarkedXValue: Int? = null
+        for (instance in optInstances) {
+            val instanceXValue= instance.key
+            if (instanceXValue <= xValue) {
+                if (maxBenchmarkedXValue == null) {
+                    maxBenchmarkedXValue = instanceXValue
+                } else if (maxBenchmarkedXValue < instanceXValue) {
+                    maxBenchmarkedXValue = instanceXValue
                 }
             }
         }
-        return maxBenchmarkedLoad
+        return maxBenchmarkedXValue
     }
 
     /**
diff --git a/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt b/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt
index 1af6f548b219697009c688ace712a9f7f5620bd0..dbe55ff36f591a45df3fd9898419befe5a5fdeb7 100644
--- a/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt
@@ -3,13 +3,12 @@ package theodolite
 import io.quarkus.test.junit.QuarkusTest
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Test
-import theodolite.benchmark.BenchmarkExecution
 import theodolite.strategies.searchstrategy.InitialGuessSearchStrategy
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
+import theodolite.strategies.Metric
 import theodolite.util.Results
 import mu.KotlinLogging
-import theodolite.strategies.searchstrategy.PrevResourceMinGuess
+import theodolite.benchmark.Slo
+import theodolite.strategies.searchstrategy.PrevInstanceOptGuess
 
 private val logger = KotlinLogging.logger {}
 
@@ -27,23 +26,23 @@ class InitialGuessSearchStrategyTest {
             arrayOf(false, false, false, false, false, false, true),
             arrayOf(false, false, false, false, false, false, false)
         )
-        val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
-        val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
-        val results = Results()
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..6).toList()
+        val results = Results(Metric.from("demand"))
         val benchmark = TestBenchmark()
-        val guessStrategy = PrevResourceMinGuess()
-        val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
+        val guessStrategy = PrevInstanceOptGuess()
+        val sloChecker = Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
         val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy, results)
 
-        val actual: ArrayList<Resource?> = ArrayList()
-        val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
+        val actual: ArrayList<Int?> = ArrayList()
+        val expected: ArrayList<Int?> = ArrayList(listOf(0, 2, 2, 3, 4, 6))
         expected.add(null)
 
         for (load in mockLoads) {
-            val returnVal : Resource? = strategy.findSuitableResource(load, mockResources)
+            val returnVal : Int? = strategy.findSuitableResource(load, mockResources)
             if(returnVal != null) {
-                logger.info { "returnVal '${returnVal.get()}'" }
+                logger.info { "returnVal '${returnVal}'" }
             }
             else {
                 logger.info { "returnVal is null." }
@@ -65,23 +64,23 @@ class InitialGuessSearchStrategyTest {
             arrayOf(false, false, false, false, false, false, true),
             arrayOf(false, false, false, false, false, false, false)
         )
-        val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
-        val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
-        val results = Results()
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..6).toList()
+        val results = Results(Metric.from("demand"))
         val benchmark = TestBenchmark()
-        val guessStrategy = PrevResourceMinGuess()
-        val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
+        val guessStrategy = PrevInstanceOptGuess()
+        val sloChecker = Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
         val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy, results)
 
-        val actual: ArrayList<Resource?> = ArrayList()
-        val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 1, 4, 6).map { x -> Resource(x, emptyList()) })
+        val actual: ArrayList<Int?> = ArrayList()
+        val expected: ArrayList<Int?> = ArrayList(listOf(0, 2, 2, 1, 4, 6))
         expected.add(null)
 
         for (load in mockLoads) {
-            val returnVal : Resource? = strategy.findSuitableResource(load, mockResources)
+            val returnVal : Int? = strategy.findSuitableResource(load, mockResources)
             if(returnVal != null) {
-                logger.info { "returnVal '${returnVal.get()}'" }
+                logger.info { "returnVal '${returnVal}'" }
             }
             else {
                 logger.info { "returnVal is null." }
@@ -103,24 +102,24 @@ class InitialGuessSearchStrategyTest {
                 arrayOf(false, false, false, false, false, false, true),
                 arrayOf(false, false, false, false, false, false, false)
         )
-        val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
-        val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
-        val results = Results()
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..6).toList()
+        val results = Results(Metric.from("demand"))
         val benchmark = TestBenchmark()
-        val guessStrategy = PrevResourceMinGuess()
-        val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
+        val guessStrategy = PrevInstanceOptGuess()
+        val sloChecker = Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
         val strategy = InitialGuessSearchStrategy(benchmarkExecutor, guessStrategy, results)
 
-        val actual: ArrayList<Resource?> = ArrayList()
-        var expected: ArrayList<Resource?> = ArrayList(listOf(2, 3, 0, 4, 6).map { x -> Resource(x, emptyList()) })
+        val actual: ArrayList<Int?> = ArrayList()
+        var expected: ArrayList<Int?> = ArrayList(listOf(2, 3, 0, 4, 6))
         expected.add(null)
         expected = ArrayList(listOf(null) + expected)
 
         for (load in mockLoads) {
-            val returnVal : Resource? = strategy.findSuitableResource(load, mockResources)
+            val returnVal : Int? = strategy.findSuitableResource(load, mockResources)
             if(returnVal != null) {
-                logger.info { "returnVal '${returnVal.get()}'" }
+                logger.info { "returnVal '${returnVal}'" }
             }
             else {
                 logger.info { "returnVal is null." }
diff --git a/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt b/theodolite/src/test/kotlin/theodolite/RestrictionSearchTest.kt
similarity index 53%
rename from theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt
rename to theodolite/src/test/kotlin/theodolite/RestrictionSearchTest.kt
index 580d9e747bde687a91ffb1bce2e7c9dfb6f166a2..23fa99c6d1775f291949a9068399f5bcf6e5179a 100644
--- a/theodolite/src/test/kotlin/theodolite/CompositeStrategyTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/RestrictionSearchTest.kt
@@ -3,20 +3,21 @@ package theodolite
 import io.quarkus.test.junit.QuarkusTest
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Test
-import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.Slo
+import theodolite.strategies.Metric
 import theodolite.strategies.restriction.LowerBoundRestriction
 import theodolite.strategies.searchstrategy.BinarySearch
-import theodolite.strategies.searchstrategy.CompositeStrategy
+import theodolite.strategies.searchstrategy.FullSearch
+import theodolite.strategies.searchstrategy.RestrictionSearch
 import theodolite.strategies.searchstrategy.LinearSearch
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 import theodolite.util.Results
 
 @QuarkusTest
-class CompositeStrategyTest {
+class RestrictionSearchTest {
+
 
     @Test
-    fun testEnd2EndLinearSearch() {
+    fun restrictionSearchTestLinearSearch() {
         val mockResults = arrayOf(
             arrayOf(true, true, true, true, true, true, true),
             arrayOf(false, false, true, true, true, true, true),
@@ -26,19 +27,19 @@ class CompositeStrategyTest {
             arrayOf(false, false, false, false, false, false, true),
             arrayOf(false, false, false, false, false, false, false)
         )
-        val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
-        val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
-        val results = Results()
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..6).toList()
+        val results = Results(Metric.from("demand"))
         val benchmark = TestBenchmark()
-        val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
+        val sloChecker = Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
         val linearSearch = LinearSearch(benchmarkExecutor)
         val lowerBoundRestriction = LowerBoundRestriction(results)
         val strategy =
-            CompositeStrategy(benchmarkExecutor, linearSearch, setOf(lowerBoundRestriction))
+            RestrictionSearch(benchmarkExecutor, linearSearch, setOf(lowerBoundRestriction))
 
-        val actual: ArrayList<Resource?> = ArrayList()
-        val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
+        val actual: ArrayList<Int?> = ArrayList()
+        val expected: ArrayList<Int?> = ArrayList(listOf(0, 2, 2, 3, 4, 6))
         expected.add(null)
 
         for (load in mockLoads) {
@@ -49,7 +50,40 @@ class CompositeStrategyTest {
     }
 
     @Test
-    fun testEnd2EndBinarySearch() {
+    fun restrictionSearchTestFullSearch() {
+        val mockResults = arrayOf(
+                arrayOf(true, true, true, true, true, true, true),
+                arrayOf(false, false, true, true, true, true, true),
+                arrayOf(false, false, true, true, true, true, true),
+                arrayOf(false, false, false, true, true, true, true),
+                arrayOf(false, false, false, false, true, true, true),
+                arrayOf(false, false, false, false, false, false, true),
+                arrayOf(false, false, false, false, false, false, false)
+        )
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..6).toList()
+        val results = Results(Metric.from("demand"))
+        val benchmark = TestBenchmark()
+        val sloChecker = Slo()
+        val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
+        val fullSearch = FullSearch(benchmarkExecutor)
+        val lowerBoundRestriction = LowerBoundRestriction(results)
+        val strategy =
+                RestrictionSearch(benchmarkExecutor, fullSearch, setOf(lowerBoundRestriction))
+
+        val actual: ArrayList<Int?> = ArrayList()
+        val expected: ArrayList<Int?> = ArrayList(listOf(0, 2, 2, 3, 4, 6))
+        expected.add(null)
+
+        for (load in mockLoads) {
+            actual.add(strategy.findSuitableResource(load, mockResources))
+        }
+
+        assertEquals(actual, expected)
+    }
+
+    @Test
+    fun restrictionSearchTestBinarySearch() {
         val mockResults = arrayOf(
             arrayOf(true, true, true, true, true, true, true),
             arrayOf(false, false, true, true, true, true, true),
@@ -59,20 +93,19 @@ class CompositeStrategyTest {
             arrayOf(false, false, false, false, false, false, true),
             arrayOf(false, false, false, false, false, false, false)
         )
-        val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
-        val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
-        val results = Results()
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..6).toList()
+        val results = Results(Metric.from("demand"))
         val benchmark = TestBenchmark()
-        val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
+        val sloChecker = Slo()
         val benchmarkExecutorImpl =
             TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 0)
         val binarySearch = BinarySearch(benchmarkExecutorImpl)
         val lowerBoundRestriction = LowerBoundRestriction(results)
-        val strategy =
-            CompositeStrategy(benchmarkExecutorImpl, binarySearch, setOf(lowerBoundRestriction))
+        val strategy = RestrictionSearch(benchmarkExecutorImpl, binarySearch, setOf(lowerBoundRestriction))
 
-        val actual: ArrayList<Resource?> = ArrayList()
-        val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
+        val actual: ArrayList<Int?> = ArrayList()
+        val expected: ArrayList<Int?> = ArrayList(listOf(0, 2, 2, 3, 4, 6))
         expected.add(null)
 
         for (load in mockLoads) {
@@ -83,7 +116,7 @@ class CompositeStrategyTest {
     }
 
     @Test
-    fun testEnd2EndBinarySearch2() {
+    fun restrictionSearchTestBinarySearch2() {
         val mockResults = arrayOf(
             arrayOf(true, true, true, true, true, true, true, true),
             arrayOf(false, false, true, true, true, true, true, true),
@@ -93,20 +126,20 @@ class CompositeStrategyTest {
             arrayOf(false, false, false, false, false, false, true, true),
             arrayOf(false, false, false, false, false, false, false, true)
         )
-        val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) }
-        val mockResources: List<Resource> = (0..7).map { number -> Resource(number, emptyList()) }
-        val results = Results()
+        val mockLoads: List<Int> = (0..6).toList()
+        val mockResources: List<Int> = (0..7).toList()
+        val results = Results(Metric.from("demand"))
         val benchmark = TestBenchmark()
-        val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
+        val sloChecker = Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 0)
         val binarySearch = BinarySearch(benchmarkExecutor)
         val lowerBoundRestriction = LowerBoundRestriction(results)
         val strategy =
-            CompositeStrategy(benchmarkExecutor, binarySearch, setOf(lowerBoundRestriction))
+            RestrictionSearch(benchmarkExecutor, binarySearch, setOf(lowerBoundRestriction))
 
-        val actual: ArrayList<Resource?> = ArrayList()
-        val expected: ArrayList<Resource?> =
-            ArrayList(listOf(0, 2, 2, 3, 4, 6, 7).map { x -> Resource(x, emptyList()) })
+        val actual: ArrayList<Int?> = ArrayList()
+        val expected: ArrayList<Int?> =
+            ArrayList(listOf(0, 2, 2, 3, 4, 6, 7))
 
         for (load in mockLoads) {
             actual.add(strategy.findSuitableResource(load, mockResources))
diff --git a/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt b/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt
index b08c1a18a3013e1573e4892f01698b5e509f9609..335b0f8c59ac7642c30a12e494890e8f2c52ccda 100644
--- a/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt
+++ b/theodolite/src/test/kotlin/theodolite/TestBenchmark.kt
@@ -3,8 +3,7 @@ package theodolite
 import theodolite.benchmark.Benchmark
 import theodolite.benchmark.BenchmarkDeployment
 import theodolite.util.ConfigurationOverride
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
+import theodolite.util.PatcherDefinition
 
 class TestBenchmark : Benchmark {
 
@@ -15,11 +14,13 @@ class TestBenchmark : Benchmark {
     }
 
     override fun buildDeployment(
-        load: LoadDimension,
-        res: Resource,
-        configurationOverrides: List<ConfigurationOverride?>,
-        loadGenerationDelay: Long,
-        afterTeardownDelay: Long
+            load: Int,
+            loadPatcherDefinitions: List<PatcherDefinition>,
+            resource: Int,
+            resourcePatcherDefinitions: List<PatcherDefinition>,
+            configurationOverrides: List<ConfigurationOverride?>,
+            loadGenerationDelay: Long,
+            afterTeardownDelay: Long
     ): BenchmarkDeployment {
         return TestBenchmarkDeployment()
     }
diff --git a/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt b/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt
index 2efddc48cb93a0870d1716c58a7018145c16e2ff..97197f3bad066235634869c8c37de4bc5c570f8b 100644
--- a/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt
+++ b/theodolite/src/test/kotlin/theodolite/TestBenchmarkExecutorImpl.kt
@@ -1,21 +1,19 @@
 package theodolite
 
 import theodolite.benchmark.Benchmark
-import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.Slo
 import theodolite.execution.BenchmarkExecutor
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
 import theodolite.util.Results
 import java.time.Duration
 
 class TestBenchmarkExecutorImpl(
-    private val mockResults: Array<Array<Boolean>>,
-    benchmark: Benchmark,
-    results: Results,
-    slo: List<BenchmarkExecution.Slo>,
-    executionId: Int,
-    loadGenerationDelay: Long,
-    afterTeardownDelay: Long
+        private val mockResults: Array<Array<Boolean>>,
+        benchmark: Benchmark,
+        results: Results,
+        slo: List<Slo>,
+        executionId: Int,
+        loadGenerationDelay: Long,
+        afterTeardownDelay: Long
 ) :
     BenchmarkExecutor(
         benchmark,
@@ -27,12 +25,14 @@ class TestBenchmarkExecutorImpl(
         executionId = executionId,
         loadGenerationDelay = loadGenerationDelay,
         afterTeardownDelay = afterTeardownDelay,
-        executionName = "test-execution"
+        executionName = "test-execution",
+        loadPatcherDefinitions = emptyList(),
+        resourcePatcherDefinitions = emptyList()
     ) {
 
-    override fun runExperiment(load: LoadDimension, res: Resource): Boolean {
-        val result = this.mockResults[load.get()][res.get()]
-        this.results.setResult(Pair(load, res), result)
+    override fun runExperiment(load: Int, resource: Int): Boolean {
+        val result = this.mockResults[load][resource]
+        this.results.setResult(Pair(load, resource), result)
         return result
     }
 }
diff --git a/theodolite/src/test/kotlin/theodolite/benchmark/ResourceSetsTest.kt b/theodolite/src/test/kotlin/theodolite/benchmark/ResourceSetsTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b2ce9d73447961c56b121542a4c91822e3703e95
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/benchmark/ResourceSetsTest.kt
@@ -0,0 +1,133 @@
+package theodolite.benchmark
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
+import io.fabric8.kubernetes.api.model.ConfigMap
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder
+import io.fabric8.kubernetes.api.model.HasMetadata
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer
+import io.quarkus.test.junit.QuarkusTest
+import io.quarkus.test.kubernetes.client.KubernetesTestServer
+import io.quarkus.test.kubernetes.client.WithKubernetesTestServer
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import org.junit.jupiter.api.io.TempDir
+import theodolite.util.DeploymentFailedException
+import java.nio.file.Files
+import java.nio.file.Path
+
+@QuarkusTest
+@WithKubernetesTestServer
+internal class ResourceSetsTest {
+
+    @KubernetesTestServer
+    private lateinit var server: KubernetesServer
+
+    @TempDir
+    @JvmField
+    final var tempDir: Path? = null
+
+    private val objectMapper: ObjectMapper = ObjectMapper(YAMLFactory())
+
+    @BeforeEach
+    fun setUp() {
+        server.before()
+    }
+
+    @AfterEach
+    fun tearDown() {
+        server.after()
+    }
+
+    private fun deployAndGetResource(vararg resources: HasMetadata): ConfigMapResourceSet {
+        val configMap = ConfigMapBuilder()
+            .withNewMetadata().withName(resources[0].metadata.name).endMetadata()
+            .let {
+                resources.foldIndexed(it) { i, b, r ->
+                    b.addToData("resource_$i.yaml", objectMapper.writeValueAsString(r))
+                }
+            }
+            .build()
+
+        server.client.configMaps().createOrReplace(configMap)
+
+        val resourceSet = ConfigMapResourceSet()
+        resourceSet.name = resources[0].metadata.name
+
+        return resourceSet
+    }
+
+    private fun copyTestResourceFile(fileName: String, tempDir: Path) {
+        val stream = javaClass.getResourceAsStream("/k8s-resource-files/$fileName")
+            ?: throw IllegalArgumentException("File does not exist")
+        val target = tempDir.resolve(fileName)
+        Files.copy(stream, target)
+    }
+
+    @Test
+    fun testLoadConfigMap() {
+        val resource = ConfigMapBuilder()
+            .withNewMetadata()
+            .withName("test-configmap")
+            .endMetadata()
+            .build()
+        deployAndGetResource(resource)
+
+        val yamlString =
+            """
+            configMap:    
+                name: test-configmap
+                files:
+            """
+
+        val resourcesSet: ResourceSets = objectMapper.readValue(yamlString, ResourceSets::class.java)
+        assertTrue(resourcesSet.fileSystem == null)
+        assertTrue(resourcesSet.configMap != null)
+
+        val configMap = resourcesSet.loadResourceSet(server.client)
+        assertEquals(1, configMap.size)
+        assertTrue(configMap.toList().first().second is ConfigMap)
+        assertTrue(configMap.toList().first().second.toString().contains(other = resource.metadata.name))
+
+        assertEquals(configMap.elementAt(0).second, resource)
+    }
+
+    @Test
+    fun testLoadFileSystem(@TempDir tempDir: Path) {
+        copyTestResourceFile("test-deployment.yaml", tempDir)
+
+        val resourceSet = FileSystemResourceSet()
+        resourceSet.path = tempDir.toString()
+        resourceSet.files = listOf("test-deployment.yaml")
+        assertEquals(1, resourceSet.getResourceSet(server.client).size)
+
+        val yamlString =
+            """
+            fileSystem:    
+                path: ${resourceSet.path}
+                files:
+                    - test-deployment.yaml
+            """
+
+        val resourcesSet: ResourceSets = objectMapper.readValue(yamlString, ResourceSets::class.java)
+        assertTrue(resourcesSet.fileSystem != null)
+        assertTrue(resourcesSet.configMap == null)
+
+        val fileSystem = resourcesSet.loadResourceSet(server.client)
+        assertEquals(fileSystem.size, 1)
+        assertTrue(fileSystem.elementAt(0).second is HasMetadata)
+    }
+
+    @Test
+    fun testEmptyResourceSets() {
+        val resourceSet = ResourceSets()
+
+        assertThrows<DeploymentFailedException> {
+            resourceSet.loadResourceSet(server.client)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt
index cbddbfbfc5d6f838677c6d04b0a0c79f59d8bc66..152191bc271552dfb50c022c678a023ce0eb65cd 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/BenchmarkCRDummy.kt
@@ -20,11 +20,12 @@ class BenchmarkCRDummy(name: String) {
         kafkaConfig.bootstrapServer = ""
         kafkaConfig.topics = emptyList()
 
+
         benchmarkCR.spec = benchmark
         benchmarkCR.metadata.name = name
         benchmarkCR.kind = "Benchmark"
         benchmarkCR.apiVersion = "v1"
-
+        benchmark.waitForResourcesEnabled = false
 
         benchmark.infrastructure = Resources()
         benchmark.sut = Resources()
@@ -43,6 +44,7 @@ class BenchmarkCRDummy(name: String) {
 
         benchmark.resourceTypes = emptyList()
         benchmark.loadTypes = emptyList()
+        benchmark.slos = mutableListOf()
         benchmark.kafkaConfig = kafkaConfig
         benchmark.name = benchmarkCR.metadata.name
     }
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt
index 9274e283b48a6fd9b30d5ce0aff3cb8b995e0ce5..961c813f432d13fd2b373c74adaa00df4049a334 100644
--- a/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/ExecutionCRDummy.kt
@@ -36,16 +36,24 @@ class ExecutionCRDummy(name: String, benchmark: String) {
         resourceDef.resourceType = ""
         resourceDef.resourceValues = emptyList()
 
+        val strat = BenchmarkExecution.Strategy()
+        strat.name = ""
+        strat.restrictions = emptyList()
+        strat.guessStrategy = ""
+        strat.searchStrategy = ""
+
+
         val exec = BenchmarkExecution.Execution()
         exec.afterTeardownDelay = 0
         exec.duration = 0
         exec.loadGenerationDelay = 0
         exec.repetitions = 1
-        exec.restrictions = emptyList()
-        exec.strategy = ""
+        exec.metric = ""
+        exec.strategy = strat
+
 
         execution.benchmark = benchmark
-        execution.load = loadType
+        execution.loads = loadType
         execution.resources = resourceDef
         execution.slos = emptyList()
         execution.execution = exec
diff --git a/theodolite/src/test/kotlin/theodolite/execution/operator/SloFactoryTest.kt b/theodolite/src/test/kotlin/theodolite/execution/operator/SloFactoryTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c3dcd1b9529b6f24bd5b0deda920ba3e3ebb2978
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/execution/operator/SloFactoryTest.kt
@@ -0,0 +1,72 @@
+package theodolite.execution.operator
+
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.Test
+import theodolite.benchmark.BenchmarkExecution
+import theodolite.benchmark.BenchmarkExecution.SloConfiguration
+import theodolite.benchmark.KubernetesBenchmark
+import theodolite.benchmark.Slo
+import theodolite.execution.SloFactory
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class SloFactoryTest {
+
+    @Test
+    fun overwriteSloTest() {
+
+        val benchmark = KubernetesBenchmark()
+        val execution = BenchmarkExecution()
+
+        // Define Benchmark SLOs
+        val slo = Slo()
+        slo.name="test"
+        slo.sloType="lag trend"
+        slo.prometheusUrl="test.de"
+        slo.offset=0
+
+        val benchmarkSloProperties = mutableMapOf<String, String>()
+        benchmarkSloProperties["threshold"] = "2000"
+        benchmarkSloProperties["externalSloUrl"] = "http://localhost:80/evaluate-slope"
+        benchmarkSloProperties["warmup"] = "60"
+
+        slo.properties=benchmarkSloProperties
+
+        benchmark.slos = mutableListOf(slo)
+
+
+        // Define Execution SLOs, benchmark SLO values for these properties should be overwritten
+        val sloConfig = SloConfiguration()
+        sloConfig.name = "test"
+
+        val executionSloProperties = mutableMapOf<String, String>()
+        // overwriting properties 'threshold' and 'warmup' and adding property 'extensionTest'
+        executionSloProperties["threshold"] = "3000"
+        executionSloProperties["warmup"] = "80"
+        executionSloProperties["extensionTest"] = "extended"
+
+        sloConfig.properties = executionSloProperties
+
+        // SLO has 'name' that isn't defined in the benchmark, therefore it will be ignored by the SloFactory
+        val sloConfig2 = SloConfiguration()
+        sloConfig2.name = "test2"
+        sloConfig2.properties = executionSloProperties
+
+        execution.slos = listOf(sloConfig, sloConfig2)
+
+        val sloFactory = SloFactory()
+        val combinedSlos = sloFactory.createSlos(execution,benchmark)
+
+        assertEquals(1, combinedSlos.size)
+        assertEquals("test", combinedSlos[0].name)
+        assertEquals("lag trend", combinedSlos[0].sloType)
+        assertEquals("test.de", combinedSlos[0].prometheusUrl)
+        assertEquals(0, combinedSlos[0].offset)
+
+        assertEquals(4, combinedSlos[0].properties.size)
+        assertEquals("3000", combinedSlos[0].properties["threshold"])
+        assertEquals("http://localhost:80/evaluate-slope", combinedSlos[0].properties["externalSloUrl"])
+        assertEquals("80", combinedSlos[0].properties["warmup"])
+        assertEquals("extended", combinedSlos[0].properties["extensionTest"])
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/model/crd/CRDExecutionTest.kt b/theodolite/src/test/kotlin/theodolite/model/crd/CRDExecutionTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1150141ecc6a7147c930375af5bc965b81647e5a
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/model/crd/CRDExecutionTest.kt
@@ -0,0 +1,90 @@
+package theodolite.model.crd
+
+import io.fabric8.kubernetes.api.model.KubernetesResourceList
+import io.fabric8.kubernetes.client.dsl.MixedOperation
+import io.fabric8.kubernetes.client.dsl.Resource
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer
+import io.quarkus.test.junit.QuarkusTest
+import io.quarkus.test.kubernetes.client.KubernetesTestServer
+import io.quarkus.test.kubernetes.client.WithKubernetesTestServer
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.mockito.internal.matchers.apachecommons.ReflectionEquals
+import org.apache.commons.lang3.builder.EqualsBuilder
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.instanceOf
+import org.mockito.kotlin.isA
+import org.mockito.kotlin.mock
+import theodolite.benchmark.BenchmarkExecution
+import theodolite.execution.operator.*
+import theodolite.util.ConfigurationOverride
+import java.io.FileInputStream
+
+
+// TODO move somewhere else
+typealias ExecutionClient = MixedOperation<ExecutionCRD, KubernetesResourceList<ExecutionCRD>, Resource<ExecutionCRD>>
+
+@WithKubernetesTestServer
+@QuarkusTest
+internal class CRDExecutionTest {
+
+     @KubernetesTestServer
+     private lateinit var server: KubernetesServer
+
+     lateinit var executionClient: ExecutionClient
+
+     lateinit var controller: TheodoliteController
+
+     lateinit var stateHandler: ExecutionStateHandler
+
+     lateinit var eventHandler: ExecutionEventHandler
+
+     @BeforeEach
+     fun setUp() {
+          server.before()
+
+          this.server.client
+                  .apiextensions().v1()
+                  .customResourceDefinitions()
+                  .load(FileInputStream("crd/crd-execution.yaml"))
+                  .create()
+
+          this.executionClient = this.server.client.resources(ExecutionCRD::class.java)
+
+          this.controller = mock()
+          this.stateHandler = ExecutionStateHandler(server.client)
+          this.eventHandler = ExecutionEventHandler(this.controller, this.stateHandler)
+     }
+
+     @AfterEach
+     fun tearDown() {
+          server.after()
+     }
+
+     @Test
+     fun checkParsingCRDTest(){
+          // BenchmarkExecution from yaml
+          val execution = executionClient.load(ClassLoader.getSystemResourceAsStream("k8s-resource-files/test-execution.yaml")).create().spec
+
+          assertEquals(0, execution.executionId)
+          assertEquals("test", execution.name)
+          assertEquals("uc1-kstreams", execution.benchmark)
+          assertEquals(mutableListOf<ConfigurationOverride?>(), execution.configOverrides)
+
+          assertEquals("NumSensors", execution.loads.loadType)
+          assertEquals(listOf(25000, 50000, 75000, 100000, 125000, 150000),execution.loads.loadValues)
+
+          assertEquals("Instances", execution.resources.resourceType)
+          assertEquals(listOf(1, 2, 3, 4, 5), execution.resources.resourceValues)
+
+          assertEquals("demand", execution.execution.metric)
+          assertEquals(300, execution.execution.duration)
+          assertEquals(1, execution.execution.repetitions)
+
+          assertEquals("RestrictionSearch", execution.execution.strategy.name)
+          assertEquals("LinearSearch", execution.execution.strategy.searchStrategy)
+          assertEquals(listOf("LowerBound"), execution.execution.strategy.restrictions)
+     }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/AbstractPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/AbstractPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..05bb9588a2de5656b9c0b39d16d2160f691bbe91
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/AbstractPatcherTest.kt
@@ -0,0 +1,101 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.*
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.Test
+import theodolite.util.PatcherDefinition
+
+@QuarkusTest
+abstract class AbstractPatcherTest {
+
+    lateinit var resource: List<HasMetadata>
+    lateinit var patcher: Patcher
+    lateinit var value: String
+
+    fun createDeployment(): HasMetadata {
+        return DeploymentBuilder()
+            .withNewMetadata()
+                .withName("dummy")
+            .endMetadata()
+            .withNewSpec()
+                .withNewSelector()
+                    .withMatchLabels<String, String>(mapOf("labelName" to "labelValue"))
+                .endSelector()
+                    .withNewTemplate()
+                        .withNewMetadata()
+                            .withLabels<String, String>(mapOf("labelName" to "labelValue"))
+                        .endMetadata()
+                        .withNewSpec()
+                        .withContainers(
+                                ContainerBuilder()
+                                    .withName("container")
+                                    .withImage("test-image")
+                                    .build())
+                            .addNewVolume()
+                                .withName("test-volume")
+                                .withNewConfigMap()
+                                    .withName("test-configmap")
+                                .endConfigMap()
+                            .endVolume()
+                        .endSpec()
+                .endTemplate()
+            .endSpec()
+            .build()
+    }
+
+    fun createStateFulSet(): HasMetadata {
+        return StatefulSetBuilder()
+            .withNewMetadata()
+                .withName("dummy")
+            .endMetadata()
+            .withNewSpec()
+                .withNewSelector()
+                    .withMatchLabels<String, String>(mapOf("labelName" to "labelValue"))
+                .endSelector()
+                .withNewTemplate()
+                    .withNewMetadata()
+                        .withLabels<String, String>(mapOf("labelName" to "labelValue"))
+                    .endMetadata()
+                    .withNewSpec()
+                    .addNewVolume()
+                        .withName("test-volume")
+                            .withNewConfigMap()
+                                .withName("test-configmap")
+                            .endConfigMap()
+                        .endVolume()
+                    .endSpec()
+                .endTemplate()
+            .endSpec()
+            .build()
+    }
+
+    fun createService(): HasMetadata {
+        return ServiceBuilder()
+            .withNewMetadata()
+            .withName("dummy")
+            .endMetadata()
+            .build()
+    }
+
+    fun createConfigMap(): HasMetadata {
+        return ConfigMapBuilder()
+            .withNewMetadata()
+                .withName("dummy")
+            .endMetadata()
+            .withData<String, String>(mapOf("application.properties" to "propA = valueA"))
+            .build()
+    }
+
+    fun patch() {
+        resource = patcher.patch(resource, value)
+    }
+
+    @Test
+    abstract fun validate()
+
+
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e55767ea79f1925a3825aca11eb74a8641c17a90
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/DataVolumeLoadGeneratorReplicaPatcherTest.kt
@@ -0,0 +1,28 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class DataVolumeLoadGeneratorReplicaPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = VolumesConfigMapPatcher((resource.first() as Deployment).spec.template.spec.volumes[0].configMap.name)
+        value = "new-configMapName"
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assert((it as Deployment).spec.template.spec.volumes[0].configMap.name == value)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/EnvVarPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/EnvVarPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cc46347acf5b005ed05170fe27a40de3ca69599d
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/EnvVarPatcherTest.kt
@@ -0,0 +1,35 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.EnvVar
+import io.fabric8.kubernetes.api.model.EnvVarBuilder
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+
+@QuarkusTest
+internal class EnvVarPatcherTest : AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = EnvVarPatcher(variableName = "testEnv", container = "container")
+        value = "testValue"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        val envVar = EnvVarBuilder().withName("testEnv").withValue("testValue").build()
+        resource.forEach {
+        assertTrue((it as Deployment).spec.template.spec.containers[0].env.contains(envVar))
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ImagePatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ImagePatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6592f65934716bfd74d562c5a3fb52ddb40c8b86
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/ImagePatcherTest.kt
@@ -0,0 +1,32 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class ImagePatcherTest: AbstractPatcherTest(){
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = ImagePatcher(container = "container")
+        value = "testValue"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.template.spec.containers[0].image  == value)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/LabelPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/LabelPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..64583e4be67282543a44d09b36e657eede2f9eac
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/LabelPatcherTest.kt
@@ -0,0 +1,37 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class LabelPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = LabelPatcher("labelName")
+        value = "labelValue"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).metadata.labels.containsKey("labelName"))
+            assertTrue(it.metadata.labels.get("labelName")=="labelValue")
+        }
+    }
+
+    @Test
+    fun getVariableName() {
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/MatchLabelPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/MatchLabelPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..796f2ffeb6f4c22b9d00218b91f0fbe2ee9f6567
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/MatchLabelPatcherTest.kt
@@ -0,0 +1,37 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class MatchLabelPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = MatchLabelPatcher("labelName")
+        value = "labelValue"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.selector.matchLabels.containsKey("labelName"))
+            assertTrue(it.spec.selector.matchLabels.get("labelName")=="labelValue")
+        }
+    }
+
+    @Test
+    fun getVariableName() {
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/NamePatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/NamePatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5ae75c5b0dca038b8e351683bfd0ee2a40d217eb
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/NamePatcherTest.kt
@@ -0,0 +1,33 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class NamePatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = NamePatcher()
+        value = "newName"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            println(it.toString())
+            assertTrue(it.toString().contains("name=$value"))
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/NodeSelectorPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/NodeSelectorPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a042faf8484eb0ce7e1e21a6069be2beeff0b693
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/NodeSelectorPatcherTest.kt
@@ -0,0 +1,36 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+import org.mockito.kotlin.reset
+
+@QuarkusTest
+internal class NodeSelectorPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = NodeSelectorPatcher("nodeName")
+        value = "nodeValue"
+
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.template.spec.nodeSelector.containsKey("nodeName"))
+            assertTrue(it.spec.template.spec.nodeSelector["nodeName"] == value)
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6b2a639285b134c0efcaaf5b296f18779f4f8322
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/NumNestedGroupsLoadGeneratorReplicaPatcherTest.kt
@@ -0,0 +1,32 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class NumNestedGroupsLoadGeneratorReplicaPatcherTest : AbstractPatcherTest(){
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = NumNestedGroupsLoadGeneratorReplicaPatcher("10", "500")
+        value = "2"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.replicas == 1)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..50d122e60104ad0239824e5b4471ade8b3ff7bfb
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/NumSensorsLoadGeneratorReplicaPatcherTest.kt
@@ -0,0 +1,32 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class NumSensorsLoadGeneratorReplicaPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = NumSensorsLoadGeneratorReplicaPatcher("10")
+        value = "2"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.replicas == 1)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/PatcherDefinitionFactoryTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/PatcherDefinitionFactoryTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4696e646726f9ed6ad3e4c5cda1631ded42930e4
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/PatcherDefinitionFactoryTest.kt
@@ -0,0 +1,22 @@
+package theodolite.patcher
+
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+internal class PatcherDefinitionFactoryTest {
+
+    @BeforeEach
+    fun setUp() {
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    fun createPatcherDefinition() {
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/PatcherFactoryTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/PatcherFactoryTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1c3ecffa06f91d1d6c87706bb3fb28e94c414c35
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/PatcherFactoryTest.kt
@@ -0,0 +1,17 @@
+package theodolite.patcher
+
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+
+import org.junit.jupiter.api.Assertions.*
+
+internal class PatcherFactoryTest {
+
+    @BeforeEach
+    fun setUp() {
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ReplicaPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ReplicaPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0e01dead66509e40237952e4d65ea3a377943c5b
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/ReplicaPatcherTest.kt
@@ -0,0 +1,32 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class ReplicaPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = ReplicaPatcher()
+        value = "5"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.replicas == 5)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ResourceLimitPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ResourceLimitPatcherTest.kt
index 2769f2fef607a03d820b0821969db98894944cb3..b794ec6ed983dba92526aff67ecb3cab915871eb 100644
--- a/theodolite/src/test/kotlin/theodolite/patcher/ResourceLimitPatcherTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/patcher/ResourceLimitPatcherTest.kt
@@ -1,5 +1,6 @@
 package theodolite.patcher
 
+import io.fabric8.kubernetes.api.model.HasMetadata
 import io.fabric8.kubernetes.client.server.mock.KubernetesServer
 import io.quarkus.test.junit.QuarkusTest
 import io.quarkus.test.kubernetes.client.KubernetesTestServer
@@ -7,7 +8,6 @@ import io.quarkus.test.kubernetes.client.WithKubernetesTestServer
 import org.junit.jupiter.api.Assertions.assertTrue
 import org.junit.jupiter.api.Disabled
 import org.junit.jupiter.api.Test
-import theodolite.patcher.PatcherFactory
 import theodolite.util.PatcherDefinition
 
 /**
@@ -25,8 +25,6 @@ import theodolite.util.PatcherDefinition
 @Disabled
 class ResourceLimitPatcherTest {
 
-    val patcherFactory = PatcherFactory()
-
     @KubernetesTestServer
     private lateinit var server: KubernetesServer
 
@@ -51,15 +49,8 @@ class ResourceLimitPatcherTest {
             "container" to "uc-application"
         )
 
-        patcherFactory.createPatcher(
-            patcherDefinition = defCPU,
-            k8sResources = listOf(Pair("/cpu-memory-deployment.yaml", k8sResource))
-        ).patch(value = cpuValue)
-
-        patcherFactory.createPatcher(
-            patcherDefinition = defMEM,
-            k8sResources = listOf(Pair("/cpu-memory-deployment.yaml", k8sResource))
-        ).patch(value = memValue)
+        PatchHandler.patchResource(mutableMapOf(Pair("cpu-memory-deployment.yaml", listOf(k8sResource as HasMetadata))), defCPU, cpuValue)
+        PatchHandler.patchResource(mutableMapOf(Pair("cpu-memory-deployment.yaml", listOf(k8sResource as HasMetadata))), defMEM, memValue)
 
         k8sResource.spec.template.spec.containers.filter { it.name == defCPU.properties["container"]!! }
             .forEach {
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ResourceRequestPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ResourceRequestPatcherTest.kt
index dba91eb65d4474d38f64d7fdd7f7ab981f8eb30f..300397a96abd34f17f1a4a3d2b3c76e2d9da13ea 100644
--- a/theodolite/src/test/kotlin/theodolite/patcher/ResourceRequestPatcherTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/patcher/ResourceRequestPatcherTest.kt
@@ -25,8 +25,6 @@ class ResourceRequestPatcherTest {
     @KubernetesTestServer
     private lateinit var server: KubernetesServer
 
-    val patcherFactory = PatcherFactory()
-
     fun applyTest(fileName: String) {
         val cpuValue = "50m"
         val memValue = "3Gi"
@@ -48,14 +46,8 @@ class ResourceRequestPatcherTest {
             "container" to "application"
         )
 
-        patcherFactory.createPatcher(
-            patcherDefinition = defCPU,
-            k8sResources = listOf(Pair("/cpu-memory-deployment.yaml", k8sResource))
-        ).patch(value = cpuValue)
-        patcherFactory.createPatcher(
-            patcherDefinition = defMEM,
-            k8sResources = listOf(Pair("/cpu-memory-deployment.yaml", k8sResource))
-        ).patch(value = memValue)
+        PatchHandler.patchResource(mutableMapOf(Pair("/cpu-memory-deployment.yaml", listOf(k8sResource))), defCPU, cpuValue)
+        PatchHandler.patchResource(mutableMapOf(Pair("/cpu-memory-deployment.yaml", listOf(k8sResource))), defMEM, memValue)
 
         k8sResource.spec.template.spec.containers.filter { it.name == defCPU.properties["container"]!! }
             .forEach {
@@ -87,4 +79,4 @@ class ResourceRequestPatcherTest {
         // Case 4: In the given YAML declaration neither `Resource Request` nor `Request Limit` is defined
         applyTest("/no-resources-deployment.yaml")
     }
-}
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/SchedulerNamePatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/SchedulerNamePatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8b6f3e9b1371bce3e17cbbc6e399d425baffd699
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/SchedulerNamePatcherTest.kt
@@ -0,0 +1,32 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class SchedulerNamePatcherTest : AbstractPatcherTest(){
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = SchedulerNamePatcher()
+        value = "testScheduler"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.template.spec.schedulerName == value)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/ServiceSelectorPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/ServiceSelectorPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..caffb7eaf37c3930dbbb8a043ccd1cb7bbfd8d74
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/ServiceSelectorPatcherTest.kt
@@ -0,0 +1,22 @@
+package theodolite.patcher
+
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+internal class ServiceSelectorPatcherTest {
+
+    @BeforeEach
+    fun setUp() {
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    fun patch() {
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/TemplateLabelPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/TemplateLabelPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ebfe147e7b503defe14439fb1b954b9dd269ea3e
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/TemplateLabelPatcherTest.kt
@@ -0,0 +1,34 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class TemplateLabelPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = TemplateLabelPatcher( "labelName")
+        value = "labelValue"
+    }
+
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            assertTrue((it as Deployment).spec.template.metadata.labels.containsKey("labelName"))
+            assertTrue(it.spec.template.metadata.labels["labelName"] =="labelValue")
+        }
+    }
+
+    @Test
+    fun getVariableName() {
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/patcher/VolumesConfigMapPatcherTest.kt b/theodolite/src/test/kotlin/theodolite/patcher/VolumesConfigMapPatcherTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5628fd7c50336dc620dec79945c69fd9856a9c91
--- /dev/null
+++ b/theodolite/src/test/kotlin/theodolite/patcher/VolumesConfigMapPatcherTest.kt
@@ -0,0 +1,33 @@
+package theodolite.patcher
+
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+@QuarkusTest
+internal class VolumesConfigMapPatcherTest: AbstractPatcherTest() {
+
+    @BeforeEach
+    fun setUp() {
+        resource = listOf(createDeployment())
+        patcher = VolumesConfigMapPatcher("test-configmap")
+        value = "patchedVolumeName"
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    override fun validate() {
+        patch()
+        resource.forEach {
+            println((it as Deployment).spec.template.spec.volumes[0].configMap.name)
+            assertTrue((it as Deployment).spec.template.spec.volumes[0].configMap.name == value)
+        }
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt b/theodolite/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt
index b368647e314a4d803b444268c8218aefbee00ad4..e659d5f542910611af96d7eb6a68140ebd43065b 100644
--- a/theodolite/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/strategies/restriction/LowerBoundRestrictionTest.kt
@@ -4,22 +4,17 @@ import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Assertions.assertNotNull
 import org.junit.jupiter.api.Disabled
 import org.junit.jupiter.api.Test
-import theodolite.util.LoadDimension
-import theodolite.util.Resource
+import theodolite.strategies.Metric
 import theodolite.util.Results
 
 internal class LowerBoundRestrictionTest {
 
     @Test
     fun testNoPreviousResults() {
-        val results = Results()
+        val results = Results(Metric.from("demand"))
         val strategy = LowerBoundRestriction(results)
-        val load = buildLoadDimension(10000)
-        val resources = listOf(
-            buildResourcesDimension(1),
-            buildResourcesDimension(2),
-            buildResourcesDimension(3)
-        )
+        val load = 10000
+        val resources = listOf(1, 2, 3)
         val restriction = strategy.apply(load, resources)
 
         assertEquals(3, restriction.size)
@@ -28,17 +23,13 @@ internal class LowerBoundRestrictionTest {
 
     @Test
     fun testWithSuccessfulPreviousResults() {
-        val results = Results()
+        val results = Results(Metric.from("demand"))
         results.setResult(10000, 1, true)
         results.setResult(20000, 1, false)
         results.setResult(20000, 2, true)
         val strategy = LowerBoundRestriction(results)
-        val load = buildLoadDimension(30000)
-        val resources = listOf(
-            buildResourcesDimension(1),
-            buildResourcesDimension(2),
-            buildResourcesDimension(3)
-        )
+        val load = 30000
+        val resources = listOf(1, 2, 3)
         val restriction = strategy.apply(load, resources)
 
         assertEquals(2, restriction.size)
@@ -49,70 +40,54 @@ internal class LowerBoundRestrictionTest {
     @Disabled
     fun testWithNoSuccessfulPreviousResults() {
         // This test is currently not implemented this way, but might later be the desired behavior.
-        val results = Results()
+        val results = Results(Metric.from("demand"))
         results.setResult(10000, 1, true)
         results.setResult(20000, 1, false)
         results.setResult(20000, 2, false)
         results.setResult(20000, 3, false)
         val strategy = LowerBoundRestriction(results)
-        val load = buildLoadDimension(30000)
-        val resources = listOf(
-            buildResourcesDimension(1),
-            buildResourcesDimension(2),
-            buildResourcesDimension(3)
-        )
+        val load = 30000
+        val resources = listOf(1, 2, 3)
         val restriction = strategy.apply(load, resources)
 
         assertEquals(0, restriction.size)
-        assertEquals(emptyList<Resource>(), restriction)
+        assertEquals(emptyList<Int>(), restriction)
     }
 
 
     @Test
     fun testNoPreviousResults2() {
-        val results = Results()
+        val results = Results(Metric.from("demand"))
         results.setResult(10000, 1, true)
         results.setResult(20000, 2, true)
         results.setResult(10000, 1, false)
         results.setResult(20000, 2, true)
 
-        val minRequiredInstances = results.getMinRequiredInstances(LoadDimension(20000, emptyList()))
+        val minRequiredInstances = results.getOptYDimensionValue(20000)
 
         assertNotNull(minRequiredInstances)
-        assertEquals(2, minRequiredInstances!!.get())
+        assertEquals(2, minRequiredInstances!!)
     }
 
     @Test
     @Disabled
     fun testMinRequiredInstancesWhenNotSuccessful() {
         // This test is currently not implemented this way, but might later be the desired behavior.
-        val results = Results()
+        val results = Results(Metric.from("demand"))
         results.setResult(10000, 1, true)
         results.setResult(20000, 2, true)
         results.setResult(10000, 1, false)
         results.setResult(20000, 2, false)
 
-        val minRequiredInstances = results.getMinRequiredInstances(LoadDimension(20000, emptyList()))
+        val minRequiredInstances = results.getOptYDimensionValue(20000)
 
         assertNotNull(minRequiredInstances)
-        assertEquals(2, minRequiredInstances!!.get())
+        assertEquals(2, minRequiredInstances!!)
     }
 
-    private fun buildLoadDimension(load: Int): LoadDimension {
-        return LoadDimension(load, emptyList())
-    }
 
-    private fun buildResourcesDimension(resources: Int): Resource {
-        return Resource(resources, emptyList())
-    }
 
-    private fun Results.setResult(load: Int, resources: Int, successful: Boolean) {
-        this.setResult(
-            Pair(
-                buildLoadDimension(load),
-                buildResourcesDimension(resources)
-            ),
-            successful
-        )
+    private fun Results.setResult(load: Int, resource: Int, successful: Boolean) {
+        this.setResult(Pair(load, resource),successful)
     }
 }
diff --git a/theodolite/src/test/kotlin/theodolite/util/IOHandlerTest.kt b/theodolite/src/test/kotlin/theodolite/util/IOHandlerTest.kt
index 3b31f389bdeb35e6016a56a98abb1e13bf83ae18..cec18832ad99a01dc7977b64a19111f57f49d7f4 100644
--- a/theodolite/src/test/kotlin/theodolite/util/IOHandlerTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/util/IOHandlerTest.kt
@@ -69,14 +69,14 @@ internal class IOHandlerTest {
     fun testWriteToJSONFile() {
         temporaryFolder.create()
         val folder = temporaryFolder.newFolder(FOLDER_URL)
-        val testContent = Resource(0, emptyList())
+        val testContentResource = 0
 
         IOHandler().writeToJSONFile(
             fileURL = "${folder.absolutePath}/test-file.json",
-            objectToSave = testContent
+            objectToSave = testContentResource
         )
 
-        val expected = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create().toJson(testContent)
+        val expected = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create().toJson(testContentResource)
 
         assertEquals(
             expected,
diff --git a/theodolite/src/test/kotlin/theodolite/util/ResultsTest.kt b/theodolite/src/test/kotlin/theodolite/util/ResultsTest.kt
index 9cfc2ae78e7a8846e3f0fa136699509145e5de22..d453587a9aeeee1ad48cf750a614009ef6be9aff 100644
--- a/theodolite/src/test/kotlin/theodolite/util/ResultsTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/util/ResultsTest.kt
@@ -3,73 +3,89 @@ package theodolite.util
 import io.quarkus.test.junit.QuarkusTest
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Assertions.assertNotNull
-import org.junit.jupiter.api.Disabled
 import org.junit.jupiter.api.Test
+import theodolite.strategies.Metric
 
 @QuarkusTest
 internal class ResultsTest {
 
     @Test
-    fun testMinRequiredInstancesWhenSuccessful() {
-        val results = Results()
-        results.setResult(10000, 1, true)
-        results.setResult(10000, 2, true)
-        results.setResult(20000, 1, false)
-        results.setResult(20000, 2, true)
+    fun testMinRequiredInstancesWhenSuccessfulDemand() {
+        val results = Results(Metric.from("demand"))
+        results.setResult(Pair(10000, 1), true)
+        results.setResult(Pair(10000, 2), true)
+        results.setResult(Pair(20000, 1), false)
+        results.setResult(Pair(20000, 2), true)
 
-        val minRequiredInstances = results.getMinRequiredInstances(LoadDimension(20000, emptyList()))
+        val minRequiredInstances = results.getOptYDimensionValue(20000)
 
         assertNotNull(minRequiredInstances)
-        assertEquals(2, minRequiredInstances!!.get())
+        assertEquals(2, minRequiredInstances)
     }
 
     @Test
-    @Disabled
-    fun testMinRequiredInstancesWhenNotSuccessful() {
-        // This test is currently not implemented this way, but might later be the desired behavior.
-        val results = Results()
-        results.setResult(10000, 1, true)
-        results.setResult(10000, 2, true)
-        results.setResult(20000, 1, false)
-        results.setResult(20000, 2, false)
+    fun testGetMaxBenchmarkedLoadWhenAllSuccessfulDemand() {
+        val results = Results(Metric.from("demand"))
+        results.setResult(Pair(10000, 1), true)
+        results.setResult(Pair(10000, 2), true)
 
-        val minRequiredInstances = results.getMinRequiredInstances(LoadDimension(20000, emptyList()))
+        val test1 = results.getMaxBenchmarkedXDimensionValue(100000)
 
-        assertNotNull(minRequiredInstances)
-        assertEquals(2, minRequiredInstances!!.get())
+        assertNotNull(test1)
+        assertEquals(10000, test1)
+    }
+
+    @Test
+    fun testGetMaxBenchmarkedLoadWhenLargestNotSuccessfulDemand() {
+        val results = Results(Metric.from("demand"))
+        results.setResult(Pair(10000, 1), true)
+        results.setResult(Pair(10000, 2), true)
+        results.setResult(Pair(20000, 1), false)
+
+        val test2 = results.getMaxBenchmarkedXDimensionValue(100000)
+
+        assertNotNull(test2)
+        assertEquals(20000, test2)
     }
 
-    private fun Results.setResult(load: Int, resources: Int, successful: Boolean) {
-        this.setResult(
-            Pair(
-                LoadDimension(load, emptyList()),
-                Resource(resources, emptyList())
-            ),
-            successful
-        )
+    @Test
+    fun testMaxRequiredInstancesWhenSuccessfulCapacity() {
+        val results = Results(Metric.from("capacity"))
+        results.setResult(Pair(10000, 1), true)
+        results.setResult(Pair(20000, 1), false)
+        results.setResult(Pair(10000, 2), true)
+        results.setResult(Pair(20000, 2), true)
+
+        val maxRequiredInstances = results.getOptYDimensionValue(2)
+
+        assertNotNull(maxRequiredInstances)
+        assertEquals(20000, maxRequiredInstances)
     }
 
 
     @Test
-    fun testGetMaxBenchmarkedLoadWhenAllSuccessful() {
-        val results = Results()
-        results.setResult(10000, 1, true)
-        results.setResult(10000, 2, true)
+    fun testGetMaxBenchmarkedLoadWhenAllSuccessfulCapacity() {
+        val results = Results(Metric.from("capacity"))
+        results.setResult(Pair(10000, 1), true)
+        results.setResult(Pair(10000, 2), true)
 
-        val test1 = results.getMaxBenchmarkedLoad(LoadDimension(100000, emptyList()))!!.get()
+        val test1 = results.getMaxBenchmarkedXDimensionValue(5)
 
-        assertEquals(10000, test1)
+        assertNotNull(test1)
+        assertEquals(2, test1)
     }
 
     @Test
-    fun testGetMaxBenchmarkedLoadWhenLargestNotSuccessful() {
-        val results = Results()
-        results.setResult(10000, 1, true)
-        results.setResult(10000, 2, true)
-        results.setResult(20000, 1, false)
+    fun testGetMaxBenchmarkedLoadWhenLargestNotSuccessfulCapacity() {
+        val results = Results(Metric.from("capacity"))
+        results.setResult(Pair(10000, 1), true)
+        results.setResult(Pair(20000, 1), true)
+        results.setResult(Pair(10000, 2), false)
 
-        val test2 = results.getMaxBenchmarkedLoad(LoadDimension(100000, emptyList()))!!.get()
 
-        assertEquals(20000, test2)
+        val test2 = results.getMaxBenchmarkedXDimensionValue(5)
+
+        assertNotNull(test2)
+        assertEquals(2, test2)
     }
 }
diff --git a/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml b/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml
index ea9ee8471d3da1dc6011348bd978696bd0fa6f36..ad26f6c658c72231887a8e3cd4c5dc17cc787641 100644
--- a/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml
+++ b/theodolite/src/test/resources/k8s-resource-files/test-benchmark.yaml
@@ -3,6 +3,7 @@ kind: benchmark
 metadata:
   name: example-benchmark
 spec:
+  waitForResourcesEnabled: false
   sut:
     resources:
       - configMap:
@@ -33,6 +34,15 @@ spec:
           resource: "uc1-load-generator-deployment.yaml"
           properties:
             loadGenMaxRecords: "15000"
+  slos:
+    - name: "lag trend"
+      sloType: "lag trend"
+      prometheusUrl: "http://prometheus-operated:9090"
+      offset: 0
+      properties:
+        threshold: 3000
+        externalSloUrl: "http://localhost:80/evaluate-slope"
+        warmup: 60 # in seconds
   kafkaConfig:
     bootstrapServer: "theodolite-kafka-kafka-bootstrap:9092"
     topics:
diff --git a/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml b/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml
index 1407a9952b7454053d204454841d51cfb4d7dbf4..077c4ab410e3fc78a9bb47c563c2b237b922c1ba 100644
--- a/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml
+++ b/theodolite/src/test/resources/k8s-resource-files/test-execution-1.yaml
@@ -5,24 +5,26 @@ metadata:
 spec:
   name: test
   benchmark: "uc1-kstreams"
-  load:
+  loads:
     loadType: "NumSensors"
     loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
   resources:
     resourceType: "Instances"
     resourceValues: [1, 2, 3, 4, 5]
   slos:
-    - sloType: "lag trend"
+    - name: "lag trend"
       threshold: 2000
       prometheusUrl: "http://prometheus-operated:9090"
       externalSloUrl: "http://localhost:80/evaluate-slope"
       offset: 0
       warmup: 60 # in seconds
   execution:
-    strategy: "LinearSearch"
+    strategy:
+      name: "RestrictionSearch"
+      restrictions:
+        - "LowerBound"
+      searchStrategy: "LinearSearch"
     duration: 300 # in seconds
     repetitions: 1
     loadGenerationDelay: 30 # in seconds
-    restrictions:
-      - "LowerBound"
   configOverrides: []
diff --git a/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml b/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml
index c075702da218397352f1dc1e5b283534fbb4d718..504a73fe3b325368301897cacdc922e7f6e70430 100644
--- a/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml
+++ b/theodolite/src/test/resources/k8s-resource-files/test-execution-update.yaml
@@ -5,25 +5,23 @@ metadata:
 spec:
   name: test
   benchmark: "uc1-kstreams-update"
-  load:
+  loads:
     loadType: "NumSensors"
     loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
   resources:
     resourceType: "Instances"
     resourceValues: [1, 2, 3, 4, 5]
   slos:
-    - sloType: "lag trend"
-      prometheusUrl: "http://prometheus-operated:9090"
-      offset: 0
+    - name: "lag trend"
       properties:
         threshold: 2000
-        externalSloUrl: "http://localhost:80/evaluate-slope"
-        warmup: 60 # in seconds
   execution:
-    strategy: "LinearSearch"
+    strategy:
+      name: "RestrictionSearch"
+      restrictions:
+        - "LowerBound"
+      searchStrategy: "LinearSearch"
     duration: 300 # in seconds
     repetitions: 1
     loadGenerationDelay: 30 # in seconds
-    restrictions:
-      - "LowerBound"
   configOverrides: []
diff --git a/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml b/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml
index e12c851da5d8a79f57b1fa59b86239c219370c0f..2bd0bfc4b3602c52fc3cc5cce9729777c21f4ac4 100644
--- a/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml
+++ b/theodolite/src/test/resources/k8s-resource-files/test-execution.yaml
@@ -5,25 +5,23 @@ metadata:
 spec:
   name: test
   benchmark: "uc1-kstreams"
-  load:
+  loads:
     loadType: "NumSensors"
     loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
   resources:
     resourceType: "Instances"
     resourceValues: [1, 2, 3, 4, 5]
   slos:
-    - sloType: "lag trend"
-      prometheusUrl: "http://prometheus-operated:9090"
-      offset: 0
+    - name: "lag trend"
       properties:
         threshold: 2000
-        externalSloUrl: "http://localhost:80/evaluate-slope"
-        warmup: 60 # in seconds
   execution:
-    strategy: "LinearSearch"
+    strategy:
+      name: "RestrictionSearch"
+      restrictions:
+        - "LowerBound"
+      searchStrategy: "LinearSearch"
     duration: 300 # in seconds
     repetitions: 1
     loadGenerationDelay: 30 # in seconds
-    restrictions:
-      - "LowerBound"
   configOverrides: []