github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/ext/dload/diff_resolver_test.go (about)

     1  // Package dloader_test is a unit test
     2  /*
     3   * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package dload_test
     6  
     7  import (
     8  	"testing"
     9  
    10  	"github.com/NVIDIA/aistore/cmn/debug"
    11  	"github.com/NVIDIA/aistore/core"
    12  	"github.com/NVIDIA/aistore/ext/dload"
    13  	"github.com/NVIDIA/aistore/tools/tassert"
    14  )
    15  
    16  const (
    17  	fromRemoteFQN = "remote"
    18  )
    19  
    20  type (
    21  	mockDiffResolverCtx struct{}
    22  
    23  	obj struct {
    24  		name   string
    25  		remote bool
    26  	}
    27  
    28  	testCase struct {
    29  		name     string
    30  		src      []obj
    31  		dst      []obj
    32  		expected []dload.DiffResolverResult
    33  	}
    34  )
    35  
    36  func (*mockDiffResolverCtx) CompareObjects(*core.LOM, *dload.DstElement) (bool, error) {
    37  	return true, nil
    38  }
    39  
    40  func (*mockDiffResolverCtx) IsObjFromRemote(lom *core.LOM) (bool, error) {
    41  	return lom.FQN == fromRemoteFQN, nil
    42  }
    43  
    44  func TestDiffResolver(t *testing.T) {
    45  	tests := []testCase{
    46  		{
    47  			name:     "empty",
    48  			src:      []obj{},
    49  			dst:      []obj{},
    50  			expected: []dload.DiffResolverResult{{Action: dload.DiffResolverEOF}},
    51  		},
    52  		{
    53  			name: "all_send",
    54  			src:  []obj{{name: "a"}, {name: "b"}, {name: "c"}},
    55  			dst:  []obj{},
    56  			expected: []dload.DiffResolverResult{
    57  				{Action: dload.DiffResolverSend},
    58  				{Action: dload.DiffResolverSend},
    59  				{Action: dload.DiffResolverSend},
    60  				{Action: dload.DiffResolverEOF},
    61  			},
    62  		},
    63  		{
    64  			name: "all_recv",
    65  			src:  []obj{},
    66  			dst:  []obj{{name: "a"}, {name: "b"}, {name: "c"}},
    67  			expected: []dload.DiffResolverResult{
    68  				{Action: dload.DiffResolverRecv},
    69  				{Action: dload.DiffResolverRecv},
    70  				{Action: dload.DiffResolverRecv},
    71  				{Action: dload.DiffResolverEOF},
    72  			},
    73  		},
    74  		{
    75  			name: "mixed_send_recv",
    76  			src:  []obj{{name: "a"}, {name: "c"}},
    77  			dst:  []obj{{name: "b"}, {name: "d"}},
    78  			expected: []dload.DiffResolverResult{
    79  				{Action: dload.DiffResolverSend},
    80  				{Action: dload.DiffResolverRecv},
    81  				{Action: dload.DiffResolverSend},
    82  				{Action: dload.DiffResolverRecv},
    83  				{Action: dload.DiffResolverEOF},
    84  			},
    85  		},
    86  		{
    87  			name: "all_send_then_all_recv",
    88  			src:  []obj{{name: "a"}, {name: "b"}, {name: "c"}},
    89  			dst:  []obj{{name: "d"}, {name: "e"}},
    90  			expected: []dload.DiffResolverResult{
    91  				{Action: dload.DiffResolverSend},
    92  				{Action: dload.DiffResolverSend},
    93  				{Action: dload.DiffResolverSend},
    94  				{Action: dload.DiffResolverRecv},
    95  				{Action: dload.DiffResolverRecv},
    96  				{Action: dload.DiffResolverEOF},
    97  			},
    98  		},
    99  		{
   100  			name: "all_recv_then_all_send",
   101  			src:  []obj{{name: "d"}, {name: "e"}},
   102  			dst:  []obj{{name: "a"}, {name: "b"}, {name: "c"}},
   103  			expected: []dload.DiffResolverResult{
   104  				{Action: dload.DiffResolverRecv},
   105  				{Action: dload.DiffResolverRecv},
   106  				{Action: dload.DiffResolverRecv},
   107  				{Action: dload.DiffResolverSend},
   108  				{Action: dload.DiffResolverSend},
   109  				{Action: dload.DiffResolverEOF},
   110  			},
   111  		},
   112  		{
   113  			name: "all_delete",
   114  			src:  []obj{{name: "a", remote: true}, {name: "b", remote: true}},
   115  			dst:  []obj{},
   116  			expected: []dload.DiffResolverResult{
   117  				{Action: dload.DiffResolverDelete},
   118  				{Action: dload.DiffResolverDelete},
   119  				{Action: dload.DiffResolverEOF},
   120  			},
   121  		},
   122  		{
   123  			name: "mixed_send_delete",
   124  			src:  []obj{{name: "a"}, {name: "b", remote: true}, {name: "c"}, {name: "d", remote: true}},
   125  			dst:  []obj{},
   126  			expected: []dload.DiffResolverResult{
   127  				{Action: dload.DiffResolverSend},
   128  				{Action: dload.DiffResolverDelete},
   129  				{Action: dload.DiffResolverSend},
   130  				{Action: dload.DiffResolverDelete},
   131  				{Action: dload.DiffResolverEOF},
   132  			},
   133  		},
   134  		{
   135  			name: "all_skip_then_all_recv",
   136  			src:  []obj{{name: "a", remote: true}, {name: "b", remote: true}},
   137  			dst:  []obj{{name: "a"}, {name: "b"}, {name: "c"}, {name: "d"}},
   138  			expected: []dload.DiffResolverResult{
   139  				{Action: dload.DiffResolverSkip},
   140  				{Action: dload.DiffResolverSkip},
   141  				{Action: dload.DiffResolverRecv},
   142  				{Action: dload.DiffResolverRecv},
   143  				{Action: dload.DiffResolverEOF},
   144  			},
   145  		},
   146  	}
   147  
   148  	for _, test := range tests {
   149  		t.Run(test.name, func(t *testing.T) {
   150  			ctx := &mockDiffResolverCtx{}
   151  			dr := dload.NewDiffResolver(ctx)
   152  			go dr.Start()
   153  			for _, s := range test.src {
   154  				lom := &core.LOM{ObjName: s.name}
   155  				if s.remote {
   156  					lom.FQN = fromRemoteFQN
   157  				}
   158  				dr.PushSrc(lom)
   159  			}
   160  			dr.CloseSrc()
   161  			for _, d := range test.dst {
   162  				dr.PushDst(&dload.BackendResource{ObjName: d.name})
   163  			}
   164  			dr.CloseDst()
   165  
   166  			for i := range len(test.expected) {
   167  				result, err := dr.Next()
   168  				tassert.CheckFatal(t, err)
   169  
   170  				expectedResult := test.expected[i]
   171  				tassert.Errorf(
   172  					t, result.Action == expectedResult.Action,
   173  					"actions differ: (got: %d, expected: %d)", result.Action, expectedResult.Action,
   174  				)
   175  				tassert.Fatalf(t, result.Err == nil, "error has been set")
   176  				switch result.Action {
   177  				case dload.DiffResolverRecv:
   178  					tassert.Errorf(t, result.Dst != nil, "destination has not been set for recv")
   179  				case dload.DiffResolverSend:
   180  					tassert.Errorf(t, result.Src != nil, "source has not been set for send")
   181  				case dload.DiffResolverDelete:
   182  					tassert.Errorf(t, result.Src != nil, "source has not been set for delete")
   183  				case dload.DiffResolverSkip:
   184  					tassert.Errorf(t, result.Src != nil, "source has not been set for skip")
   185  					tassert.Errorf(t, result.Dst != nil, "destination has not been set for skip")
   186  				case dload.DiffResolverEOF:
   187  				default:
   188  					debug.Assertf(false, "invalid diff-resolver action %d", result.Action)
   189  				}
   190  			}
   191  
   192  			// Check that EOF is followed by EOF.
   193  			for range 2 {
   194  				result, err := dr.Next()
   195  				tassert.CheckFatal(t, err)
   196  				tassert.Errorf(t, result.Action == dload.DiffResolverEOF, "eof not followed by eof")
   197  			}
   198  		})
   199  	}
   200  }