blob: cb7d8c208fb120f8ec3b456d83fe10add81b0023 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package mysql
import (
_ "crypto/tls"
"database/sql/driver"
"errors"
"fmt"
"regexp"
"strconv"
"testing"
"github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
)
func Test_ShowFrontends(t *testing.T) {
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
columns := []string{"Name", "Host", "EditLogPort", "HttpPort", "QueryPort", "RpcPort", "ArrowFlightSqlPort", "Role", "IsMaster",
"ClusterId", "Join", "Alive", "ReplayedJournalId", "LastStartTime", "LastHeartbeat", "IsHelper", "ErrMsg", "Version", "CurrentConnected", "LiveSince", "FutureUnknownColumn"}
values := []driver.Value{"fe_36d7bccc_d358_4dfd_ad4c_6e988f94f12d", "doriscluster-sample-fe-0.doriscluster-sample-fe-internal.default.svc.cluster.local", 9010, 8030, 9030, 9020, -1, "FOLLOWER", true, "1807668748", true, true, "15443", "2024-08-21 10:04:29",
"2024-08-22 07:29:55", true, "", "doris-2.1.5-rc02-d5a02e095d", "Yes", "2024-08-21 10:04:29", "ignored"}
mock.ExpectQuery("show frontends").WillReturnRows(sqlmock.NewRows(columns).AddRows(values))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
fts, err := db.ShowFrontends()
if err != nil {
t.Errorf("show frontends failed, %s", err.Error())
}
if len(fts) != 1 {
t.Fatalf("show frontends failed, expected one frontend, got %d", len(fts))
}
if fts[0].Host != "doriscluster-sample-fe-0.doriscluster-sample-fe-internal.default.svc.cluster.local" || fts[0].Role != "FOLLOWER" {
t.Errorf("show frontends failed, known fields were not mapped: %+v", fts[0])
}
}
func Test_ShowBackends(t *testing.T) {
columns := []string{"BackendId", "Host", "HeartbeatPort", "BePort", "HttpPort", "BrpcPort", "ArrowFlightSqlPort", "LastStartTime",
"LastHeartbeat", "Alive", "SystemDecommissioned", "TabletNum", "DataUsedCapacity", "TrashUsedCapacity", "AvailCapacity", "TotalCapacity", "UsedPct", "MaxDiskUsedPct",
"RemoteUsedCapacity", "Tag", "ErrMsg", "Version", "Status", "HeartbeatFailureCounter", "NodeRole", "LiveSince", "FutureUnknownColumn"}
values := []driver.Value{"10009", "doriscluster-sample-be-0.doriscluster-sample-be-internal.default.svc.cluster.local", 9050, 9060, 8040, 8060, -1, "2024-08-21 10:05:37",
"2024-08-22 08:29:46", true, false, 24, "0.000", "0.000", "74.619 GB", "439.037 GB", "83.00 %", "83.00 %", "0.000",
"{\"location\" : \"default\"}", "", "doris-2.1.5-rc02-d5a02e095d", "{\"lastSuccessReportTabletsTime\":\"2024-08-22 08:29:09\",\"lastStreamLoadTime\":-1,\"isQueryDisabled\":false,\"isLoadDisabled\":false}",
0, "mix", "2024-08-21 10:05:37", "ignored"}
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
mock.ExpectQuery("show backends").WillReturnRows(sqlmock.NewRows(columns).AddRows(values))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
bds, err := db.ShowBackends()
if err != nil {
t.Errorf("show backends failed, %s", err.Error())
}
if len(bds) != 1 {
t.Fatalf("show backends failed, expected one backend, got %d", len(bds))
}
if bds[0].BackendID != "10009" || bds[0].NodeRole != "mix" {
t.Errorf("show backends failed, known fields were not mapped: %+v", bds[0])
}
}
func TestDB_GetBackendsByCGName(t *testing.T) {
columns := []string{"BackendId", "Host", "HeartbeatPort", "BePort", "HttpPort", "BrpcPort", "ArrowFlightSqlPort", "LastStartTime",
"LastHeartbeat", "Alive", "SystemDecommissioned", "TabletNum", "DataUsedCapacity", "TrashUsedCapacity", "AvailCapacity", "TotalCapacity", "UsedPct", "MaxDiskUsedPct",
"RemoteUsedCapacity", "Tag", "ErrMsg", "Version", "Status", "HeartbeatFailureCounter", "NodeRole"}
values := []driver.Value{"10009", "doriscluster-sample-be-0.doriscluster-sample-be-internal.default.svc.cluster.local", 9050, 9060, 8040, 8060, -1, "2024-08-21 10:05:37",
"2024-08-22 08:29:46", true, false, 24, "0.000", "0.000", "74.619 GB", "439.037 GB", "83.00 %", "83.00 %", "0.000",
"{\"location\" : \"default\",\"compute_group_name\":\"test\"}", "", "doris-2.1.5-rc02-d5a02e095d", "{\"lastSuccessReportTabletsTime\":\"2024-08-22 08:29:09\",\"lastStreamLoadTime\":-1,\"isQueryDisabled\":false,\"isLoadDisabled\":false}",
0, "mix"}
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
mock.ExpectQuery("show backends").WillReturnRows(sqlmock.NewRows(columns).AddRows(values))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
db.GetBackendsByComputeGroupId("test")
}
func Test_DecommissionBE(t *testing.T) {
version := "doris-2.1.5-rc02-d5a02e095d"
startTime := "2024-08-21 10:05:37"
heartbeat := "2024-08-22 08:29:46"
values := []*Backend{{BackendID: "10009", Host: "doriscluster-sample-be-0.doriscluster-sample-be-internal.default.svc.cluster.local", HeartbeatPort: 9050, BePort: 9060, HttpPort: 8040, BrpcPort: 8060, ArrowFlightSqlPort: -1, LastStartTime: &startTime,
LastHeartbeat: &heartbeat, Alive: true, TabletNum: 24, DataUsedCapacity: "0.000", TrashUsedCapacity: "0.000", AvailCapacity: "74.619 GB", TotalCapacity: "439.037 GB", UsedPct: "83.00 %", MaxDiskUsedPct: "83.00 %",
RemoteUsedCapacity: "0.000", ErrMsg: "", Version: &version, Status: "{\"lastSuccessReportTabletsTime\":\"2024-08-22 08:29:09\",\"lastStreamLoadTime\":-1,\"isQueryDisabled\":false,\"isLoadDisabled\":false}", HeartbeatFailureCounter: 0, NodeRole: "mix"}}
values2 := []*Backend{{BackendID: "10009", Host: "doriscluster-sample-be-0.doriscluster-sample-be-internal.default.svc.cluster.local", HeartbeatPort: 9050, BePort: 9060, HttpPort: 8040, BrpcPort: 8060, ArrowFlightSqlPort: -1, LastStartTime: &startTime,
LastHeartbeat: &heartbeat, Alive: true, TabletNum: 24, DataUsedCapacity: "0.000", TrashUsedCapacity: "0.000", AvailCapacity: "74.619 GB", TotalCapacity: "439.037 GB", UsedPct: "83.00 %", MaxDiskUsedPct: "83.00 %",
RemoteUsedCapacity: "0.000", ErrMsg: "", Version: &version, Status: "{\"lastSuccessReportTabletsTime\":\"2024-08-22 08:29:09\",\"lastStreamLoadTime\":-1,\"isQueryDisabled\":false,\"isLoadDisabled\":false}", HeartbeatFailureCounter: 0, NodeRole: "mix"},
{BackendID: "10010", Host: "doriscluster-sample-be-1.doriscluster-sample-be-internal.default.svc.cluster.local", HeartbeatPort: 9050, BePort: 9060, HttpPort: 8040, BrpcPort: 8060, ArrowFlightSqlPort: -1, LastStartTime: &startTime,
LastHeartbeat: &heartbeat, Alive: true, TabletNum: 24, DataUsedCapacity: "0.000", TrashUsedCapacity: "0.000", AvailCapacity: "74.619 GB", TotalCapacity: "439.037 GB", UsedPct: "83.00 %", MaxDiskUsedPct: "83.00 %",
RemoteUsedCapacity: "0.000", ErrMsg: "", Version: &version, Status: "{\"lastSuccessReportTabletsTime\":\"2024-08-22 08:29:09\",\"lastStreamLoadTime\":-1,\"isQueryDisabled\":false,\"isLoadDisabled\":false}", HeartbeatFailureCounter: 0, NodeRole: "mix"}}
tests := [][]*Backend{
{},
values,
values2,
}
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
mock.ExpectExec("ALTER SYSTEM DECOMMISSION BACKEND").WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER SYSTEM DECOMMISSION BACKEND "doriscluster-sample-be-0.doriscluster-sample-be-internal.default.svc.cluster.local:9050","doriscluster-sample-be-1.doriscluster-sample-be-internal.default.svc.cluster.local:9050"`).WillReturnResult(sqlmock.NewResult(1, 2))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
for i, test := range tests {
t.Run("test"+strconv.Itoa(i), func(t *testing.T) {
err = db.DecommissionBE(test)
if err != nil {
t.Errorf("test decommission failed, err=%s", err.Error())
}
})
}
}
func Test_DropObserver(t *testing.T) {
values := []*Frontend{
{Host: "doriscluster-sample-fe-4.doriscluster-sample-fe-internal.default.svc.cluster.local", EditLogPort: 9010},
{Host: "doriscluster-sample-fe-3.doriscluster-sample-fe-internal.default.svc.cluster.local", EditLogPort: 9010},
}
tests := [][]*Frontend{
{},
values,
}
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
mock.ExpectExec(regexp.QuoteMeta("ALTER SYSTEM DROP OBSERVER \"doriscluster-sample-fe-4.doriscluster-sample-fe-internal.default.svc.cluster.local:9010\";")).
WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(regexp.QuoteMeta("ALTER SYSTEM DROP OBSERVER \"doriscluster-sample-fe-3.doriscluster-sample-fe-internal.default.svc.cluster.local:9010\";")).
WillReturnResult(sqlmock.NewResult(1, 1))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
for i, test := range tests {
t.Run("test"+strconv.Itoa(i), func(t *testing.T) {
err = db.DropObserver(test)
if err != nil {
t.Errorf("test decommission failed, err=%s", err.Error())
}
})
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("drop observer expectations were not met: %s", err)
}
}
func Test_GetObservers(t *testing.T) {
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
columns := []string{"Name", "Host", "EditLogPort", "HttpPort", "QueryPort", "RpcPort", "ArrowFlightSqlPort", "Role", "IsMaster",
"ClusterId", "Join", "Alive", "ReplayedJournalId", "LastStartTime", "LastHeartbeat", "IsHelper", "ErrMsg", "Version", "CurrentConnected"}
values := []driver.Value{"fe_36d7bccc_d358_4dfd_ad4c_6e988f94f12d", "doriscluster-sample-fe-0.doriscluster-sample-fe-internal.default.svc.cluster.local", 9010, 8030, 9030, 9020, -1, "OBSERVER", true, "1807668748", true, true, "15443", "2024-08-21 10:04:29",
"2024-08-22 07:29:55", true, "", "doris-2.1.5-rc02-d5a02e095d", "Yes"}
mock.ExpectQuery("show frontends").WillReturnRows(sqlmock.NewRows(columns).AddRows(values))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
fts, err := db.GetObservers()
if err != nil {
t.Errorf("get observers failed, err=%s", err.Error())
}
if len(fts) != 1 {
t.Errorf("get observers failed, not observer")
}
}
func Test_GetFollowers(t *testing.T) {
mysql_db, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
columns := []string{"Name", "Host", "EditLogPort", "HttpPort", "QueryPort", "RpcPort", "ArrowFlightSqlPort", "Role", "IsMaster",
"ClusterId", "Join", "Alive", "ReplayedJournalId", "LastStartTime", "LastHeartbeat", "IsHelper", "ErrMsg", "Version", "CurrentConnected"}
values := []driver.Value{"fe_36d7bccc_d358_4dfd_ad4c_6e988f94f12d", "doriscluster-sample-fe-0.doriscluster-sample-fe-internal.default.svc.cluster.local", 9010, 8030, 9030, 9020, -1, "FOLLOWER", true, "1807668748", true, true, "15443", "2024-08-21 10:04:29",
"2024-08-22 07:29:55", true, "", "doris-2.1.5-rc02-d5a02e095d", "Yes"}
mock.ExpectQuery("show frontends").WillReturnRows(sqlmock.NewRows(columns).AddRows(values))
dorisdb := sqlx.NewDb(mysql_db, "mysql")
db := &DB{
DB: dorisdb,
}
defer db.Close()
_, fts, err := db.GetFollowers()
if err != nil {
t.Errorf("get observers failed, err=%s", err.Error())
}
if len(fts) != 1 {
t.Errorf("get observers failed, not observer")
}
}
func Test_DropBE(t *testing.T) {
mysqlDB, mock, err := sqlmock.New()
if err != nil {
t.Errorf("sqlmock new failed %s", err.Error())
}
db := &DB{
DB: sqlx.NewDb(mysqlDB, "mysql"),
}
defer db.Close()
nodes := []*Backend{
{Host: "test", HeartbeatPort: 9050},
{Host: "test1", HeartbeatPort: 9050},
}
for _, node := range nodes {
query := regexp.QuoteMeta(fmt.Sprintf(`ALTER SYSTEM DROPP BACKEND "%s:%d";`, node.Host, node.HeartbeatPort))
mock.ExpectExec(query).WillReturnResult(sqlmock.NewResult(1, 1))
}
if err := db.DropBE(nodes); err != nil {
t.Fatalf("drop backends failed: %v", err)
}
if err := db.DropBE(nil); err != nil {
t.Fatalf("drop empty backends failed: %v", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet sql expectations: %v", err)
}
}
func TestDropBEReturnsUnexpectedError(t *testing.T) {
mysqlDB, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock new failed: %v", err)
}
db := &DB{DB: sqlx.NewDb(mysqlDB, "mysql")}
defer db.Close()
query := regexp.QuoteMeta(`ALTER SYSTEM DROPP BACKEND "test:9050";`)
mock.ExpectExec(query).WillReturnError(errors.New("access denied"))
if err := db.DropBE([]*Backend{{Host: "test", HeartbeatPort: 9050}}); err == nil {
t.Fatal("expected unexpected DropBE error to be returned")
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet sql expectations: %v", err)
}
}