github.com/weaviate/weaviate@v1.24.6/entities/backup/descriptor_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 backup
    13  
    14  import (
    15  	"sort"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func TestExcludeClasses(t *testing.T) {
    23  	tests := []struct {
    24  		in  BackupDescriptor
    25  		xs  []string
    26  		out []string
    27  	}{
    28  		{in: BackupDescriptor{}, xs: []string{}, out: []string{}},
    29  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{}, out: []string{"a"}},
    30  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{"a"}, out: []string{}},
    31  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}}, xs: []string{"2", "3"}, out: []string{"1", "4"}},
    32  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}}}, xs: []string{"1", "3"}, out: []string{"2"}},
    33  
    34  		// {in: []BackupDescriptor{"1", "2", "3", "4"}, xs: []string{"2", "3"}, out: []string{"1", "4"}},
    35  		// {in: []BackupDescriptor{"1", "2", "3"}, xs: []string{"1", "3"}, out: []string{"2"}},
    36  	}
    37  	for _, tc := range tests {
    38  		tc.in.Exclude(tc.xs)
    39  		lst := tc.in.List()
    40  		assert.Equal(t, tc.out, lst)
    41  	}
    42  }
    43  
    44  func TestIncludeClasses(t *testing.T) {
    45  	tests := []struct {
    46  		in  BackupDescriptor
    47  		xs  []string
    48  		out []string
    49  	}{
    50  		{in: BackupDescriptor{}, xs: []string{}, out: []string{}},
    51  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{}, out: []string{"a"}},
    52  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{"a"}, out: []string{"a"}},
    53  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}}, xs: []string{"2", "3"}, out: []string{"2", "3"}},
    54  		{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}}}, xs: []string{"1", "3"}, out: []string{"1", "3"}},
    55  	}
    56  	for _, tc := range tests {
    57  		tc.in.Include(tc.xs)
    58  		lst := tc.in.List()
    59  		assert.Equal(t, tc.out, lst)
    60  	}
    61  }
    62  
    63  func TestAllExist(t *testing.T) {
    64  	x := BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}
    65  	if y := x.AllExist(nil); y != "" {
    66  		t.Errorf("x.AllExists(nil) got=%v want=%v", y, "")
    67  	}
    68  	if y := x.AllExist([]string{"a"}); y != "" {
    69  		t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "")
    70  	}
    71  	if y := x.AllExist([]string{"b"}); y != "b" {
    72  		t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "b")
    73  	}
    74  }
    75  
    76  func TestValidateBackup(t *testing.T) {
    77  	timept := time.Now().UTC()
    78  	bytes := []byte("hello")
    79  	tests := []struct {
    80  		desc      BackupDescriptor
    81  		successV1 bool
    82  		successV2 bool
    83  	}{
    84  		// first level check
    85  		{desc: BackupDescriptor{}},
    86  		{desc: BackupDescriptor{ID: "1"}},
    87  		{desc: BackupDescriptor{ID: "1", Version: "1"}},
    88  		{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}},
    89  		{
    90  			desc:      BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept},
    91  			successV1: true, successV2: true,
    92  		},
    93  		{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}},
    94  		{desc: BackupDescriptor{
    95  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
    96  			Classes: []ClassDescriptor{{}},
    97  		}},
    98  		{desc: BackupDescriptor{
    99  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   100  			Classes: []ClassDescriptor{{Name: "n"}},
   101  		}},
   102  		{desc: BackupDescriptor{
   103  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   104  			Classes: []ClassDescriptor{{Name: "n", Schema: bytes}},
   105  		}},
   106  		{desc: BackupDescriptor{
   107  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   108  			Classes: []ClassDescriptor{{Name: "n", Schema: bytes, ShardingState: bytes}},
   109  		}, successV1: true, successV2: true},
   110  		{desc: BackupDescriptor{
   111  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   112  			Classes: []ClassDescriptor{{
   113  				Name: "n", Schema: bytes, ShardingState: bytes,
   114  				Shards: []*ShardDescriptor{{Name: ""}},
   115  			}},
   116  		}},
   117  		{desc: BackupDescriptor{
   118  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   119  			Classes: []ClassDescriptor{{
   120  				Name: "n", Schema: bytes, ShardingState: bytes,
   121  				Shards: []*ShardDescriptor{{Name: "n", Node: ""}},
   122  			}},
   123  		}},
   124  		{desc: BackupDescriptor{
   125  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   126  			Classes: []ClassDescriptor{{
   127  				Name: "n", Schema: bytes, ShardingState: bytes,
   128  				Shards: []*ShardDescriptor{{Name: "n", Node: "n"}},
   129  			}},
   130  		}, successV2: true},
   131  		{desc: BackupDescriptor{
   132  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   133  			Classes: []ClassDescriptor{{
   134  				Name: "n", Schema: bytes, ShardingState: bytes,
   135  				Shards: []*ShardDescriptor{{
   136  					Name: "n", Node: "n",
   137  					PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n",
   138  				}},
   139  			}},
   140  		}, successV1: true, successV2: true},
   141  		{desc: BackupDescriptor{
   142  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   143  			Classes: []ClassDescriptor{{
   144  				Name: "n", Schema: bytes, ShardingState: bytes,
   145  				Shards: []*ShardDescriptor{{
   146  					Name: "n", Node: "n",
   147  					PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n",
   148  					Files: []string{"file"},
   149  				}},
   150  			}},
   151  		}, successV2: true},
   152  		{desc: BackupDescriptor{
   153  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   154  			Classes: []ClassDescriptor{{
   155  				Name: "n", Schema: bytes, ShardingState: bytes,
   156  				Shards: []*ShardDescriptor{{
   157  					Name: "n", Node: "n",
   158  					PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n",
   159  					DocIDCounter: bytes, Files: []string{"file"},
   160  				}},
   161  			}},
   162  		}, successV2: true},
   163  		{desc: BackupDescriptor{
   164  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   165  			Classes: []ClassDescriptor{{
   166  				Name: "n", Schema: bytes, ShardingState: bytes,
   167  				Shards: []*ShardDescriptor{{
   168  					Name: "n", Node: "n",
   169  					PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n",
   170  					DocIDCounter: bytes, Version: bytes, PropLengthTracker: bytes, Files: []string{""},
   171  				}},
   172  			}},
   173  		}, successV2: true},
   174  		{desc: BackupDescriptor{
   175  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   176  			Classes: []ClassDescriptor{{
   177  				Name: "n", Schema: bytes, ShardingState: bytes,
   178  				Shards: []*ShardDescriptor{{
   179  					Name: "n", Node: "n",
   180  					PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n",
   181  					DocIDCounter: bytes, Version: bytes, PropLengthTracker: bytes, Files: []string{"file"},
   182  				}},
   183  			}},
   184  		}, successV1: true, successV2: true},
   185  	}
   186  	for i, tc := range tests {
   187  		err := tc.desc.Validate(false)
   188  		if got := err == nil; got != tc.successV1 {
   189  			t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.successV1, got, err)
   190  		}
   191  		err = tc.desc.Validate(true)
   192  		if got := err == nil; got != tc.successV2 {
   193  			t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.successV1, got, err)
   194  		}
   195  	}
   196  }
   197  
   198  func TestBackwardCompatibility(t *testing.T) {
   199  	timept := time.Now().UTC()
   200  	tests := []struct {
   201  		desc    BackupDescriptor
   202  		success bool
   203  	}{
   204  		// first level check
   205  		{desc: BackupDescriptor{}},
   206  		{desc: BackupDescriptor{ID: "1"}},
   207  		{desc: BackupDescriptor{ID: "1", Version: "1"}},
   208  		{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}},
   209  		{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}},
   210  		{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}},
   211  		{desc: BackupDescriptor{
   212  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   213  			Classes: []ClassDescriptor{{
   214  				Name:   "n",
   215  				Shards: []*ShardDescriptor{{Name: "n", Node: ""}},
   216  			}},
   217  		}},
   218  		{desc: BackupDescriptor{
   219  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   220  			Classes: []ClassDescriptor{{
   221  				Name: "n",
   222  				Shards: []*ShardDescriptor{{
   223  					Name: "n", Node: "n",
   224  				}},
   225  			}},
   226  		}, success: true},
   227  	}
   228  	for i, tc := range tests {
   229  		desc := tc.desc.ToDistributed()
   230  		err := desc.Validate()
   231  		if got := err == nil; got != tc.success {
   232  			t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.success, got, err)
   233  		}
   234  	}
   235  }
   236  
   237  func TestDistributedBackup(t *testing.T) {
   238  	d := DistributedBackupDescriptor{
   239  		Nodes: map[string]*NodeDescriptor{
   240  			"N1": {Classes: []string{"1", "2"}},
   241  			"N2": {Classes: []string{"3", "4"}},
   242  		},
   243  	}
   244  	if n := d.Len(); n != 2 {
   245  		t.Errorf("#nodes got:%v want:%v", n, 2)
   246  	}
   247  	if n := d.Count(); n != 4 {
   248  		t.Errorf("#classes got:%v want:%v", n, 4)
   249  	}
   250  	d.Exclude([]string{"3", "4"})
   251  	d.RemoveEmpty()
   252  	if n := d.Len(); n != 1 {
   253  		t.Errorf("#nodes got:%v want:%v", n, 2)
   254  	}
   255  	if n := d.Count(); n != 2 {
   256  		t.Errorf("#classes got:%v want:%v", n, 4)
   257  	}
   258  }
   259  
   260  func TestDistributedBackupExcludeClasses(t *testing.T) {
   261  	tests := []struct {
   262  		in  DistributedBackupDescriptor
   263  		xs  []string
   264  		out []string
   265  	}{
   266  		{
   267  			in:  DistributedBackupDescriptor{},
   268  			xs:  []string{},
   269  			out: []string{},
   270  		},
   271  		{
   272  			in: DistributedBackupDescriptor{
   273  				Nodes: map[string]*NodeDescriptor{
   274  					"N1": {Classes: []string{"a"}},
   275  				},
   276  			},
   277  			xs:  []string{},
   278  			out: []string{"a"},
   279  		},
   280  		{
   281  			in: DistributedBackupDescriptor{
   282  				Nodes: map[string]*NodeDescriptor{
   283  					"N1": {Classes: []string{"a"}},
   284  				},
   285  			},
   286  			xs:  []string{"a"},
   287  			out: []string{},
   288  		},
   289  		{
   290  			in: DistributedBackupDescriptor{
   291  				Nodes: map[string]*NodeDescriptor{
   292  					"N1": {Classes: []string{"1", "2"}},
   293  					"N2": {Classes: []string{"3", "4"}},
   294  				},
   295  			},
   296  			xs:  []string{"2", "3"},
   297  			out: []string{"1", "4"},
   298  		},
   299  
   300  		{
   301  			in: DistributedBackupDescriptor{
   302  				Nodes: map[string]*NodeDescriptor{
   303  					"N1": {Classes: []string{"1", "2"}},
   304  					"N2": {Classes: []string{"3"}},
   305  				},
   306  			},
   307  			xs:  []string{"1", "3"},
   308  			out: []string{"2"},
   309  		},
   310  	}
   311  
   312  	for _, tc := range tests {
   313  		tc.in.Exclude(tc.xs)
   314  		lst := tc.in.Classes()
   315  		sort.Strings(lst)
   316  		assert.Equal(t, tc.out, lst)
   317  	}
   318  }
   319  
   320  func TestDistributedBackupIncludeClasses(t *testing.T) {
   321  	tests := []struct {
   322  		in  DistributedBackupDescriptor
   323  		xs  []string
   324  		out []string
   325  	}{
   326  		{
   327  			in:  DistributedBackupDescriptor{},
   328  			xs:  []string{},
   329  			out: []string{},
   330  		},
   331  		{
   332  			in: DistributedBackupDescriptor{
   333  				Nodes: map[string]*NodeDescriptor{
   334  					"N1": {Classes: []string{"a"}},
   335  				},
   336  			},
   337  			xs:  []string{},
   338  			out: []string{"a"},
   339  		},
   340  		{
   341  			in: DistributedBackupDescriptor{
   342  				Nodes: map[string]*NodeDescriptor{
   343  					"N1": {Classes: []string{"a"}},
   344  				},
   345  			},
   346  			xs:  []string{"a"},
   347  			out: []string{"a"},
   348  		},
   349  		{
   350  			in: DistributedBackupDescriptor{
   351  				Nodes: map[string]*NodeDescriptor{
   352  					"N1": {Classes: []string{"1", "2"}},
   353  					"N2": {Classes: []string{"3", "4"}},
   354  				},
   355  			},
   356  			xs:  []string{"2", "3"},
   357  			out: []string{"2", "3"},
   358  		},
   359  
   360  		{
   361  			in: DistributedBackupDescriptor{
   362  				Nodes: map[string]*NodeDescriptor{
   363  					"N1": {Classes: []string{"1", "2"}},
   364  					"N2": {Classes: []string{"3"}},
   365  				},
   366  			},
   367  			xs:  []string{"1", "3"},
   368  			out: []string{"1", "3"},
   369  		},
   370  	}
   371  	for _, tc := range tests {
   372  		tc.in.Include(tc.xs)
   373  		lst := tc.in.Classes()
   374  		sort.Strings(lst)
   375  		assert.Equal(t, tc.out, lst)
   376  	}
   377  }
   378  
   379  func TestDistributedBackupAllExist(t *testing.T) {
   380  	x := DistributedBackupDescriptor{Nodes: map[string]*NodeDescriptor{"N1": {Classes: []string{"a"}}}}
   381  	if y := x.AllExist(nil); y != "" {
   382  		t.Errorf("x.AllExists(nil) got=%v want=%v", y, "")
   383  	}
   384  	if y := x.AllExist([]string{"a"}); y != "" {
   385  		t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "")
   386  	}
   387  	if y := x.AllExist([]string{"b"}); y != "b" {
   388  		t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "b")
   389  	}
   390  }
   391  
   392  func TestDistributedBackupValidate(t *testing.T) {
   393  	timept := time.Now().UTC()
   394  	tests := []struct {
   395  		desc    DistributedBackupDescriptor
   396  		success bool
   397  	}{
   398  		// first level check
   399  		{desc: DistributedBackupDescriptor{}},
   400  		{desc: DistributedBackupDescriptor{ID: "1"}},
   401  		{desc: DistributedBackupDescriptor{ID: "1", Version: "1"}},
   402  		{desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}},
   403  		{desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}},
   404  		{desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}},
   405  		{desc: DistributedBackupDescriptor{
   406  			ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept,
   407  			Nodes: map[string]*NodeDescriptor{"N": {}},
   408  		}, success: true},
   409  	}
   410  	for i, tc := range tests {
   411  		err := tc.desc.Validate()
   412  		if got := err == nil; got != tc.success {
   413  			t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.success, got, err)
   414  		}
   415  	}
   416  }
   417  
   418  func TestTestDistributedBackupResetStatus(t *testing.T) {
   419  	begin := time.Now().UTC().Add(-2)
   420  	desc := DistributedBackupDescriptor{
   421  		StartedAt:     begin,
   422  		CompletedAt:   begin.Add(2),
   423  		ID:            "1",
   424  		Version:       "1",
   425  		ServerVersion: "1",
   426  		Nodes: map[string]*NodeDescriptor{
   427  			"1": {},
   428  			"2": {Status: Success},
   429  			"3": {Error: "error"},
   430  		},
   431  		Error: "error",
   432  	}
   433  
   434  	desc.ResetStatus()
   435  	if !desc.StartedAt.After(begin) {
   436  		t.Fatalf("!desc.StartedAt.After(begin)")
   437  	}
   438  	want := DistributedBackupDescriptor{
   439  		StartedAt:     desc.StartedAt,
   440  		ID:            "1",
   441  		Version:       "1",
   442  		ServerVersion: "1",
   443  		Nodes: map[string]*NodeDescriptor{
   444  			"1": {Status: Started},
   445  			"2": {Status: Started},
   446  			"3": {Status: Started, Error: ""},
   447  		},
   448  		Status: Started,
   449  	}
   450  	assert.Equal(t, want, desc)
   451  }
   452  
   453  func TestShardDescriptorClear(t *testing.T) {
   454  	s := ShardDescriptor{
   455  		Name:                  "name",
   456  		Node:                  "node",
   457  		PropLengthTrackerPath: "a/b",
   458  		PropLengthTracker:     []byte{1},
   459  		DocIDCounterPath:      "a/c",
   460  		DocIDCounter:          []byte{2},
   461  		ShardVersionPath:      "a/d",
   462  		Version:               []byte{3},
   463  		Files:                 []string{"file"},
   464  		Chunk:                 1,
   465  	}
   466  
   467  	want := ShardDescriptor{
   468  		Name:  "name",
   469  		Node:  "node",
   470  		Files: []string{"file"},
   471  		Chunk: 1,
   472  	}
   473  	s.ClearTemporary()
   474  	assert.Equal(t, want, s)
   475  }