woodpecker/pipeline/frontend/yaml/container_test.go
6543 18d3139e9e
Use modern error handling and enforce it via lint (#1327)
Co-authored-by: Anbraten <anton@ju60.de>
2023-02-02 00:08:02 +01:00

310 lines
7.6 KiB
Go

package yaml
import (
"testing"
"github.com/docker/docker/api/types/strslice"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/constraint"
"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/types"
)
var containerYaml = []byte(`
image: golang:latest
auth_config:
username: janedoe
password: password
cap_add: [ ALL ]
cap_drop: [ NET_ADMIN, SYS_ADMIN ]
commands:
- go build
- go test
cpu_quota: 11
cpuset: 1,2
cpu_shares: 99
detach: true
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
directory: example/
dns: 8.8.8.8
dns_search: example.com
environment:
- RACK_ENV=development
- SHOW=true
extra_hosts:
- somehost:162.242.195.82
- otherhost:50.31.209.229
isolation: hyperv
name: my-build-container
network_mode: bridge
networks:
- some-network
- other-network
pull: true
privileged: true
labels:
com.example.type: build
com.example.team: frontend
shm_size: 1kb
mem_limit: 1kb
memswap_limit: 1kb
mem_swappiness: 1kb
volumes:
- /var/lib/mysql
- /opt/data:/var/lib/mysql
- /etc/configs:/etc/configs/:ro
tmpfs:
- /var/lib/test
when:
- branch: master
- event: cron
cron: job1
settings:
foo: bar
baz: false
`)
func TestUnmarshalContainer(t *testing.T) {
want := Container{
AuthConfig: AuthConfig{
Username: "janedoe",
Password: "password",
},
CapAdd: []string{"ALL"},
CapDrop: []string{"NET_ADMIN", "SYS_ADMIN"},
Commands: types.StringOrSlice{"go build", "go test"},
CPUQuota: types.StringorInt(11),
CPUSet: "1,2",
CPUShares: types.StringorInt(99),
Detached: true,
Devices: []string{"/dev/ttyUSB0:/dev/ttyUSB0"},
Directory: "example/",
DNS: types.StringOrSlice{"8.8.8.8"},
DNSSearch: types.StringOrSlice{"example.com"},
Environment: types.SliceorMap{"RACK_ENV": "development", "SHOW": "true"},
ExtraHosts: []string{"somehost:162.242.195.82", "otherhost:50.31.209.229"},
Image: "golang:latest",
Isolation: "hyperv",
Labels: types.SliceorMap{"com.example.type": "build", "com.example.team": "frontend"},
MemLimit: types.MemStringorInt(1024),
MemSwapLimit: types.MemStringorInt(1024),
MemSwappiness: types.MemStringorInt(1024),
Name: "my-build-container",
Networks: types.Networks{
Networks: []*types.Network{
{Name: "some-network"},
{Name: "other-network"},
},
},
NetworkMode: "bridge",
Pull: true,
Privileged: true,
ShmSize: types.MemStringorInt(1024),
Tmpfs: types.StringOrSlice{"/var/lib/test"},
Volumes: types.Volumes{
Volumes: []*types.Volume{
{Source: "", Destination: "/var/lib/mysql"},
{Source: "/opt/data", Destination: "/var/lib/mysql"},
{Source: "/etc/configs", Destination: "/etc/configs/", AccessMode: "ro"},
},
},
When: constraint.When{
Constraints: []constraint.Constraint{
{
Branch: constraint.List{
Include: []string{"master"},
},
},
{
Event: constraint.List{
Include: []string{"cron"},
},
Cron: constraint.List{
Include: []string{"job1"},
},
},
},
},
Settings: map[string]interface{}{
"foo": "bar",
"baz": false,
},
}
got := Container{}
err := yaml.Unmarshal(containerYaml, &got)
assert.NoError(t, err)
assert.EqualValues(t, want, got, "problem parsing container")
}
// TestUnmarshalContainersErr unmarshals a map of containers. The order is
// retained and the container key may be used as the container name if a
// name is not explicitly provided.
func TestUnmarshalContainers(t *testing.T) {
testdata := []struct {
from string
want []*Container
}{
{
from: "build: { image: golang }",
want: []*Container{
{
Name: "build",
Image: "golang",
},
},
},
{
from: "test: { name: unit_test, image: node, settings: { normal_setting: true } }",
want: []*Container{
{
Name: "unit_test",
Image: "node",
Settings: map[string]interface{}{
"normal_setting": true,
},
},
},
},
{
from: `publish-agent:
group: bundle
image: print/env
settings:
repo: woodpeckerci/woodpecker-agent
dry_run: true
dockerfile: docker/Dockerfile.agent
tag: [next, latest]
secrets: [docker_username, docker_password]
when:
branch: ${CI_REPO_DEFAULT_BRANCH}
event: push`,
want: []*Container{
{
Name: "publish-agent",
Image: "print/env",
Group: "bundle",
Secrets: Secrets{Secrets: []*Secret{{
Source: "docker_username",
Target: "docker_username",
}, {
Source: "docker_password",
Target: "docker_password",
}}},
Settings: map[string]interface{}{
"repo": "woodpeckerci/woodpecker-agent",
"dockerfile": "docker/Dockerfile.agent",
"tag": stringsToInterface("next", "latest"),
"dry_run": true,
},
When: constraint.When{
Constraints: []constraint.Constraint{
{
Event: constraint.List{Include: []string{"push"}},
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
},
},
},
},
},
},
{
from: `publish-cli:
group: docker
image: print/env
settings:
repo: woodpeckerci/woodpecker-cli
dockerfile: docker/Dockerfile.cli
tag: [next]
when:
branch: ${CI_REPO_DEFAULT_BRANCH}
event: push`,
want: []*Container{
{
Name: "publish-cli",
Image: "print/env",
Group: "docker",
Settings: map[string]interface{}{
"repo": "woodpeckerci/woodpecker-cli",
"dockerfile": "docker/Dockerfile.cli",
"tag": stringsToInterface("next"),
},
When: constraint.When{
Constraints: []constraint.Constraint{
{
Event: constraint.List{Include: []string{"push"}},
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
},
},
},
},
},
},
{
from: `publish-cli:
image: print/env
when:
- branch: ${CI_REPO_DEFAULT_BRANCH}
event: push
- event: pull_request`,
want: []*Container{
{
Name: "publish-cli",
Image: "print/env",
When: constraint.When{
Constraints: []constraint.Constraint{
{
Event: constraint.List{Include: []string{"push"}},
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
},
{
Event: constraint.List{Include: []string{"pull_request"}},
},
},
},
},
},
},
}
for _, test := range testdata {
in := []byte(test.from)
got := Containers{}
err := yaml.Unmarshal(in, &got)
assert.NoError(t, err)
assert.EqualValues(t, test.want, got.Containers, "problem parsing containers %q", test.from)
}
}
// TestUnmarshalContainersErr unmarshals a container map where invalid inputs
// are provided to verify error messages are returned.
func TestUnmarshalContainersErr(t *testing.T) {
testdata := []string{
"foo: { name: [ foo, bar] }",
"- foo",
}
for _, test := range testdata {
in := []byte(test)
containers := new(Containers)
err := yaml.Unmarshal(in, &containers)
assert.Error(t, err, "wanted error for containers %q", test)
}
}
func stringsToInterface(val ...string) []interface{} {
res := make([]interface{}, len(val))
for i := range val {
res[i] = val[i]
}
return res
}
func TestIsPlugin(t *testing.T) {
assert.True(t, (&Container{}).IsPlugin())
assert.True(t, (&Container{
Commands: types.StringOrSlice(strslice.StrSlice{}),
}).IsPlugin())
assert.False(t, (&Container{
Commands: types.StringOrSlice(strslice.StrSlice{"echo 'this is not a plugin'"}),
}).IsPlugin())
}