You've already forked dcmerge
							
							The following patch adapts the logic of the merge strategy existing and last
win for service ports.
In the past, the complete object has been replaced based on the merge strategy.
This behavior has been adapted, that each port should now considered
individually per strategy.
Both strategies now focus on the src port of the host system. With a last-win,
the dest port of the container is overwritten with an existing src port.
```diff
  service:
    my-app:
      ports:
- - 0.0.0.0:8080:80
+ - 0.0.0.0:8080:8080
      - 0.0.0.0:8443:8443
```
The situation is different with the existing win strategy. There, the destination
port can no longer be changed once there is a connection with a sourc port.
		
	
		
			
				
	
	
		
			419 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package dockerCompose
 | 
						|
 | 
						|
import (
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
func Test_splitStringInPortMapping(t *testing.T) {
 | 
						|
	require := require.New(t)
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		s                string
 | 
						|
		expectedSrc      string
 | 
						|
		expectedDst      string
 | 
						|
		expectedProtocol string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			s:                "53:53",
 | 
						|
			expectedSrc:      "53",
 | 
						|
			expectedDst:      "53",
 | 
						|
			expectedProtocol: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:                "0.0.0.0:53:53",
 | 
						|
			expectedSrc:      "0.0.0.0:53",
 | 
						|
			expectedDst:      "53",
 | 
						|
			expectedProtocol: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:                "0.0.0.0:53:10.11.12.13:53",
 | 
						|
			expectedSrc:      "0.0.0.0:53",
 | 
						|
			expectedDst:      "10.11.12.13:53",
 | 
						|
			expectedProtocol: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:                "0.0.0.0:53:10.11.12.13:53/tcp",
 | 
						|
			expectedSrc:      "0.0.0.0:53",
 | 
						|
			expectedDst:      "10.11.12.13:53",
 | 
						|
			expectedProtocol: "tcp",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		actualSrc, actualDst, actualProtocol := splitStringInPortMapping(testCase.s)
 | 
						|
		require.Equal(testCase.expectedSrc, actualSrc, "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedDst, actualDst, "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedProtocol, actualProtocol, "TestCase %v", i)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPort_DstIP(t *testing.T) {
 | 
						|
	require := require.New(t)
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		s              string
 | 
						|
		expectedBool   bool
 | 
						|
		expectedString string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			s:              "",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/tcp",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/udp",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:0.0.0.0:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "0.0.0.0",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:0.0.0.0:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "0.0.0.0",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:0.0.0.0:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "0.0.0.0",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:10.11.12.13:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "10.11.12.13",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:10.11.12.13:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "10.11.12.13",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:10.11.12.13:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "10.11.12.13",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		p := Port(testCase.s)
 | 
						|
		require.Equal(testCase.expectedBool, p.existsDstIP(), "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedString, p.getDstIP(), "TestCase %v", i)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPort_DstPort(t *testing.T) {
 | 
						|
	require := require.New(t)
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		s              string
 | 
						|
		expectedBool   bool
 | 
						|
		expectedString string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			s:              "",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "53:0.0.0.0:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:0.0.0.0:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:0.0.0.0:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "53:10.11.12.13:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:10.11.12.13:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:10.11.12.13:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		p := Port(testCase.s)
 | 
						|
		require.Equal(testCase.expectedBool, p.existsDstPort(), "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedString, p.getDstPort(), "TestCase %v", i)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPort_Protocol(t *testing.T) {
 | 
						|
	require := require.New(t)
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		s              string
 | 
						|
		expectedBool   bool
 | 
						|
		expectedString string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			s:              "0",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53/tcp",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53/udp",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "tcp",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "udp",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "tcp",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "udp",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "tcp",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:11.12.13.14:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "tcp",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:11.12.13.14:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "udp",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		p := Port(testCase.s)
 | 
						|
		require.Equal(testCase.expectedBool, p.existsProtocol(), "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedString, p.getProtocol(), "TestCase %v", i)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPort_SrcIP(t *testing.T) {
 | 
						|
	require := require.New(t)
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		s              string
 | 
						|
		expectedBool   bool
 | 
						|
		expectedString string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			s:              "",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/tcp",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/udp",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "0.0.0.0",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "0.0.0.0",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "0.0.0.0",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "10.11.12.13",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "10.11.12.13",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "10.11.12.13",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		p := Port(testCase.s)
 | 
						|
		require.Equal(testCase.expectedBool, p.existsSrcIP(), "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedString, p.getSrcIP(), "TestCase %v", i)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestPort_SrcPort(t *testing.T) {
 | 
						|
	require := require.New(t)
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		s              string
 | 
						|
		expectedBool   bool
 | 
						|
		expectedString string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			s:              "",
 | 
						|
			expectedBool:   false,
 | 
						|
			expectedString: "",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "0.0.0.0:53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53:53",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53:53/tcp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			s:              "10.11.12.13:53:53/udp",
 | 
						|
			expectedBool:   true,
 | 
						|
			expectedString: "53",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		p := Port(testCase.s)
 | 
						|
		require.Equal(testCase.expectedBool, p.existsSrcPort(), "TestCase %v", i)
 | 
						|
		require.Equal(testCase.expectedString, p.getSrcPort(), "TestCase %v", i)
 | 
						|
	}
 | 
						|
}
 |