From 078b2eed344b23fbc647c578eef451d1a37fc26d Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Thu, 12 Oct 2023 17:34:06 +0200 Subject: [PATCH] fix TestLoadMultipleConfigs Signed-off-by: Nicolas De Loof --- loader/merge_test.go | 213 +++++++++++++++++++------------------------ types/hostList.go | 66 ++++++++++++++ types/mapping.go | 22 +++-- types/types.go | 24 ----- 4 files changed, 171 insertions(+), 154 deletions(-) create mode 100644 types/hostList.go diff --git a/loader/merge_test.go b/loader/merge_test.go index 9648639d..02584cd1 100644 --- a/loader/merge_test.go +++ b/loader/merge_test.go @@ -861,137 +861,108 @@ func TestLoadMultipleServiceNetworks(t *testing.T) { } func TestLoadMultipleConfigs(t *testing.T) { - base := map[string]interface{}{ - "services": map[string]interface{}{ - "foo": map[string]interface{}{ - "image": "foo", - "entrypoint": "echo", - "command": "hellow world", - "build": map[string]interface{}{ - "context": ".", - "dockerfile": "bar.Dockerfile", - }, - "ports": []interface{}{ - "8080:80", - "9090:90", - }, - "expose": []interface{}{ - "8080", - }, - "labels": []interface{}{ - "foo=bar", - }, - "cap_add": []interface{}{ - "NET_ADMIN", - }, - }, - }, - "volumes": map[string]interface{}{}, - "networks": map[string]interface{}{}, - "secrets": map[string]interface{}{}, - "configs": map[string]interface{}{}, - } - override := map[string]interface{}{ - "services": map[string]interface{}{ - "foo": map[string]interface{}{ - "image": "baz", - "entrypoint": "ping", - "command": "localhost", - "build": map[string]interface{}{ - "dockerfile": "foo.Dockerfile", - "args": []interface{}{ - "buildno=1", - "password=secret", - }, - }, - "ports": []interface{}{ - map[string]interface{}{ - "target": 81, - "published": 8080, - }, - }, - "expose": []interface{}{ - "8080", - }, - "labels": map[string]interface{}{ - "foo": "baz", - }, - "cap_add": []interface{}{ - "SYS_ADMIN", - }, - }, - "bar": map[string]interface{}{ - "image": "bar", - }, - }, - "volumes": map[string]interface{}{}, - "networks": map[string]interface{}{}, - "secrets": map[string]interface{}{}, - "configs": map[string]interface{}{}, - } + base := ` +name: test-load-multiple-configs +services: + foo: + image: foo + entrypoint: echo + command: hello world + build: + context: . + dockerfile: bar.Dockerfile + ports: + - 8080:80 + - 9090:90 + expose: + - 8080 + labels: + - foo=bar + cap_add: + - NET_ADMIN +` + + override := ` +services: + foo: + image: baz + entrypoint: ping + command: localhost + build: + context: . + dockerfile: foo.Dockerfile + args: + - buildno=1 + - password=secret + ports: + - 8080:81 + expose: + - 8080 + labels: + - foo=baz + cap_add: + - SYS_ADMIN + bar: + image: bar +` configDetails := types.ConfigDetails{ ConfigFiles: []types.ConfigFile{ - {Filename: "base.yml", Config: base}, - {Filename: "override.yml", Config: override}, + {Filename: "base.yml", Content: []byte(base)}, + {Filename: "override.yml", Content: []byte(override)}, }, + Environment: map[string]string{}, } config, err := loadTestProject(configDetails) assert.NilError(t, err) - assert.DeepEqual(t, &types.Project{ - Name: "", - WorkingDir: "", - Services: []types.ServiceConfig{ - { - Name: "bar", - Image: "bar", - Environment: types.MappingWithEquals{}, - Scale: 1, + assert.DeepEqual(t, types.Services{ + { + Name: "foo", + Image: "baz", + Entrypoint: types.ShellCommand{"ping"}, + Command: types.ShellCommand{"localhost"}, + Build: &types.BuildConfig{ + Context: ".", + Dockerfile: "foo.Dockerfile", + Args: types.MappingWithEquals{ + "buildno": strPtr("1"), + "password": strPtr("secret"), + }, }, - { - Name: "foo", - Image: "baz", - Entrypoint: types.ShellCommand{"ping"}, - Command: types.ShellCommand{"localhost"}, - Build: &types.BuildConfig{ - Context: ".", - Dockerfile: "foo.Dockerfile", - Args: types.MappingWithEquals{ - "buildno": strPtr("1"), - "password": strPtr("secret"), - }, + Expose: []string{"8080"}, + Ports: []types.ServicePortConfig{ + { + Mode: "ingress", + Target: 80, + Published: "8080", + Protocol: "tcp", }, - Expose: []string{"8080"}, - Ports: []types.ServicePortConfig{ - { - Mode: "ingress", - Target: 80, - Published: "8080", - Protocol: "tcp", - }, - { - Target: 81, - Published: "8080", - }, - { - Mode: "ingress", - Target: 90, - Published: "9090", - Protocol: "tcp", - }, + { + Mode: "ingress", + Target: 90, + Published: "9090", + Protocol: "tcp", }, - Labels: types.Labels{ - "foo": "baz", + { + Mode: "ingress", + Target: 81, + Published: "8080", + Protocol: "tcp", }, - CapAdd: []string{"NET_ADMIN", "SYS_ADMIN"}, - Environment: types.MappingWithEquals{}, - Scale: 1, - }}, - Networks: types.Networks{}, - Volumes: types.Volumes{}, - Secrets: types.Secrets{}, - Configs: types.Configs{}, - Extensions: types.Extensions{}, - }, config) + }, + Labels: types.Labels{ + "foo": "baz", + }, + CapAdd: []string{"NET_ADMIN", "SYS_ADMIN"}, + Environment: types.MappingWithEquals{}, + Scale: 1, + }, + { + Name: "bar", + Image: "bar", + Environment: types.MappingWithEquals{}, + Scale: 1, + }, + }, config.Services) } // Issue#972 diff --git a/types/hostList.go b/types/hostList.go new file mode 100644 index 00000000..007f9ea1 --- /dev/null +++ b/types/hostList.go @@ -0,0 +1,66 @@ +/* + Copyright 2020 The Compose Specification Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package types + +import ( + "encoding/json" + "fmt" + "sort" +) + +// HostsList is a list of colon-separated host-ip mappings +type HostsList map[string]string + +// AsList return host-ip mappings as a list of colon-separated strings +func (h HostsList) AsList() []string { + l := make([]string, 0, len(h)) + for k, v := range h { + l = append(l, fmt.Sprintf("%s:%s", k, v)) + } + return l +} + +func (h HostsList) MarshalYAML() (interface{}, error) { + list := h.AsList() + sort.Strings(list) + return list, nil +} + +func (h HostsList) MarshalJSON() ([]byte, error) { + list := h.AsList() + sort.Strings(list) + return json.Marshal(list) +} + +func (h *HostsList) DecodeMapstructure(value interface{}) error { + switch v := value.(type) { + case map[string]interface{}: + list := make(HostsList, len(v)) + for i, e := range v { + if e == nil { + e = "" + } + list[i] = fmt.Sprint(e) + } + *h = list + case []interface{}: + *h = decodeMapping(v, ":") + default: + return fmt.Errorf("unexpected value type %T for mapping", value) + } + return nil +} diff --git a/types/mapping.go b/types/mapping.go index 2a399168..5e79e308 100644 --- a/types/mapping.go +++ b/types/mapping.go @@ -188,17 +188,21 @@ func (m *Mapping) DecodeMapstructure(value interface{}) error { } *m = mapping case []interface{}: - mapping := make(Mapping, len(v)) - for _, s := range v { - k, e, ok := strings.Cut(fmt.Sprint(s), "=") - if !ok { - e = "" - } - mapping[k] = fmt.Sprint(e) - } - *m = mapping + *m = decodeMapping(v, "=") default: return fmt.Errorf("unexpected value type %T for mapping", value) } return nil } + +func decodeMapping(v []interface{}, sep string) map[string]string { + mapping := make(Mapping, len(v)) + for _, s := range v { + k, e, ok := strings.Cut(fmt.Sprint(s), sep) + if !ok { + e = "" + } + mapping[k] = fmt.Sprint(e) + } + return mapping +} diff --git a/types/types.go b/types/types.go index 5d87e397..84a9b525 100644 --- a/types/types.go +++ b/types/types.go @@ -365,30 +365,6 @@ func (s SSHKey) MarshalJSON() ([]byte, error) { // 'key: value' strings type MappingWithColon map[string]string -// HostsList is a list of colon-separated host-ip mappings -type HostsList map[string]string - -// AsList return host-ip mappings as a list of colon-separated strings -func (h HostsList) AsList() []string { - l := make([]string, 0, len(h)) - for k, v := range h { - l = append(l, fmt.Sprintf("%s:%s", k, v)) - } - return l -} - -func (h HostsList) MarshalYAML() (interface{}, error) { - list := h.AsList() - sort.Strings(list) - return list, nil -} - -func (h HostsList) MarshalJSON() ([]byte, error) { - list := h.AsList() - sort.Strings(list) - return json.Marshal(list) -} - // LoggingConfig the logging configuration for a service type LoggingConfig struct { Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`