Skip to content

Commit

Permalink
Add template tester (#175)
Browse files Browse the repository at this point in the history
* Add template testerscript and workflow

* Toggle template tester

* Add missing dependency

* Use the correct templates path

* Test

* Test

* Test

* Uncomment relevant section

* Test

* Fix Gradle template

* Install CCom in workflow

* Fix Spring Maven

* Add Docker prune every five stacks

* Skip Rocket

* Skip FaunaDB

* Reduce log lines

* Skip Gitea

* Skip Gitlab service

* Remove workflow push trigger
  • Loading branch information
marcauberer committed Oct 16, 2021
1 parent d1587db commit e831474
Show file tree
Hide file tree
Showing 21 changed files with 265 additions and 19 deletions.
80 changes: 80 additions & 0 deletions .github/scripts/service-tester/predefined-service-tester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""Script to test all combinations of predefined service templates"""

from os.path import isdir, join
from os import listdir, system, remove
import sys
import itertools
import yaml

MAX_COMBINATION_SIZE = 1 # Careful! Runtime increases exponentially
TEMPLATES_PATH = "../../../predefined-services"
BIN_PATH = "../../../bin"

def get_all_template_names():
"""Returns a string array with all existing template names"""

template_tuples = []
template_types = ["backend", "database", "db-admin", "frontend"]
skipped_names = ["rocket", "faunadb", "gitea", "gitlab"]
for template_type in template_types:
template_type_path = TEMPLATES_PATH + '/' + template_type
services = [f for f in listdir(template_type_path) if isdir(join(template_type_path, f))]
for service in services:
if service not in skipped_names:
template_tuples.append((service, template_type))

return template_tuples

def test_combination(comb):
"""Tests one particular combination of services"""
# Create config file
services = []
for service in comb:
services.append({"name": service[0], "type": service[1]})
config = {"project_name": "Example project", "services": services}
with open(BIN_PATH + "/config.yml", "w", encoding='utf-8') as file:
yaml.dump(config, file, default_flow_style=False)

# Execute Compose Generator with the config file
if system(f"cd {BIN_PATH} && compose-generator -c config.yml -i") != 0:
sys.exit("Compose Generator failed when generating stack for combination " + str(comb))

# Delete config file
remove(BIN_PATH + "/config.yml")

# Execute Compose Generator with the config file
if system(f"cd {BIN_PATH} && docker compose up -d") != 0:
sys.exit("Docker failed when generating stack for combination " + str(comb))

if system(f"cd {BIN_PATH} && docker compose down") != 0:
sys.exit("Error on 'docker compose down' for " + str(comb))

def reset_environment():
"""Deletes all Docker related stuff. Should be executed after each test"""
system("docker system prune -af > /dev/null")
system(f"sudo rm -rf {BIN_PATH}/*")

# Initially reset the testing environment
print("Do initial cleanup ...", end='')
reset_environment()
print(" done")

# Find all possible template combinations
print("Collecting template names ...", end='')
templates = get_all_template_names()
combinations = []
for i in range(1, MAX_COMBINATION_SIZE +1):
combinations.extend(list(itertools.combinations(templates, i)))
print(" done")
print(combinations)

# Execute test for each combination
print("Execute tests ...")
for i, combination in enumerate(combinations):
print(f"Testing combination {i+1} of {len(combinations)}: {str(combination)} ...")
test_combination(combination)
reset_environment()
print("Done")

# Test was successful
print("Tested all combinations successfully!")
1 change: 1 addition & 0 deletions .github/scripts/service-tester/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pyyaml
21 changes: 13 additions & 8 deletions .github/scripts/service-validator/predefined-service-validator.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""Script to validate the files of all predefined service templates"""

from os.path import isfile, isdir, join
from os import listdir
from cerberus import Validator
import sys
import yaml
import json
from cerberus import Validator
import yaml

def checkFileExistence():
def check_file_existence():
"""Checks if all required files exist"""
print('Checking file existence ...', end='')
status = True
template_path = '../../../predefined-services'
Expand All @@ -30,7 +33,8 @@ def checkFileExistence():
print(' done')
return status

def checkYamlValidity():
def check_yaml_validity():
"""Checks the validity of a YAML file"""
print('Checking YAML validity ...', end='')
status = True
schema = eval(open('./service-schema.py').read())
Expand All @@ -49,7 +53,8 @@ def checkYamlValidity():
print(' done')
return status

def checkJsonValidity():
def check_json_validity():
"""Checks the validity of a JSON file"""
print('Checking JSON validity ...', end='')
status = True
schema = eval(open('./config-schema.py').read())
Expand Down Expand Up @@ -83,9 +88,9 @@ def loadJsonDoc(path):
raise exception

# Execute checks
if not checkFileExistence():
if not check_file_existence():
sys.exit('File existence check failed.')
if not checkYamlValidity():
if not check_yaml_validity():
sys.exit('Yaml validation check failed.')
if not checkJsonValidity():
if not check_json_validity():
sys.exit('Json validation check failed.')
47 changes: 47 additions & 0 deletions .github/workflows/service-testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Predefined service testing
name: Service testing

on:
pull_request:
paths:
- predefined-services/**
branches:
- main
- release/**

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.17.x

- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x

- name: Prepare environment.env
working-directory: .github/scripts/service-tester
run: pip install -r requirements.txt

- name: Install CCom
run: |
curl -fsSL https://server.chillibits.com/files/repo/gpg | sudo apt-key add -
sudo add-apt-repository "deb https://admin.repo.chillibits.com/repository/ubuntu-$(lsb_release -cs) $(lsb_release -cs) main"
sudo apt-get update
sudo apt-get install ccom
- name: Install CG
run: ./install.sh

- name: Run testing script
working-directory: .github/scripts/service-tester
run: python predefined-service-tester.py
env:
COMPOSE_GENERATOR_CI: 1
4 changes: 2 additions & 2 deletions .github/workflows/service-validation.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Predefined service validation

name: Service validation

on:
Expand All @@ -25,7 +24,8 @@ jobs:
python-version: 3.x

- name: Prepare environment.env
run: pip install -r ./.github/scripts/service-validator/requirements.txt
working-directory: .github/scripts/service-validator
run: pip install -r requirements.txt

- name: Run validation script
working-directory: .github/scripts/service-validator
Expand Down
4 changes: 2 additions & 2 deletions media/example-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ project_name: Test
compose_version: 3.8
production_ready: true
services:
- service: angular
- name: angular
type: frontend
params:
ANGULAR_SOURCE_DIRECTORY: ./frontend-angular
ANGULAR_PORT: 81
- service: spring-maven
- name: spring-maven
type: backend
params:
SPRING_MAVEN_SOURCE_DIRECTORY: ./backend-spring
Expand Down
4 changes: 2 additions & 2 deletions predefined-services/backend/rocket/backend-rocket/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM rust:${{ROCKET_RUST_VERSION}} as builder
WORKDIR /usr/src/${{ROCKET_APP_NAME}}
WORKDIR /usr/src

RUN rustup default nightly
RUN rustup override set nightly
Expand All @@ -9,4 +9,4 @@ RUN cargo install --path .

FROM debian:buster-slim
COPY --from=builder /usr/local/cargo/bin/${{ROCKET_APP_NAME}} /usr/local/bin/${{ROCKET_APP_NAME}}
CMD ["${{ROCKET_APP_NAME}}"]
CMD [ "${{ROCKET_APP_NAME}}" ]
4 changes: 3 additions & 1 deletion predefined-services/backend/rocket/backend-rocket/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ fn index() -> &'static str {
}

fn main() {
rocket::ignite().mount("/", routes![index]).launch();
rocket::ignite()
.mount("/", routes![index])
.launch();
}
2 changes: 1 addition & 1 deletion predefined-services/backend/rocket/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
{
"text": "Which version of Rust do you want to use?",
"type": 2,
"defaultValue": "1.54",
"defaultValue": "1.55",
"variable": "ROCKET_RUST_VERSION"
}
],
Expand Down
2 changes: 1 addition & 1 deletion predefined-services/backend/spring-gradle/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"preselected": "false",
"proxied": true,
"demoAppInitCmd": [
"curl https://start.spring.io/starter.zip -d applicationName=${{PROJECT_NAME}} -d packageName=${{SPRING_GRADLE_PACKAGE_NAME}} -d dependencies=${{SPRING_GRADLE_DEPENDENCIES}} -d type=gradle-project -d language=${{SPRING_GRADLE_LANGUAGE}} -d bootVersion=${{SPRING_GRADLE_VERSION}} -o ${{SPRING_GRADLE_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip",
"curl https://start.spring.io/starter.zip -d applicationName=$(echo ${{PROJECT_NAME_CONTAINER}} | tr -s '-' '_') -d packageName=${{SPRING_GRADLE_PACKAGE_NAME}} -d dependencies=${{SPRING_GRADLE_DEPENDENCIES}} -d type=gradle-project -d language=${{SPRING_GRADLE_LANGUAGE}} -d bootVersion=${{SPRING_GRADLE_VERSION}} -o ${{SPRING_GRADLE_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip",
"unzip -o -q ${{SPRING_GRADLE_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip -d ${{SPRING_GRADLE_SOURCE_DIRECTORY}}",
"rm ${{SPRING_GRADLE_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip"
],
Expand Down
2 changes: 1 addition & 1 deletion predefined-services/backend/spring-maven/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"preselected": "false",
"proxied": true,
"demoAppInitCmd": [
"curl https://start.spring.io/starter.zip -d applicationName=${{PROJECT_NAME}} -d packageName=${{SPRING_MAVEN_PACKAGE_NAME}} -d dependencies=${{SPRING_MAVEN_DEPENDENCIES}} -d language=${{SPRING_MAVEN_LANGUAGE}} -d bootVersion=${{SPRING_MAVEN_VERSION}} -o ${{SPRING_MAVEN_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip",
"curl https://start.spring.io/starter.zip -d applicationName=$(echo ${{PROJECT_NAME_CONTAINER}} | tr -s '-' '_') -d packageName=${{SPRING_MAVEN_PACKAGE_NAME}} -d dependencies=${{SPRING_MAVEN_DEPENDENCIES}} -d language=${{SPRING_MAVEN_LANGUAGE}} -d bootVersion=${{SPRING_MAVEN_VERSION}} -o ${{SPRING_MAVEN_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip",
"unzip -q ${{SPRING_MAVEN_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip -d ${{SPRING_MAVEN_SOURCE_DIRECTORY}}",
"rm ${{SPRING_MAVEN_SOURCE_DIRECTORY}}/${{PROJECT_NAME_CONTAINER}}.zip"
],
Expand Down
Empty file.
14 changes: 14 additions & 0 deletions src/pass/generate/gen_choose_backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ func GenerateChooseBackends(
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.ProxyQuestions {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.Volumes {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
// Add template to selected templates
selected.BackendServices = append(selected.BackendServices, template)
break
Expand Down
14 changes: 14 additions & 0 deletions src/pass/generate/gen_choose_databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ func GenerateChooseDatabases(
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.ProxyQuestions {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.Volumes {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
// Add template to selected templates
selected.DatabaseServices = append(selected.DatabaseServices, template)
break
Expand Down
14 changes: 14 additions & 0 deletions src/pass/generate/gen_choose_db_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ func GenerateChooseDbAdmins(
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.ProxyQuestions {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.Volumes {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
// Add template to selected templates
selected.DbAdminServices = append(selected.DbAdminServices, template)
break
Expand Down
14 changes: 14 additions & 0 deletions src/pass/generate/gen_choose_frontends.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ func GenerateChooseFrontends(
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.ProxyQuestions {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.Volumes {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
// Add template to selected templates
selected.FrontendServices = append(selected.FrontendServices, template)
break
Expand Down
7 changes: 7 additions & 0 deletions src/pass/generate/gen_choose_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ func GenerateChooseProxies(
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.Volumes {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
// Add template to selected templates
selected.ProxyService = append(selected.ProxyService, template)
break
Expand Down
7 changes: 7 additions & 0 deletions src/pass/generate/gen_choose_tls_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ func GenerateChooseTlsHelpers(
project.Vars[question.Variable] = question.DefaultValue
}
}
for _, question := range template.Volumes {
if value, ok := selectedConfig.Params[question.Variable]; ok {
project.Vars[question.Variable] = value
} else {
project.Vars[question.Variable] = question.DefaultValue
}
}
// Add template to selected templates
selected.TlsHelperService = append(selected.TlsHelperService, template)
break
Expand Down
5 changes: 5 additions & 0 deletions src/util/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ func IsDockerizedEnvironment() bool {
return getEnv("COMPOSE_GENERATOR_DOCKERIZED") == "1"
}

// IsCIEnvironment checks if Compose Generator runs within a CI environment
func IsCIEnvironment() bool {
return getEnv("COMPOSE_GENERATOR_CI") == "1"
}

// GetUsername returns the username of the current username. If it is not determinable it returns "unknown"
func GetUsername() string {
if user, err := currentUser(); err == nil {
Expand Down

0 comments on commit e831474

Please sign in to comment.