| /* |
| * 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 cmd |
| |
| import ( |
| "context" |
| "errors" |
| |
| "bou.ke/monkey" |
| "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg" |
| mock_pkg "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/mocks" |
| "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/model" |
| "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/xerr" |
| "github.com/apache/shardingsphere-on-cloud/pitr/cli/pkg/httputils" |
| mock_httputils "github.com/apache/shardingsphere-on-cloud/pitr/cli/pkg/httputils/mocks" |
| "github.com/apache/shardingsphere-on-cloud/pitr/cli/pkg/promptutil" |
| "github.com/golang/mock/gomock" |
| . "github.com/onsi/ginkgo/v2" |
| . "github.com/onsi/gomega" |
| ) |
| |
| var _ = Describe("Backup", func() { |
| |
| Context("do check", func() { |
| var ( |
| as *mock_pkg.MockIAgentServer |
| sn = &model.StorageNode{ |
| IP: "127.0.0.1", |
| } |
| |
| task = &backuptask{} |
| ) |
| BeforeEach(func() { |
| ctrl = gomock.NewController(GinkgoT()) |
| as = mock_pkg.NewMockIAgentServer(ctrl) |
| task = &backuptask{ |
| As: as, |
| Sn: sn, |
| Dn: &model.DataNode{}, |
| DnCh: make(chan *model.DataNode, 2), |
| |
| Backup: &model.BackupInfo{}, |
| } |
| }) |
| AfterEach(func() { |
| ctrl.Finish() |
| }) |
| |
| It("mock agent server return err", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(nil, errors.New("mock agent timeout")) |
| |
| finished, err := task.checkProgress() |
| Expect(err).To(HaveOccurred()) |
| Expect(finished).To(BeFalse()) |
| Expect(task.Dn.Status).To(Equal(model.SsBackupStatusCheckError)) |
| }) |
| |
| It("mock agent server and return failed status", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusFailed}, nil) |
| finished, err := task.checkProgress() |
| Expect(err).ToNot(HaveOccurred()) |
| Expect(finished).To(BeTrue()) |
| Expect(task.Backup.Status).To(Equal(model.SsBackupStatusFailed)) |
| }) |
| |
| It("mock agent server and return completed status", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusCompleted}, nil) |
| |
| finished, err := task.checkProgress() |
| Expect(err).ToNot(HaveOccurred()) |
| Expect(finished).To(BeTrue()) |
| Expect(task.Backup.Status).To(Equal(model.SsBackupStatusCompleted)) |
| }) |
| |
| It("mock agent server and return check err first time and then success", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(nil, errors.New("mock agent timeout")) |
| finished, err := task.checkProgress() |
| Expect(err).To(HaveOccurred()) |
| Expect(finished).To(BeFalse()) |
| Expect(task.Dn.Status).To(Equal(model.SsBackupStatusCheckError)) |
| |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusCompleted}, nil) |
| finished, err = task.checkProgress() |
| Expect(err).ToNot(HaveOccurred()) |
| Expect(finished).To(BeTrue()) |
| Expect(task.Backup.Status).To(Equal(model.SsBackupStatusCompleted)) |
| }) |
| }) |
| |
| Context("export data", func() { |
| var ( |
| proxy *mock_pkg.MockIShardingSphereProxy |
| ls *mock_pkg.MockILocalStorage |
| ) |
| BeforeEach(func() { |
| ctrl = gomock.NewController(GinkgoT()) |
| proxy = mock_pkg.NewMockIShardingSphereProxy(ctrl) |
| ls = mock_pkg.NewMockILocalStorage(ctrl) |
| |
| }) |
| AfterEach(func() { |
| ctrl.Finish() |
| }) |
| It("export data", func() { |
| // mock proxy export metadata |
| proxy.EXPECT().ExportMetaData().Return(&model.ClusterInfo{}, nil) |
| // mock proxy export node storage data |
| proxy.EXPECT().ExportStorageNodes().Return([]*model.StorageNode{}, nil) |
| // mock ls generate filename |
| ls.EXPECT().GenFilename(pkg.ExtnJSON).Return("mock.json") |
| // mock ls write by json |
| ls.EXPECT().WriteByJSON("mock.json", gomock.Any()).Return(nil) |
| |
| bk, err := exportData(proxy, ls) |
| Expect(err).To(BeNil()) |
| Expect(bk.Info.CSN).To(Equal("")) |
| }) |
| }) |
| |
| Context("exec backup", func() { |
| var ( |
| as *mock_pkg.MockIAgentServer |
| ) |
| BeforeEach(func() { |
| ctrl = gomock.NewController(GinkgoT()) |
| as = mock_pkg.NewMockIAgentServer(ctrl) |
| }) |
| AfterEach(func() { |
| ctrl.Finish() |
| }) |
| bak := &model.LsBackup{ |
| DnList: nil, |
| SsBackup: &model.SsBackup{ |
| Status: "Running", |
| StorageNodes: []*model.StorageNode{}, |
| }, |
| } |
| |
| It("exec backup empty storage nodes", func() { |
| Expect(execBackup(bak)).To(BeNil()) |
| }) |
| It("exec backup 2 storage nodes", func() { |
| bak.SsBackup.StorageNodes = []*model.StorageNode{ |
| { |
| IP: "127.0.0.1", |
| Port: 80, |
| Username: "", |
| Password: "", |
| Database: "", |
| Remark: "", |
| }, |
| { |
| IP: "127.0.0.2", |
| Port: 443, |
| Username: "", |
| Password: "", |
| Database: "", |
| Remark: "", |
| }, |
| } |
| as.EXPECT().Backup(gomock.Any()).Return("", nil) |
| dnCh := make(chan *model.DataNode, 10) |
| |
| Expect(_execBackup(as, bak.SsBackup.StorageNodes[0], dnCh)).To(BeNil()) |
| Expect(len(dnCh)).To(Equal(1)) |
| |
| as.EXPECT().Backup(gomock.Any()).Return("", xerr.NewCliErr("backup failed")) |
| |
| Expect(_execBackup(as, bak.SsBackup.StorageNodes[1], dnCh)).ToNot(BeNil()) |
| close(dnCh) |
| Expect(len(dnCh)).To(Equal(2)) |
| |
| }) |
| }) |
| |
| Context("check backup status", func() { |
| var ( |
| as *mock_pkg.MockIAgentServer |
| lsbackup *model.LsBackup |
| ) |
| BeforeEach(func() { |
| lsbackup = &model.LsBackup{ |
| DnList: []*model.DataNode{ |
| { |
| IP: "127.0.0.1", |
| Port: 3306, |
| }, |
| { |
| IP: "127.0.0.2", |
| Port: 3307, |
| }, |
| }, |
| SsBackup: &model.SsBackup{ |
| Status: "Running", |
| StorageNodes: []*model.StorageNode{ |
| { |
| IP: "127.0.0.1", |
| Port: 3306, |
| }, |
| { |
| IP: "127.0.0.2", |
| Port: 3307, |
| }, |
| }, |
| }, |
| Info: &model.BackupMetaInfo{}, |
| } |
| |
| ctrl = gomock.NewController(GinkgoT()) |
| as = mock_pkg.NewMockIAgentServer(ctrl) |
| |
| monkey.Patch(pkg.NewAgentServer, func(_ string) pkg.IAgentServer { |
| return as |
| }) |
| }) |
| AfterEach(func() { |
| ctrl.Finish() |
| monkey.UnpatchAll() |
| }) |
| |
| It("check error 1", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(nil, errors.New("timeout")).AnyTimes() |
| Expect(checkBackupStatus(lsbackup)).To(Equal(model.SsBackupStatusFailed)) |
| }) |
| |
| It("check error 2", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(nil, errors.New("timeout")).Times(1) |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusFailed}, nil).AnyTimes() |
| Expect(checkBackupStatus(lsbackup)).To(Equal(model.SsBackupStatusFailed)) |
| }) |
| |
| It("check error 3", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(nil, errors.New("timeout")).Times(2) |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusCompleted}, nil).AnyTimes() |
| Expect(checkBackupStatus(lsbackup)).To(Equal(model.SsBackupStatusCompleted)) |
| }) |
| |
| It("check failed", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusFailed}, nil).AnyTimes() |
| Expect(checkBackupStatus(lsbackup)).To(Equal(model.SsBackupStatusFailed)) |
| }) |
| |
| It("check success", func() { |
| as.EXPECT().ShowDetail(gomock.Any()).Return(&model.BackupInfo{Status: model.SsBackupStatusCompleted}, nil).AnyTimes() |
| Expect(checkBackupStatus(lsbackup)).To(Equal(model.SsBackupStatusCompleted)) |
| }) |
| }) |
| }) |
| |
| var _ = Describe("test backup manually", func() { |
| var ( |
| // implement with your own dev |
| u string |
| p string |
| db string |
| h string |
| pt uint16 |
| ) |
| Context("test manually", func() { |
| It("unlock after lock", func() { |
| if u == "" || p == "" || db == "" || h == "" || pt == 0 { |
| Skip("need to set u, p, db, h, pt first") |
| } |
| proxy, _ := pkg.NewShardingSphereProxy(u, p, db, h, pt) |
| Expect(proxy.LockForBackup()).To(BeNil()) |
| Expect(proxy.Unlock()).To(BeNil()) |
| }) |
| |
| It("export data in dev", func() { |
| if u == "" || p == "" || db == "" || h == "" || pt == 0 { |
| Skip("need to set u, p, db, h, pt first") |
| } |
| proxy, _ := pkg.NewShardingSphereProxy(u, p, db, h, pt) |
| ls, _ := pkg.NewLocalStorage("./") |
| |
| Expect(proxy.LockForBackup()).To(BeNil()) |
| defer func() { |
| Expect(proxy.Unlock()).To(BeNil()) |
| }() |
| |
| bk, err := exportData(proxy, ls) |
| |
| Expect(err).To(BeNil()) |
| Expect(bk.Info).NotTo(BeNil()) |
| }) |
| |
| It("test all", func() { |
| if u == "" || p == "" || db == "" || h == "" || pt == 0 { |
| Skip("need to set u, p, db, h, pt first") |
| } |
| proxy, _ := pkg.NewShardingSphereProxy(u, p, db, h, pt) |
| ls, _ := pkg.NewLocalStorage(pkg.DefaultRootDir()) |
| bak, err := exportData(proxy, ls) |
| Expect(err).To(BeNil()) |
| Expect(bak.Info).NotTo(BeNil()) |
| |
| AgentPort = 18080 |
| BackupPath = "/home/omm/data" |
| ThreadsNum = 1 |
| |
| err = execBackup(bak) |
| Expect(err).To(BeNil()) |
| Expect(bak.SsBackup.Status).To(Equal(model.SsBackupStatusRunning)) |
| |
| err = ls.WriteByJSON(filename, bak) |
| Expect(err).To(BeNil()) |
| |
| Expect(checkBackupStatus(bak)).To(Equal(model.SsBackupStatusCompleted)) |
| |
| err = ls.WriteByJSON(filename, bak) |
| Expect(err).To(BeNil()) |
| }) |
| }) |
| }) |
| |
| var _ = Describe("test backup mock", func() { |
| Context("test by mock", func() { |
| var ( |
| proxy *mock_pkg.MockIShardingSphereProxy |
| ls *mock_pkg.MockILocalStorage |
| as *mock_pkg.MockIAgentServer |
| ) |
| BeforeEach(func() { |
| ctrl = gomock.NewController(GinkgoT()) |
| proxy = mock_pkg.NewMockIShardingSphereProxy(ctrl) |
| ls = mock_pkg.NewMockILocalStorage(ctrl) |
| as = mock_pkg.NewMockIAgentServer(ctrl) |
| |
| monkey.Patch(pkg.NewShardingSphereProxy, func(u, p, db, h string, pt uint16) (pkg.IShardingSphereProxy, error) { |
| return proxy, nil |
| }) |
| monkey.Patch(pkg.NewLocalStorage, func(rootDir string) (pkg.ILocalStorage, error) { |
| return ls, nil |
| }) |
| monkey.Patch(pkg.NewAgentServer, func(addr string) pkg.IAgentServer { |
| return as |
| }) |
| monkey.Patch(promptutil.GetUserApproveInTerminal, func(_ string) error { |
| return nil |
| }) |
| }) |
| AfterEach(func() { |
| monkey.UnpatchAll() |
| ctrl.Finish() |
| }) |
| |
| It("test backup empty", func() { |
| proxy.EXPECT().LockForBackup().Return(nil) |
| proxy.EXPECT().ExportMetaData().Return(&model.ClusterInfo{}, nil) |
| proxy.EXPECT().ExportStorageNodes().Return([]*model.StorageNode{}, nil) |
| proxy.EXPECT().Unlock().Return(nil) |
| ls.EXPECT().GenFilename(gomock.Any()).Return("filename") |
| ls.EXPECT().WriteByJSON(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() |
| Expect(backup()).To(BeNil()) |
| }) |
| }) |
| |
| Context("test check agent server status", func() { |
| var mockCtrl *gomock.Controller |
| var mockIreq *mock_httputils.MockIreq |
| |
| ls := &model.LsBackup{ |
| Info: nil, |
| DnList: nil, |
| SsBackup: &model.SsBackup{ |
| StorageNodes: []*model.StorageNode{ |
| { |
| IP: "127.0.0.1", |
| Port: 3306, |
| }, |
| { |
| IP: "127.0.0.2", |
| Port: 3307, |
| }, |
| }, |
| }, |
| } |
| BeforeEach(func() { |
| mockCtrl = gomock.NewController(GinkgoT()) |
| mockIreq = mock_httputils.NewMockIreq(mockCtrl) |
| mockIreq.EXPECT().Body(gomock.Any()).AnyTimes() |
| |
| monkey.Patch(httputils.NewRequest, func(ctx context.Context, method, url string) httputils.Ireq { |
| return mockIreq |
| }) |
| }) |
| |
| AfterEach(func() { |
| monkey.UnpatchAll() |
| mockCtrl.Finish() |
| }) |
| |
| It("agent server is not running", func() { |
| mockIreq.EXPECT().Send(gomock.Any()).Return(errors.New("error")).AnyTimes() |
| mockIreq.EXPECT().Header(gomock.Any()).AnyTimes() |
| Expect(checkAgentServerStatus(ls)).To(BeFalse()) |
| }) |
| |
| It("agent server are running", func() { |
| mockIreq.EXPECT().Send(gomock.Any()).Return(nil).AnyTimes() |
| mockIreq.EXPECT().Header(gomock.Any()).AnyTimes() |
| Expect(checkAgentServerStatus(ls)).To(BeTrue()) |
| }) |
| |
| It("one agent server is not running", func() { |
| mockIreq.EXPECT().Send(gomock.Any()).Return(errors.New("failed")) |
| mockIreq.EXPECT().Send(gomock.Any()).Return(nil).AnyTimes() |
| mockIreq.EXPECT().Header(gomock.Any()).AnyTimes() |
| Expect(checkAgentServerStatus(ls)).To(BeFalse()) |
| }) |
| }) |
| |
| Context("test delete backup data", func() { |
| var ( |
| ls *mock_pkg.MockILocalStorage |
| ) |
| |
| bak := &model.LsBackup{ |
| Info: nil, |
| DnList: []*model.DataNode{ |
| { |
| IP: "test.delete.backup", |
| Port: 3306, |
| }, |
| }, |
| SsBackup: &model.SsBackup{ |
| StorageNodes: []*model.StorageNode{ |
| { |
| IP: "test.delete.backup", |
| Port: 3306, |
| }, |
| }, |
| }, |
| } |
| BeforeEach(func() { |
| ctrl = gomock.NewController(GinkgoT()) |
| ls = mock_pkg.NewMockILocalStorage(ctrl) |
| |
| monkey.Patch(pkg.NewLocalStorage, func(rootDir string) (pkg.ILocalStorage, error) { |
| return ls, nil |
| }) |
| }) |
| AfterEach(func() { |
| monkey.UnpatchAll() |
| ctrl.Finish() |
| }) |
| |
| It("should delete failed", func() { |
| ls.EXPECT().DeleteByName(gomock.Any()).Return(errors.New("failed")) |
| deleteBackupFiles(ls, bak, deleteModeNormal) |
| }) |
| |
| It("should delete success", func() { |
| ctrl := gomock.NewController(GinkgoT()) |
| as := mock_pkg.NewMockIAgentServer(ctrl) |
| monkey.Patch(pkg.NewAgentServer, func(addr string) pkg.IAgentServer { |
| return as |
| }) |
| |
| defer monkey.UnpatchAll() |
| defer ctrl.Finish() |
| as.EXPECT().DeleteBackup(gomock.Any()).Return(nil) |
| ls.EXPECT().DeleteByName(gomock.Any()).Return(nil) |
| deleteBackupFiles(ls, bak, deleteModeNormal) |
| }) |
| }) |
| }) |