github.com/matrixorigin/matrixone@v0.7.0/pkg/util/metric/metric_test.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package metric
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"net/http"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/config"
    27  	"github.com/matrixorigin/matrixone/pkg/util/export/table"
    28  	prom "github.com/prometheus/client_golang/prometheus"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  const InternalExecutor = "InternalExecutor"
    34  const FileService = "FileService"
    35  
    36  func TestMetric(t *testing.T) {
    37  	sqlch := make(chan string, 100)
    38  	factory := newExecutorFactory(sqlch)
    39  
    40  	withModifiedConfig(func() {
    41  		SV := &config.ObservabilityParameters{}
    42  		SV.SetDefaultValues("test")
    43  		SV.Host = "0.0.0.0"
    44  		SV.StatusPort = 7001
    45  		SV.EnableMetricToProm = true
    46  		SV.BatchProcessor = FileService
    47  		SV.MetricExportInterval = 1
    48  		SV.MetricMultiTable = true
    49  		defer setGatherInterval(setGatherInterval(30 * time.Millisecond))
    50  		defer setRawHistBufLimit(setRawHistBufLimit(5))
    51  		InitMetric(context.TODO(), factory, SV, "node_uuid", "test", WithInitAction(true))
    52  		defer StopMetricSync()
    53  
    54  		const (
    55  			none      = "--None"
    56  			createDB  = "create database"
    57  			createTbl = "create EXTERNAL table"
    58  			insertRow = "insert into"
    59  		)
    60  		prevSqlKind := none
    61  		for sql := range sqlch {
    62  			if strings.HasPrefix(sql, prevSqlKind) {
    63  				continue
    64  			}
    65  			switch prevSqlKind {
    66  			case none:
    67  				require.True(t, strings.HasPrefix(sql, createDB), "income sql: %s", sql)
    68  				prevSqlKind = createDB
    69  			case createDB:
    70  				require.True(t, strings.HasPrefix(sql, createTbl), "income sql: %s", sql)
    71  				prevSqlKind = createTbl
    72  			case createTbl:
    73  				require.True(t, strings.HasPrefix(sql, insertRow), "income sql: %s", sql)
    74  				goto GOON
    75  			default:
    76  				require.True(t, false, "unknow sql kind %s", sql)
    77  			}
    78  		}
    79  	GOON:
    80  		client := http.Client{
    81  			Timeout: 120 * time.Second,
    82  		}
    83  		r, err := client.Get("http://127.0.0.1:7001/metrics")
    84  		require.Nil(t, err)
    85  		require.Equal(t, r.StatusCode, 200)
    86  
    87  		content, _ := io.ReadAll(r.Body)
    88  		require.Contains(t, string(content), "# HELP") // check we have metrics output
    89  	})
    90  }
    91  
    92  func TestMetricNoProm(t *testing.T) {
    93  	sqlch := make(chan string, 100)
    94  	factory := newExecutorFactory(sqlch)
    95  
    96  	withModifiedConfig(func() {
    97  		SV := &config.ObservabilityParameters{}
    98  		SV.SetDefaultValues("test")
    99  		SV.Host = "0.0.0.0"
   100  		SV.StatusPort = 7001
   101  		SV.EnableMetricToProm = false
   102  		SV.BatchProcessor = FileService
   103  		SV.MetricMultiTable = true
   104  
   105  		defer setGatherInterval(setGatherInterval(30 * time.Millisecond))
   106  		defer setRawHistBufLimit(setRawHistBufLimit(5))
   107  		InitMetric(context.TODO(), factory, SV, "node_uuid", "test", WithInitAction(true))
   108  		defer StopMetricSync()
   109  
   110  		client := http.Client{
   111  			Timeout: 120 * time.Second,
   112  		}
   113  		_, err := client.Get("http://127.0.0.1:7001/metrics")
   114  		require.NotNil(t, err)
   115  		require.Contains(t, err.Error(), "connection refused")
   116  
   117  		// make static-check(errcheck) happay
   118  		SV.EnableMetricToProm = true
   119  	})
   120  }
   121  
   122  func TestDescExtra(t *testing.T) {
   123  	desc := prom.NewDesc("sys_xxx_yyy_FEFA", "help info", []string{"is_internal", "xy"}, map[string]string{"node": "1"})
   124  	extra := newDescExtra(desc)
   125  	assert.Equal(t, extra.fqName, "sys_xxx_yyy_FEFA")
   126  	assert.Equal(t, extra.labels[0].GetName(), "is_internal")
   127  	assert.Equal(t, extra.labels[1].GetName(), "node")
   128  	assert.Equal(t, extra.labels[2].GetName(), "xy")
   129  }
   130  
   131  var dummyOptionsFactory = table.GetOptionFactory(context.TODO(), table.NormalTableEngine)
   132  
   133  func TestCreateTable(t *testing.T) {
   134  	buf := new(bytes.Buffer)
   135  	name := "sql_test_counter"
   136  	sql := createTableSqlFromMetricFamily(prom.NewDesc(name, "", []string{"zzz", "aaa"}, nil), buf, dummyOptionsFactory)
   137  	assert.Equal(t, sql, fmt.Sprintf(
   138  		"create table if not exists %s.%s (`%s` datetime(6), `%s` double, `%s` varchar(36), `%s` varchar(20), `aaa` varchar(20), `zzz` varchar(20))",
   139  		MetricDBConst, name, lblTimeConst, lblValueConst, lblNodeConst, lblRoleConst,
   140  	))
   141  
   142  	sql = createTableSqlFromMetricFamily(prom.NewDesc(name, "", nil, nil), buf, dummyOptionsFactory)
   143  	assert.Equal(t, sql, fmt.Sprintf(
   144  		"create table if not exists %s.%s (`%s` datetime(6), `%s` double, `%s` varchar(36), `%s` varchar(20))",
   145  		MetricDBConst, name, lblTimeConst, lblValueConst, lblNodeConst, lblRoleConst,
   146  	))
   147  }
   148  
   149  func TestMetricSingleTable(t *testing.T) {
   150  	sqlch := make(chan string, 100)
   151  	factory := newExecutorFactory(sqlch)
   152  
   153  	withModifiedConfig(func() {
   154  		SV := &config.ObservabilityParameters{}
   155  		SV.SetDefaultValues("test")
   156  		SV.Host = "0.0.0.0"
   157  		SV.StatusPort = 7001
   158  		SV.EnableMetricToProm = true
   159  		SV.BatchProcessor = FileService
   160  		SV.MetricExportInterval = 1
   161  		SV.MetricMultiTable = false
   162  		defer setGatherInterval(setGatherInterval(30 * time.Millisecond))
   163  		defer setRawHistBufLimit(setRawHistBufLimit(5))
   164  		InitMetric(context.TODO(), factory, SV, "node_uuid", "test", WithInitAction(true))
   165  		defer StopMetricSync()
   166  
   167  		const (
   168  			none       = "--None"
   169  			createDB   = "create database"
   170  			createTbl  = "CREATE EXTERNAL TABLE"
   171  			createView = "CREATE VIEW"
   172  			insertRow  = "insert into"
   173  		)
   174  		prevSqlKind := none
   175  		for sql := range sqlch {
   176  			t.Logf("sql: %s", sql)
   177  			if strings.HasPrefix(sql, prevSqlKind) {
   178  				continue
   179  			}
   180  			switch prevSqlKind {
   181  			case none:
   182  				require.True(t, strings.HasPrefix(sql, createDB), "income sql: %s", sql)
   183  				prevSqlKind = createDB
   184  			case createDB:
   185  				require.True(t, strings.HasPrefix(sql, createTbl), "income sql: %s", sql)
   186  				prevSqlKind = createTbl
   187  			case createTbl:
   188  				require.True(t, strings.HasPrefix(sql, createView), "income sql: %s", sql)
   189  				prevSqlKind = createView
   190  			case createView:
   191  				require.True(t, strings.HasPrefix(sql, insertRow), "income sql: %s", sql)
   192  				goto GOON
   193  			default:
   194  				require.True(t, false, "unknow sql kind %s", sql)
   195  			}
   196  		}
   197  	GOON:
   198  		client := http.Client{
   199  			Timeout: 120 * time.Second,
   200  		}
   201  		r, err := client.Get("http://127.0.0.1:7001/metrics")
   202  		require.Nil(t, err)
   203  		require.Equal(t, r.StatusCode, 200)
   204  
   205  		content, _ := io.ReadAll(r.Body)
   206  		require.Contains(t, string(content), "# HELP") // check we have metrics output
   207  	})
   208  }
   209  
   210  func TestGetSchemaForAccount(t *testing.T) {
   211  	type args struct {
   212  		account string
   213  	}
   214  	tests := []struct {
   215  		name     string
   216  		args     args
   217  		wantPath string
   218  		wantSche int
   219  	}{
   220  		{
   221  			name: "test_account_user1",
   222  			args: args{
   223  				account: "user1",
   224  			},
   225  			wantPath: "/user1/*/*/*/*/metric/*",
   226  			wantSche: 7,
   227  		},
   228  	}
   229  	ctx := context.Background()
   230  	for _, tt := range tests {
   231  		t.Run(tt.name, func(t *testing.T) {
   232  			schemas := GetSchemaForAccount(ctx, tt.args.account)
   233  			found := false
   234  			for _, sche := range schemas {
   235  				t.Logf("schma: %s", sche)
   236  				if strings.Contains(sche, tt.wantPath) {
   237  					found = true
   238  				}
   239  			}
   240  			require.Equal(t, tt.wantSche, len(schemas))
   241  			require.Equal(t, true, found)
   242  			found = false
   243  			if strings.Contains(SingleMetricTable.ToCreateSql(ctx, true), "/*/*/*/*/*/metric/*") {
   244  				found = true
   245  			}
   246  			require.Equal(t, true, found)
   247  		})
   248  	}
   249  }