github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/integration/resources/inprocess/dbnode_test.go (about)

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