vitess.io/vitess@v0.16.2/go/test/endtoend/clustertest/vtctld_test.go (about)

     1  /*
     2  Copyright 2019 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  
    18  package clustertest
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"io"
    24  	"net/http"
    25  	"reflect"
    26  	"strings"
    27  	"testing"
    28  
    29  	"vitess.io/vitess/go/vt/log"
    30  
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  
    34  	"vitess.io/vitess/go/test/endtoend/cluster"
    35  )
    36  
    37  var (
    38  	oneTableOutput = `+---+
    39  | a |
    40  +---+
    41  | 1 |
    42  +---+
    43  `
    44  )
    45  
    46  func TestVtctldProcess(t *testing.T) {
    47  	defer cluster.PanicHandler(t)
    48  	url := fmt.Sprintf("http://%s:%d/api/keyspaces/", clusterInstance.Hostname, clusterInstance.VtctldHTTPPort)
    49  	testURL(t, url, "keyspace url")
    50  
    51  	healthCheckURL := fmt.Sprintf("http://%s:%d/debug/health", clusterInstance.Hostname, clusterInstance.VtctldHTTPPort)
    52  	testURL(t, healthCheckURL, "vtctld health check url")
    53  
    54  	url = fmt.Sprintf("http://%s:%d/api/topodata/", clusterInstance.Hostname, clusterInstance.VtctldHTTPPort)
    55  	testTopoDataAPI(t, url)
    56  
    57  	testListAllTablets(t)
    58  	testTabletStatus(t)
    59  	testExecuteAsDba(t)
    60  	testExecuteAsApp(t)
    61  }
    62  
    63  func testTopoDataAPI(t *testing.T, url string) {
    64  	resp, err := http.Get(url)
    65  	require.NoError(t, err)
    66  	defer resp.Body.Close()
    67  	assert.Equal(t, resp.StatusCode, 200)
    68  
    69  	resultMap := make(map[string]any)
    70  	respByte, err := io.ReadAll(resp.Body)
    71  	require.NoError(t, err)
    72  	err = json.Unmarshal(respByte, &resultMap)
    73  	require.NoError(t, err)
    74  
    75  	errorValue := reflect.ValueOf(resultMap["Error"])
    76  	assert.Empty(t, errorValue.String())
    77  
    78  	assert.Contains(t, resultMap, "Children")
    79  	children := reflect.ValueOf(resultMap["Children"])
    80  	childrenGot := fmt.Sprintf("%s", children)
    81  	assert.Contains(t, childrenGot, "global")
    82  	assert.Contains(t, childrenGot, clusterInstance.Cell)
    83  }
    84  
    85  func testListAllTablets(t *testing.T) {
    86  	// first w/o any filters, aside from cell
    87  	result, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("ListAllTablets", clusterInstance.Cell)
    88  	require.NoError(t, err)
    89  
    90  	tablets := getAllTablets()
    91  
    92  	tabletsFromCMD := strings.Split(result, "\n")
    93  	tabletCountFromCMD := 0
    94  
    95  	for _, line := range tabletsFromCMD {
    96  		if len(line) > 0 {
    97  			tabletCountFromCMD = tabletCountFromCMD + 1
    98  			assert.Contains(t, tablets, strings.Split(line, " ")[0])
    99  		}
   100  	}
   101  	assert.Equal(t, tabletCountFromCMD, len(tablets))
   102  
   103  	// now filtering with the first keyspace and tablet type of primary, in
   104  	// addition to the cell
   105  	result, err = clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput(
   106  		"ListAllTablets", "--", "--keyspace", clusterInstance.Keyspaces[0].Name,
   107  		"--tablet_type", "primary",
   108  		clusterInstance.Cell)
   109  	require.NoError(t, err)
   110  
   111  	// We should only return a single primary tablet per shard in the first keyspace
   112  	tabletsFromCMD = strings.Split(result, "\n")
   113  	// We don't count the final newline with nothing after it (it becomes an empty
   114  	// line at the end of the slice)
   115  	assert.Equal(t, len(clusterInstance.Keyspaces[0].Shards), len(tabletsFromCMD)-1)
   116  }
   117  
   118  func testTabletStatus(t *testing.T) {
   119  	resp, err := http.Get(fmt.Sprintf("http://%s:%d", clusterInstance.Hostname, clusterInstance.Keyspaces[0].Shards[0].Vttablets[0].HTTPPort))
   120  	require.NoError(t, err)
   121  	defer resp.Body.Close()
   122  	respByte, err := io.ReadAll(resp.Body)
   123  	require.NoError(t, err)
   124  	result := string(respByte)
   125  	log.Infof("Tablet status response: %v", result)
   126  	assert.True(t, strings.Contains(result, `Alias: <a href="http://localhost:`))
   127  	assert.True(t, strings.Contains(result, `</html>`))
   128  }
   129  
   130  func testExecuteAsDba(t *testing.T) {
   131  	result, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("ExecuteFetchAsDba", clusterInstance.Keyspaces[0].Shards[0].Vttablets[0].Alias, `SELECT 1 AS a`)
   132  	require.NoError(t, err)
   133  	assert.Equal(t, result, oneTableOutput)
   134  }
   135  
   136  func testExecuteAsApp(t *testing.T) {
   137  	result, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("ExecuteFetchAsApp", clusterInstance.Keyspaces[0].Shards[0].Vttablets[0].Alias, `SELECT 1 AS a`)
   138  	require.NoError(t, err)
   139  	assert.Equal(t, result, oneTableOutput)
   140  }
   141  
   142  func getAllTablets() []string {
   143  	tablets := make([]string, 0)
   144  	for _, ks := range clusterInstance.Keyspaces {
   145  		for _, shard := range ks.Shards {
   146  			for _, tablet := range shard.Vttablets {
   147  				tablets = append(tablets, tablet.Alias)
   148  			}
   149  		}
   150  	}
   151  	return tablets
   152  }