github.imxd.top/hashicorp/consul@v1.4.5/api/health_test.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/consul/testutil"
     8  	"github.com/hashicorp/consul/testutil/retry"
     9  	"github.com/pascaldekloe/goe/verify"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestAPI_HealthNode(t *testing.T) {
    14  	t.Parallel()
    15  	c, s := makeClient(t)
    16  	defer s.Stop()
    17  
    18  	agent := c.Agent()
    19  	health := c.Health()
    20  
    21  	info, err := agent.Self()
    22  	if err != nil {
    23  		t.Fatalf("err: %v", err)
    24  	}
    25  	name := info["Config"]["NodeName"].(string)
    26  	retry.Run(t, func(r *retry.R) {
    27  		checks, meta, err := health.Node(name, nil)
    28  		if err != nil {
    29  			r.Fatal(err)
    30  		}
    31  		if meta.LastIndex == 0 {
    32  			r.Fatalf("bad: %v", meta)
    33  		}
    34  		if len(checks) == 0 {
    35  			r.Fatalf("bad: %v", checks)
    36  		}
    37  	})
    38  }
    39  
    40  func TestAPI_HealthChecks_AggregatedStatus(t *testing.T) {
    41  	t.Parallel()
    42  
    43  	cases := []struct {
    44  		name   string
    45  		checks HealthChecks
    46  		exp    string
    47  	}{
    48  		{
    49  			"empty",
    50  			nil,
    51  			HealthPassing,
    52  		},
    53  		{
    54  			"passing",
    55  			HealthChecks{
    56  				&HealthCheck{
    57  					Status: HealthPassing,
    58  				},
    59  			},
    60  			HealthPassing,
    61  		},
    62  		{
    63  			"warning",
    64  			HealthChecks{
    65  				&HealthCheck{
    66  					Status: HealthWarning,
    67  				},
    68  			},
    69  			HealthWarning,
    70  		},
    71  		{
    72  			"critical",
    73  			HealthChecks{
    74  				&HealthCheck{
    75  					Status: HealthCritical,
    76  				},
    77  			},
    78  			HealthCritical,
    79  		},
    80  		{
    81  			"node_maintenance",
    82  			HealthChecks{
    83  				&HealthCheck{
    84  					CheckID: NodeMaint,
    85  				},
    86  			},
    87  			HealthMaint,
    88  		},
    89  		{
    90  			"service_maintenance",
    91  			HealthChecks{
    92  				&HealthCheck{
    93  					CheckID: ServiceMaintPrefix + "service",
    94  				},
    95  			},
    96  			HealthMaint,
    97  		},
    98  		{
    99  			"unknown",
   100  			HealthChecks{
   101  				&HealthCheck{
   102  					Status: "nope-nope-noper",
   103  				},
   104  			},
   105  			"",
   106  		},
   107  		{
   108  			"maintenance_over_critical",
   109  			HealthChecks{
   110  				&HealthCheck{
   111  					CheckID: NodeMaint,
   112  				},
   113  				&HealthCheck{
   114  					Status: HealthCritical,
   115  				},
   116  			},
   117  			HealthMaint,
   118  		},
   119  		{
   120  			"critical_over_warning",
   121  			HealthChecks{
   122  				&HealthCheck{
   123  					Status: HealthCritical,
   124  				},
   125  				&HealthCheck{
   126  					Status: HealthWarning,
   127  				},
   128  			},
   129  			HealthCritical,
   130  		},
   131  		{
   132  			"warning_over_passing",
   133  			HealthChecks{
   134  				&HealthCheck{
   135  					Status: HealthWarning,
   136  				},
   137  				&HealthCheck{
   138  					Status: HealthPassing,
   139  				},
   140  			},
   141  			HealthWarning,
   142  		},
   143  		{
   144  			"lots",
   145  			HealthChecks{
   146  				&HealthCheck{
   147  					Status: HealthPassing,
   148  				},
   149  				&HealthCheck{
   150  					Status: HealthPassing,
   151  				},
   152  				&HealthCheck{
   153  					Status: HealthPassing,
   154  				},
   155  				&HealthCheck{
   156  					Status: HealthWarning,
   157  				},
   158  			},
   159  			HealthWarning,
   160  		},
   161  	}
   162  
   163  	for i, tc := range cases {
   164  		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
   165  			act := tc.checks.AggregatedStatus()
   166  			if tc.exp != act {
   167  				t.Errorf("\nexp: %#v\nact: %#v", tc.exp, act)
   168  			}
   169  		})
   170  	}
   171  }
   172  
   173  func TestAPI_HealthChecks(t *testing.T) {
   174  	t.Parallel()
   175  	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
   176  		conf.NodeName = "node123"
   177  	})
   178  	defer s.Stop()
   179  
   180  	agent := c.Agent()
   181  	health := c.Health()
   182  
   183  	// Make a service with a check
   184  	reg := &AgentServiceRegistration{
   185  		Name: "foo",
   186  		Tags: []string{"bar"},
   187  		Check: &AgentServiceCheck{
   188  			TTL: "15s",
   189  		},
   190  	}
   191  	if err := agent.ServiceRegister(reg); err != nil {
   192  		t.Fatalf("err: %v", err)
   193  	}
   194  	defer agent.ServiceDeregister("foo")
   195  
   196  	retry.Run(t, func(r *retry.R) {
   197  		checks := HealthChecks{
   198  			&HealthCheck{
   199  				Node:        "node123",
   200  				CheckID:     "service:foo",
   201  				Name:        "Service 'foo' check",
   202  				Status:      "critical",
   203  				ServiceID:   "foo",
   204  				ServiceName: "foo",
   205  				ServiceTags: []string{"bar"},
   206  			},
   207  		}
   208  
   209  		out, meta, err := health.Checks("foo", nil)
   210  		if err != nil {
   211  			r.Fatal(err)
   212  		}
   213  		if meta.LastIndex == 0 {
   214  			r.Fatalf("bad: %v", meta)
   215  		}
   216  		checks[0].CreateIndex = out[0].CreateIndex
   217  		checks[0].ModifyIndex = out[0].ModifyIndex
   218  		verify.Values(r, "checks", out, checks)
   219  	})
   220  }
   221  
   222  func TestAPI_HealthChecks_NodeMetaFilter(t *testing.T) {
   223  	t.Parallel()
   224  	meta := map[string]string{"somekey": "somevalue"}
   225  	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
   226  		conf.NodeMeta = meta
   227  	})
   228  	defer s.Stop()
   229  
   230  	agent := c.Agent()
   231  	health := c.Health()
   232  
   233  	// Make a service with a check
   234  	reg := &AgentServiceRegistration{
   235  		Name: "foo",
   236  		Check: &AgentServiceCheck{
   237  			TTL: "15s",
   238  		},
   239  	}
   240  	if err := agent.ServiceRegister(reg); err != nil {
   241  		t.Fatalf("err: %v", err)
   242  	}
   243  	defer agent.ServiceDeregister("foo")
   244  
   245  	retry.Run(t, func(r *retry.R) {
   246  		checks, meta, err := health.Checks("foo", &QueryOptions{NodeMeta: meta})
   247  		if err != nil {
   248  			r.Fatal(err)
   249  		}
   250  		if meta.LastIndex == 0 {
   251  			r.Fatalf("bad: %v", meta)
   252  		}
   253  		if len(checks) == 0 {
   254  			r.Fatalf("Bad: %v", checks)
   255  		}
   256  	})
   257  }
   258  
   259  func TestAPI_HealthService(t *testing.T) {
   260  	t.Parallel()
   261  	c, s := makeClient(t)
   262  	defer s.Stop()
   263  
   264  	health := c.Health()
   265  	retry.Run(t, func(r *retry.R) {
   266  		// consul service should always exist...
   267  		checks, meta, err := health.Service("consul", "", true, nil)
   268  		if err != nil {
   269  			r.Fatal(err)
   270  		}
   271  		if meta.LastIndex == 0 {
   272  			r.Fatalf("bad: %v", meta)
   273  		}
   274  		if len(checks) == 0 {
   275  			r.Fatalf("Bad: %v", checks)
   276  		}
   277  		if _, ok := checks[0].Node.TaggedAddresses["wan"]; !ok {
   278  			r.Fatalf("Bad: %v", checks[0].Node)
   279  		}
   280  		if checks[0].Node.Datacenter != "dc1" {
   281  			r.Fatalf("Bad datacenter: %v", checks[0].Node)
   282  		}
   283  	})
   284  }
   285  
   286  func TestAPI_HealthService_SingleTag(t *testing.T) {
   287  	t.Parallel()
   288  	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
   289  		conf.NodeName = "node123"
   290  	})
   291  	defer s.Stop()
   292  	agent := c.Agent()
   293  	health := c.Health()
   294  	reg := &AgentServiceRegistration{
   295  		Name: "foo",
   296  		ID:   "foo1",
   297  		Tags: []string{"bar"},
   298  		Check: &AgentServiceCheck{
   299  			Status: HealthPassing,
   300  			TTL:    "15s",
   301  		},
   302  	}
   303  	require.NoError(t, agent.ServiceRegister(reg))
   304  	defer agent.ServiceDeregister("foo1")
   305  	retry.Run(t, func(r *retry.R) {
   306  		services, meta, err := health.Service("foo", "bar", true, nil)
   307  		require.NoError(t, err)
   308  		require.NotEqual(t, meta.LastIndex, 0)
   309  		require.Len(t, services, 1)
   310  		require.Equal(t, services[0].Service.ID, "foo1")
   311  	})
   312  }
   313  func TestAPI_HealthService_MultipleTags(t *testing.T) {
   314  	t.Parallel()
   315  	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
   316  		conf.NodeName = "node123"
   317  	})
   318  	defer s.Stop()
   319  
   320  	agent := c.Agent()
   321  	health := c.Health()
   322  
   323  	// Make two services with a check
   324  	reg := &AgentServiceRegistration{
   325  		Name: "foo",
   326  		ID:   "foo1",
   327  		Tags: []string{"bar"},
   328  		Check: &AgentServiceCheck{
   329  			Status: HealthPassing,
   330  			TTL:    "15s",
   331  		},
   332  	}
   333  	require.NoError(t, agent.ServiceRegister(reg))
   334  	defer agent.ServiceDeregister("foo1")
   335  
   336  	reg2 := &AgentServiceRegistration{
   337  		Name: "foo",
   338  		ID:   "foo2",
   339  		Tags: []string{"bar", "v2"},
   340  		Check: &AgentServiceCheck{
   341  			Status: HealthPassing,
   342  			TTL:    "15s",
   343  		},
   344  	}
   345  	require.NoError(t, agent.ServiceRegister(reg2))
   346  	defer agent.ServiceDeregister("foo2")
   347  
   348  	// Test searching with one tag (two results)
   349  	retry.Run(t, func(r *retry.R) {
   350  		services, meta, err := health.ServiceMultipleTags("foo", []string{"bar"}, true, nil)
   351  
   352  		require.NoError(t, err)
   353  		require.NotEqual(t, meta.LastIndex, 0)
   354  		require.Len(t, services, 2)
   355  	})
   356  
   357  	// Test searching with two tags (one result)
   358  	retry.Run(t, func(r *retry.R) {
   359  		services, meta, err := health.ServiceMultipleTags("foo", []string{"bar", "v2"}, true, nil)
   360  
   361  		require.NoError(t, err)
   362  		require.NotEqual(t, meta.LastIndex, 0)
   363  		require.Len(t, services, 1)
   364  		require.Equal(t, services[0].Service.ID, "foo2")
   365  	})
   366  }
   367  
   368  func TestAPI_HealthService_NodeMetaFilter(t *testing.T) {
   369  	t.Parallel()
   370  	meta := map[string]string{"somekey": "somevalue"}
   371  	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
   372  		conf.NodeMeta = meta
   373  	})
   374  	defer s.Stop()
   375  
   376  	health := c.Health()
   377  	retry.Run(t, func(r *retry.R) {
   378  		// consul service should always exist...
   379  		checks, meta, err := health.Service("consul", "", true, &QueryOptions{NodeMeta: meta})
   380  		require.NoError(t, err)
   381  		require.NotEqual(t, meta.LastIndex, 0)
   382  		require.NotEqual(t, len(checks), 0)
   383  		require.Equal(t, checks[0].Node.Datacenter, "dc1")
   384  		require.Contains(t, checks[0].Node.TaggedAddresses, "wan")
   385  	})
   386  }
   387  
   388  func TestAPI_HealthConnect(t *testing.T) {
   389  	t.Parallel()
   390  	c, s := makeClient(t)
   391  	defer s.Stop()
   392  
   393  	agent := c.Agent()
   394  	health := c.Health()
   395  
   396  	// Make a service with a proxy
   397  	reg := &AgentServiceRegistration{
   398  		Name: "foo",
   399  		Port: 8000,
   400  	}
   401  	err := agent.ServiceRegister(reg)
   402  	require.NoError(t, err)
   403  	defer agent.ServiceDeregister("foo")
   404  
   405  	// Register the proxy
   406  	proxyReg := &AgentServiceRegistration{
   407  		Name: "foo-proxy",
   408  		Port: 8001,
   409  		Kind: ServiceKindConnectProxy,
   410  		Proxy: &AgentServiceConnectProxyConfig{
   411  			DestinationServiceName: "foo",
   412  		},
   413  	}
   414  	err = agent.ServiceRegister(proxyReg)
   415  	require.NoError(t, err)
   416  	defer agent.ServiceDeregister("foo-proxy")
   417  
   418  	retry.Run(t, func(r *retry.R) {
   419  		services, meta, err := health.Connect("foo", "", true, nil)
   420  		if err != nil {
   421  			r.Fatal(err)
   422  		}
   423  		if meta.LastIndex == 0 {
   424  			r.Fatalf("bad: %v", meta)
   425  		}
   426  		// Should be exactly 1 service - the original shouldn't show up as a connect
   427  		// endpoint, only it's proxy.
   428  		if len(services) != 1 {
   429  			r.Fatalf("Bad: %v", services)
   430  		}
   431  		if services[0].Node.Datacenter != "dc1" {
   432  			r.Fatalf("Bad datacenter: %v", services[0].Node)
   433  		}
   434  		if services[0].Service.Port != proxyReg.Port {
   435  			r.Fatalf("Bad port: %v", services[0])
   436  		}
   437  	})
   438  }
   439  
   440  func TestAPI_HealthState(t *testing.T) {
   441  	t.Parallel()
   442  	c, s := makeClient(t)
   443  	defer s.Stop()
   444  
   445  	health := c.Health()
   446  	retry.Run(t, func(r *retry.R) {
   447  		checks, meta, err := health.State("any", nil)
   448  		if err != nil {
   449  			r.Fatal(err)
   450  		}
   451  		if meta.LastIndex == 0 {
   452  			r.Fatalf("bad: %v", meta)
   453  		}
   454  		if len(checks) == 0 {
   455  			r.Fatalf("Bad: %v", checks)
   456  		}
   457  	})
   458  }
   459  
   460  func TestAPI_HealthState_NodeMetaFilter(t *testing.T) {
   461  	t.Parallel()
   462  	meta := map[string]string{"somekey": "somevalue"}
   463  	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
   464  		conf.NodeMeta = meta
   465  	})
   466  	defer s.Stop()
   467  
   468  	health := c.Health()
   469  	retry.Run(t, func(r *retry.R) {
   470  		checks, meta, err := health.State("any", &QueryOptions{NodeMeta: meta})
   471  		if err != nil {
   472  			r.Fatal(err)
   473  		}
   474  		if meta.LastIndex == 0 {
   475  			r.Fatalf("bad: %v", meta)
   476  		}
   477  		if len(checks) == 0 {
   478  			r.Fatalf("Bad: %v", checks)
   479  		}
   480  	})
   481  }