From b09bccdd86b1f9a093e4d0485652fa6cbb80a02d Mon Sep 17 00:00:00 2001 From: Brian Cunnie Date: Sat, 30 Sep 2023 09:01:01 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20Make=20integration=20tests=20IPv?= =?UTF-8?q?4/IPv6=20stack-agnostic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The integration test which worked fine on my dual-stack laptop failed on my IPv4-only Concourse. Fixes, when running `ginkgo -r -p .` on an IPv4-only machine: ``` sslip.io-dns-server When it can't bind to a port on loopback [BeforeEach] prints an informative message and continues [BeforeEach] /tmp/build/b4e0c68a/sslip.io/src/sslip.io-dns-server/integration_test.go:399 [It] /tmp/build/b4e0c68a/sslip.io/src/sslip.io-dns-server/integration_test.go:409 [FAILED] Unexpected error: <*net.OpError | 0xc000310d20>: listen udp [::1]:1918: socket: address family not supported by protocol ``` --- src/sslip.io-dns-server/integration_test.go | 34 +++++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/sslip.io-dns-server/integration_test.go b/src/sslip.io-dns-server/integration_test.go index a98f31e..793f682 100644 --- a/src/sslip.io-dns-server/integration_test.go +++ b/src/sslip.io-dns-server/integration_test.go @@ -395,26 +395,22 @@ var _ = Describe("sslip.io-dns-server", func() { }) }) Describe("When it can't bind to a port on loopback", func() { - var udpConnSquatter *net.UDPConn + var squatter *net.UDPConn BeforeEach(func() { port = getFreePort() - // the following won't work on an IPv6-only machine; change to "::1" in that case - udpAddr := net.UDPAddr{ - IP: net.ParseIP("::1"), - Port: port, - } - udpConnSquatter, err = net.ListenUDP("udp", &udpAddr) + squatter, err = squatOnUdpLoopbackPort(port) Expect(err).ToNot(HaveOccurred()) + }) - It("prints an informative message and continues", func() { + It("prints an informative message and binds to the addresses it can", func() { Expect(err).ToNot(HaveOccurred()) secondServerCmd := exec.Command(serverPath, "-port", strconv.Itoa(port), "-blocklistURL", "file://../../etc/blocklist.txt") secondServerSession, err := Start(secondServerCmd, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) Eventually(secondServerSession.Err, 10).Should(Say(` version \d+\.\d+\.\d+ starting`)) Eventually(secondServerSession.Err, 10).Should(Say(`I couldn't bind via UDP to "\[::\]:\d+" \(INADDR_ANY, all interfaces\), so I'll try to bind to each address individually.`)) - Eventually(secondServerSession.Err, 10).Should(Say(`I couldn't bind via UDP to the following IPs:.* "::1"`)) - err = udpConnSquatter.Close() + Eventually(secondServerSession.Err, 10).Should(Say(`I couldn't bind via UDP to the following IPs:.* "(::1|127\.0\.0\.1)"`)) + err = squatter.Close() Expect(err).ToNot(HaveOccurred()) Eventually(secondServerSession.Err, 10).Should(Say("Ready to answer queries")) secondServerSession.Terminate() @@ -425,6 +421,24 @@ var _ = Describe("sslip.io-dns-server", func() { var listenPort = 1023 // lowest unprivileged port - 1 (immediately incremented) +func squatOnUdpLoopbackPort(port int) (squatter *net.UDPConn, err error) { + // try IPv6's loopback + udpAddr := net.UDPAddr{ + IP: net.ParseIP("::1"), + Port: port, + } + squatter, err = net.ListenUDP("udp", &udpAddr) + if err != nil { + // try IPv4's loopback + udpAddr = net.UDPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: port, + } + squatter, err = net.ListenUDP("udp", &udpAddr) + } + return squatter, err +} + // getFreePort should always succeed unless something awful has happened, e.g. port exhaustion func getFreePort() int { // we randomize the start based on the millisecond to avoid collisions in our test