github.com/m3db/m3@v1.5.0/src/integration/resources/inprocess/dbnode_test.go (about)

     1  // +build test_harness
     2  // Copyright (c) 2021  Uber Technologies, Inc.
     3  //
     4  // Permission is hereby granted, free of charge, to any person obtaining a copy
     5  // of this software and associated documentation files (the "Software"), to deal
     6  // in the Software without restriction, including without limitation the rights
     7  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8  // copies of the Software, and to permit persons to whom the Software is
     9  // furnished to do so, subject to the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be included in
    12  // all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    20  // THE SOFTWARE.
    21  
    22  package inprocess
    23  
    24  import (
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  
    31  	"github.com/m3db/m3/src/dbnode/generated/thrift/rpc"
    32  	"github.com/m3db/m3/src/integration/resources"
    33  	"github.com/m3db/m3/src/m3ninx/idx"
    34  	"github.com/m3db/m3/src/query/generated/proto/admin"
    35  	"github.com/m3db/m3/src/x/checked"
    36  	"github.com/m3db/m3/src/x/ident"
    37  	"github.com/m3db/m3/src/x/pool"
    38  	"github.com/m3db/m3/src/x/serialize"
    39  )
    40  
    41  func TestNewDBNodeNoSetup(t *testing.T) {
    42  	dbnode, err := NewDBNodeFromYAML(defaultDBNodeConfig, DBNodeOptions{Start: true})
    43  	require.NoError(t, err)
    44  
    45  	require.NoError(t, dbnode.Close())
    46  
    47  	// Restart and shutdown again to test restarting
    48  	dbnode, err = NewDBNodeFromYAML(defaultDBNodeConfig, DBNodeOptions{Start: true})
    49  	require.NoError(t, err)
    50  
    51  	require.NoError(t, dbnode.Close())
    52  }
    53  
    54  func TestDBNode(t *testing.T) {
    55  	dbnode, _, closer := setupNodeAndCoordinator(t)
    56  	defer closer()
    57  
    58  	testHealth(t, dbnode)
    59  	testWaitForBootstrap(t, dbnode)
    60  	testWriteFetchRoundtrip(t, dbnode)
    61  	testWriteTaggedFetchTaggedRoundtrip(t, dbnode)
    62  }
    63  
    64  func testHealth(t *testing.T, dbnode resources.Node) {
    65  	res, err := dbnode.Health()
    66  	require.NoError(t, err)
    67  
    68  	require.True(t, res.Ok)
    69  }
    70  
    71  func testWaitForBootstrap(t *testing.T, dbnode resources.Node) {
    72  	res, err := dbnode.Health()
    73  	require.NoError(t, err)
    74  
    75  	require.Equal(t, true, res.Bootstrapped)
    76  }
    77  
    78  func testWriteFetchRoundtrip(t *testing.T, dbnode resources.Node) {
    79  	var (
    80  		id  = "foo"
    81  		ts  = time.Now()
    82  		val = 1.0
    83  	)
    84  	req := &rpc.WriteRequest{
    85  		NameSpace: resources.UnaggName,
    86  		ID:        id,
    87  		Datapoint: &rpc.Datapoint{
    88  			Timestamp: ts.Unix(),
    89  			Value:     val,
    90  		},
    91  	}
    92  	require.NoError(t, dbnode.WritePoint(req))
    93  
    94  	freq := &rpc.FetchRequest{
    95  		RangeStart: ts.Add(-1 * time.Minute).Unix(),
    96  		RangeEnd:   ts.Add(1 * time.Minute).Unix(),
    97  		NameSpace:  resources.UnaggName,
    98  		ID:         id,
    99  	}
   100  	res, err := dbnode.Fetch(freq)
   101  	require.NoError(t, err)
   102  
   103  	require.Equal(t, 1, len(res.Datapoints))
   104  	require.Equal(t, rpc.Datapoint{
   105  		Timestamp: ts.Unix(),
   106  		Value:     val,
   107  	}, *res.Datapoints[0])
   108  }
   109  
   110  func testWriteTaggedFetchTaggedRoundtrip(t *testing.T, dbnode resources.Node) {
   111  	var (
   112  		id  = "fooTagged"
   113  		ts  = time.Now()
   114  		val = 1.0
   115  	)
   116  	req := &rpc.WriteTaggedRequest{
   117  		NameSpace: resources.UnaggName,
   118  		ID:        id,
   119  		Datapoint: &rpc.Datapoint{
   120  			Timestamp:         ts.UnixNano(),
   121  			TimestampTimeType: rpc.TimeType_UNIX_NANOSECONDS,
   122  			Value:             val,
   123  		},
   124  		Tags: []*rpc.Tag{
   125  			{Name: "__name__", Value: id},
   126  			{Name: "job", Value: "bar"},
   127  		},
   128  	}
   129  	require.NoError(t, dbnode.WriteTaggedPoint(req))
   130  
   131  	query := idx.NewTermQuery([]byte("job"), []byte("bar"))
   132  	encoded, err := idx.Marshal(query)
   133  	require.NoError(t, err)
   134  
   135  	freq := &rpc.FetchTaggedRequest{
   136  		RangeStart:    ts.Add(-1 * time.Minute).UnixNano(),
   137  		RangeEnd:      ts.Add(1 * time.Minute).UnixNano(),
   138  		NameSpace:     []byte(resources.UnaggName),
   139  		RangeTimeType: rpc.TimeType_UNIX_NANOSECONDS,
   140  		FetchData:     true,
   141  		Query:         encoded,
   142  	}
   143  	res, err := dbnode.FetchTagged(freq)
   144  	require.NoError(t, err)
   145  
   146  	require.Equal(t, 1, len(res.Elements))
   147  	require.Equal(t, id, string(res.Elements[0].ID))
   148  	require.Equal(t, resources.UnaggName, string(res.Elements[0].NameSpace))
   149  
   150  	// Validate Tags
   151  	testTagDecoderPool := serialize.NewTagDecoderPool(
   152  		serialize.NewTagDecoderOptions(serialize.TagDecoderOptionsConfig{}),
   153  		pool.NewObjectPoolOptions())
   154  	testTagDecoderPool.Init()
   155  
   156  	dec := testTagDecoderPool.Get()
   157  	dec.Reset(checked.NewBytes(res.Elements[0].EncodedTags, nil))
   158  
   159  	require.True(t, dec.Next())
   160  	validateTag(t, dec.Current(), "__name__", id)
   161  	require.True(t, dec.Next())
   162  	validateTag(t, dec.Current(), "job", "bar")
   163  	require.False(t, dec.Next())
   164  }
   165  
   166  func validateTag(t *testing.T, tag ident.Tag, name string, value string) {
   167  	require.Equal(t, name, tag.Name.String())
   168  	require.Equal(t, value, tag.Value.String())
   169  }
   170  
   171  func setupNodeAndCoordinator(t *testing.T) (resources.Node, resources.Coordinator, func()) {
   172  	dbnode, err := NewDBNodeFromYAML(defaultDBNodeConfig, DBNodeOptions{
   173  		GenerateHostID: true,
   174  		Start:          true,
   175  	})
   176  	require.NoError(t, err)
   177  
   178  	coord, err := NewCoordinatorFromYAML(defaultCoordConfig, CoordinatorOptions{Start: true})
   179  	require.NoError(t, err)
   180  
   181  	require.NoError(t, coord.WaitForNamespace(""))
   182  
   183  	host, err := dbnode.HostDetails(9000)
   184  	require.NoError(t, err)
   185  
   186  	_, err = coord.CreateDatabase(admin.DatabaseCreateRequest{
   187  		Type:              "cluster",
   188  		NamespaceName:     resources.UnaggName,
   189  		RetentionTime:     "1h",
   190  		NumShards:         4,
   191  		ReplicationFactor: 1,
   192  		Hosts:             []*admin.Host{host},
   193  	})
   194  	require.NoError(t, err)
   195  
   196  	require.NoError(t, coord.WaitForShardsReady())
   197  	require.NoError(t, coord.WaitForClusterReady())
   198  
   199  	return dbnode, coord, func() {
   200  		assert.NoError(t, coord.Close())
   201  		assert.NoError(t, dbnode.Close())
   202  	}
   203  }
   204  
   205  const defaultDBNodeConfig = `
   206  db:
   207    writeNewSeriesAsync: false
   208  `