github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/namespace/convert_prop_test.go (about)

     1  // Copyright (c) 2017 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 namespace_test
    22  
    23  import (
    24  	"fmt"
    25  	"github.com/stretchr/testify/require"
    26  	"math/rand"
    27  	"os"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/m3db/m3/src/dbnode/namespace"
    32  	"github.com/m3db/m3/src/dbnode/retention"
    33  	"github.com/m3db/m3/src/x/ident"
    34  
    35  	"github.com/leanovate/gopter"
    36  	"github.com/leanovate/gopter/gen"
    37  	"github.com/leanovate/gopter/prop"
    38  )
    39  
    40  const (
    41  	testRandomSeeed        int64 = 7823434
    42  	testMinSuccessfulTests       = 1000
    43  )
    44  
    45  func TestConvert(t *testing.T) {
    46  	parameters := gopter.DefaultTestParameters()
    47  	parameters.Rng.Seed(testRandomSeeed) // generate reproducible results
    48  	parameters.MinSuccessfulTests = testMinSuccessfulTests
    49  	parameters.MaxSize = 10
    50  	parameters.MinSize = 2
    51  	props := gopter.NewProperties(parameters)
    52  
    53  	props.Property("Conversion rooted at metadata is bijective", prop.ForAll(
    54  		func(nsMap namespace.Map) (bool, error) {
    55  			reg, err := namespace.ToProto(nsMap)
    56  			require.NoError(t, err)
    57  			cmd, err := namespace.FromProto(*reg)
    58  			if err != nil {
    59  				return false, err
    60  			}
    61  			return nsMap.Equal(cmd), nil
    62  		},
    63  		genMap(),
    64  	))
    65  	reporter := gopter.NewFormatedReporter(true, 160, os.Stdout)
    66  	if !props.Run(reporter) {
    67  		t.Errorf("failed with initial seed: %d", 0) // seed)
    68  	}
    69  }
    70  
    71  // map generator
    72  func genMap() gopter.Gen {
    73  	return gen.SliceOf(genMetadata()).Map(
    74  		func(metadatas []namespace.Metadata) namespace.Map {
    75  			nsMap, err := namespace.NewMap(metadatas)
    76  			if err != nil {
    77  				panic(err.Error())
    78  			}
    79  			return nsMap
    80  		})
    81  }
    82  
    83  // metadata generator
    84  func genMetadata() gopter.Gen {
    85  	return gopter.CombineGens(
    86  		gen.Identifier(),
    87  		gen.SliceOfN(7, gen.Bool()),
    88  		genRetention(),
    89  	).Map(func(values []interface{}) namespace.Metadata {
    90  		var (
    91  			id        = values[0].(string)
    92  			bools     = values[1].([]bool)
    93  			retention = values[2].(retention.Options)
    94  		)
    95  		testSchemaReg, _ := namespace.LoadSchemaHistory(testSchemaOptions)
    96  		md, err := namespace.NewMetadata(ident.StringID(id), namespace.NewOptions().
    97  			SetBootstrapEnabled(bools[0]).
    98  			SetCleanupEnabled(bools[1]).
    99  			SetFlushEnabled(bools[2]).
   100  			SetRepairEnabled(bools[3]).
   101  			SetWritesToCommitLog(bools[4]).
   102  			SetSnapshotEnabled(bools[5]).
   103  			SetSchemaHistory(testSchemaReg).
   104  			SetRetentionOptions(retention).
   105  			SetIndexOptions(namespace.NewIndexOptions().
   106  				SetEnabled(bools[6]).
   107  				SetBlockSize(retention.BlockSize())))
   108  		if err != nil {
   109  			panic(err.Error())
   110  		}
   111  		return md
   112  	})
   113  }
   114  
   115  func newRandomRetention(rng *rand.Rand) *generatedRetention {
   116  	var (
   117  		blockSizeMins    = maxInt(1, rng.Intn(60*12)) // 12 hours
   118  		retentionMins    = maxInt(1, rng.Intn(40)) * blockSizeMins
   119  		bufferPastMins   = maxInt(1, rng.Intn(blockSizeMins))
   120  		bufferFutureMins = maxInt(1, rng.Intn(blockSizeMins))
   121  	)
   122  
   123  	return &generatedRetention{retention.NewOptions().
   124  		SetRetentionPeriod(time.Duration(retentionMins) * time.Minute).
   125  		SetBlockSize(time.Duration(blockSizeMins) * time.Minute).
   126  		SetBufferPast(time.Duration(bufferPastMins) * time.Minute).
   127  		SetBufferFuture(time.Duration(bufferFutureMins) * time.Minute)}
   128  }
   129  
   130  // generator for retention options
   131  func genRetention() gopter.Gen {
   132  	return func(genParams *gopter.GenParameters) *gopter.GenResult {
   133  		opts := newRandomRetention(genParams.Rng)
   134  		genResult := gopter.NewGenResult(opts, gopter.NoShrinker)
   135  		genResult.Sieve = func(v interface{}) bool {
   136  			return v.(retention.Options).Validate() == nil
   137  		}
   138  		return genResult
   139  	}
   140  }
   141  
   142  type generatedRetention struct {
   143  	retention.Options
   144  }
   145  
   146  func (ro *generatedRetention) String() string {
   147  	return fmt.Sprintf(
   148  		"[ retention-period = %v, block-size = %v, buffer-past = %v, buffer-future = %v ]",
   149  		ro.RetentionPeriod().String(),
   150  		ro.BlockSize().String(),
   151  		ro.BufferPast().String(),
   152  		ro.BufferFuture().String())
   153  }
   154  
   155  func maxInt(x, y int) int {
   156  	if x > y {
   157  		return x
   158  	}
   159  	return y
   160  }