From 851d05161ad584abfc9845fc1af1ff3cd443847b Mon Sep 17 00:00:00 2001 From: Jesse Lucas Date: Fri, 29 Jul 2016 17:05:31 -0400 Subject: [PATCH] Adding return error value to checkPortAvailability to enable testing of function. Adding checkport_test.go to test checkPortAvailability. Updated server-main.go to use error value from checkPortAvailability and calls fatalIf if an error is returned. (#2322) --- checkport.go | 29 ++++++++++++++++--------- checkport_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ server-main.go | 5 +++-- 3 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 checkport_test.go diff --git a/checkport.go b/checkport.go index 5b8cc8090..0573cf87a 100644 --- a/checkport.go +++ b/checkport.go @@ -18,6 +18,7 @@ package main import ( "errors" + "fmt" "net" "os" "syscall" @@ -32,7 +33,7 @@ import ( // This causes confusion on Mac OSX that minio server is not reachable // on 127.0.0.1 even though minio server is running. So before we start // the minio server we make sure that the port is free on all the IPs. -func checkPortAvailability(port int) { +func checkPortAvailability(port int) error { isAddrInUse := func(err error) bool { // Check if the syscall error is EADDRINUSE. // EADDRINUSE is the system call error if another process is @@ -54,40 +55,48 @@ func checkPortAvailability(port int) { } return true } + ifcs, err := net.Interfaces() if err != nil { - fatalIf(err, "Unable to list interfaces.") + return err } + for _, ifc := range ifcs { addrs, err := ifc.Addrs() if err != nil { - fatalIf(err, "Unable to list addresses on interface %s.", ifc.Name) + return err } + for _, addr := range addrs { ipnet, ok := addr.(*net.IPNet) if !ok { errorIf(errors.New(""), "Failed to assert type on (*net.IPNet) interface.") continue } + ip := ipnet.IP network := "tcp4" if ip.To4() == nil { network = "tcp6" } - tcpAddr := net.TCPAddr{IP: ip, Port: port, Zone: ifc.Name} - l, err := net.ListenTCP(network, &tcpAddr) + + l, err := net.Listen(network, fmt.Sprintf(":%d", port)) if err != nil { if isAddrInUse(err) { // Fail if port is already in use. - fatalIf(err, "Unable to listen on %s:%.d.", tcpAddr.IP, tcpAddr.Port) - } else { - // Ignore other errors. - continue + return err } + + // Ignore other errors. + continue + } + if err = l.Close(); err != nil { - fatalIf(err, "Unable to close listener on %s:%.d.", tcpAddr.IP, tcpAddr.Port) + return err } } } + + return nil } diff --git a/checkport_test.go b/checkport_test.go new file mode 100644 index 000000000..84a3d9d3e --- /dev/null +++ b/checkport_test.go @@ -0,0 +1,54 @@ +/* + * Minio Cloud Storage, (C) 2016 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "fmt" + "net" + "runtime" + "testing" +) + +func TestCheckPortAvailability(t *testing.T) { + tests := []struct { + port int + }{ + {9000}, + {10000}, + } + for _, test := range tests { + // This test should pass if the ports are available + err := checkPortAvailability(test.port) + if err != nil { + t.Fatalf("checkPortAvailability test failed for port: %d. Error: %v", test.port, err) + } + + // Now use the ports and check again + ln, err := net.Listen("tcp", fmt.Sprintf(":%d", test.port)) + if err != nil { + t.Fail() + } + defer ln.Close() + + err = checkPortAvailability(test.port) + + // Skip if the os is windows due to https://github.com/golang/go/issues/7598 + if err == nil && runtime.GOOS != "windows" { + t.Fatalf("checkPortAvailability should fail for port: %d. Error: %v", test.port, err) + } + } +} diff --git a/server-main.go b/server-main.go index 97d959225..1321088fa 100644 --- a/server-main.go +++ b/server-main.go @@ -246,7 +246,9 @@ func serverMain(c *cli.Context) { serverAddress := c.String("address") // Check if requested port is available. - checkPortAvailability(getPort(serverAddress)) + port := getPort(serverAddress) + err := checkPortAvailability(port) + fatalIf(err, "Port unavailable %d", port) // Disks to be ignored in server init, to skip format healing. ignoredDisks := strings.Split(c.String("ignore-disks"), ",") @@ -268,7 +270,6 @@ func serverMain(c *cli.Context) { printStartupMessage(endPoints) // Start server. - var err error // Configure TLS if certs are available. if tls { err = apiServer.ListenAndServeTLS(mustGetCertFile(), mustGetKeyFile())