github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/tiltfile/docker_compose_test.go (about)

     1  package tiltfile
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  
     9  	"github.com/tilt-dev/tilt/internal/dockercompose"
    10  	"github.com/tilt-dev/tilt/internal/testutils"
    11  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    12  )
    13  
    14  // ParseConfig must return services topologically sorted wrt dependencies.
    15  
    16  func TestParseConfigPreservesServiceOrder(t *testing.T) {
    17  	f := newDCFixture(t)
    18  
    19  	var output = `version: '3'
    20  services:
    21    a:
    22      image: imga
    23      depends_on: [b]
    24    b:
    25      image: imgb
    26      depends_on: [c]
    27    c:
    28      image: imgc
    29      depends_on: [d, e, f]
    30    d:
    31      image: imgd
    32      depends_on: [f, e]
    33    e:
    34      image: imge
    35      depends_on: [f]
    36    f:
    37      image: imgf
    38  `
    39  
    40  	services := f.parse(output)
    41  	if assert.Len(t, services, 6) {
    42  		serviceOrder := []string{"f", "e", "d", "c", "b", "a"}
    43  		for i, name := range serviceOrder {
    44  			assert.Equal(t, name, services[i].Name)
    45  		}
    46  		depOrder := [][]string{
    47  			[]string{},
    48  			[]string{"f"},
    49  			[]string{"e", "f"},
    50  			[]string{"d", "e", "f"},
    51  			[]string{"c"},
    52  			[]string{"b"},
    53  		}
    54  		for i, deps := range depOrder {
    55  			assert.Equal(t, deps, services[i].Options.resourceDeps)
    56  		}
    57  	}
    58  }
    59  
    60  func TestPortStruct(t *testing.T) {
    61  	f := newDCFixture(t)
    62  
    63  	output := `services:
    64    app:
    65      command: sh -c 'node server.js'
    66      image: tilt.dev/express-redis-app
    67      ports:
    68      - published: 3000
    69        target: 30
    70  version: '3.2'
    71  `
    72  	services := f.parse(output)
    73  	if assert.Len(t, services, 1) {
    74  		assert.Equal(t, []int{3000}, services[0].PublishedPorts)
    75  	}
    76  
    77  }
    78  
    79  func TestPortMapRandomized(t *testing.T) {
    80  	f := newDCFixture(t)
    81  
    82  	output := `services:
    83    app:
    84      command: sh -c 'node server.js'
    85      image: tilt.dev/express-redis-app
    86      ports:
    87      - 3000/tcp
    88  version: '3.0'
    89  `
    90  	services := f.parse(output)
    91  	if assert.Len(t, services, 1) {
    92  		assert.Empty(t, services[0].PublishedPorts)
    93  	}
    94  }
    95  
    96  func TestPortMapDifferent(t *testing.T) {
    97  	f := newDCFixture(t)
    98  
    99  	output := `services:
   100    app:
   101      command: sh -c 'node server.js'
   102      image: tilt.dev/express-redis-app
   103      ports:
   104      - 3000:30/tcp
   105  version: '3.0'
   106  `
   107  
   108  	services := f.parse(output)
   109  	if assert.Len(t, services, 1) {
   110  		assert.Equal(t, []int{3000}, services[0].PublishedPorts)
   111  	}
   112  }
   113  
   114  func TestPortMapIP(t *testing.T) {
   115  	f := newDCFixture(t)
   116  
   117  	output := `services:
   118    app:
   119      command: sh -c 'node server.js'
   120      image: tilt.dev/express-redis-app
   121      ports:
   122      - 127.0.0.1:3000:30/tcp
   123  version: '3.0'
   124  `
   125  
   126  	services := f.parse(output)
   127  	if assert.Len(t, services, 1) {
   128  		assert.Equal(t, []int{3000}, services[0].PublishedPorts)
   129  	}
   130  }
   131  
   132  func TestMarshalOverflow(t *testing.T) {
   133  	f := newDCFixture(t)
   134  
   135  	// certain Compose types cause a stack overflow panic if marshaled with gopkg.in/yaml.v3
   136  	// https://github.com/tilt-dev/tilt/issues/4797
   137  	output := `services:
   138    foo:
   139      image: myimage
   140      ulimits:
   141        nproc: 65535
   142        nofile:
   143          soft: 20000
   144          hard: 40000
   145  `
   146  
   147  	services := f.parse(output)
   148  	assert.NotEmpty(t, services)
   149  }
   150  
   151  type dcFixture struct {
   152  	t     *testing.T
   153  	ctx   context.Context
   154  	dcCli *dockercompose.FakeDCClient
   155  }
   156  
   157  func newDCFixture(t *testing.T) dcFixture {
   158  	ctx, _, _ := testutils.CtxAndAnalyticsForTest()
   159  	dcCli := dockercompose.NewFakeDockerComposeClient(t, ctx)
   160  	return dcFixture{
   161  		t:     t,
   162  		ctx:   ctx,
   163  		dcCli: dcCli,
   164  	}
   165  }
   166  
   167  func (f dcFixture) parse(configOutput string) []*dcService {
   168  	f.t.Helper()
   169  
   170  	f.dcCli.ConfigOutput = configOutput
   171  
   172  	dc := &dcResourceSet{
   173  		Project:    v1alpha1.DockerComposeProject{ConfigPaths: []string{"doesn't-matter.yml"}},
   174  		services:   make(map[string]*dcService),
   175  		resOptions: make(map[string]*dcResourceOptions),
   176  	}
   177  
   178  	services, err := parseDCConfig(f.ctx, f.dcCli, dc)
   179  	if err != nil {
   180  		f.t.Fatalf("dcFixture.Parse: %v", err)
   181  	}
   182  	return services
   183  }