Commit 90e40ef8 authored by Maria C's avatar Maria C Committed by Alicja Reniewicz
Browse files

Add Functionizer Testing Tool

parent 124fe50f
......@@ -53,6 +53,9 @@ variables:
METASOLVER_CLI: "mvn --batch-mode -N -Dmaven.test.skip=$SKIP_TESTS -Ddocker.push=false -f meta_solver/pom.xml"
MQ_ADAPTER_CLI: "mvn --batch-mode -N -Dmaven.test.skip=$SKIP_TESTS -Ddocker.push=false -f mq-http-adapter/pom.xml"
GUI_BACKEND_CLI: "mvn --batch-mode -N -Dmaven.test.skip=$SKIP_TESTS -Ddocker.push=false -f gui-backend/pom.xml"
FUNCTIONIZER_TESTING_TOOL_CLI: "mvn --batch-mode -N -Dmaven.test.skip=$SKIP_TESTS -Ddocker.push=false -f functionizer-testing-tool/pom.xml"
cache:
paths:
- maven_repo/
......@@ -737,3 +740,18 @@ deploy:gui-backend:
- echo "$K8S_SECRET_DOCKER_PASSWORD" | docker login $CI_REGISTRY -u $K8S_SECRET_DOCKER_USER --password-stdin
- docker tag $LOCAL_REPO/melodic/gui-backend:unknown $CI_REGISTRY_IMAGE/gui-backend:$CI_COMMIT_BRANCH
- docker push $CI_REGISTRY_IMAGE/gui-backend:$CI_COMMIT_BRANCH
deploy:functionizer-testing-tool:
stage: deploy
only:
- master
- rc3.0
- rc3.1
image: $DOCKER_DIND_IMAGE
services:
- $DOCKER_DIND_SERVICE
script:
- $DOCKER_CLI $FUNCTIONIZER_TESTING_TOOL_CLI -Ddocker.imagePrefix=melodic/ clean install
- echo "$K8S_SECRET_DOCKER_PASSWORD" | docker login $CI_REGISTRY -u $K8S_SECRET_DOCKER_USER --password-stdin
- docker tag $LOCAL_REPO/melodic/functionizer-testing-tool:unknown $CI_REGISTRY_IMAGE/functionizer-testing-tool:$CI_COMMIT_BRANCH
- docker push $CI_REGISTRY_IMAGE/functionizer-testing-tool:$CI_COMMIT_BRANCH
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<artifactId>upperware</artifactId>
<groupId>org.ow2.paasage</groupId>
<version>3.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>eu.functionizer</groupId>
<artifactId>functionizer-testing-tool</artifactId>
<name>Upperware - Functionizer testing tool</name>
<properties>
<java.version>1.8</java.version>
<cdo.version>3.1.0-SNAPSHOT</cdo.version>
<upperware.version>3.1.0-SNAPSHOT</upperware.version>
<!--DOCKER plugin properties-->
<docker.imageName>functionizer-testing-tool</docker.imageName>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
</dependency>
<dependency>
<groupId>org.ow2.paasage</groupId>
<artifactId>melodic-commons</artifactId>
</dependency>
<dependency>
<groupId>org.ow2.paasage</groupId>
<artifactId>jwt-commons</artifactId>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>1.11.327</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-lambda</artifactId>
<version>1.11.327</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-mgmt-resources</artifactId>
<version>1.33.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure</artifactId>
<version>1.33.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-cloudfunctions</artifactId>
<version>v1-rev20200219-1.30.9</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-reporting</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>io.github.cloudiator.client</groupId>
<artifactId>java-rest</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--docker image building plugins start-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
</plugin>
<!--docker image building plugins end-->
</plugins>
</build>
</project>
FROM java:8-alpine
VOLUME /tmp
ADD functionizer-testing-tool.jar functionizer-testing-tool.jar
RUN /bin/sh -c "apk add --no-cache bash"
RUN bash -c 'touch /functionizer-testing-tool.jar'
COPY ./run.sh .
RUN bash -c 'chmod +rx run.sh'
ENTRYPOINT ["./run.sh"]
#!/bin/sh
/config/wait-for-cdo.sh && java \
-Duser.timezone=Europe/Warsaw \
-Djava.security.egd=file:/dev/./urandom \
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 \
-jar functionizer-testing-tool.jar
package eu.functionizer.functionizertestingtool;
import eu.paasage.upperware.security.authapi.properties.MelodicSecurityProperties;
import eu.passage.upperware.commons.cloudiator.CloudiatorProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties({CloudiatorProperties.class, MelodicSecurityProperties.class})
public class FunctionizerTestingToolApplication {
public static void main(String[] args) {
SpringApplication.run(FunctionizerTestingToolApplication.class, args);
}
}
package eu.functionizer.functionizertestingtool;
import eu.functionizer.functionizertestingtool.model.FunctionizerTestResult;
import eu.functionizer.functionizertestingtool.service.TestRunner;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class FunctionizerTestingToolController {
private TestRunner testRunner;
@RequestMapping("/")
@ResponseStatus(HttpStatus.OK)
public String index() {
return "Welcome to the Functionizer testing tool!";
}
@GetMapping(value = "/health")
@ResponseStatus(HttpStatus.OK)
public void health() {
}
@PostMapping("/test")
@ResponseStatus(HttpStatus.OK)
public FunctionizerTestResult runTests() {
return testRunner.runTests();
}
}
package eu.functionizer.functionizertestingtool;
import eu.paasage.upperware.security.authapi.properties.MelodicSecurityProperties;
import eu.paasage.upperware.security.authapi.token.JWTService;
import eu.paasage.upperware.security.authapi.token.JWTServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TestingToolContext {
@Bean
public JWTService jWTService(MelodicSecurityProperties melodicSecurityProperties) {
return new JWTServiceImpl(melodicSecurityProperties);
}
}
package eu.functionizer.functionizertestingtool;
import eu.paasage.upperware.security.authapi.JWTAuthorizationFilter;
import eu.paasage.upperware.security.authapi.token.JWTService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
@Slf4j
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WebSecurity extends WebSecurityConfigurerAdapter {
private final JWTService jwtService;
@Value("${melodic.security.enabled:true}")
private boolean securityEnabled;
@Override
protected void configure(HttpSecurity http) throws Exception {
if (securityEnabled) {
log.info("Running WITH security");
http.cors().and().csrf().disable().authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthorizationFilter(authenticationManager(), jwtService))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
} else {
log.info("Running WITHOUT security");
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated();
}
}
}
package eu.functionizer.functionizertestingtool.model;
import io.github.cloudiator.rest.model.Function;
import io.github.cloudiator.rest.model.NodeCandidate;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@AllArgsConstructor
@Getter
@Setter
public class CloudiatorData {
private Map<String, Function> deployedFunctions;
private Map<String, String> functionDeployNames;
private Map<String, NodeCandidate> nodeCandidates;
private Map<String, String> userSecrets;
}
package eu.functionizer.functionizertestingtool.model;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class FunctionTestResult {
private String functionName;
private double duration;
private Long passed;
private Long failed;
private Long ignored;
private List<TestCaseResult> testCaseResults;
private TestResultEnum overallResult;
private String failedAtStage;
private String message;
public FunctionTestResult(String functionName) {
this.functionName = functionName;
this.testCaseResults = new ArrayList<>();
this.passed = 0L;
this.failed = 0L;
this.ignored = 0L;
this.overallResult = TestResultEnum.SUCCESS;
}
public void addTestCaseResult(TestCaseResult testCaseResult) {
this.testCaseResults.add(testCaseResult);
TestResultEnum result = testCaseResult.getResult();
if (result == TestResultEnum.SUCCESS) {
this.passed += 1;
} else if (result == TestResultEnum.FAILURE){
this.failed += 1;
} else if (result == TestResultEnum.IGNORED) {
this.ignored += 1;
}
updateOverallResult();
}
private void updateOverallResult() {
if (this.overallResult == TestResultEnum.PARTIAL_FAILURE
|| this.overallResult == TestResultEnum.IGNORED) {
return;
}
if (this.failed == 0L && this.ignored == 0L) {
this.overallResult = TestResultEnum.SUCCESS;
} else if (this.passed == 0L) {
this.overallResult = TestResultEnum.FAILURE;
} else {
this.overallResult = TestResultEnum.PARTIAL_FAILURE;
}
}
}
package eu.functionizer.functionizertestingtool.model;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class FunctionizerTestResult {
private List<FunctionTestResult> functionTestResults;
private TestResultEnum testsRunResult;
private String failedAtStage;
private String message;
private double duration;
public FunctionizerTestResult() {
this.functionTestResults = new ArrayList<>();
}
public void addFunctionTestResult(FunctionTestResult functionTestResult) {
this.functionTestResults.add(functionTestResult);
}
}
package eu.functionizer.functionizertestingtool.model;
public class ReportEntryKey {
public final static String EVENT = "event";
public final static String EXPECTED_OUTPUT = "expectedOutput";
public final static String IGNORED = "ignored";
public final static String ROOT = "root";
public final static String STAGE = "stage";
public final static String FAILURE_CAUSE = "failureCause";
}
package eu.functionizer.functionizertestingtool.model;
import lombok.Data;
@Data
public class TestCaseResult {
private String event;
private String expectedOutput;
private String actualOutput;
private String message;
private TestResultEnum result;
private double duration;
}
package eu.functionizer.functionizertestingtool.model;
import org.junit.platform.engine.TestExecutionResult;
public enum TestResultEnum {
SUCCESS,
PARTIAL_FAILURE,
IGNORED,
FAILURE;
public static TestResultEnum fromTestExecutionResult(TestExecutionResult result) {
if (result.getStatus() == TestExecutionResult.Status.SUCCESSFUL) {
return SUCCESS;
} else {
return FAILURE;
}
}
}
package eu.functionizer.functionizertestingtool.service;
import eu.functionizer.functionizertestingtool.model.FunctionizerTestResult;
import eu.functionizer.functionizertestingtool.service.test.FunctionizerReportData;
import eu.functionizer.functionizertestingtool.service.test.FunctionizerTestListener;
import eu.functionizer.functionizertestingtool.service.test.ServerlessFunctionTestFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.TestPlan;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
@Service
@Slf4j
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class TestRunner {
public FunctionizerTestResult runTests() {
log.debug("Initiating Test Launcher");
Launcher launcher = LauncherFactory.create();
log.debug("Collecting test classes");
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(ServerlessFunctionTestFactory.class))
.build();
TestPlan testPlan = launcher.discover(request);
log.debug("Initiating Listener");
FunctionizerTestListener listener = new FunctionizerTestListener();
log.debug("Registering Listener");
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
log.info("Generating Report");
FunctionizerReportData report = listener.getReport();
log.info("Test run ended");
return report.getTestResult();
}
}
package eu.functionizer.functionizertestingtool.service.provider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.lambda.AWSLambda;
import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
import com.amazonaws.services.lambda.model.InvokeRequest;
import com.amazonaws.services.lambda.model.InvokeResult;
import eu.functionizer.functionizertestingtool.model.ReportEntryKey;
import eu.functionizer.functionizertestingtool.service.test.Stage;
import eu.passage.upperware.commons.model.testing.FunctionTestConfiguration;
import eu.passage.upperware.commons.model.testing.TestCase;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DynamicNode;