github.com/m3db/m3@v1.5.0/src/cmd/tools/dtest/util/seed/generator_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 seed
    22  
    23  import (
    24  	"fmt"
    25  	"io/ioutil"
    26  	"os"
    27  	"path"
    28  	"path/filepath"
    29  	"sort"
    30  	"strconv"
    31  	"strings"
    32  	"testing"
    33  	"time"
    34  
    35  	"github.com/m3db/m3/src/dbnode/integration/generate"
    36  	"github.com/m3db/m3/src/dbnode/namespace"
    37  	"github.com/m3db/m3/src/x/ident"
    38  	"github.com/m3db/m3/src/x/instrument"
    39  	xtest "github.com/m3db/m3/src/x/test"
    40  	xtime "github.com/m3db/m3/src/x/time"
    41  
    42  	"github.com/golang/mock/gomock"
    43  	"github.com/stretchr/testify/require"
    44  )
    45  
    46  func TestGenerator(t *testing.T) {
    47  	dir, err := ioutil.TempDir("", "test-single-conf")
    48  	require.NoError(t, err)
    49  	defer os.RemoveAll(dir)
    50  
    51  	gOpts := generate.NewOptions().
    52  		SetFilePathPrefix(dir).
    53  		SetRetentionPeriod(2 * time.Hour).
    54  		SetBlockSize(time.Hour).
    55  		SetWriteEmptyShards(false)
    56  
    57  	rawLogger := xtest.NewLogger(t)
    58  	iopts := instrument.NewOptions().SetLogger(rawLogger)
    59  
    60  	opts := NewOptions().
    61  		SetInstrumentOptions(iopts).
    62  		SetGenerateOptions(gOpts).
    63  		SetNumIDs(10).
    64  		SetMaxNumPointsPerID(10).
    65  		SetMinNumPointsPerID(2)
    66  
    67  	generator := NewGenerator(opts)
    68  
    69  	ctrl := gomock.NewController(t)
    70  	defer ctrl.Finish()
    71  
    72  	shard := uint32(123)
    73  	require.NoError(t, generator.Generate(namespace.Context{ID: ident.StringID("testmetrics")}, shard))
    74  
    75  	te := newFileInfoExtractor()
    76  	require.NoError(t, filepath.Walk(dir, te.visit))
    77  	shards := te.sortedShards()
    78  	require.Equal(t, 1, len(shards))
    79  	require.Equal(t, uint32(123), shards[0])
    80  	times := te.sortedTimes()
    81  	require.Equal(t, 2, len(times))
    82  }
    83  
    84  type fileInfoExtractor struct {
    85  	shards map[uint32]struct{}
    86  	times  map[int64]struct{}
    87  }
    88  
    89  func newFileInfoExtractor() *fileInfoExtractor {
    90  	return &fileInfoExtractor{
    91  		shards: make(map[uint32]struct{}),
    92  		times:  make(map[int64]struct{}),
    93  	}
    94  }
    95  
    96  func (t *fileInfoExtractor) sortedShards() []uint32 {
    97  	shards := make([]uint32, 0, len(t.shards))
    98  	for i := range t.shards {
    99  		shards = append(shards, i)
   100  	}
   101  	sort.Sort(uint32arr(shards))
   102  	return shards
   103  }
   104  
   105  func (t *fileInfoExtractor) sortedTimes() []time.Time {
   106  	times := make([]int64, 0, len(t.times))
   107  	for i := range t.times {
   108  		times = append(times, i)
   109  	}
   110  	sort.Sort(int64arr(times))
   111  
   112  	timets := make([]time.Time, 0, len(t.times))
   113  	for _, ts := range times {
   114  		timets = append(timets, xtime.FromNanoseconds(ts))
   115  	}
   116  	return timets
   117  }
   118  
   119  func (t *fileInfoExtractor) visit(fPath string, f os.FileInfo, err error) error {
   120  	if f.IsDir() {
   121  		return nil
   122  	}
   123  	shardDir := path.Base(path.Dir(fPath))
   124  	shardNum, err := strconv.ParseUint(shardDir, 10, 32)
   125  	if err != nil {
   126  		return err
   127  	}
   128  	t.shards[uint32(shardNum)] = struct{}{}
   129  
   130  	name := f.Name()
   131  	nameSplit := strings.Split(name, "-")
   132  	if len(nameSplit) < 2 {
   133  		return fmt.Errorf("unable to parse time from %v", name)
   134  	}
   135  
   136  	num, parseErr := strconv.ParseInt(nameSplit[1], 10, 64)
   137  	if parseErr != nil {
   138  		return err
   139  	}
   140  	t.times[num] = struct{}{}
   141  	return nil
   142  }
   143  
   144  type uint32arr []uint32
   145  
   146  func (a uint32arr) Len() int           { return len(a) }
   147  func (a uint32arr) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   148  func (a uint32arr) Less(i, j int) bool { return a[i] < a[j] }
   149  
   150  type int64arr []int64
   151  
   152  func (a int64arr) Len() int           { return len(a) }
   153  func (a int64arr) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   154  func (a int64arr) Less(i, j int) bool { return a[i] < a[j] }