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)

This commit is contained in:
Jesse Lucas 2016-07-29 17:05:31 -04:00 committed by Harshavardhana
parent cf9ba7b88f
commit 851d05161a
3 changed files with 76 additions and 12 deletions

View file

@ -18,6 +18,7 @@ package main
import ( import (
"errors" "errors"
"fmt"
"net" "net"
"os" "os"
"syscall" "syscall"
@ -32,7 +33,7 @@ import (
// This causes confusion on Mac OSX that minio server is not reachable // 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 // 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. // 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 { isAddrInUse := func(err error) bool {
// Check if the syscall error is EADDRINUSE. // Check if the syscall error is EADDRINUSE.
// EADDRINUSE is the system call error if another process is // EADDRINUSE is the system call error if another process is
@ -54,40 +55,48 @@ func checkPortAvailability(port int) {
} }
return true return true
} }
ifcs, err := net.Interfaces() ifcs, err := net.Interfaces()
if err != nil { if err != nil {
fatalIf(err, "Unable to list interfaces.") return err
} }
for _, ifc := range ifcs { for _, ifc := range ifcs {
addrs, err := ifc.Addrs() addrs, err := ifc.Addrs()
if err != nil { if err != nil {
fatalIf(err, "Unable to list addresses on interface %s.", ifc.Name) return err
} }
for _, addr := range addrs { for _, addr := range addrs {
ipnet, ok := addr.(*net.IPNet) ipnet, ok := addr.(*net.IPNet)
if !ok { if !ok {
errorIf(errors.New(""), "Failed to assert type on (*net.IPNet) interface.") errorIf(errors.New(""), "Failed to assert type on (*net.IPNet) interface.")
continue continue
} }
ip := ipnet.IP ip := ipnet.IP
network := "tcp4" network := "tcp4"
if ip.To4() == nil { if ip.To4() == nil {
network = "tcp6" 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 err != nil {
if isAddrInUse(err) { if isAddrInUse(err) {
// Fail if port is already in use. // Fail if port is already in use.
fatalIf(err, "Unable to listen on %s:%.d.", tcpAddr.IP, tcpAddr.Port) return err
} else {
// Ignore other errors.
continue
} }
// Ignore other errors.
continue
} }
if err = l.Close(); err != nil { if err = l.Close(); err != nil {
fatalIf(err, "Unable to close listener on %s:%.d.", tcpAddr.IP, tcpAddr.Port) return err
} }
} }
} }
return nil
} }

54
checkport_test.go Normal file
View file

@ -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)
}
}
}

View file

@ -246,7 +246,9 @@ func serverMain(c *cli.Context) {
serverAddress := c.String("address") serverAddress := c.String("address")
// Check if requested port is available. // 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. // Disks to be ignored in server init, to skip format healing.
ignoredDisks := strings.Split(c.String("ignore-disks"), ",") ignoredDisks := strings.Split(c.String("ignore-disks"), ",")
@ -268,7 +270,6 @@ func serverMain(c *cli.Context) {
printStartupMessage(endPoints) printStartupMessage(endPoints)
// Start server. // Start server.
var err error
// Configure TLS if certs are available. // Configure TLS if certs are available.
if tls { if tls {
err = apiServer.ListenAndServeTLS(mustGetCertFile(), mustGetKeyFile()) err = apiServer.ListenAndServeTLS(mustGetCertFile(), mustGetKeyFile())