vitess.io/vitess@v0.16.2/go/vt/vtadmin/cluster/discovery/discovery_static_file_test.go (about)

     1  /*
     2  Copyright 2020 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package discovery
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"vitess.io/vitess/go/vt/proto/vtadmin"
    27  	vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin"
    28  )
    29  
    30  func TestDiscoverVTGate(t *testing.T) {
    31  	t.Parallel()
    32  
    33  	tests := []struct {
    34  		name      string
    35  		contents  []byte
    36  		expected  *vtadminpb.VTGate
    37  		tags      []string
    38  		shouldErr bool
    39  	}{
    40  		{
    41  			name:      "empty config",
    42  			contents:  []byte(`{}`),
    43  			expected:  nil,
    44  			shouldErr: true,
    45  		},
    46  		{
    47  			name: "one gate",
    48  			contents: []byte(`
    49  				{
    50  					"vtgates": [{
    51  						"host": {
    52  							"hostname": "127.0.0.1:12345"
    53  						}
    54  					}]
    55  				}
    56  			`),
    57  			expected: &vtadmin.VTGate{
    58  				Hostname: "127.0.0.1:12345",
    59  			},
    60  		},
    61  		{
    62  			name: "filtered by tags (one match)",
    63  			contents: []byte(`
    64  				{
    65  					"vtgates": [
    66  						{
    67  							"host": {
    68  								"hostname": "127.0.0.1:11111"
    69  							},
    70  							"tags": ["cell:cellA"]
    71  						}, 
    72  						{
    73  							"host": {
    74  								"hostname": "127.0.0.1:22222"
    75  							},
    76  							"tags": ["cell:cellB"]
    77  						},
    78  						{
    79  							"host": {
    80  								"hostname": "127.0.0.1:33333"
    81  							},
    82  							"tags": ["cell:cellA"]
    83  						}
    84  					]
    85  				}
    86  			`),
    87  			expected: &vtadminpb.VTGate{
    88  				Hostname: "127.0.0.1:22222",
    89  			},
    90  			tags: []string{"cell:cellB"},
    91  		},
    92  	}
    93  
    94  	ctx := context.Background()
    95  
    96  	for _, tt := range tests {
    97  		tt := tt
    98  
    99  		t.Run(tt.name, func(t *testing.T) {
   100  			t.Parallel()
   101  
   102  			disco := &StaticFileDiscovery{}
   103  			err := disco.parseConfig(tt.contents)
   104  			require.NoError(t, err)
   105  
   106  			gate, err := disco.DiscoverVTGate(ctx, tt.tags)
   107  			if tt.shouldErr {
   108  				assert.Error(t, err)
   109  				return
   110  			}
   111  
   112  			assert.NoError(t, err)
   113  			assert.Equal(t, tt.expected, gate)
   114  		})
   115  	}
   116  }
   117  
   118  func TestDiscoverVTGates(t *testing.T) {
   119  	t.Parallel()
   120  
   121  	tests := []struct {
   122  		name     string
   123  		contents []byte
   124  		tags     []string
   125  		expected []*vtadminpb.VTGate
   126  		// True if the test should produce an error on the DiscoverVTGates call
   127  		shouldErr bool
   128  		// True if the test should produce an error on the disco.parseConfig step
   129  		shouldErrConfig bool
   130  	}{
   131  		{
   132  			name:      "empty config",
   133  			contents:  []byte(`{}`),
   134  			expected:  []*vtadminpb.VTGate{},
   135  			shouldErr: false,
   136  		},
   137  		{
   138  			name: "no tags",
   139  			contents: []byte(`
   140  				{
   141  					"vtgates": [
   142  						{
   143  							"host": {
   144  								"hostname": "127.0.0.1:12345"
   145  							}
   146  						},
   147  						{
   148  							"host": {
   149  								"hostname": "127.0.0.1:67890"
   150  							}
   151  						}
   152  					]
   153  				}
   154  			`),
   155  			expected: []*vtadminpb.VTGate{
   156  				{Hostname: "127.0.0.1:12345"},
   157  				{Hostname: "127.0.0.1:67890"},
   158  			},
   159  			shouldErr: false,
   160  		},
   161  		{
   162  			name: "filtered by tags",
   163  			contents: []byte(`
   164  				{
   165  					"vtgates": [
   166  						{
   167  							"host": {
   168  								"hostname": "127.0.0.1:11111"
   169  							},
   170  							"tags": ["cell:cellA"]
   171  						},
   172  						{
   173  							"host": {
   174  								"hostname": "127.0.0.1:22222"
   175  							},
   176  							"tags": ["cell:cellB"]
   177  						},
   178  						{
   179  							"host": {
   180  								"hostname": "127.0.0.1:33333"
   181  							},
   182  							"tags": ["cell:cellA"]
   183  						}
   184  					]
   185  				}
   186  			`),
   187  			tags: []string{"cell:cellA"},
   188  			expected: []*vtadminpb.VTGate{
   189  				{Hostname: "127.0.0.1:11111"},
   190  				{Hostname: "127.0.0.1:33333"},
   191  			},
   192  			shouldErr: false,
   193  		},
   194  		{
   195  			name: "filtered by multiple tags",
   196  			contents: []byte(`
   197  				{
   198  					"vtgates": [
   199  						{
   200  							"host": {
   201  								"hostname": "127.0.0.1:11111"
   202  							},
   203  							"tags": ["cell:cellA"]
   204  						},
   205  						{
   206  							"host": {
   207  								"hostname": "127.0.0.1:22222"
   208  							},
   209  							"tags": ["cell:cellA", "pool:poolZ"]
   210  						},
   211  						{
   212  							"host": {
   213  								"hostname": "127.0.0.1:33333"
   214  							},
   215  							"tags": ["pool:poolZ"]
   216  						}
   217  					]
   218  				}
   219  			`),
   220  			tags: []string{"cell:cellA", "pool:poolZ"},
   221  			expected: []*vtadminpb.VTGate{
   222  				{Hostname: "127.0.0.1:22222"},
   223  			},
   224  			shouldErr: false,
   225  		},
   226  		{
   227  			name: "invalid json",
   228  			contents: []byte(`
   229  				{
   230  					"vtgates": "malformed"
   231  				}
   232  			`),
   233  			tags:            []string{},
   234  			shouldErr:       false,
   235  			shouldErrConfig: true,
   236  		},
   237  	}
   238  
   239  	ctx := context.Background()
   240  
   241  	for _, tt := range tests {
   242  		tt := tt
   243  
   244  		t.Run(tt.name, func(t *testing.T) {
   245  			t.Parallel()
   246  
   247  			disco := &StaticFileDiscovery{}
   248  
   249  			err := disco.parseConfig(tt.contents)
   250  			if tt.shouldErrConfig {
   251  				assert.Error(t, err)
   252  			} else {
   253  				require.NoError(t, err)
   254  			}
   255  
   256  			gates, err := disco.DiscoverVTGates(ctx, tt.tags)
   257  			if tt.shouldErr {
   258  				assert.Error(t, err)
   259  				return
   260  			}
   261  
   262  			assert.NoError(t, err)
   263  			assert.ElementsMatch(t, tt.expected, gates)
   264  		})
   265  	}
   266  }
   267  
   268  func TestDiscoverVtctld(t *testing.T) {
   269  	t.Parallel()
   270  
   271  	tests := []struct {
   272  		name      string
   273  		contents  []byte
   274  		expected  *vtadminpb.Vtctld
   275  		tags      []string
   276  		shouldErr bool
   277  	}{
   278  		{
   279  			name:      "empty config",
   280  			contents:  []byte(`{}`),
   281  			expected:  nil,
   282  			shouldErr: true,
   283  		},
   284  		{
   285  			name: "one vtctld",
   286  			contents: []byte(`
   287  				{
   288  					"vtctlds": [{
   289  						"host": {
   290  							"hostname": "127.0.0.1:12345"
   291  						}
   292  					}]
   293  				}
   294  			`),
   295  			expected: &vtadmin.Vtctld{
   296  				Hostname: "127.0.0.1:12345",
   297  			},
   298  		},
   299  		{
   300  			name: "filtered by tags (one match)",
   301  			contents: []byte(`
   302  				{
   303  					"vtctlds": [
   304  						{
   305  							"host": {
   306  								"hostname": "127.0.0.1:11111"
   307  							},
   308  							"tags": ["cell:cellA"]
   309  						}, 
   310  						{
   311  							"host": {
   312  								"hostname": "127.0.0.1:22222"
   313  							},
   314  							"tags": ["cell:cellB"]
   315  						},
   316  						{
   317  							"host": {
   318  								"hostname": "127.0.0.1:33333"
   319  							},
   320  							"tags": ["cell:cellA"]
   321  						}
   322  					]
   323  				}
   324  			`),
   325  			expected: &vtadminpb.Vtctld{
   326  				Hostname: "127.0.0.1:22222",
   327  			},
   328  			tags: []string{"cell:cellB"},
   329  		},
   330  	}
   331  
   332  	ctx := context.Background()
   333  
   334  	for _, tt := range tests {
   335  		tt := tt
   336  
   337  		t.Run(tt.name, func(t *testing.T) {
   338  			t.Parallel()
   339  
   340  			disco := &StaticFileDiscovery{}
   341  			err := disco.parseConfig(tt.contents)
   342  			require.NoError(t, err)
   343  
   344  			vtctld, err := disco.DiscoverVtctld(ctx, tt.tags)
   345  			if tt.shouldErr {
   346  				assert.Error(t, err)
   347  				return
   348  			}
   349  
   350  			assert.NoError(t, err)
   351  			assert.Equal(t, tt.expected, vtctld)
   352  		})
   353  	}
   354  }
   355  
   356  func TestDiscoverVtctlds(t *testing.T) {
   357  	t.Parallel()
   358  
   359  	tests := []struct {
   360  		name     string
   361  		contents []byte
   362  		tags     []string
   363  		expected []*vtadminpb.Vtctld
   364  		// True if the test should produce an error on the DiscoverVTGates call
   365  		shouldErr bool
   366  		// True if the test should produce an error on the disco.parseConfig step
   367  		shouldErrConfig bool
   368  	}{
   369  		{
   370  			name:      "empty config",
   371  			contents:  []byte(`{}`),
   372  			expected:  []*vtadminpb.Vtctld{},
   373  			shouldErr: false,
   374  		},
   375  		{
   376  			name: "no tags",
   377  			contents: []byte(`
   378  				{
   379  					"vtctlds": [
   380  						{
   381  							"host": {
   382  								"hostname": "127.0.0.1:12345"
   383  							}
   384  						},
   385  						{
   386  							"host": {
   387  								"hostname": "127.0.0.1:67890"
   388  							}
   389  						}
   390  					]
   391  				}
   392  			`),
   393  			expected: []*vtadminpb.Vtctld{
   394  				{Hostname: "127.0.0.1:12345"},
   395  				{Hostname: "127.0.0.1:67890"},
   396  			},
   397  			shouldErr: false,
   398  		},
   399  		{
   400  			name: "filtered by tags",
   401  			contents: []byte(`
   402  				{
   403  					"vtctlds": [
   404  						{
   405  							"host": {
   406  								"hostname": "127.0.0.1:11111"
   407  							},
   408  							"tags": ["cell:cellA"]
   409  						},
   410  						{
   411  							"host": {
   412  								"hostname": "127.0.0.1:22222"
   413  							},
   414  							"tags": ["cell:cellB"]
   415  						},
   416  						{
   417  							"host": {
   418  								"hostname": "127.0.0.1:33333"
   419  							},
   420  							"tags": ["cell:cellA"]
   421  						}
   422  					]
   423  				}
   424  			`),
   425  			tags: []string{"cell:cellA"},
   426  			expected: []*vtadminpb.Vtctld{
   427  				{Hostname: "127.0.0.1:11111"},
   428  				{Hostname: "127.0.0.1:33333"},
   429  			},
   430  			shouldErr: false,
   431  		},
   432  		{
   433  			name: "filtered by multiple tags",
   434  			contents: []byte(`
   435  				{
   436  					"vtctlds": [
   437  						{
   438  							"host": {
   439  								"hostname": "127.0.0.1:11111"
   440  							},
   441  							"tags": ["cell:cellA"]
   442  						},
   443  						{
   444  							"host": {
   445  								"hostname": "127.0.0.1:22222"
   446  							},
   447  							"tags": ["cell:cellA", "pool:poolZ"]
   448  						},
   449  						{
   450  							"host": {
   451  								"hostname": "127.0.0.1:33333"
   452  							},
   453  							"tags": ["pool:poolZ"]
   454  						}
   455  					]
   456  				}
   457  			`),
   458  			tags: []string{"cell:cellA", "pool:poolZ"},
   459  			expected: []*vtadminpb.Vtctld{
   460  				{Hostname: "127.0.0.1:22222"},
   461  			},
   462  			shouldErr: false,
   463  		},
   464  		{
   465  			name: "invalid json",
   466  			contents: []byte(`
   467  				{
   468  					"vtctlds": "malformed"
   469  				}
   470  			`),
   471  			tags:            []string{},
   472  			shouldErr:       false,
   473  			shouldErrConfig: true,
   474  		},
   475  	}
   476  
   477  	ctx := context.Background()
   478  
   479  	for _, tt := range tests {
   480  		tt := tt
   481  
   482  		t.Run(tt.name, func(t *testing.T) {
   483  			t.Parallel()
   484  
   485  			disco := &StaticFileDiscovery{}
   486  
   487  			err := disco.parseConfig(tt.contents)
   488  			if tt.shouldErrConfig {
   489  				assert.Error(t, err)
   490  			} else {
   491  				require.NoError(t, err)
   492  			}
   493  
   494  			vtctlds, err := disco.DiscoverVtctlds(ctx, tt.tags)
   495  			if tt.shouldErr {
   496  				assert.Error(t, err)
   497  				return
   498  			}
   499  
   500  			assert.NoError(t, err)
   501  			assert.ElementsMatch(t, tt.expected, vtctlds)
   502  		})
   503  	}
   504  }