github.com/weaviate/weaviate@v1.24.6/adapters/handlers/rest/clusterapi/backups_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package clusterapi_test
    13  
    14  import (
    15  	"context"
    16  	"net/http"
    17  	"net/http/httptest"
    18  	"net/url"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/mock"
    22  	"github.com/stretchr/testify/require"
    23  	"github.com/weaviate/weaviate/adapters/clients"
    24  	"github.com/weaviate/weaviate/adapters/handlers/rest/clusterapi"
    25  	"github.com/weaviate/weaviate/usecases/backup"
    26  )
    27  
    28  func TestInternalBackupsAPI(t *testing.T) {
    29  	nodes := []*backupNode{
    30  		{
    31  			name:          "node1",
    32  			backupManager: &fakeBackupManager{},
    33  		},
    34  		{
    35  			name:          "node2",
    36  			backupManager: &fakeBackupManager{},
    37  		},
    38  	}
    39  	hosts := setupClusterAPI(t, nodes)
    40  
    41  	for _, node := range nodes {
    42  		node.backupManager.On("OnCanCommit", &backup.Request{Method: backup.OpCreate}).
    43  			Return(&backup.CanCommitResponse{})
    44  		node.backupManager.On("OnCommit", &backup.StatusRequest{}).Return(nil)
    45  		node.backupManager.On("OnAbort", &backup.AbortRequest{}).Return(nil)
    46  	}
    47  
    48  	coord := newFakeCoordinator(newFakeNodeResolver(hosts))
    49  
    50  	t.Run("can commit, commit", func(t *testing.T) {
    51  		err := coord.Backup(context.Background(), &backup.Request{Method: backup.OpCreate}, false)
    52  		require.Nil(t, err)
    53  	})
    54  
    55  	t.Run("abort", func(t *testing.T) {
    56  		err := coord.Backup(context.Background(), &backup.Request{Method: backup.OpCreate}, true)
    57  		require.Nil(t, err)
    58  	})
    59  }
    60  
    61  func setupClusterAPI(t *testing.T, nodes []*backupNode) map[string]string {
    62  	hosts := make(map[string]string)
    63  
    64  	for _, node := range nodes {
    65  		backupsHandler := clusterapi.NewBackups(node.backupManager, clusterapi.NewNoopAuthHandler())
    66  
    67  		mux := http.NewServeMux()
    68  		mux.Handle("/backups/can-commit", backupsHandler.CanCommit())
    69  		mux.Handle("/backups/commit", backupsHandler.Commit())
    70  		mux.Handle("/backups/abort", backupsHandler.Abort())
    71  		mux.Handle("/backups/status", backupsHandler.Status())
    72  		server := httptest.NewServer(mux)
    73  
    74  		parsedURL, err := url.Parse(server.URL)
    75  		require.Nil(t, err)
    76  
    77  		hosts[node.name] = parsedURL.Host
    78  	}
    79  
    80  	return hosts
    81  }
    82  
    83  type backupNode struct {
    84  	name          string
    85  	backupManager *fakeBackupManager
    86  }
    87  
    88  func newFakeNodeResolver(hosts map[string]string) *fakeNodeResolver {
    89  	return &fakeNodeResolver{hosts: hosts}
    90  }
    91  
    92  type fakeNodeResolver struct {
    93  	hosts map[string]string
    94  }
    95  
    96  func (r *fakeNodeResolver) NodeHostName(nodeName string) (string, bool) {
    97  	if host, ok := r.hosts[nodeName]; ok {
    98  		return host, true
    99  	}
   100  	return "", false
   101  }
   102  
   103  func (r *fakeNodeResolver) HostNames() []string {
   104  	hosts := make([]string, len(r.hosts))
   105  	count := 0
   106  	for _, host := range r.hosts {
   107  		hosts[count] = host
   108  		count++
   109  	}
   110  	return hosts
   111  }
   112  
   113  func newFakeCoordinator(resolver *fakeNodeResolver) *fakeCoordinator {
   114  	return &fakeCoordinator{
   115  		client:       clients.NewClusterBackups(&http.Client{}),
   116  		nodeResolver: resolver,
   117  	}
   118  }
   119  
   120  type fakeCoordinator struct {
   121  	client       *clients.ClusterBackups
   122  	nodeResolver *fakeNodeResolver
   123  }
   124  
   125  func (c *fakeCoordinator) Backup(ctx context.Context, req *backup.Request, abort bool) error {
   126  	if abort {
   127  		return c.abort(ctx)
   128  	}
   129  
   130  	for _, host := range c.nodeResolver.HostNames() {
   131  		_, err := c.client.CanCommit(ctx, host, req)
   132  		if err != nil {
   133  			return err
   134  		}
   135  	}
   136  
   137  	for _, host := range c.nodeResolver.HostNames() {
   138  		err := c.client.Commit(ctx, host, &backup.StatusRequest{})
   139  		if err != nil {
   140  			return err
   141  		}
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func (c *fakeCoordinator) abort(ctx context.Context) error {
   148  	for _, host := range c.nodeResolver.HostNames() {
   149  		err := c.client.Abort(ctx, host, &backup.AbortRequest{})
   150  		if err != nil {
   151  			return err
   152  		}
   153  	}
   154  
   155  	return nil
   156  }
   157  
   158  type fakeBackupManager struct {
   159  	mock.Mock
   160  }
   161  
   162  func (m *fakeBackupManager) OnCanCommit(ctx context.Context, req *backup.Request) *backup.CanCommitResponse {
   163  	args := m.Called(req)
   164  	return args.Get(0).(*backup.CanCommitResponse)
   165  }
   166  
   167  func (m *fakeBackupManager) OnCommit(ctx context.Context, req *backup.StatusRequest) error {
   168  	args := m.Called(req)
   169  	return args.Error(0)
   170  }
   171  
   172  func (m *fakeBackupManager) OnAbort(ctx context.Context, req *backup.AbortRequest) error {
   173  	args := m.Called(req)
   174  	return args.Error(0)
   175  }
   176  
   177  func (m *fakeBackupManager) OnStatus(ctx context.Context, req *backup.StatusRequest) *backup.StatusResponse {
   178  	args := m.Called(req)
   179  	return args.Get(0).(*backup.StatusResponse)
   180  }