github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/diff/async_differ_test.go (about)

     1  // Copyright 2021 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package diff
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  
    25  	"github.com/dolthub/dolt/go/store/chunks"
    26  	"github.com/dolthub/dolt/go/store/datas"
    27  	"github.com/dolthub/dolt/go/store/types"
    28  )
    29  
    30  func TestAsyncDiffer(t *testing.T) {
    31  	ctx := context.Background()
    32  	storage := &chunks.MemoryStorage{}
    33  	db := datas.NewDatabase(storage.NewView())
    34  
    35  	vals := []types.Value{
    36  		types.Uint(0), types.String("a"),
    37  		types.Uint(1), types.String("b"),
    38  		types.Uint(3), types.String("d"),
    39  		types.Uint(4), types.String("e"),
    40  		types.Uint(6), types.String("g"),
    41  		types.Uint(7), types.String("h"),
    42  		types.Uint(9), types.String("j"),
    43  		types.Uint(10), types.String("k"),
    44  		types.Uint(12), types.String("m"),
    45  		types.Uint(13), types.String("n"),
    46  		types.Uint(15), types.String("p"),
    47  		types.Uint(16), types.String("q"),
    48  		types.Uint(18), types.String("s"),
    49  		types.Uint(19), types.String("t"),
    50  		types.Uint(21), types.String("v"),
    51  		types.Uint(22), types.String("w"),
    52  		types.Uint(24), types.String("y"),
    53  		types.Uint(25), types.String("z"),
    54  	}
    55  
    56  	m1, err := types.NewMap(ctx, db, vals...)
    57  	require.NoError(t, err)
    58  
    59  	vals = []types.Value{
    60  		types.Uint(0), types.String("a"), // unchanged
    61  		//types.Uint(1), types.String("b"),		// deleted
    62  		types.Uint(2), types.String("c"), // added
    63  		types.Uint(3), types.String("d"), // unchanged
    64  		//types.Uint(4), types.String("e"),		// deleted
    65  		types.Uint(5), types.String("f"), // added
    66  		types.Uint(6), types.String("g"), // unchanged
    67  		//types.Uint(7), types.String("h"),		// deleted
    68  		types.Uint(8), types.String("i"), // added
    69  		types.Uint(9), types.String("j"), // unchanged
    70  		//types.Uint(10), types.String("k"),	// deleted
    71  		types.Uint(11), types.String("l"), // added
    72  		types.Uint(12), types.String("m2"), // changed
    73  		//types.Uint(13), types.String("n"),	// deleted
    74  		types.Uint(14), types.String("o"), // added
    75  		types.Uint(15), types.String("p2"), // changed
    76  		//types.Uint(16), types.String("q"),	// deleted
    77  		types.Uint(17), types.String("r"), // added
    78  		types.Uint(18), types.String("s2"), // changed
    79  		//types.Uint(19), types.String("t"),	// deleted
    80  		types.Uint(20), types.String("u"), // added
    81  		types.Uint(21), types.String("v2"), // changed
    82  		//types.Uint(22), types.String("w"),	// deleted
    83  		types.Uint(23), types.String("x"), // added
    84  		types.Uint(24), types.String("y2"), // changed
    85  		//types.Uint(25), types.String("z"),	// deleted
    86  	}
    87  	m2, err := types.NewMap(ctx, db, vals...)
    88  	require.NoError(t, err)
    89  
    90  	tests := []struct {
    91  		name           string
    92  		createdStarted func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer
    93  		expectedStats  map[types.DiffChangeType]uint64
    94  	}{
    95  		{
    96  			name: "iter all",
    97  			createdStarted: func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer {
    98  				ad := NewAsyncDiffer(4)
    99  				ad.Start(ctx, m1, m2)
   100  				return ad
   101  			},
   102  			expectedStats: map[types.DiffChangeType]uint64{
   103  				types.DiffChangeModified: 5,
   104  				types.DiffChangeAdded:    8,
   105  				types.DiffChangeRemoved:  9,
   106  			},
   107  		},
   108  
   109  		{
   110  			name: "iter range starting with nil",
   111  			createdStarted: func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer {
   112  				ad := NewAsyncDiffer(4)
   113  				ad.StartWithRange(ctx, m1, m2, nil, func(value types.Value) (bool, error) {
   114  					return true, nil
   115  				})
   116  				return ad
   117  			},
   118  			expectedStats: map[types.DiffChangeType]uint64{
   119  				types.DiffChangeModified: 5,
   120  				types.DiffChangeAdded:    8,
   121  				types.DiffChangeRemoved:  9,
   122  			},
   123  		},
   124  
   125  		{
   126  			name: "iter range staring with Null Value",
   127  			createdStarted: func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer {
   128  				ad := NewAsyncDiffer(4)
   129  				ad.StartWithRange(ctx, m1, m2, types.NullValue, func(value types.Value) (bool, error) {
   130  					return true, nil
   131  				})
   132  				return ad
   133  			},
   134  			expectedStats: map[types.DiffChangeType]uint64{
   135  				types.DiffChangeModified: 5,
   136  				types.DiffChangeAdded:    8,
   137  				types.DiffChangeRemoved:  9,
   138  			},
   139  		},
   140  
   141  		{
   142  			name: "iter range less than 17",
   143  			createdStarted: func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer {
   144  				ad := NewAsyncDiffer(4)
   145  				end := types.Uint(27)
   146  				ad.StartWithRange(ctx, m1, m2, types.NullValue, func(value types.Value) (bool, error) {
   147  					return value.Less(m1.Format(), end)
   148  				})
   149  				return ad
   150  			},
   151  			expectedStats: map[types.DiffChangeType]uint64{
   152  				types.DiffChangeModified: 5,
   153  				types.DiffChangeAdded:    8,
   154  				types.DiffChangeRemoved:  9,
   155  			},
   156  		},
   157  
   158  		{
   159  			name: "iter range less than 15",
   160  			createdStarted: func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer {
   161  				ad := NewAsyncDiffer(4)
   162  				end := types.Uint(15)
   163  				ad.StartWithRange(ctx, m1, m2, types.NullValue, func(value types.Value) (bool, error) {
   164  					return value.Less(m1.Format(), end)
   165  				})
   166  				return ad
   167  			},
   168  			expectedStats: map[types.DiffChangeType]uint64{
   169  				types.DiffChangeModified: 1,
   170  				types.DiffChangeAdded:    5,
   171  				types.DiffChangeRemoved:  5,
   172  			},
   173  		},
   174  
   175  		{
   176  			name: "iter range 10 < 15",
   177  			createdStarted: func(ctx context.Context, m1, m2 types.Map) *AsyncDiffer {
   178  				ad := NewAsyncDiffer(4)
   179  				start := types.Uint(10)
   180  				end := types.Uint(15)
   181  				ad.StartWithRange(ctx, m1, m2, start, func(value types.Value) (bool, error) {
   182  					return value.Less(m1.Format(), end)
   183  				})
   184  				return ad
   185  			},
   186  			expectedStats: map[types.DiffChangeType]uint64{
   187  				types.DiffChangeModified: 1,
   188  				types.DiffChangeAdded:    2,
   189  				types.DiffChangeRemoved:  2,
   190  			},
   191  		},
   192  	}
   193  
   194  	for _, test := range tests {
   195  		t.Run(test.name, func(t *testing.T) {
   196  			ctx := context.Background()
   197  			ad := test.createdStarted(ctx, m1, m2)
   198  			err := readAll(ad)
   199  			require.NoError(t, err)
   200  			require.Equal(t, test.expectedStats, ad.diffStats)
   201  		})
   202  	}
   203  
   204  	t.Run("can close without reading all", func(t *testing.T) {
   205  		ad := NewAsyncDiffer(1)
   206  		ad.Start(ctx, m1, m2)
   207  		res, more, err := ad.GetDiffs(1, -1)
   208  		require.NoError(t, err)
   209  		assert.True(t, more)
   210  		assert.Len(t, res, 1)
   211  		err = ad.Close()
   212  		assert.NoError(t, err)
   213  	})
   214  
   215  	t.Run("can filter based on change type", func(t *testing.T) {
   216  		ad := NewAsyncDiffer(20)
   217  		ad.Start(ctx, m1, m2)
   218  		res, more, err := ad.GetDiffs(10, -1)
   219  		require.NoError(t, err)
   220  		assert.True(t, more)
   221  		assert.Len(t, res, 10)
   222  		err = ad.Close()
   223  		assert.NoError(t, err)
   224  
   225  		ad = NewAsyncDiffer(20)
   226  		ad.Start(ctx, m1, m2)
   227  		res, more, err = ad.GetDiffsWithFilter(10, 20*time.Second, types.DiffChangeModified)
   228  		require.NoError(t, err)
   229  		assert.False(t, more)
   230  		assert.Len(t, res, 5)
   231  		err = ad.Close()
   232  		assert.NoError(t, err)
   233  
   234  		ad = NewAsyncDiffer(20)
   235  		ad.Start(ctx, m1, m2)
   236  		res, more, err = ad.GetDiffsWithFilter(6, -1, types.DiffChangeAdded)
   237  		require.NoError(t, err)
   238  		assert.True(t, more)
   239  		assert.Len(t, res, 6)
   240  		err = ad.Close()
   241  		assert.NoError(t, err)
   242  	})
   243  }
   244  
   245  func readAll(ad *AsyncDiffer) error {
   246  	for {
   247  		_, more, err := ad.GetDiffs(10, -1)
   248  
   249  		if err != nil {
   250  			return err
   251  		}
   252  
   253  		if !more {
   254  			break
   255  		}
   256  	}
   257  
   258  	return nil
   259  }