github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/cli/command/stack/kubernetes/convert_test.go (about) 1 package kubernetes 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "path/filepath" 7 "testing" 8 9 "github.com/docker/cli/cli/compose/loader" 10 composetypes "github.com/docker/cli/cli/compose/types" 11 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3" 12 "github.com/docker/compose-on-kubernetes/api/compose/v1beta1" 13 "github.com/docker/compose-on-kubernetes/api/compose/v1beta2" 14 "gotest.tools/assert" 15 is "gotest.tools/assert/cmp" 16 v1 "k8s.io/api/core/v1" 17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 ) 19 20 func TestNewStackConverter(t *testing.T) { 21 _, err := NewStackConverter("v1alpha1") 22 assert.Check(t, is.ErrorContains(err, "stack version v1alpha1 unsupported")) 23 24 _, err = NewStackConverter("v1beta1") 25 assert.NilError(t, err) 26 _, err = NewStackConverter("v1beta2") 27 assert.NilError(t, err) 28 _, err = NewStackConverter("v1alpha3") 29 assert.NilError(t, err) 30 } 31 32 func TestConvertFromToV1beta1(t *testing.T) { 33 composefile := `version: "3.3" 34 services: 35 test: 36 image: nginx 37 secrets: 38 test: 39 file: testdata/secret 40 configs: 41 test: 42 file: testdata/config 43 ` 44 stackv1beta1 := &v1beta1.Stack{ 45 ObjectMeta: metav1.ObjectMeta{ 46 Name: "test", 47 }, 48 Spec: v1beta1.StackSpec{ 49 ComposeFile: composefile, 50 }, 51 } 52 53 result, err := stackFromV1beta1(stackv1beta1) 54 assert.NilError(t, err) 55 expected := Stack{ 56 Name: "test", 57 ComposeFile: composefile, 58 Spec: &v1alpha3.StackSpec{ 59 Services: []v1alpha3.ServiceConfig{ 60 { 61 Name: "test", 62 Image: "nginx", 63 Environment: make(map[string]*string), 64 }, 65 }, 66 Secrets: map[string]v1alpha3.SecretConfig{ 67 "test": {File: filepath.FromSlash("testdata/secret")}, 68 }, 69 Configs: map[string]v1alpha3.ConfigObjConfig{ 70 "test": {File: filepath.FromSlash("testdata/config")}, 71 }, 72 }, 73 } 74 assert.DeepEqual(t, expected, result) 75 assert.DeepEqual(t, stackv1beta1, stackToV1beta1(result)) 76 } 77 78 func TestConvertFromToV1beta2(t *testing.T) { 79 stackv1beta2 := &v1beta2.Stack{ 80 ObjectMeta: metav1.ObjectMeta{ 81 Name: "test", 82 }, 83 Spec: &v1beta2.StackSpec{ 84 Services: []v1beta2.ServiceConfig{ 85 { 86 Name: "test", 87 Image: "nginx", 88 Environment: make(map[string]*string), 89 }, 90 }, 91 Secrets: map[string]v1beta2.SecretConfig{ 92 "test": {File: filepath.FromSlash("testdata/secret")}, 93 }, 94 Configs: map[string]v1beta2.ConfigObjConfig{ 95 "test": {File: filepath.FromSlash("testdata/config")}, 96 }, 97 }, 98 } 99 expected := Stack{ 100 Name: "test", 101 Spec: &v1alpha3.StackSpec{ 102 Services: []v1alpha3.ServiceConfig{ 103 { 104 Name: "test", 105 Image: "nginx", 106 Environment: make(map[string]*string), 107 }, 108 }, 109 Secrets: map[string]v1alpha3.SecretConfig{ 110 "test": {File: filepath.FromSlash("testdata/secret")}, 111 }, 112 Configs: map[string]v1alpha3.ConfigObjConfig{ 113 "test": {File: filepath.FromSlash("testdata/config")}, 114 }, 115 }, 116 } 117 result, err := stackFromV1beta2(stackv1beta2) 118 assert.NilError(t, err) 119 assert.DeepEqual(t, expected, result) 120 gotBack, err := stackToV1beta2(result) 121 assert.NilError(t, err) 122 assert.DeepEqual(t, stackv1beta2, gotBack) 123 } 124 125 func TestConvertFromToV1alpha3(t *testing.T) { 126 stackv1alpha3 := &v1alpha3.Stack{ 127 ObjectMeta: metav1.ObjectMeta{ 128 Name: "test", 129 }, 130 Spec: &v1alpha3.StackSpec{ 131 Services: []v1alpha3.ServiceConfig{ 132 { 133 Name: "test", 134 Image: "nginx", 135 Environment: make(map[string]*string), 136 }, 137 }, 138 Secrets: map[string]v1alpha3.SecretConfig{ 139 "test": {File: filepath.FromSlash("testdata/secret")}, 140 }, 141 Configs: map[string]v1alpha3.ConfigObjConfig{ 142 "test": {File: filepath.FromSlash("testdata/config")}, 143 }, 144 }, 145 } 146 expected := Stack{ 147 Name: "test", 148 Spec: &v1alpha3.StackSpec{ 149 Services: []v1alpha3.ServiceConfig{ 150 { 151 Name: "test", 152 Image: "nginx", 153 Environment: make(map[string]*string), 154 }, 155 }, 156 Secrets: map[string]v1alpha3.SecretConfig{ 157 "test": {File: filepath.FromSlash("testdata/secret")}, 158 }, 159 Configs: map[string]v1alpha3.ConfigObjConfig{ 160 "test": {File: filepath.FromSlash("testdata/config")}, 161 }, 162 }, 163 } 164 result := stackFromV1alpha3(stackv1alpha3) 165 assert.DeepEqual(t, expected, result) 166 gotBack := stackToV1alpha3(result) 167 assert.DeepEqual(t, stackv1alpha3, gotBack) 168 } 169 170 func loadTestStackWith(t *testing.T, with string) *composetypes.Config { 171 t.Helper() 172 filePath := fmt.Sprintf("testdata/compose-with-%s.yml", with) 173 data, err := ioutil.ReadFile(filePath) 174 assert.NilError(t, err) 175 yamlData, err := loader.ParseYAML(data) 176 assert.NilError(t, err) 177 cfg, err := loader.Load(composetypes.ConfigDetails{ 178 ConfigFiles: []composetypes.ConfigFile{ 179 {Config: yamlData, Filename: filePath}, 180 }, 181 }) 182 assert.NilError(t, err) 183 return cfg 184 } 185 186 func TestHandlePullSecret(t *testing.T) { 187 testData := loadTestStackWith(t, "pull-secret") 188 cases := []struct { 189 version string 190 err string 191 }{ 192 {version: "v1beta1", err: `stack API version v1beta1 does not support pull secrets (field "x-kubernetes.pull_secret"), please use version v1alpha3 or higher`}, 193 {version: "v1beta2", err: `stack API version v1beta2 does not support pull secrets (field "x-kubernetes.pull_secret"), please use version v1alpha3 or higher`}, 194 {version: "v1alpha3"}, 195 } 196 197 for _, c := range cases { 198 t.Run(c.version, func(t *testing.T) { 199 conv, err := NewStackConverter(c.version) 200 assert.NilError(t, err) 201 s, err := conv.FromCompose(ioutil.Discard, "test", testData) 202 if c.err != "" { 203 assert.Error(t, err, c.err) 204 205 } else { 206 assert.NilError(t, err) 207 assert.Equal(t, s.Spec.Services[0].PullSecret, "some-secret") 208 } 209 }) 210 } 211 } 212 213 func TestHandlePullPolicy(t *testing.T) { 214 testData := loadTestStackWith(t, "pull-policy") 215 cases := []struct { 216 version string 217 err string 218 }{ 219 {version: "v1beta1", err: `stack API version v1beta1 does not support pull policies (field "x-kubernetes.pull_policy"), please use version v1alpha3 or higher`}, 220 {version: "v1beta2", err: `stack API version v1beta2 does not support pull policies (field "x-kubernetes.pull_policy"), please use version v1alpha3 or higher`}, 221 {version: "v1alpha3"}, 222 } 223 224 for _, c := range cases { 225 t.Run(c.version, func(t *testing.T) { 226 conv, err := NewStackConverter(c.version) 227 assert.NilError(t, err) 228 s, err := conv.FromCompose(ioutil.Discard, "test", testData) 229 if c.err != "" { 230 assert.Error(t, err, c.err) 231 232 } else { 233 assert.NilError(t, err) 234 assert.Equal(t, s.Spec.Services[0].PullPolicy, "Never") 235 } 236 }) 237 } 238 } 239 240 func TestHandleInternalServiceType(t *testing.T) { 241 cases := []struct { 242 name string 243 value string 244 caps composeCapabilities 245 err string 246 expected v1alpha3.InternalServiceType 247 }{ 248 { 249 name: "v1beta1", 250 value: "ClusterIP", 251 caps: v1beta1Capabilities, 252 err: `stack API version v1beta1 does not support intra-stack load balancing (field "x-kubernetes.internal_service_type"), please use version v1alpha3 or higher`, 253 }, 254 { 255 name: "v1beta2", 256 value: "ClusterIP", 257 caps: v1beta2Capabilities, 258 err: `stack API version v1beta2 does not support intra-stack load balancing (field "x-kubernetes.internal_service_type"), please use version v1alpha3 or higher`, 259 }, 260 { 261 name: "v1alpha3", 262 value: "ClusterIP", 263 caps: v1alpha3Capabilities, 264 expected: v1alpha3.InternalServiceTypeClusterIP, 265 }, 266 { 267 name: "v1alpha3-invalid", 268 value: "invalid", 269 caps: v1alpha3Capabilities, 270 err: `invalid value "invalid" for field "x-kubernetes.internal_service_type", valid values are "ClusterIP" or "Headless"`, 271 }, 272 } 273 for _, c := range cases { 274 t.Run(c.name, func(t *testing.T) { 275 res, err := fromComposeServiceConfig(composetypes.ServiceConfig{ 276 Name: "test", 277 Image: "test", 278 Extras: map[string]interface{}{ 279 "x-kubernetes": map[string]interface{}{ 280 "internal_service_type": c.value, 281 }, 282 }, 283 }, c.caps) 284 if c.err == "" { 285 assert.NilError(t, err) 286 assert.Equal(t, res.InternalServiceType, c.expected) 287 } else { 288 assert.ErrorContains(t, err, c.err) 289 } 290 }) 291 } 292 } 293 294 func TestIgnoreExpose(t *testing.T) { 295 testData := loadTestStackWith(t, "expose") 296 for _, version := range []string{"v1beta1", "v1beta2"} { 297 conv, err := NewStackConverter(version) 298 assert.NilError(t, err) 299 s, err := conv.FromCompose(ioutil.Discard, "test", testData) 300 assert.NilError(t, err) 301 assert.Equal(t, len(s.Spec.Services[0].InternalPorts), 0) 302 } 303 } 304 305 func TestParseExpose(t *testing.T) { 306 testData := loadTestStackWith(t, "expose") 307 conv, err := NewStackConverter("v1alpha3") 308 assert.NilError(t, err) 309 s, err := conv.FromCompose(ioutil.Discard, "test", testData) 310 assert.NilError(t, err) 311 expected := []v1alpha3.InternalPort{ 312 { 313 Port: 1, 314 Protocol: v1.ProtocolTCP, 315 }, 316 { 317 Port: 2, 318 Protocol: v1.ProtocolTCP, 319 }, 320 { 321 Port: 3, 322 Protocol: v1.ProtocolTCP, 323 }, 324 { 325 Port: 4, 326 Protocol: v1.ProtocolTCP, 327 }, 328 { 329 Port: 5, 330 Protocol: v1.ProtocolUDP, 331 }, 332 { 333 Port: 6, 334 Protocol: v1.ProtocolUDP, 335 }, 336 { 337 Port: 7, 338 Protocol: v1.ProtocolUDP, 339 }, 340 { 341 Port: 8, 342 Protocol: v1.ProtocolUDP, 343 }, 344 } 345 assert.DeepEqual(t, s.Spec.Services[0].InternalPorts, expected) 346 }