github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/clusterintegrationtest/fakes_for_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  //go:build integrationTest
    13  // +build integrationTest
    14  
    15  package clusterintegrationtest
    16  
    17  import (
    18  	"context"
    19  	"encoding/json"
    20  	"fmt"
    21  	"io"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"net/url"
    25  	"path"
    26  	"sync"
    27  	"time"
    28  
    29  	"github.com/sirupsen/logrus/hooks/test"
    30  	"github.com/weaviate/weaviate/adapters/clients"
    31  	"github.com/weaviate/weaviate/adapters/handlers/rest/clusterapi"
    32  	"github.com/weaviate/weaviate/adapters/repos/db"
    33  	"github.com/weaviate/weaviate/entities/backup"
    34  	"github.com/weaviate/weaviate/entities/models"
    35  	"github.com/weaviate/weaviate/entities/modulecapabilities"
    36  	"github.com/weaviate/weaviate/entities/schema"
    37  	modstgfs "github.com/weaviate/weaviate/modules/backup-filesystem"
    38  	ubak "github.com/weaviate/weaviate/usecases/backup"
    39  	"github.com/weaviate/weaviate/usecases/sharding"
    40  )
    41  
    42  type node struct {
    43  	name          string
    44  	repo          *db.DB
    45  	schemaManager *fakeSchemaManager
    46  	backupManager *ubak.Handler
    47  	scheduler     *ubak.Scheduler
    48  	migrator      *db.Migrator
    49  	hostname      string
    50  }
    51  
    52  func (n *node) init(dirName string, shardStateRaw []byte,
    53  	allNodes *[]*node,
    54  ) {
    55  	localDir := path.Join(dirName, n.name)
    56  	logger, _ := test.NewNullLogger()
    57  
    58  	nodeResolver := &nodeResolver{
    59  		nodes: allNodes,
    60  		local: n.name,
    61  	}
    62  
    63  	shardState, err := sharding.StateFromJSON(shardStateRaw, nodeResolver)
    64  	if err != nil {
    65  		panic(err)
    66  	}
    67  
    68  	client := clients.NewRemoteIndex(&http.Client{})
    69  	nodesClient := clients.NewRemoteNode(&http.Client{})
    70  	replicaClient := clients.NewReplicationClient(&http.Client{})
    71  	n.repo, err = db.New(logger, db.Config{
    72  		MemtablesFlushDirtyAfter:  60,
    73  		RootPath:                  localDir,
    74  		QueryMaximumResults:       10000,
    75  		MaxImportGoroutinesFactor: 1,
    76  	}, client, nodeResolver, nodesClient, replicaClient, nil)
    77  	if err != nil {
    78  		panic(err)
    79  	}
    80  	n.schemaManager = &fakeSchemaManager{
    81  		shardState:   shardState,
    82  		schema:       schema.Schema{Objects: &models.Schema{}},
    83  		nodeResolver: nodeResolver,
    84  	}
    85  
    86  	n.repo.SetSchemaGetter(n.schemaManager)
    87  	err = n.repo.WaitForStartup(context.Background())
    88  	if err != nil {
    89  		panic(err)
    90  	}
    91  
    92  	backendProvider := newFakeBackupBackendProvider(localDir)
    93  	n.backupManager = ubak.NewHandler(
    94  		logger, &fakeAuthorizer{}, n.schemaManager, n.repo, backendProvider)
    95  
    96  	backupClient := clients.NewClusterBackups(&http.Client{})
    97  	n.scheduler = ubak.NewScheduler(
    98  		&fakeAuthorizer{}, backupClient, n.repo, backendProvider, nodeResolver, logger)
    99  
   100  	n.migrator = db.NewMigrator(n.repo, logger)
   101  
   102  	indices := clusterapi.NewIndices(sharding.NewRemoteIndexIncoming(n.repo), n.repo, clusterapi.NewNoopAuthHandler())
   103  	mux := http.NewServeMux()
   104  	mux.Handle("/indices/", indices.Indices())
   105  
   106  	backups := clusterapi.NewBackups(n.backupManager, clusterapi.NewNoopAuthHandler())
   107  	mux.Handle("/backups/can-commit", backups.CanCommit())
   108  	mux.Handle("/backups/commit", backups.Commit())
   109  	mux.Handle("/backups/abort", backups.Abort())
   110  	mux.Handle("/backups/status", backups.Status())
   111  
   112  	srv := httptest.NewServer(mux)
   113  	u, err := url.Parse(srv.URL)
   114  	if err != nil {
   115  		panic(err)
   116  	}
   117  	n.hostname = u.Host
   118  }
   119  
   120  type fakeNodes struct {
   121  	nodes []string
   122  }
   123  
   124  func (f fakeNodes) Candidates() []string {
   125  	return f.nodes
   126  }
   127  
   128  func (f fakeNodes) LocalName() string {
   129  	return f.nodes[0]
   130  }
   131  
   132  type fakeSchemaManager struct {
   133  	schema       schema.Schema
   134  	shardState   *sharding.State
   135  	nodeResolver *nodeResolver
   136  }
   137  
   138  func (f *fakeSchemaManager) GetSchemaSkipAuth() schema.Schema {
   139  	return f.schema
   140  }
   141  
   142  func (f *fakeSchemaManager) CopyShardingState(class string) *sharding.State {
   143  	return f.shardState
   144  }
   145  
   146  func (f *fakeSchemaManager) ShardOwner(class, shard string) (string, error) {
   147  	ss := f.shardState
   148  	x, ok := ss.Physical[shard]
   149  	if !ok {
   150  		return "", fmt.Errorf("shard not found")
   151  	}
   152  	if len(x.BelongsToNodes) < 1 || x.BelongsToNodes[0] == "" {
   153  		return "", fmt.Errorf("owner node not found")
   154  	}
   155  	return ss.Physical[shard].BelongsToNodes[0], nil
   156  }
   157  
   158  func (f *fakeSchemaManager) ShardReplicas(class, shard string) ([]string, error) {
   159  	ss := f.shardState
   160  	x, ok := ss.Physical[shard]
   161  	if !ok {
   162  		return nil, fmt.Errorf("shard not found")
   163  	}
   164  	return x.BelongsToNodes, nil
   165  }
   166  
   167  func (f *fakeSchemaManager) TenantShard(class, tenant string) (string, string) {
   168  	return tenant, models.TenantActivityStatusHOT
   169  }
   170  
   171  func (f *fakeSchemaManager) ShardFromUUID(class string, uuid []byte) string {
   172  	ss := f.shardState
   173  	return ss.Shard("", string(uuid))
   174  }
   175  
   176  func (f *fakeSchemaManager) RestoreClass(ctx context.Context, d *backup.ClassDescriptor, nodeMapping map[string]string) error {
   177  	return nil
   178  }
   179  
   180  func (f *fakeSchemaManager) Nodes() []string {
   181  	return []string{"NOT SET"}
   182  }
   183  
   184  func (f *fakeSchemaManager) NodeName() string {
   185  	return f.nodeResolver.local
   186  }
   187  
   188  func (f *fakeSchemaManager) ClusterHealthScore() int {
   189  	return 0
   190  }
   191  
   192  func (f *fakeSchemaManager) ResolveParentNodes(_ string, shard string,
   193  ) (map[string]string, error) {
   194  	return nil, nil
   195  }
   196  
   197  type nodeResolver struct {
   198  	nodes *[]*node
   199  	local string
   200  }
   201  
   202  func (r nodeResolver) AllNames() []string {
   203  	xs := []string{}
   204  	for _, n := range *r.nodes {
   205  		xs = append(xs, n.name)
   206  	}
   207  	return xs
   208  }
   209  
   210  func (r nodeResolver) Candidates() []string {
   211  	return nil
   212  }
   213  
   214  func (r nodeResolver) LocalName() string {
   215  	return r.local
   216  }
   217  
   218  func (r nodeResolver) NodeCount() int {
   219  	return len(*r.nodes)
   220  }
   221  
   222  func (r nodeResolver) NodeHostname(nodeName string) (string, bool) {
   223  	for _, node := range *r.nodes {
   224  		if node.name == nodeName {
   225  			return node.hostname, true
   226  		}
   227  	}
   228  
   229  	return "", false
   230  }
   231  
   232  func newFakeBackupBackendProvider(backupsPath string) *fakeBackupBackendProvider {
   233  	return &fakeBackupBackendProvider{
   234  		backupsPath: backupsPath,
   235  	}
   236  }
   237  
   238  type fakeBackupBackendProvider struct {
   239  	backupsPath string
   240  }
   241  
   242  func (f *fakeBackupBackendProvider) BackupBackend(name string) (modulecapabilities.BackupBackend, error) {
   243  	backend.setLocal(name == modstgfs.Name)
   244  	return backend, nil
   245  }
   246  
   247  type fakeBackupBackend struct {
   248  	sync.Mutex
   249  	backupsPath string
   250  	backupID    string
   251  	counter     int
   252  	isLocal     bool
   253  	startedAt   time.Time
   254  }
   255  
   256  func (f *fakeBackupBackend) HomeDir(backupID string) string {
   257  	f.Lock()
   258  	defer f.Unlock()
   259  	return f.backupsPath
   260  }
   261  
   262  func (f *fakeBackupBackend) GetObject(ctx context.Context, backupID, key string) ([]byte, error) {
   263  	f.Lock()
   264  	defer f.Unlock()
   265  
   266  	f.counter++
   267  
   268  	if f.counter <= 2 {
   269  		return nil, backup.ErrNotFound{}
   270  	}
   271  
   272  	var resp interface{}
   273  
   274  	if key == ubak.GlobalBackupFile {
   275  		resp = f.successGlobalMeta()
   276  	} else {
   277  		resp = f.successLocalMeta()
   278  	}
   279  
   280  	b, _ := json.Marshal(resp)
   281  	return b, nil
   282  }
   283  
   284  func (f *fakeBackupBackend) WriteToFile(ctx context.Context, backupID, key, destPath string) error {
   285  	f.Lock()
   286  	defer f.Unlock()
   287  	return nil
   288  }
   289  
   290  func (f *fakeBackupBackend) Write(ctx context.Context, backupID, key string, r io.ReadCloser) (int64, error) {
   291  	f.Lock()
   292  	defer f.Unlock()
   293  	defer r.Close()
   294  	return 0, nil
   295  }
   296  
   297  func (f *fakeBackupBackend) Read(ctx context.Context, backupID, key string, w io.WriteCloser) (int64, error) {
   298  	f.Lock()
   299  	defer f.Unlock()
   300  	defer w.Close()
   301  	return 0, nil
   302  }
   303  
   304  func (f *fakeBackupBackend) SourceDataPath() string {
   305  	f.Lock()
   306  	defer f.Unlock()
   307  	return f.backupsPath
   308  }
   309  
   310  func (f *fakeBackupBackend) setLocal(v bool) {
   311  	f.Lock()
   312  	defer f.Unlock()
   313  	f.isLocal = v
   314  }
   315  
   316  func (f *fakeBackupBackend) IsExternal() bool {
   317  	f.Lock()
   318  	defer f.Unlock()
   319  	return !f.isLocal
   320  }
   321  
   322  func (f *fakeBackupBackend) Name() string {
   323  	return "fakeBackupBackend"
   324  }
   325  
   326  func (f *fakeBackupBackend) PutFile(ctx context.Context, backupID, key, srcPath string) error {
   327  	f.Lock()
   328  	defer f.Unlock()
   329  	return nil
   330  }
   331  
   332  func (f *fakeBackupBackend) PutObject(ctx context.Context, backupID, key string, byes []byte) error {
   333  	f.Lock()
   334  	defer f.Unlock()
   335  	return nil
   336  }
   337  
   338  func (f *fakeBackupBackend) Initialize(ctx context.Context, backupID string) error {
   339  	f.Lock()
   340  	defer f.Unlock()
   341  	return nil
   342  }
   343  
   344  func (f *fakeBackupBackend) successGlobalMeta() backup.DistributedBackupDescriptor {
   345  	return backup.DistributedBackupDescriptor{
   346  		StartedAt: f.startedAt,
   347  		ID:        f.backupID,
   348  		Nodes: map[string]*backup.NodeDescriptor{
   349  			"node-0": {
   350  				Classes: []string{distributedClass},
   351  				Status:  "SUCCESS",
   352  			},
   353  		},
   354  		Status:        "SUCCESS",
   355  		Version:       ubak.Version,
   356  		ServerVersion: "x.x.x",
   357  	}
   358  }
   359  
   360  func (f *fakeBackupBackend) successLocalMeta() backup.BackupDescriptor {
   361  	return backup.BackupDescriptor{
   362  		ID:            f.backupID,
   363  		Status:        "SUCCESS",
   364  		ServerVersion: "x.x.x",
   365  		Version:       ubak.Version,
   366  		StartedAt:     f.startedAt,
   367  		Classes: []backup.ClassDescriptor{
   368  			{
   369  				Name: distributedClass,
   370  				Shards: []*backup.ShardDescriptor{
   371  					{
   372  						Name:                  "123",
   373  						Node:                  "node-0",
   374  						Files:                 []string{"some-file.db"},
   375  						DocIDCounter:          []byte("1"),
   376  						DocIDCounterPath:      ".",
   377  						Version:               []byte("1"),
   378  						ShardVersionPath:      ".",
   379  						PropLengthTracker:     []byte("1"),
   380  						PropLengthTrackerPath: ".",
   381  					},
   382  				},
   383  				ShardingState: []byte("sharding state!"),
   384  				Schema:        []byte("schema!"),
   385  			},
   386  		},
   387  	}
   388  }
   389  
   390  func (f *fakeBackupBackend) reset() {
   391  	f.counter = 0
   392  }
   393  
   394  type fakeAuthorizer struct{}
   395  
   396  func (f *fakeAuthorizer) Authorize(_ *models.Principal, _, _ string) error {
   397  	return nil
   398  }