--- /dev/null
+package main_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os/exec"
+ "strings"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gbytes"
+ "github.com/onsi/gomega/gexec"
+)
+
+var binaryPath string
+
+var _ = SynchronizedBeforeSuite(func() []byte {
+ binaryPath, err := gexec.Build("github.com/containernetworking/plugins/plugins/meta/portmap/echosvr")
+ Expect(err).NotTo(HaveOccurred())
+ return []byte(binaryPath)
+}, func(data []byte) {
+ binaryPath = string(data)
+})
+
+var _ = SynchronizedAfterSuite(func() {}, func() {
+ gexec.CleanupBuildArtifacts()
+})
+
+var _ = Describe("Echosvr", func() {
+ var session *gexec.Session
+ BeforeEach(func() {
+ var err error
+ cmd := exec.Command(binaryPath)
+ session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ session.Terminate().Wait()
+ })
+
+ It("starts and doesn't terminate immediately", func() {
+ Consistently(session).ShouldNot(gexec.Exit())
+ })
+
+ tryConnect := func() (net.Conn, error) {
+ programOutput := session.Out.Contents()
+ addr := strings.TrimSpace(string(programOutput))
+
+ conn, err := net.Dial("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+ return conn, err
+ }
+
+ It("prints its listening address to stdout", func() {
+ Eventually(session.Out).Should(gbytes.Say("\n"))
+ conn, err := tryConnect()
+ Expect(err).NotTo(HaveOccurred())
+ conn.Close()
+ })
+
+ It("will echo data back to us", func() {
+ Eventually(session.Out).Should(gbytes.Say("\n"))
+ conn, err := tryConnect()
+ Expect(err).NotTo(HaveOccurred())
+ defer conn.Close()
+
+ fmt.Fprintf(conn, "hello")
+ Expect(ioutil.ReadAll(conn)).To(Equal([]byte("hello")))
+ })
+})
--- /dev/null
+package main_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestEchosvr(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Echosvr Suite")
+}
--- /dev/null
+package main
+
+import (
+ "fmt"
+ "net"
+)
+
+func main() {
+ listener, err := net.Listen("tcp", ":")
+ if err != nil {
+ panic(err)
+ }
+ _, port, err := net.SplitHostPort(listener.Addr().String())
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("127.0.0.1:%s\n", port)
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ panic(err)
+ }
+ go handleConnection(conn)
+ }
+}
+
+func handleConnection(conn net.Conn) {
+ buf := make([]byte, 512)
+ nBytesRead, _ := conn.Read(buf)
+ conn.Write(buf[0:nBytesRead])
+ conn.Close()
+}
"github.com/coreos/go-iptables/iptables"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gexec"
"github.com/vishvananda/netlink"
)
const TIMEOUT = 90
var _ = Describe("portmap integration tests", func() {
- rand.Seed(time.Now().UTC().UnixNano())
-
- var configList *libcni.NetworkConfigList
- var cniConf *libcni.CNIConfig
- var targetNS ns.NetNS
- var containerPort int
- var closeChan chan interface{}
+ var (
+ configList *libcni.NetworkConfigList
+ cniConf *libcni.CNIConfig
+ targetNS ns.NetNS
+ containerPort int
+ session *gexec.Session
+ )
BeforeEach(func() {
var err error
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS.Path())
// Start an echo server and get the port
- containerPort, closeChan, err = RunEchoServerInNS(targetNS)
+ containerPort, session, err = StartEchoServerInNamespace(targetNS)
Expect(err).NotTo(HaveOccurred())
-
})
AfterEach(func() {
+ session.Terminate().Wait()
if targetNS != nil {
targetNS.Close()
}
snatOK := testEchoServer(fmt.Sprintf("%s:%d", "127.0.0.1", hostPort))
// Cleanup
- close(closeChan)
+ session.Terminate()
err = deleteNetwork()
Expect(err).NotTo(HaveOccurred())
package main
import (
- "fmt"
+ "math/rand"
"net"
- "time"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
"github.com/containernetworking/plugins/pkg/ns"
. "github.com/onsi/ginkgo"
+ "github.com/onsi/ginkgo/config"
. "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gbytes"
+ "github.com/onsi/gomega/gexec"
"testing"
)
func TestPortmap(t *testing.T) {
+ rand.Seed(config.GinkgoConfig.RandomSeed)
+
RegisterFailHandler(Fail)
RunSpecs(t, "portmap Suite")
}
-// OpenEchoServer opens a server that listens until closeChan is closed.
-// It opens on a random port and sends the port number on portChan when
-// the server is up and running. If an error is encountered, closes portChan.
-// If closeChan is closed, closes the socket.
-func OpenEchoServer(portChan chan<- int, closeChan <-chan interface{}) error {
- laddr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:0")
- if err != nil {
- close(portChan)
- return err
- }
- sock, err := net.ListenTCP("tcp", laddr)
- if err != nil {
- close(portChan)
- return err
- }
- defer sock.Close()
+var echoServerBinaryPath string
- switch addr := sock.Addr().(type) {
- case *net.TCPAddr:
- portChan <- addr.Port
- default:
- close(portChan)
- return fmt.Errorf("addr cast failed!")
- }
- for {
- select {
- case <-closeChan:
- break
- default:
- }
+var _ = SynchronizedBeforeSuite(func() []byte {
+ binaryPath, err := gexec.Build("github.com/containernetworking/plugins/plugins/meta/portmap/echosvr")
+ Expect(err).NotTo(HaveOccurred())
+ return []byte(binaryPath)
+}, func(data []byte) {
+ echoServerBinaryPath = string(data)
+})
- sock.SetDeadline(time.Now().Add(time.Second))
- con, err := sock.AcceptTCP()
- if err != nil {
- if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
- continue
- }
- continue
- }
+var _ = SynchronizedAfterSuite(func() {}, func() {
+ gexec.CleanupBuildArtifacts()
+})
- buf := make([]byte, 512)
- con.Read(buf)
- con.Write(buf)
- con.Close()
- }
+func startInNetNS(binPath string, netNS ns.NetNS) (*gexec.Session, error) {
+ baseName := filepath.Base(netNS.Path())
+ // we are relying on the netNS path living in /var/run/netns
+ // where `ip netns exec` can find it
+ cmd := exec.Command("ip", "netns", "exec", baseName, binPath)
+ session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
+ return session, err
}
-func RunEchoServerInNS(netNS ns.NetNS) (int, chan interface{}, error) {
- portChan := make(chan int)
- closeChan := make(chan interface{})
-
- go func() {
- err := netNS.Do(func(ns.NetNS) error {
- OpenEchoServer(portChan, closeChan)
- return nil
- })
- // Somehow the ns.Do failed
- if err != nil {
- close(portChan)
- }
- }()
+func StartEchoServerInNamespace(netNS ns.NetNS) (int, *gexec.Session, error) {
+ session, err := startInNetNS(echoServerBinaryPath, netNS)
+ Expect(err).NotTo(HaveOccurred())
- portNum := <-portChan
- if portNum == 0 {
- return 0, nil, fmt.Errorf("failed to execute server")
- }
+ // wait for it to print it's address on stdout
+ Eventually(session.Out).Should(gbytes.Say("\n"))
+ _, portString, err := net.SplitHostPort(strings.TrimSpace(string(session.Out.Contents())))
+ Expect(err).NotTo(HaveOccurred())
- return portNum, closeChan, nil
+ port, err := strconv.Atoi(portString)
+ Expect(err).NotTo(HaveOccurred())
+ return port, session, nil
}