forked from toolshed/abra
fix: recover tests from overzealous cleanup
This commit is contained in:
parent
dc04cf5ff7
commit
963f8dcc73
46
pkg/client/client_test.go
Normal file
46
pkg/client/client_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package client_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// use at the start to ensure testContext[0, 1, ..., amnt-1] exist and
|
||||||
|
// testContextFail[0, 1, ..., failAmnt-1] don't exist
|
||||||
|
func ensureTestState(amnt, failAmnt int) error {
|
||||||
|
for i := 0; i < amnt; i++ {
|
||||||
|
err := client.CreateContext(fmt.Sprintf("testContext%d", i), "", "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < failAmnt; i++ {
|
||||||
|
if _, er := client.GetContext(fmt.Sprintf("testContextFail%d", i)); er == nil {
|
||||||
|
err := client.DeleteContext(fmt.Sprintf("testContextFail%d", i))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
err := ensureTestState(1, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Couldn't ensure existence/nonexistence of contexts: %s", err)
|
||||||
|
}
|
||||||
|
contextName := "testContext0"
|
||||||
|
_, err = client.New(contextName)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("couldn't initialise a new client with context %s: %s", contextName, err)
|
||||||
|
}
|
||||||
|
contextName = "testContextFail0"
|
||||||
|
_, err = client.New(contextName)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("client.New(\"testContextFail0\") should have failed but didn't return an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
pkg/client/context_test.go
Normal file
80
pkg/client/context_test.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package client_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/pkg/client"
|
||||||
|
dContext "github.com/docker/cli/cli/context"
|
||||||
|
dCliContextStore "github.com/docker/cli/cli/context/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestContext struct {
|
||||||
|
context dCliContextStore.Metadata
|
||||||
|
expected_endpoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
func dockerContext(host, key string) TestContext {
|
||||||
|
dockerContext := dCliContextStore.Metadata{
|
||||||
|
Name: "foo",
|
||||||
|
Metadata: nil,
|
||||||
|
Endpoints: map[string]interface{}{
|
||||||
|
key: dContext.EndpointMetaBase{
|
||||||
|
Host: host,
|
||||||
|
SkipTLSVerify: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return TestContext{
|
||||||
|
context: dockerContext,
|
||||||
|
expected_endpoint: host,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateContext(t *testing.T) {
|
||||||
|
err := client.CreateContext("testContext0", "wronguser", "wrongport")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("client.CreateContext(\"testContextCreate\", \"wronguser\", \"wrongport\") should have failed but didn't return an error")
|
||||||
|
}
|
||||||
|
err = client.CreateContext("testContext0", "", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Couldn't create context: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteContext(t *testing.T) {
|
||||||
|
ensureTestState(1, 1)
|
||||||
|
err := client.DeleteContext("default")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("client.DeleteContext(\"default\") should have failed but didn't return an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.DeleteContext("testContext0")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("client.DeleteContext(\"testContext0\") failed: %s", err)
|
||||||
|
}
|
||||||
|
err = client.DeleteContext("testContextFail0")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("client.DeleteContext(\"testContextFail0\") should have failed (attempt to delete non-existent context) but didn't return an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetContextEndpoint(t *testing.T) {
|
||||||
|
var testDockerContexts = []TestContext{
|
||||||
|
dockerContext("ssh://foobar", "docker"),
|
||||||
|
dockerContext("ssh://foobar", "k8"),
|
||||||
|
}
|
||||||
|
for _, context := range testDockerContexts {
|
||||||
|
endpoint, err := client.GetContextEndpoint(context.context)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() != "context lacks Docker endpoint" {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if endpoint != context.expected_endpoint {
|
||||||
|
t.Errorf("did not get correct context endpoint. Expected: %s, received: %s", context.expected_endpoint, endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
171
pkg/upstream/convert/compose_test.go
Normal file
171
pkg/upstream/convert/compose_test.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
composetypes "github.com/docker/cli/cli/compose/types"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/network"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
is "gotest.tools/v3/assert/cmp"
|
||||||
|
"gotest.tools/v3/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNamespaceScope(t *testing.T) {
|
||||||
|
scoped := Namespace{name: "foo"}.Scope("bar")
|
||||||
|
assert.Check(t, is.Equal("foo_bar", scoped))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddStackLabel(t *testing.T) {
|
||||||
|
labels := map[string]string{
|
||||||
|
"something": "labeled",
|
||||||
|
}
|
||||||
|
actual := AddStackLabel(Namespace{name: "foo"}, labels)
|
||||||
|
expected := map[string]string{
|
||||||
|
"something": "labeled",
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
}
|
||||||
|
assert.Check(t, is.DeepEqual(expected, actual))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworks(t *testing.T) {
|
||||||
|
namespace := Namespace{name: "foo"}
|
||||||
|
serviceNetworks := map[string]struct{}{
|
||||||
|
"normal": {},
|
||||||
|
"outside": {},
|
||||||
|
"default": {},
|
||||||
|
"attachablenet": {},
|
||||||
|
"named": {},
|
||||||
|
}
|
||||||
|
source := networkMap{
|
||||||
|
"normal": composetypes.NetworkConfig{
|
||||||
|
Driver: "overlay",
|
||||||
|
DriverOpts: map[string]string{
|
||||||
|
"opt": "value",
|
||||||
|
},
|
||||||
|
Ipam: composetypes.IPAMConfig{
|
||||||
|
Driver: "driver",
|
||||||
|
Config: []*composetypes.IPAMPool{
|
||||||
|
{
|
||||||
|
Subnet: "10.0.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"something": "labeled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"outside": composetypes.NetworkConfig{
|
||||||
|
External: composetypes.External{External: true},
|
||||||
|
Name: "special",
|
||||||
|
},
|
||||||
|
"attachablenet": composetypes.NetworkConfig{
|
||||||
|
Driver: "overlay",
|
||||||
|
Attachable: true,
|
||||||
|
},
|
||||||
|
"named": composetypes.NetworkConfig{
|
||||||
|
Name: "othername",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected := map[string]types.NetworkCreate{
|
||||||
|
"foo_default": {
|
||||||
|
Labels: map[string]string{
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foo_normal": {
|
||||||
|
Driver: "overlay",
|
||||||
|
IPAM: &network.IPAM{
|
||||||
|
Driver: "driver",
|
||||||
|
Config: []network.IPAMConfig{
|
||||||
|
{
|
||||||
|
Subnet: "10.0.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Options: map[string]string{
|
||||||
|
"opt": "value",
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
"something": "labeled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foo_attachablenet": {
|
||||||
|
Driver: "overlay",
|
||||||
|
Attachable: true,
|
||||||
|
Labels: map[string]string{
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"othername": {
|
||||||
|
Labels: map[string]string{LabelNamespace: "foo"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
networks, externals := Networks(namespace, source, serviceNetworks)
|
||||||
|
assert.DeepEqual(t, expected, networks)
|
||||||
|
assert.DeepEqual(t, []string{"special"}, externals)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSecrets(t *testing.T) {
|
||||||
|
namespace := Namespace{name: "foo"}
|
||||||
|
|
||||||
|
secretText := "this is the first secret"
|
||||||
|
secretFile := fs.NewFile(t, "convert-secrets", fs.WithContent(secretText))
|
||||||
|
defer secretFile.Remove()
|
||||||
|
|
||||||
|
source := map[string]composetypes.SecretConfig{
|
||||||
|
"one": {
|
||||||
|
File: secretFile.Path(),
|
||||||
|
Labels: map[string]string{"monster": "mash"},
|
||||||
|
},
|
||||||
|
"ext": {
|
||||||
|
External: composetypes.External{
|
||||||
|
External: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
specs, err := Secrets(namespace, source)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, is.Len(specs, 1))
|
||||||
|
secret := specs[0]
|
||||||
|
assert.Check(t, is.Equal("foo_one", secret.Name))
|
||||||
|
assert.Check(t, is.DeepEqual(map[string]string{
|
||||||
|
"monster": "mash",
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
}, secret.Labels))
|
||||||
|
assert.Check(t, is.DeepEqual([]byte(secretText), secret.Data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigs(t *testing.T) {
|
||||||
|
namespace := Namespace{name: "foo"}
|
||||||
|
|
||||||
|
configText := "this is the first config"
|
||||||
|
configFile := fs.NewFile(t, "convert-configs", fs.WithContent(configText))
|
||||||
|
defer configFile.Remove()
|
||||||
|
|
||||||
|
source := map[string]composetypes.ConfigObjConfig{
|
||||||
|
"one": {
|
||||||
|
File: configFile.Path(),
|
||||||
|
Labels: map[string]string{"monster": "mash"},
|
||||||
|
},
|
||||||
|
"ext": {
|
||||||
|
External: composetypes.External{
|
||||||
|
External: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
specs, err := Configs(namespace, source)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, is.Len(specs, 1))
|
||||||
|
config := specs[0]
|
||||||
|
assert.Check(t, is.Equal("foo_one", config.Name))
|
||||||
|
assert.Check(t, is.DeepEqual(map[string]string{
|
||||||
|
"monster": "mash",
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
}, config.Labels))
|
||||||
|
assert.Check(t, is.DeepEqual([]byte(configText), config.Data))
|
||||||
|
}
|
678
pkg/upstream/convert/service_test.go
Normal file
678
pkg/upstream/convert/service_test.go
Normal file
@ -0,0 +1,678 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
composetypes "github.com/docker/cli/cli/compose/types"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/swarm"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
is "gotest.tools/v3/assert/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertRestartPolicyFromNone(t *testing.T) {
|
||||||
|
policy, err := convertRestartPolicy("no", nil)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual((*swarm.RestartPolicy)(nil), policy))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertRestartPolicyFromUnknown(t *testing.T) {
|
||||||
|
_, err := convertRestartPolicy("unknown", nil)
|
||||||
|
assert.Error(t, err, "unknown restart policy: unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertRestartPolicyFromAlways(t *testing.T) {
|
||||||
|
policy, err := convertRestartPolicy("always", nil)
|
||||||
|
expected := &swarm.RestartPolicy{
|
||||||
|
Condition: swarm.RestartPolicyConditionAny,
|
||||||
|
}
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, policy))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertRestartPolicyFromFailure(t *testing.T) {
|
||||||
|
policy, err := convertRestartPolicy("on-failure:4", nil)
|
||||||
|
attempts := uint64(4)
|
||||||
|
expected := &swarm.RestartPolicy{
|
||||||
|
Condition: swarm.RestartPolicyConditionOnFailure,
|
||||||
|
MaxAttempts: &attempts,
|
||||||
|
}
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, policy))
|
||||||
|
}
|
||||||
|
|
||||||
|
func strPtr(val string) *string {
|
||||||
|
return &val
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertEnvironment(t *testing.T) {
|
||||||
|
source := map[string]*string{
|
||||||
|
"foo": strPtr("bar"),
|
||||||
|
"key": strPtr("value"),
|
||||||
|
}
|
||||||
|
env := convertEnvironment(source)
|
||||||
|
sort.Strings(env)
|
||||||
|
assert.Check(t, is.DeepEqual([]string{"foo=bar", "key=value"}, env))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertExtraHosts(t *testing.T) {
|
||||||
|
source := composetypes.HostsList{
|
||||||
|
"zulu:127.0.0.2",
|
||||||
|
"alpha:127.0.0.1",
|
||||||
|
"zulu:ff02::1",
|
||||||
|
}
|
||||||
|
assert.Check(t, is.DeepEqual([]string{"127.0.0.2 zulu", "127.0.0.1 alpha", "ff02::1 zulu"}, convertExtraHosts(source)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertResourcesFull(t *testing.T) {
|
||||||
|
source := composetypes.Resources{
|
||||||
|
Limits: &composetypes.ResourceLimit{
|
||||||
|
NanoCPUs: "0.003",
|
||||||
|
MemoryBytes: composetypes.UnitBytes(300000000),
|
||||||
|
},
|
||||||
|
Reservations: &composetypes.Resource{
|
||||||
|
NanoCPUs: "0.002",
|
||||||
|
MemoryBytes: composetypes.UnitBytes(200000000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resources, err := convertResources(source)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
expected := &swarm.ResourceRequirements{
|
||||||
|
Limits: &swarm.Limit{
|
||||||
|
NanoCPUs: 3000000,
|
||||||
|
MemoryBytes: 300000000,
|
||||||
|
},
|
||||||
|
Reservations: &swarm.Resources{
|
||||||
|
NanoCPUs: 2000000,
|
||||||
|
MemoryBytes: 200000000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Check(t, is.DeepEqual(expected, resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertResourcesOnlyMemory(t *testing.T) {
|
||||||
|
source := composetypes.Resources{
|
||||||
|
Limits: &composetypes.ResourceLimit{
|
||||||
|
MemoryBytes: composetypes.UnitBytes(300000000),
|
||||||
|
},
|
||||||
|
Reservations: &composetypes.Resource{
|
||||||
|
MemoryBytes: composetypes.UnitBytes(200000000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resources, err := convertResources(source)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
expected := &swarm.ResourceRequirements{
|
||||||
|
Limits: &swarm.Limit{
|
||||||
|
MemoryBytes: 300000000,
|
||||||
|
},
|
||||||
|
Reservations: &swarm.Resources{
|
||||||
|
MemoryBytes: 200000000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Check(t, is.DeepEqual(expected, resources))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertHealthcheck(t *testing.T) {
|
||||||
|
retries := uint64(10)
|
||||||
|
timeout := composetypes.Duration(30 * time.Second)
|
||||||
|
interval := composetypes.Duration(2 * time.Millisecond)
|
||||||
|
source := &composetypes.HealthCheckConfig{
|
||||||
|
Test: []string{"EXEC", "touch", "/foo"},
|
||||||
|
Timeout: &timeout,
|
||||||
|
Interval: &interval,
|
||||||
|
Retries: &retries,
|
||||||
|
}
|
||||||
|
expected := &container.HealthConfig{
|
||||||
|
Test: source.Test,
|
||||||
|
Timeout: time.Duration(timeout),
|
||||||
|
Interval: time.Duration(interval),
|
||||||
|
Retries: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
healthcheck, err := convertHealthcheck(source)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, healthcheck))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertHealthcheckDisable(t *testing.T) {
|
||||||
|
source := &composetypes.HealthCheckConfig{Disable: true}
|
||||||
|
expected := &container.HealthConfig{
|
||||||
|
Test: []string{"NONE"},
|
||||||
|
}
|
||||||
|
|
||||||
|
healthcheck, err := convertHealthcheck(source)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, healthcheck))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertHealthcheckDisableWithTest(t *testing.T) {
|
||||||
|
source := &composetypes.HealthCheckConfig{
|
||||||
|
Disable: true,
|
||||||
|
Test: []string{"EXEC", "touch"},
|
||||||
|
}
|
||||||
|
_, err := convertHealthcheck(source)
|
||||||
|
assert.Error(t, err, "test and disable can't be set at the same time")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertEndpointSpec(t *testing.T) {
|
||||||
|
source := []composetypes.ServicePortConfig{
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
Target: 53,
|
||||||
|
Published: 1053,
|
||||||
|
Mode: "host",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Target: 8080,
|
||||||
|
Published: 80,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
endpoint := convertEndpointSpec("vip", source)
|
||||||
|
|
||||||
|
expected := swarm.EndpointSpec{
|
||||||
|
Mode: swarm.ResolutionMode(strings.ToLower("vip")),
|
||||||
|
Ports: []swarm.PortConfig{
|
||||||
|
{
|
||||||
|
TargetPort: 8080,
|
||||||
|
PublishedPort: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 53,
|
||||||
|
PublishedPort: 1053,
|
||||||
|
PublishMode: "host",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Check(t, is.DeepEqual(expected, *endpoint))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertServiceNetworksOnlyDefault(t *testing.T) {
|
||||||
|
networkConfigs := networkMap{}
|
||||||
|
|
||||||
|
configs, err := convertServiceNetworks(
|
||||||
|
nil, networkConfigs, NewNamespace("foo"), "service")
|
||||||
|
|
||||||
|
expected := []swarm.NetworkAttachmentConfig{
|
||||||
|
{
|
||||||
|
Target: "foo_default",
|
||||||
|
Aliases: []string{"service"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, configs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertServiceNetworks(t *testing.T) {
|
||||||
|
networkConfigs := networkMap{
|
||||||
|
"front": composetypes.NetworkConfig{
|
||||||
|
External: composetypes.External{External: true},
|
||||||
|
Name: "fronttier",
|
||||||
|
},
|
||||||
|
"back": composetypes.NetworkConfig{},
|
||||||
|
}
|
||||||
|
networks := map[string]*composetypes.ServiceNetworkConfig{
|
||||||
|
"front": {
|
||||||
|
Aliases: []string{"something"},
|
||||||
|
},
|
||||||
|
"back": {
|
||||||
|
Aliases: []string{"other"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
configs, err := convertServiceNetworks(
|
||||||
|
networks, networkConfigs, NewNamespace("foo"), "service")
|
||||||
|
|
||||||
|
expected := []swarm.NetworkAttachmentConfig{
|
||||||
|
{
|
||||||
|
Target: "foo_back",
|
||||||
|
Aliases: []string{"other", "service"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Target: "fronttier",
|
||||||
|
Aliases: []string{"something", "service"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, configs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertServiceNetworksCustomDefault(t *testing.T) {
|
||||||
|
networkConfigs := networkMap{
|
||||||
|
"default": composetypes.NetworkConfig{
|
||||||
|
External: composetypes.External{External: true},
|
||||||
|
Name: "custom",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networks := map[string]*composetypes.ServiceNetworkConfig{}
|
||||||
|
|
||||||
|
configs, err := convertServiceNetworks(
|
||||||
|
networks, networkConfigs, NewNamespace("foo"), "service")
|
||||||
|
|
||||||
|
expected := []swarm.NetworkAttachmentConfig{
|
||||||
|
{
|
||||||
|
Target: "custom",
|
||||||
|
Aliases: []string{"service"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, configs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertDNSConfigEmpty(t *testing.T) {
|
||||||
|
dnsConfig := convertDNSConfig(nil, nil)
|
||||||
|
assert.Check(t, is.DeepEqual((*swarm.DNSConfig)(nil), dnsConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nameservers = []string{"8.8.8.8", "9.9.9.9"}
|
||||||
|
search = []string{"dc1.example.com", "dc2.example.com"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertDNSConfigAll(t *testing.T) {
|
||||||
|
dnsConfig := convertDNSConfig(nameservers, search)
|
||||||
|
assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
|
||||||
|
Nameservers: nameservers,
|
||||||
|
Search: search,
|
||||||
|
}, dnsConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertDNSConfigNameservers(t *testing.T) {
|
||||||
|
dnsConfig := convertDNSConfig(nameservers, nil)
|
||||||
|
assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
|
||||||
|
Nameservers: nameservers,
|
||||||
|
Search: nil,
|
||||||
|
}, dnsConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertDNSConfigSearch(t *testing.T) {
|
||||||
|
dnsConfig := convertDNSConfig(nil, search)
|
||||||
|
assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
|
||||||
|
Nameservers: nil,
|
||||||
|
Search: search,
|
||||||
|
}, dnsConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertCredentialSpec(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
in composetypes.CredentialSpecConfig
|
||||||
|
out *swarm.CredentialSpec
|
||||||
|
configs []*swarm.ConfigReference
|
||||||
|
expectedErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config-and-file",
|
||||||
|
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", File: "somefile.json"},
|
||||||
|
expectedErr: `invalid credential spec: cannot specify both "Config" and "File"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config-and-registry",
|
||||||
|
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", Registry: "testing"},
|
||||||
|
expectedErr: `invalid credential spec: cannot specify both "Config" and "Registry"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file-and-registry",
|
||||||
|
in: composetypes.CredentialSpecConfig{File: "somefile.json", Registry: "testing"},
|
||||||
|
expectedErr: `invalid credential spec: cannot specify both "File" and "Registry"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config-and-file-and-registry",
|
||||||
|
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", File: "somefile.json", Registry: "testing"},
|
||||||
|
expectedErr: `invalid credential spec: cannot specify both "Config", "File", and "Registry"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing-config-reference",
|
||||||
|
in: composetypes.CredentialSpecConfig{Config: "missing"},
|
||||||
|
expectedErr: "invalid credential spec: spec specifies config missing, but no such config can be found",
|
||||||
|
configs: []*swarm.ConfigReference{
|
||||||
|
{
|
||||||
|
ConfigName: "someName",
|
||||||
|
ConfigID: "missing",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "namespaced-config",
|
||||||
|
in: composetypes.CredentialSpecConfig{Config: "name"},
|
||||||
|
configs: []*swarm.ConfigReference{
|
||||||
|
{
|
||||||
|
ConfigName: "namespaced-config_name",
|
||||||
|
ConfigID: "someID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
out: &swarm.CredentialSpec{Config: "someID"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config",
|
||||||
|
in: composetypes.CredentialSpecConfig{Config: "someName"},
|
||||||
|
configs: []*swarm.ConfigReference{
|
||||||
|
{
|
||||||
|
ConfigName: "someOtherName",
|
||||||
|
ConfigID: "someOtherID",
|
||||||
|
}, {
|
||||||
|
ConfigName: "someName",
|
||||||
|
ConfigID: "someID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
out: &swarm.CredentialSpec{Config: "someID"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file",
|
||||||
|
in: composetypes.CredentialSpecConfig{File: "somefile.json"},
|
||||||
|
out: &swarm.CredentialSpec{File: "somefile.json"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "registry",
|
||||||
|
in: composetypes.CredentialSpecConfig{Registry: "testing"},
|
||||||
|
out: &swarm.CredentialSpec{Registry: "testing"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
namespace := NewNamespace(tc.name)
|
||||||
|
swarmSpec, err := convertCredentialSpec(namespace, tc.in, tc.configs)
|
||||||
|
|
||||||
|
if tc.expectedErr != "" {
|
||||||
|
assert.Error(t, err, tc.expectedErr)
|
||||||
|
} else {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
assert.DeepEqual(t, swarmSpec, tc.out)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertUpdateConfigOrder(t *testing.T) {
|
||||||
|
// test default behavior
|
||||||
|
updateConfig := convertUpdateConfig(&composetypes.UpdateConfig{})
|
||||||
|
assert.Check(t, is.Equal("", updateConfig.Order))
|
||||||
|
|
||||||
|
// test start-first
|
||||||
|
updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
|
||||||
|
Order: "start-first",
|
||||||
|
})
|
||||||
|
assert.Check(t, is.Equal(updateConfig.Order, "start-first"))
|
||||||
|
|
||||||
|
// test stop-first
|
||||||
|
updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
|
||||||
|
Order: "stop-first",
|
||||||
|
})
|
||||||
|
assert.Check(t, is.Equal(updateConfig.Order, "stop-first"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertFileObject(t *testing.T) {
|
||||||
|
namespace := NewNamespace("testing")
|
||||||
|
config := composetypes.FileReferenceConfig{
|
||||||
|
Source: "source",
|
||||||
|
Target: "target",
|
||||||
|
UID: "user",
|
||||||
|
GID: "group",
|
||||||
|
Mode: uint32Ptr(0644),
|
||||||
|
}
|
||||||
|
swarmRef, err := convertFileObject(namespace, config, lookupConfig)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
expected := swarmReferenceObject{
|
||||||
|
Name: "testing_source",
|
||||||
|
File: swarmReferenceTarget{
|
||||||
|
Name: config.Target,
|
||||||
|
UID: config.UID,
|
||||||
|
GID: config.GID,
|
||||||
|
Mode: os.FileMode(0644),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Check(t, is.DeepEqual(expected, swarmRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupConfig(key string) (composetypes.FileObjectConfig, error) {
|
||||||
|
if key != "source" {
|
||||||
|
return composetypes.FileObjectConfig{}, errors.New("bad key")
|
||||||
|
}
|
||||||
|
return composetypes.FileObjectConfig{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertFileObjectDefaults(t *testing.T) {
|
||||||
|
namespace := NewNamespace("testing")
|
||||||
|
config := composetypes.FileReferenceConfig{Source: "source"}
|
||||||
|
swarmRef, err := convertFileObject(namespace, config, lookupConfig)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
expected := swarmReferenceObject{
|
||||||
|
Name: "testing_source",
|
||||||
|
File: swarmReferenceTarget{
|
||||||
|
Name: config.Source,
|
||||||
|
UID: "0",
|
||||||
|
GID: "0",
|
||||||
|
Mode: os.FileMode(0444),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Check(t, is.DeepEqual(expected, swarmRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServiceConvertsIsolation(t *testing.T) {
|
||||||
|
src := composetypes.ServiceConfig{
|
||||||
|
Isolation: "hyperv",
|
||||||
|
}
|
||||||
|
result, err := Service("1.35", Namespace{name: "foo"}, src, nil, nil, nil, nil)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.Equal(container.IsolationHyperV, result.TaskTemplate.ContainerSpec.Isolation))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertServiceSecrets(t *testing.T) {
|
||||||
|
namespace := Namespace{name: "foo"}
|
||||||
|
secrets := []composetypes.ServiceSecretConfig{
|
||||||
|
{Source: "foo_secret"},
|
||||||
|
{Source: "bar_secret"},
|
||||||
|
}
|
||||||
|
secretSpecs := map[string]composetypes.SecretConfig{
|
||||||
|
"foo_secret": {
|
||||||
|
Name: "foo_secret",
|
||||||
|
},
|
||||||
|
"bar_secret": {
|
||||||
|
Name: "bar_secret",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := &fakeClient{
|
||||||
|
secretListFunc: func(opts types.SecretListOptions) ([]swarm.Secret, error) {
|
||||||
|
assert.Check(t, is.Contains(opts.Filters.Get("name"), "foo_secret"))
|
||||||
|
assert.Check(t, is.Contains(opts.Filters.Get("name"), "bar_secret"))
|
||||||
|
return []swarm.Secret{
|
||||||
|
{Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "foo_secret"}}},
|
||||||
|
{Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "bar_secret"}}},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
refs, err := convertServiceSecrets(client, namespace, secrets, secretSpecs)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
expected := []*swarm.SecretReference{
|
||||||
|
{
|
||||||
|
SecretName: "bar_secret",
|
||||||
|
File: &swarm.SecretReferenceFileTarget{
|
||||||
|
Name: "bar_secret",
|
||||||
|
UID: "0",
|
||||||
|
GID: "0",
|
||||||
|
Mode: 0444,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SecretName: "foo_secret",
|
||||||
|
File: &swarm.SecretReferenceFileTarget{
|
||||||
|
Name: "foo_secret",
|
||||||
|
UID: "0",
|
||||||
|
GID: "0",
|
||||||
|
Mode: 0444,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.DeepEqual(t, expected, refs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertServiceConfigs(t *testing.T) {
|
||||||
|
namespace := Namespace{name: "foo"}
|
||||||
|
service := composetypes.ServiceConfig{
|
||||||
|
Configs: []composetypes.ServiceConfigObjConfig{
|
||||||
|
{Source: "foo_config"},
|
||||||
|
{Source: "bar_config"},
|
||||||
|
},
|
||||||
|
CredentialSpec: composetypes.CredentialSpecConfig{
|
||||||
|
Config: "baz_config",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
configSpecs := map[string]composetypes.ConfigObjConfig{
|
||||||
|
"foo_config": {
|
||||||
|
Name: "foo_config",
|
||||||
|
},
|
||||||
|
"bar_config": {
|
||||||
|
Name: "bar_config",
|
||||||
|
},
|
||||||
|
"baz_config": {
|
||||||
|
Name: "baz_config",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client := &fakeClient{
|
||||||
|
configListFunc: func(opts types.ConfigListOptions) ([]swarm.Config, error) {
|
||||||
|
assert.Check(t, is.Contains(opts.Filters.Get("name"), "foo_config"))
|
||||||
|
assert.Check(t, is.Contains(opts.Filters.Get("name"), "bar_config"))
|
||||||
|
assert.Check(t, is.Contains(opts.Filters.Get("name"), "baz_config"))
|
||||||
|
return []swarm.Config{
|
||||||
|
{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "foo_config"}}},
|
||||||
|
{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "bar_config"}}},
|
||||||
|
{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "baz_config"}}},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
refs, err := convertServiceConfigObjs(client, namespace, service, configSpecs)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
expected := []*swarm.ConfigReference{
|
||||||
|
{
|
||||||
|
ConfigName: "bar_config",
|
||||||
|
File: &swarm.ConfigReferenceFileTarget{
|
||||||
|
Name: "bar_config",
|
||||||
|
UID: "0",
|
||||||
|
GID: "0",
|
||||||
|
Mode: 0444,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ConfigName: "baz_config",
|
||||||
|
Runtime: &swarm.ConfigReferenceRuntimeTarget{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ConfigName: "foo_config",
|
||||||
|
File: &swarm.ConfigReferenceFileTarget{
|
||||||
|
Name: "foo_config",
|
||||||
|
UID: "0",
|
||||||
|
GID: "0",
|
||||||
|
Mode: 0444,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.DeepEqual(t, expected, refs)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeClient struct {
|
||||||
|
client.Client
|
||||||
|
secretListFunc func(types.SecretListOptions) ([]swarm.Secret, error)
|
||||||
|
configListFunc func(types.ConfigListOptions) ([]swarm.Config, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
|
||||||
|
if c.secretListFunc != nil {
|
||||||
|
return c.secretListFunc(options)
|
||||||
|
}
|
||||||
|
return []swarm.Secret{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||||
|
if c.configListFunc != nil {
|
||||||
|
return c.configListFunc(options)
|
||||||
|
}
|
||||||
|
return []swarm.Config{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertUpdateConfigParallelism(t *testing.T) {
|
||||||
|
parallel := uint64(4)
|
||||||
|
|
||||||
|
// test default behavior
|
||||||
|
updateConfig := convertUpdateConfig(&composetypes.UpdateConfig{})
|
||||||
|
assert.Check(t, is.Equal(uint64(1), updateConfig.Parallelism))
|
||||||
|
|
||||||
|
// Non default value
|
||||||
|
updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
|
||||||
|
Parallelism: ¶llel,
|
||||||
|
})
|
||||||
|
assert.Check(t, is.Equal(parallel, updateConfig.Parallelism))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertServiceCapAddAndCapDrop(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
title string
|
||||||
|
in, out composetypes.ServiceConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
title: "default behavior",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "some values",
|
||||||
|
in: composetypes.ServiceConfig{
|
||||||
|
CapAdd: []string{"SYS_NICE", "CAP_NET_ADMIN"},
|
||||||
|
CapDrop: []string{"CHOWN", "CAP_NET_ADMIN", "DAC_OVERRIDE", "CAP_FSETID", "CAP_FOWNER"},
|
||||||
|
},
|
||||||
|
out: composetypes.ServiceConfig{
|
||||||
|
CapAdd: []string{"CAP_NET_ADMIN", "CAP_SYS_NICE"},
|
||||||
|
CapDrop: []string{"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "adding ALL capabilities",
|
||||||
|
in: composetypes.ServiceConfig{
|
||||||
|
CapAdd: []string{"ALL", "CAP_NET_ADMIN"},
|
||||||
|
CapDrop: []string{"CHOWN", "CAP_NET_ADMIN", "DAC_OVERRIDE", "CAP_FSETID", "CAP_FOWNER"},
|
||||||
|
},
|
||||||
|
out: composetypes.ServiceConfig{
|
||||||
|
CapAdd: []string{"ALL"},
|
||||||
|
CapDrop: []string{"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID", "CAP_NET_ADMIN"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "dropping ALL capabilities",
|
||||||
|
in: composetypes.ServiceConfig{
|
||||||
|
CapAdd: []string{"CHOWN", "CAP_NET_ADMIN", "DAC_OVERRIDE", "CAP_FSETID", "CAP_FOWNER"},
|
||||||
|
CapDrop: []string{"ALL", "CAP_NET_ADMIN", "CAP_FOO"},
|
||||||
|
},
|
||||||
|
out: composetypes.ServiceConfig{
|
||||||
|
CapAdd: []string{"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_FSETID", "CAP_NET_ADMIN"},
|
||||||
|
CapDrop: []string{"ALL"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.title, func(t *testing.T) {
|
||||||
|
result, err := Service("1.41", Namespace{name: "foo"}, tc.in, nil, nil, nil, nil)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(result.TaskTemplate.ContainerSpec.CapabilityAdd, tc.out.CapAdd))
|
||||||
|
assert.Check(t, is.DeepEqual(result.TaskTemplate.ContainerSpec.CapabilityDrop, tc.out.CapDrop))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
361
pkg/upstream/convert/volume_test.go
Normal file
361
pkg/upstream/convert/volume_test.go
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
composetypes "github.com/docker/cli/cli/compose/types"
|
||||||
|
"github.com/docker/docker/api/types/mount"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
is "gotest.tools/v3/assert/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountAnonymousVolume(t *testing.T) {
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Target: "/foo/bar",
|
||||||
|
}
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeVolume,
|
||||||
|
Target: "/foo/bar",
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountAnonymousBind(t *testing.T) {
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "bind",
|
||||||
|
Target: "/foo/bar",
|
||||||
|
Bind: &composetypes.ServiceVolumeBind{
|
||||||
|
Propagation: "slave",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
||||||
|
assert.Error(t, err, "invalid bind source, source cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountUnapprovedType(t *testing.T) {
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "foo",
|
||||||
|
Target: "/foo/bar",
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
||||||
|
assert.Error(t, err, "volume type must be volume, bind, tmpfs or npipe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountConflictingOptionsBindInVolume(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "foo",
|
||||||
|
Target: "/target",
|
||||||
|
Bind: &composetypes.ServiceVolumeBind{
|
||||||
|
Propagation: "slave",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "bind options are incompatible with type volume")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountConflictingOptionsTmpfsInVolume(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "foo",
|
||||||
|
Target: "/target",
|
||||||
|
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
||||||
|
Size: 1000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "tmpfs options are incompatible with type volume")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountConflictingOptionsVolumeInBind(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "bind",
|
||||||
|
Source: "/foo",
|
||||||
|
Target: "/target",
|
||||||
|
Volume: &composetypes.ServiceVolumeVolume{
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "volume options are incompatible with type bind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountConflictingOptionsTmpfsInBind(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "bind",
|
||||||
|
Source: "/foo",
|
||||||
|
Target: "/target",
|
||||||
|
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
||||||
|
Size: 1000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "tmpfs options are incompatible with type bind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountConflictingOptionsBindInTmpfs(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "tmpfs",
|
||||||
|
Target: "/target",
|
||||||
|
Bind: &composetypes.ServiceVolumeBind{
|
||||||
|
Propagation: "slave",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "bind options are incompatible with type tmpfs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountConflictingOptionsVolumeInTmpfs(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "tmpfs",
|
||||||
|
Target: "/target",
|
||||||
|
Volume: &composetypes.ServiceVolumeVolume{
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "volume options are incompatible with type tmpfs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountNamedVolume(t *testing.T) {
|
||||||
|
stackVolumes := volumes{
|
||||||
|
"normal": composetypes.VolumeConfig{
|
||||||
|
Driver: "glusterfs",
|
||||||
|
DriverOpts: map[string]string{
|
||||||
|
"opt": "value",
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"something": "labeled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeVolume,
|
||||||
|
Source: "foo_normal",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
VolumeOptions: &mount.VolumeOptions{
|
||||||
|
Labels: map[string]string{
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
"something": "labeled",
|
||||||
|
},
|
||||||
|
DriverConfig: &mount.Driver{
|
||||||
|
Name: "glusterfs",
|
||||||
|
Options: map[string]string{
|
||||||
|
"opt": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "normal",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
Volume: &composetypes.ServiceVolumeVolume{
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountNamedVolumeWithNameCustomizd(t *testing.T) {
|
||||||
|
stackVolumes := volumes{
|
||||||
|
"normal": composetypes.VolumeConfig{
|
||||||
|
Name: "user_specified_name",
|
||||||
|
Driver: "vsphere",
|
||||||
|
DriverOpts: map[string]string{
|
||||||
|
"opt": "value",
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"something": "labeled",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeVolume,
|
||||||
|
Source: "user_specified_name",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
VolumeOptions: &mount.VolumeOptions{
|
||||||
|
Labels: map[string]string{
|
||||||
|
LabelNamespace: "foo",
|
||||||
|
"something": "labeled",
|
||||||
|
},
|
||||||
|
DriverConfig: &mount.Driver{
|
||||||
|
Name: "vsphere",
|
||||||
|
Options: map[string]string{
|
||||||
|
"opt": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "normal",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
Volume: &composetypes.ServiceVolumeVolume{
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountNamedVolumeExternal(t *testing.T) {
|
||||||
|
stackVolumes := volumes{
|
||||||
|
"outside": composetypes.VolumeConfig{
|
||||||
|
Name: "special",
|
||||||
|
External: composetypes.External{External: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeVolume,
|
||||||
|
Source: "special",
|
||||||
|
Target: "/foo",
|
||||||
|
VolumeOptions: &mount.VolumeOptions{NoCopy: false},
|
||||||
|
}
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "outside",
|
||||||
|
Target: "/foo",
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountNamedVolumeExternalNoCopy(t *testing.T) {
|
||||||
|
stackVolumes := volumes{
|
||||||
|
"outside": composetypes.VolumeConfig{
|
||||||
|
Name: "special",
|
||||||
|
External: composetypes.External{External: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeVolume,
|
||||||
|
Source: "special",
|
||||||
|
Target: "/foo",
|
||||||
|
VolumeOptions: &mount.VolumeOptions{
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "outside",
|
||||||
|
Target: "/foo",
|
||||||
|
Volume: &composetypes.ServiceVolumeVolume{
|
||||||
|
NoCopy: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountBind(t *testing.T) {
|
||||||
|
stackVolumes := volumes{}
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeBind,
|
||||||
|
Source: "/bar",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
BindOptions: &mount.BindOptions{Propagation: mount.PropagationShared},
|
||||||
|
}
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "bind",
|
||||||
|
Source: "/bar",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
Bind: &composetypes.ServiceVolumeBind{Propagation: "shared"},
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, stackVolumes, namespace)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountVolumeDoesNotExist(t *testing.T) {
|
||||||
|
namespace := NewNamespace("foo")
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "volume",
|
||||||
|
Source: "unknown",
|
||||||
|
Target: "/foo",
|
||||||
|
ReadOnly: true,
|
||||||
|
}
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, namespace)
|
||||||
|
assert.Error(t, err, "undefined volume \"unknown\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertTmpfsToMountVolume(t *testing.T) {
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "tmpfs",
|
||||||
|
Target: "/foo/bar",
|
||||||
|
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
||||||
|
Size: 1000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeTmpfs,
|
||||||
|
Target: "/foo/bar",
|
||||||
|
TmpfsOptions: &mount.TmpfsOptions{SizeBytes: 1000},
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertTmpfsToMountVolumeWithSource(t *testing.T) {
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "tmpfs",
|
||||||
|
Source: "/bar",
|
||||||
|
Target: "/foo/bar",
|
||||||
|
Tmpfs: &composetypes.ServiceVolumeTmpfs{
|
||||||
|
Size: 1000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
||||||
|
assert.Error(t, err, "invalid tmpfs source, source must be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertVolumeToMountAnonymousNpipe(t *testing.T) {
|
||||||
|
config := composetypes.ServiceVolumeConfig{
|
||||||
|
Type: "npipe",
|
||||||
|
Source: `\\.\pipe\foo`,
|
||||||
|
Target: `\\.\pipe\foo`,
|
||||||
|
}
|
||||||
|
expected := mount.Mount{
|
||||||
|
Type: mount.TypeNamedPipe,
|
||||||
|
Source: `\\.\pipe\foo`,
|
||||||
|
Target: `\\.\pipe\foo`,
|
||||||
|
}
|
||||||
|
mount, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo"))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(expected, mount))
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user