github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/handlers/health_test.go (about)

     1  package handlers
     2  
     3  import (
     4  	"io/ioutil"
     5  	"net"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/docker/distribution/configuration"
    13  	"github.com/docker/distribution/context"
    14  	"github.com/docker/distribution/health"
    15  )
    16  
    17  func TestFileHealthCheck(t *testing.T) {
    18  	interval := time.Second
    19  
    20  	tmpfile, err := ioutil.TempFile(os.TempDir(), "healthcheck")
    21  	if err != nil {
    22  		t.Fatalf("could not create temporary file: %v", err)
    23  	}
    24  	defer tmpfile.Close()
    25  
    26  	config := &configuration.Configuration{
    27  		Storage: configuration.Storage{
    28  			"inmemory": configuration.Parameters{},
    29  		},
    30  		Health: configuration.Health{
    31  			FileCheckers: []configuration.FileChecker{
    32  				{
    33  					Interval: interval,
    34  					File:     tmpfile.Name(),
    35  				},
    36  			},
    37  		},
    38  	}
    39  
    40  	ctx := context.Background()
    41  
    42  	app := NewApp(ctx, config)
    43  	healthRegistry := health.NewRegistry()
    44  	app.RegisterHealthChecks(healthRegistry)
    45  
    46  	// Wait for health check to happen
    47  	<-time.After(2 * interval)
    48  
    49  	status := healthRegistry.CheckStatus()
    50  	if len(status) != 1 {
    51  		t.Fatal("expected 1 item in health check results")
    52  	}
    53  	if status[tmpfile.Name()] != "file exists" {
    54  		t.Fatal(`did not get "file exists" result for health check`)
    55  	}
    56  
    57  	os.Remove(tmpfile.Name())
    58  
    59  	<-time.After(2 * interval)
    60  	if len(healthRegistry.CheckStatus()) != 0 {
    61  		t.Fatal("expected 0 items in health check results")
    62  	}
    63  }
    64  
    65  func TestTCPHealthCheck(t *testing.T) {
    66  	interval := time.Second
    67  
    68  	ln, err := net.Listen("tcp", "127.0.0.1:0")
    69  	if err != nil {
    70  		t.Fatalf("could not create listener: %v", err)
    71  	}
    72  	addrStr := ln.Addr().String()
    73  
    74  	// Start accepting
    75  	go func() {
    76  		for {
    77  			conn, err := ln.Accept()
    78  			if err != nil {
    79  				// listener was closed
    80  				return
    81  			}
    82  			defer conn.Close()
    83  		}
    84  	}()
    85  
    86  	config := &configuration.Configuration{
    87  		Storage: configuration.Storage{
    88  			"inmemory": configuration.Parameters{},
    89  		},
    90  		Health: configuration.Health{
    91  			TCPCheckers: []configuration.TCPChecker{
    92  				{
    93  					Interval: interval,
    94  					Addr:     addrStr,
    95  					Timeout:  500 * time.Millisecond,
    96  				},
    97  			},
    98  		},
    99  	}
   100  
   101  	ctx := context.Background()
   102  
   103  	app := NewApp(ctx, config)
   104  	healthRegistry := health.NewRegistry()
   105  	app.RegisterHealthChecks(healthRegistry)
   106  
   107  	// Wait for health check to happen
   108  	<-time.After(2 * interval)
   109  
   110  	if len(healthRegistry.CheckStatus()) != 0 {
   111  		t.Fatal("expected 0 items in health check results")
   112  	}
   113  
   114  	ln.Close()
   115  	<-time.After(2 * interval)
   116  
   117  	// Health check should now fail
   118  	status := healthRegistry.CheckStatus()
   119  	if len(status) != 1 {
   120  		t.Fatal("expected 1 item in health check results")
   121  	}
   122  	if status[addrStr] != "connection to "+addrStr+" failed" {
   123  		t.Fatal(`did not get "connection failed" result for health check`)
   124  	}
   125  }
   126  
   127  func TestHTTPHealthCheck(t *testing.T) {
   128  	interval := time.Second
   129  	threshold := 3
   130  
   131  	stopFailing := make(chan struct{})
   132  
   133  	checkedServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   134  		if r.Method != "HEAD" {
   135  			t.Fatalf("expected HEAD request, got %s", r.Method)
   136  		}
   137  		select {
   138  		case <-stopFailing:
   139  			w.WriteHeader(http.StatusOK)
   140  		default:
   141  			w.WriteHeader(http.StatusInternalServerError)
   142  		}
   143  	}))
   144  
   145  	config := &configuration.Configuration{
   146  		Storage: configuration.Storage{
   147  			"inmemory": configuration.Parameters{},
   148  		},
   149  		Health: configuration.Health{
   150  			HTTPCheckers: []configuration.HTTPChecker{
   151  				{
   152  					Interval:  interval,
   153  					URI:       checkedServer.URL,
   154  					Threshold: threshold,
   155  				},
   156  			},
   157  		},
   158  	}
   159  
   160  	ctx := context.Background()
   161  
   162  	app := NewApp(ctx, config)
   163  	healthRegistry := health.NewRegistry()
   164  	app.RegisterHealthChecks(healthRegistry)
   165  
   166  	for i := 0; ; i++ {
   167  		<-time.After(interval)
   168  
   169  		status := healthRegistry.CheckStatus()
   170  
   171  		if i < threshold-1 {
   172  			// definitely shouldn't have hit the threshold yet
   173  			if len(status) != 0 {
   174  				t.Fatal("expected 1 item in health check results")
   175  			}
   176  			continue
   177  		}
   178  		if i < threshold+1 {
   179  			// right on the threshold - don't expect a failure yet
   180  			continue
   181  		}
   182  
   183  		if len(status) != 1 {
   184  			t.Fatal("expected 1 item in health check results")
   185  		}
   186  		if status[checkedServer.URL] != "downstream service returned unexpected status: 500" {
   187  			t.Fatal("did not get expected result for health check")
   188  		}
   189  
   190  		break
   191  	}
   192  
   193  	// Signal HTTP handler to start returning 200
   194  	close(stopFailing)
   195  
   196  	<-time.After(2 * interval)
   197  
   198  	if len(healthRegistry.CheckStatus()) != 0 {
   199  		t.Fatal("expected 0 items in health check results")
   200  	}
   201  }