woodpecker/pipeline/frontend/yaml/container_test.go
6543 b15ca52a63
Move constrain to only have a single command in backend to run to dedicated backends (#1032)
at the moment we compile a script that we can pipe in as single command
this is because of the constrains the docker backend gives us.

so we move it into the docker backend and eventually get rid of it altogether
2022-10-31 00:26:49 +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())
}