Add some tests...
Not very efficient to make this after development, but at least I can ensure that some basic stuffs are checked.
This commit is contained in:
@@ -21,22 +21,40 @@ type Parser struct {
|
|||||||
|
|
||||||
var Appname = ""
|
var Appname = ""
|
||||||
|
|
||||||
// NewParser create a Parser and parse the file given in filename.
|
// NewParser create a Parser and parse the file given in filename. If filename is empty, we try to parse the content[0] argument that should be a valid YAML content.
|
||||||
func NewParser(filename string) *Parser {
|
func NewParser(filename string, content ...string) *Parser {
|
||||||
|
|
||||||
f, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
c := NewCompose()
|
c := NewCompose()
|
||||||
dec := yaml.NewDecoder(f)
|
if filename != "" {
|
||||||
dec.Decode(c)
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
dec := yaml.NewDecoder(f)
|
||||||
|
err = dec.Decode(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dec := yaml.NewDecoder(strings.NewReader(content[0]))
|
||||||
|
err := dec.Decode(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p := &Parser{Data: c}
|
p := &Parser{Data: c}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) Parse(appname string) {
|
||||||
|
Appname = appname
|
||||||
|
|
||||||
services := make(map[string][]string)
|
services := make(map[string][]string)
|
||||||
// get the service list, to be sure that everything is ok
|
// get the service list, to be sure that everything is ok
|
||||||
|
|
||||||
|
c := p.Data
|
||||||
for name, s := range c.Services {
|
for name, s := range c.Services {
|
||||||
if portlabel, ok := s.Labels[helm.LABEL_PORT]; ok {
|
if portlabel, ok := s.Labels[helm.LABEL_PORT]; ok {
|
||||||
services := strings.Split(portlabel, ",")
|
services := strings.Split(portlabel, ",")
|
||||||
@@ -87,10 +105,4 @@ func NewParser(filename string) *Parser {
|
|||||||
" for the \"" + name + "\" service \x1b[0m")
|
" for the \"" + name + "\" service \x1b[0m")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Parser) Parse(appname string) {
|
|
||||||
Appname = appname
|
|
||||||
}
|
}
|
||||||
|
89
compose/parser_test.go
Normal file
89
compose/parser_test.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package compose
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
const DOCKER_COMPOSE_YML1 = `
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
# first service, very basic
|
||||||
|
web:
|
||||||
|
image: nginx
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
environment:
|
||||||
|
FOO: bar
|
||||||
|
BAZ: qux
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: postgres
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: mysecretpassword
|
||||||
|
POSTGRES_DB: mydb
|
||||||
|
labels:
|
||||||
|
katenary.io/ports: "5432"
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestParser(t *testing.T) {
|
||||||
|
p := NewParser("", DOCKER_COMPOSE_YML1)
|
||||||
|
p.Parse("test")
|
||||||
|
|
||||||
|
// check if the "web" and "database" service is parsed correctly
|
||||||
|
// by checking if the "ports" and "environment"
|
||||||
|
for name, service := range p.Data.Services {
|
||||||
|
if name == "web" {
|
||||||
|
if len(service.Ports) != 1 {
|
||||||
|
t.Errorf("Expected 1 port, got %d", len(service.Ports))
|
||||||
|
}
|
||||||
|
if service.Ports[0] != "80:80" {
|
||||||
|
t.Errorf("Expected port 80:80, got %s", service.Ports[0])
|
||||||
|
}
|
||||||
|
if len(service.Environment) != 2 {
|
||||||
|
t.Errorf("Expected 2 environment variables, got %d", len(service.Environment))
|
||||||
|
}
|
||||||
|
if service.Environment["FOO"] != "bar" {
|
||||||
|
t.Errorf("Expected FOO=bar, got %s", service.Environment["FOO"])
|
||||||
|
}
|
||||||
|
if service.Environment["BAZ"] != "qux" {
|
||||||
|
t.Errorf("Expected BAZ=qux, got %s", service.Environment["BAZ"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// same for the "database" service
|
||||||
|
if name == "database" {
|
||||||
|
if len(service.Ports) != 1 {
|
||||||
|
t.Errorf("Expected 1 port, got %d", len(service.Ports))
|
||||||
|
}
|
||||||
|
if service.Ports[0] != "5432" {
|
||||||
|
t.Errorf("Expected port 5432, got %s", service.Ports[0])
|
||||||
|
}
|
||||||
|
if len(service.Environment) != 3 {
|
||||||
|
t.Errorf("Expected 3 environment variables, got %d", len(service.Environment))
|
||||||
|
}
|
||||||
|
if service.Environment["POSTGRES_USER"] != "postgres" {
|
||||||
|
t.Errorf("Expected POSTGRES_USER=postgres, got %s", service.Environment["POSTGRES_USER"])
|
||||||
|
}
|
||||||
|
if service.Environment["POSTGRES_PASSWORD"] != "mysecretpassword" {
|
||||||
|
t.Errorf("Expected POSTGRES_PASSWORD=mysecretpassword, got %s", service.Environment["POSTGRES_PASSWORD"])
|
||||||
|
}
|
||||||
|
if service.Environment["POSTGRES_DB"] != "mydb" {
|
||||||
|
t.Errorf("Expected POSTGRES_DB=mydb, got %s", service.Environment["POSTGRES_DB"])
|
||||||
|
}
|
||||||
|
// check labels
|
||||||
|
if len(service.Labels) != 1 {
|
||||||
|
t.Errorf("Expected 1 label, got %d", len(service.Labels))
|
||||||
|
}
|
||||||
|
// is label katenary.io/ports correct?
|
||||||
|
if service.Labels["katenary.io/ports"] != "5432" {
|
||||||
|
t.Errorf("Expected katenary.io/ports=5432, got %s", service.Labels["katenary.io/ports"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
159
generator/main_test.go
Normal file
159
generator/main_test.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package generator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"katenary/compose"
|
||||||
|
"katenary/helm"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DOCKER_COMPOSE_YML = `version: '3'
|
||||||
|
services:
|
||||||
|
# first service, very simple
|
||||||
|
http:
|
||||||
|
image: nginx
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
|
||||||
|
# second service, with environment variables
|
||||||
|
http2:
|
||||||
|
image: nginx
|
||||||
|
environment:
|
||||||
|
SOME_ENV_VAR: some_value
|
||||||
|
ANOTHER_ENV_VAR: another_value
|
||||||
|
|
||||||
|
# third service with ingress label
|
||||||
|
web:
|
||||||
|
image: nginx
|
||||||
|
labels:
|
||||||
|
katenary.io/ingress: 80
|
||||||
|
|
||||||
|
# fourth service is a php service depending on database
|
||||||
|
php:
|
||||||
|
image: php:7.2-apache
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
environment:
|
||||||
|
SOME_ENV_VAR: some_value
|
||||||
|
ANOTHER_ENV_VAR: another_value
|
||||||
|
DB_HOST: database
|
||||||
|
labels:
|
||||||
|
katenary.io/env-to-service: DB_HOST
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: mysql:5.7
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
MYSQL_DATABASE: database
|
||||||
|
MYSQL_USER: user
|
||||||
|
MYSQL_PASSWORD: password
|
||||||
|
volumes:
|
||||||
|
- data:/var/lib/mysql
|
||||||
|
labels:
|
||||||
|
katenary.io/ports: 3306
|
||||||
|
|
||||||
|
|
||||||
|
# try to deploy 2 services but one is in the same pod than the other
|
||||||
|
http3:
|
||||||
|
image: nginx
|
||||||
|
|
||||||
|
http4:
|
||||||
|
image: nginx
|
||||||
|
labels:
|
||||||
|
katenary.io/same-pod: http3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
|
driver: local
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestGenerate(t *testing.T) {
|
||||||
|
p := compose.NewParser("", DOCKER_COMPOSE_YML)
|
||||||
|
p.Parse("testapp")
|
||||||
|
|
||||||
|
// create a temporary directory
|
||||||
|
tmp, err := os.MkdirTemp(os.TempDir(), "katenary-test")
|
||||||
|
t.Log("Generated ", tmp, "directory")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
Generate(p, "test-0", "testapp", "1.2.3", DOCKER_COMPOSE_YML, tmp)
|
||||||
|
|
||||||
|
// for each service name, there should be a deploument file in temporary directory
|
||||||
|
for name, service := range p.Data.Services {
|
||||||
|
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
||||||
|
if _, found := service.Labels[helm.LABEL_SAMEPOD]; found {
|
||||||
|
// fail if the service has a deployment
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
t.Error("Service ", name, " should not have a deployment")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// others should have a deployment file
|
||||||
|
t.Log("Checking ", name, " deployment file")
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the service has a port found in helm.LABEL_PORT or ports, so the service file should exist
|
||||||
|
hasPort := false
|
||||||
|
if _, found := service.Labels[helm.LABEL_PORT]; found {
|
||||||
|
hasPort = true
|
||||||
|
}
|
||||||
|
if service.Ports != nil {
|
||||||
|
hasPort = true
|
||||||
|
}
|
||||||
|
if hasPort {
|
||||||
|
path = filepath.Join(tmp, "templates", name+".service.yaml")
|
||||||
|
t.Log("Checking ", name, " service file")
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the "database" service should have a pvc file in templates (name-data.pvc.yaml)
|
||||||
|
if name == "database" {
|
||||||
|
path = filepath.Join(tmp, "templates", name+"-data.pvc.yaml")
|
||||||
|
t.Log("Checking ", name, " pvc file")
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "php" {
|
||||||
|
// the "DB_HOST" environment variable inside the template must be set to '{{ .Release.Name }}-database'
|
||||||
|
path = filepath.Join(tmp, "templates", name+".deployment.yaml")
|
||||||
|
// read the file and find the DB_HOST variable
|
||||||
|
matched := false
|
||||||
|
fp, _ := os.Open(path)
|
||||||
|
defer fp.Close()
|
||||||
|
lines, _ := ioutil.ReadAll(fp)
|
||||||
|
next := false
|
||||||
|
for _, line := range strings.Split(string(lines), "\n") {
|
||||||
|
if strings.Contains(line, "DB_HOST") {
|
||||||
|
next = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if next {
|
||||||
|
matched = true
|
||||||
|
if !strings.Contains(line, helm.RELEASE_NAME+"-database") {
|
||||||
|
t.Error("DB_HOST variable should be set to " + helm.RELEASE_NAME + "-database")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !matched {
|
||||||
|
t.Error("DB_HOST variable not found in ", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -21,6 +21,13 @@ func Generate(p *compose.Parser, katernayVersion, appName, appVersion, composeFi
|
|||||||
helm.Appname = appName
|
helm.Appname = appName
|
||||||
helm.Version = katernayVersion
|
helm.Version = katernayVersion
|
||||||
templatesDir := filepath.Join(dirName, "templates")
|
templatesDir := filepath.Join(dirName, "templates")
|
||||||
|
|
||||||
|
// try to create the directory
|
||||||
|
err := os.MkdirAll(templatesDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
files := make(map[string]chan interface{})
|
files := make(map[string]chan interface{})
|
||||||
|
|
||||||
// list avoided services
|
// list avoided services
|
||||||
@@ -123,7 +130,7 @@ func Generate(p *compose.Parser, katernayVersion, appName, appVersion, composeFi
|
|||||||
fp.WriteString(`# Create on ` + time.Now().Format(time.RFC3339) + "\n")
|
fp.WriteString(`# Create on ` + time.Now().Format(time.RFC3339) + "\n")
|
||||||
fp.WriteString(`# Katenary command line: ` + strings.Join(os.Args, " ") + "\n")
|
fp.WriteString(`# Katenary command line: ` + strings.Join(os.Args, " ") + "\n")
|
||||||
enc = yaml.NewEncoder(fp)
|
enc = yaml.NewEncoder(fp)
|
||||||
enc.SetIndent(2)
|
enc.SetIndent(writers.IndentSize)
|
||||||
enc.Encode(map[string]interface{}{
|
enc.Encode(map[string]interface{}{
|
||||||
"apiVersion": "v2",
|
"apiVersion": "v2",
|
||||||
"name": appName,
|
"name": appName,
|
||||||
|
@@ -14,6 +14,7 @@ func TestDownloadLatestRelease(t *testing.T) {
|
|||||||
|
|
||||||
// change "exe" to /tmp/test-katenary
|
// change "exe" to /tmp/test-katenary
|
||||||
exe = "/tmp/test-katenary"
|
exe = "/tmp/test-katenary"
|
||||||
|
defer os.Remove(exe)
|
||||||
|
|
||||||
// Now call the CheckLatestVersion function
|
// Now call the CheckLatestVersion function
|
||||||
version, assets, err := CheckLatestVersion()
|
version, assets, err := CheckLatestVersion()
|
||||||
|
Reference in New Issue
Block a user