github.com/m3db/m3@v1.5.0/src/dbnode/storage/bootstrap/bootstrapper/commitlog/source_test.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package commitlog
    22  
    23  import (
    24  	"errors"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/cluster/shard"
    29  	"github.com/m3db/m3/src/dbnode/persist/fs"
    30  	"github.com/m3db/m3/src/dbnode/runtime"
    31  	"github.com/m3db/m3/src/dbnode/storage/bootstrap"
    32  	"github.com/m3db/m3/src/dbnode/storage/bootstrap/result"
    33  	"github.com/m3db/m3/src/dbnode/topology"
    34  	tu "github.com/m3db/m3/src/dbnode/topology/testutil"
    35  	"github.com/m3db/m3/src/x/instrument"
    36  	xtime "github.com/m3db/m3/src/x/time"
    37  
    38  	"github.com/stretchr/testify/require"
    39  )
    40  
    41  var (
    42  	testDefaultOpts = NewOptions().
    43  			SetRuntimeOptionsManager(runtime.NewOptionsManager())
    44  	notSelfID = "not-self"
    45  )
    46  
    47  func TestAvailableData(t *testing.T) {
    48  	var (
    49  		nsMetadata                 = testNsMetadata(t)
    50  		blockSize                  = 2 * time.Hour
    51  		numShards                  = uint32(4)
    52  		blockStart                 = xtime.Now().Truncate(blockSize)
    53  		shardTimeRangesToBootstrap = result.NewShardTimeRanges()
    54  		bootstrapRanges            = xtime.NewRanges(xtime.Range{
    55  			Start: blockStart,
    56  			End:   blockStart.Add(blockSize),
    57  		})
    58  		cacheOptions = bootstrap.NewCacheOptions().
    59  				SetFilesystemOptions(fs.NewOptions()).
    60  				SetInstrumentOptions(instrument.NewOptions())
    61  	)
    62  
    63  	for i := 0; i < int(numShards); i++ {
    64  		shardTimeRangesToBootstrap.Set(uint32(i), bootstrapRanges)
    65  	}
    66  
    67  	testCases := []struct {
    68  		title                             string
    69  		topoState                         *topology.StateSnapshot
    70  		shardsTimeRangesToBootstrap       result.ShardTimeRanges
    71  		expectedAvailableShardsTimeRanges result.ShardTimeRanges
    72  		expectedErr                       error
    73  	}{
    74  		{
    75  			title: "Single node - Shard initializing",
    76  			topoState: tu.NewStateSnapshot(1, tu.HostShardStates{
    77  				tu.SelfID: tu.ShardsRange(0, numShards, shard.Initializing),
    78  			}),
    79  			shardsTimeRangesToBootstrap:       shardTimeRangesToBootstrap,
    80  			expectedAvailableShardsTimeRanges: result.NewShardTimeRanges(),
    81  		},
    82  		{
    83  			title: "Single node - Shard unknown",
    84  			topoState: tu.NewStateSnapshot(1, tu.HostShardStates{
    85  				tu.SelfID: tu.ShardsRange(0, numShards, shard.Unknown),
    86  			}),
    87  			shardsTimeRangesToBootstrap:       shardTimeRangesToBootstrap,
    88  			expectedAvailableShardsTimeRanges: result.NewShardTimeRanges(),
    89  			expectedErr:                       errors.New("unknown shard state: Unknown"),
    90  		},
    91  		{
    92  			title: "Single node - Shard leaving",
    93  			topoState: tu.NewStateSnapshot(1, tu.HostShardStates{
    94  				tu.SelfID: tu.ShardsRange(0, numShards, shard.Leaving),
    95  			}),
    96  			shardsTimeRangesToBootstrap:       shardTimeRangesToBootstrap,
    97  			expectedAvailableShardsTimeRanges: shardTimeRangesToBootstrap,
    98  		},
    99  		{
   100  			title: "Single node - Shard available",
   101  			topoState: tu.NewStateSnapshot(1, tu.HostShardStates{
   102  				tu.SelfID: tu.ShardsRange(0, numShards, shard.Available),
   103  			}),
   104  			shardsTimeRangesToBootstrap:       shardTimeRangesToBootstrap,
   105  			expectedAvailableShardsTimeRanges: shardTimeRangesToBootstrap,
   106  		},
   107  		{
   108  			title: "Multi node - Origin available",
   109  			topoState: tu.NewStateSnapshot(1, tu.HostShardStates{
   110  				tu.SelfID: tu.ShardsRange(0, numShards, shard.Available),
   111  				notSelfID: tu.ShardsRange(0, numShards, shard.Initializing),
   112  			}),
   113  			shardsTimeRangesToBootstrap:       shardTimeRangesToBootstrap,
   114  			expectedAvailableShardsTimeRanges: shardTimeRangesToBootstrap,
   115  		},
   116  		{
   117  			title: "Multi node - Origin not available",
   118  			topoState: tu.NewStateSnapshot(1, tu.HostShardStates{
   119  				tu.SelfID: tu.ShardsRange(0, numShards, shard.Initializing),
   120  				notSelfID: tu.ShardsRange(0, numShards, shard.Available),
   121  			}),
   122  			shardsTimeRangesToBootstrap:       shardTimeRangesToBootstrap,
   123  			expectedAvailableShardsTimeRanges: result.NewShardTimeRanges(),
   124  		},
   125  	}
   126  
   127  	for _, tc := range testCases {
   128  		t.Run(tc.title, func(t *testing.T) {
   129  			var shards []uint32
   130  			for shard := range tc.shardsTimeRangesToBootstrap.Iter() {
   131  				shards = append(shards, shard)
   132  			}
   133  			cache, sErr := bootstrap.NewCache(cacheOptions.
   134  				SetNamespaceDetails([]bootstrap.NamespaceDetails{
   135  					{
   136  						Namespace: nsMetadata,
   137  						Shards:    shards,
   138  					},
   139  				}))
   140  			require.NoError(t, sErr)
   141  
   142  			var (
   143  				src          = newCommitLogSource(testDefaultOpts, fs.Inspection{})
   144  				runOpts      = testDefaultRunOpts.SetInitialTopologyState(tc.topoState)
   145  				dataRes, err = src.AvailableData(nsMetadata, tc.shardsTimeRangesToBootstrap, cache, runOpts)
   146  			)
   147  
   148  			if tc.expectedErr != nil {
   149  				require.Equal(t, err, tc.expectedErr)
   150  			} else {
   151  				require.NoError(t, err)
   152  				require.Equal(t, tc.expectedAvailableShardsTimeRanges, dataRes)
   153  			}
   154  
   155  			indexRes, err := src.AvailableIndex(nsMetadata, tc.shardsTimeRangesToBootstrap, cache, runOpts)
   156  			if tc.expectedErr != nil {
   157  				require.Equal(t, err, tc.expectedErr)
   158  			} else {
   159  				require.NoError(t, err)
   160  				require.Equal(t, tc.expectedAvailableShardsTimeRanges, indexRes)
   161  			}
   162  		})
   163  	}
   164  }