github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/perf/suite/suite_test.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package suite
    23  
    24  import (
    25  	"context"
    26  	"io/ioutil"
    27  	"os"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  
    34  	"github.com/dolthub/dolt/go/store/spec"
    35  	"github.com/dolthub/dolt/go/store/types"
    36  )
    37  
    38  type testSuite struct {
    39  	PerfSuite
    40  	tempFileName, tempDir                  string
    41  	setupTest, tearDownTest                int
    42  	setupRep, tearDownRep                  int
    43  	setupSuite, tearDownSuite              int
    44  	foo, bar, abc, def, nothing, testimate int
    45  }
    46  
    47  func (s *testSuite) TestNonEmptyPaths() {
    48  	assert := s.NewAssert()
    49  	assert.NotEqual("", s.AtticLabs)
    50  	assert.NotEqual("", s.Testdata)
    51  	assert.NotEqual("", s.DatabaseSpec)
    52  }
    53  
    54  func (s *testSuite) TestDatabase() {
    55  	assert := s.NewAssert()
    56  	val := types.Bool(true)
    57  	r, err := s.Database.WriteValue(context.Background(), val)
    58  	require.NoError(s.T, err)
    59  	v2, err := s.Database.ReadValue(context.Background(), r.TargetHash())
    60  	require.NoError(s.T, err)
    61  	assert.True(v2.Equals(val))
    62  }
    63  
    64  func (s *testSuite) TestTempFile() {
    65  	s.tempFileName = s.TempFile().Name()
    66  	s.tempDir = s.TempDir()
    67  }
    68  
    69  func (s *testSuite) TestGlob() {
    70  	assert := s.NewAssert()
    71  	f := s.TempFile()
    72  	f.Close()
    73  
    74  	create := func(suffix string) error {
    75  		f, err := os.Create(f.Name() + suffix)
    76  		if err != nil {
    77  			return err
    78  		}
    79  		f.Close()
    80  		return nil
    81  	}
    82  
    83  	err := create("a")
    84  	require.NoError(s.T, err)
    85  	err = create(".a")
    86  	require.NoError(s.T, err)
    87  	err = create(".b")
    88  	require.NoError(s.T, err)
    89  
    90  	glob := s.OpenGlob(f.Name() + ".*")
    91  	assert.Equal(2, len(glob))
    92  	assert.Equal(f.Name()+".a", glob[0].(*os.File).Name())
    93  	assert.Equal(f.Name()+".b", glob[1].(*os.File).Name())
    94  
    95  	s.CloseGlob(glob)
    96  	b := make([]byte, 16)
    97  	_, err = glob[0].Read(b)
    98  	assert.Error(err)
    99  	_, err = glob[1].Read(b)
   100  	assert.Error(err)
   101  }
   102  
   103  func (s *testSuite) TestPause() {
   104  	s.Pause(func() {
   105  		s.waitForSmidge()
   106  	})
   107  }
   108  
   109  func (s *testSuite) TestFoo() {
   110  	s.foo++
   111  	s.waitForSmidge()
   112  }
   113  
   114  func (s *testSuite) TestBar() {
   115  	s.bar++
   116  	s.waitForSmidge()
   117  }
   118  
   119  func (s *testSuite) Test01Abc() {
   120  	s.abc++
   121  	s.waitForSmidge()
   122  }
   123  
   124  func (s *testSuite) Test02Def() {
   125  	s.def++
   126  	s.waitForSmidge()
   127  }
   128  
   129  func (s *testSuite) Testimate() {
   130  	s.testimate++
   131  	s.waitForSmidge()
   132  }
   133  
   134  func (s *testSuite) SetupTest() {
   135  	s.setupTest++
   136  }
   137  
   138  func (s *testSuite) TearDownTest() {
   139  	s.tearDownTest++
   140  }
   141  
   142  func (s *testSuite) SetupRep() {
   143  	s.setupRep++
   144  }
   145  
   146  func (s *testSuite) TearDownRep() {
   147  	s.tearDownRep++
   148  }
   149  
   150  func (s *testSuite) SetupSuite() {
   151  	s.setupSuite++
   152  }
   153  
   154  func (s *testSuite) TearDownSuite() {
   155  	s.tearDownSuite++
   156  }
   157  
   158  func (s *testSuite) waitForSmidge() {
   159  	// Tests should call this to make sure the measurement shows up as > 0, not that it shows up as a millisecond.
   160  	<-time.After(time.Millisecond)
   161  }
   162  
   163  func TestSuite(t *testing.T) {
   164  	runTestSuite(t, false)
   165  }
   166  
   167  func TestSuiteWithMem(t *testing.T) {
   168  	t.Skip("Flaky on Jenkins")
   169  	runTestSuite(t, true)
   170  }
   171  
   172  func runTestSuite(t *testing.T, mem bool) {
   173  	assert := assert.New(t)
   174  
   175  	// Write test results to our own temporary LDB database.
   176  	ldbDir, err := ioutil.TempDir("", "suite.TestSuite")
   177  	require.NoError(t, err)
   178  	defer os.RemoveAll(ldbDir)
   179  
   180  	flagVal, repeatFlagVal, memFlagVal := *perfFlag, *perfRepeatFlag, *perfMemFlag
   181  	*perfFlag, *perfRepeatFlag, *perfMemFlag = ldbDir, 3, mem
   182  	defer func() {
   183  		*perfFlag, *perfRepeatFlag, *perfMemFlag = flagVal, repeatFlagVal, memFlagVal
   184  	}()
   185  
   186  	s := &testSuite{}
   187  	Run("ds", t, s)
   188  
   189  	expectedTests := []string{
   190  		"Abc",
   191  		"Bar",
   192  		"Database",
   193  		"Def",
   194  		"Foo",
   195  		"Glob",
   196  		"NonEmptyPaths",
   197  		"Pause",
   198  		"TempFile",
   199  	}
   200  
   201  	// The temp file and dir should have been cleaned up.
   202  	_, err = os.Stat(s.tempFileName)
   203  	assert.NotNil(err)
   204  	_, err = os.Stat(s.tempDir)
   205  	assert.NotNil(err)
   206  
   207  	// The correct number of Setup/TearDown calls should have been run.
   208  	assert.Equal(1, s.setupSuite)
   209  	assert.Equal(1, s.tearDownSuite)
   210  	assert.Equal(*perfRepeatFlag, s.setupRep)
   211  	assert.Equal(*perfRepeatFlag, s.tearDownRep)
   212  	assert.Equal(*perfRepeatFlag*len(expectedTests), s.setupTest)
   213  	assert.Equal(*perfRepeatFlag*len(expectedTests), s.tearDownTest)
   214  
   215  	// The results should have been written to the "ds" dataset.
   216  	sp, err := spec.ForDataset(ldbDir + "::ds")
   217  	require.NoError(t, err)
   218  	defer sp.Close()
   219  	headVal, ok, err := sp.GetDataset(context.Background()).MaybeHeadValue()
   220  	require.NoError(t, err)
   221  	assert.True(ok)
   222  	head := headVal.(types.Struct)
   223  
   224  	// These tests mostly assert that the structure of the results is correct. Specific values are hard.
   225  
   226  	getOrFail := func(s types.Struct, f string) types.Value {
   227  		val, ok, err := s.MaybeGet(f)
   228  		require.NoError(t, err)
   229  		assert.True(ok)
   230  		return val
   231  	}
   232  
   233  	env, ok := getOrFail(head, "environment").(types.Struct)
   234  	assert.True(ok)
   235  
   236  	getOrFail(env, "diskUsages")
   237  	getOrFail(env, "cpus")
   238  	getOrFail(env, "mem")
   239  	getOrFail(env, "host")
   240  	getOrFail(env, "partitions")
   241  
   242  	// Todo: re-enable this code once demo-server gets build without CodePipeline
   243  	// This fails with CodePipeline because the source code is brought into
   244  	// Jenkins as a zip file rather than as a git repo.
   245  	//nomsRevision := getOrFail(head, "nomsRevision")
   246  	//assert.True(ok)
   247  	//assert.True(string(nomsRevision.(types.String)) != "")
   248  	//getOrFail(head, "testdataRevision")
   249  
   250  	reps, ok := getOrFail(head, "reps").(types.List)
   251  	assert.True(ok)
   252  	assert.Equal(*perfRepeatFlag, int(reps.Len()))
   253  
   254  	err = reps.IterAll(context.Background(), func(rep types.Value, _ uint64) error {
   255  		i := 0
   256  
   257  		err := rep.(types.Map).IterAll(context.Background(), func(k, timesVal types.Value) error {
   258  			if assert.True(i < len(expectedTests)) {
   259  				assert.Equal(expectedTests[i], string(k.(types.String)))
   260  			}
   261  
   262  			times := timesVal.(types.Struct)
   263  			assert.True(getOrFail(times, "elapsed").(types.Float) > 0)
   264  			assert.True(getOrFail(times, "total").(types.Float) > 0)
   265  
   266  			paused := getOrFail(times, "paused").(types.Float)
   267  			if k == types.String("Pause") {
   268  				assert.True(paused > 0)
   269  			} else {
   270  				assert.True(paused == 0)
   271  			}
   272  
   273  			i++
   274  
   275  			return nil
   276  		})
   277  
   278  		require.NoError(t, err)
   279  		assert.Equal(i, len(expectedTests))
   280  		return nil
   281  	})
   282  
   283  	require.NoError(t, err)
   284  }
   285  
   286  func TestPrefixFlag(t *testing.T) {
   287  	t.Skip("Flaky on Jenkins")
   288  	assert := assert.New(t)
   289  
   290  	// Write test results to a temporary database.
   291  	ldbDir, err := ioutil.TempDir("", "suite.TestSuite")
   292  	require.NoError(t, err)
   293  	defer os.RemoveAll(ldbDir)
   294  
   295  	flagVal, prefixFlagVal := *perfFlag, *perfPrefixFlag
   296  	*perfFlag, *perfPrefixFlag = ldbDir, "foo/"
   297  	defer func() {
   298  		*perfFlag, *perfPrefixFlag = flagVal, prefixFlagVal
   299  	}()
   300  
   301  	Run("my-prefix/test", t, &PerfSuite{})
   302  
   303  	// The results should have been written to "foo/my-prefix/test" not "my-prefix/test".
   304  	sp, err := spec.ForDataset(ldbDir + "::my-prefix/test")
   305  	require.NoError(t, err)
   306  	defer sp.Close()
   307  	_, ok := sp.GetDataset(context.Background()).MaybeHead()
   308  	assert.False(ok)
   309  
   310  	sp, err = spec.ForDataset(ldbDir + "::foo/my-prefix/test")
   311  	require.NoError(t, err)
   312  	defer sp.Close()
   313  	_, ok, err = sp.GetDataset(context.Background()).MaybeHeadValue()
   314  	require.NoError(t, err)
   315  	assert.True(ok)
   316  }
   317  
   318  func TestRunFlag(t *testing.T) {
   319  	t.Skip("Flaky on Jenkins")
   320  	assert := assert.New(t)
   321  
   322  	type expect struct {
   323  		foo, bar, abc, def, nothing, testimate int
   324  	}
   325  
   326  	run := func(re string, exp expect) {
   327  		flagVal, memFlagVal, runFlagVal := *perfFlag, *perfMemFlag, *perfRunFlag
   328  		*perfFlag, *perfMemFlag, *perfRunFlag = "mem", true, re
   329  		defer func() {
   330  			*perfFlag, *perfMemFlag, *perfRunFlag = flagVal, memFlagVal, runFlagVal
   331  		}()
   332  		s := testSuite{}
   333  		Run("test", t, &s)
   334  		assert.Equal(exp, expect{s.foo, s.bar, s.abc, s.def, s.nothing, s.testimate})
   335  	}
   336  
   337  	run("", expect{foo: 1, bar: 1, abc: 1, def: 1})
   338  	run(".", expect{foo: 1, bar: 1, abc: 1, def: 1})
   339  	run("test", expect{foo: 1, bar: 1, abc: 1, def: 1})
   340  	run("^test", expect{foo: 1, bar: 1, abc: 1, def: 1})
   341  	run("Test", expect{foo: 1, bar: 1, abc: 1, def: 1})
   342  	run("^Test", expect{foo: 1, bar: 1, abc: 1, def: 1})
   343  
   344  	run("f", expect{foo: 1, def: 1})
   345  	run("^f", expect{foo: 1})
   346  	run("testf", expect{foo: 1})
   347  	run("^testf", expect{foo: 1})
   348  	run("testF", expect{foo: 1})
   349  	run("^testF", expect{foo: 1})
   350  
   351  	run("F", expect{foo: 1, def: 1})
   352  	run("^F", expect{foo: 1})
   353  	run("Testf", expect{foo: 1})
   354  	run("^Testf", expect{foo: 1})
   355  	run("TestF", expect{foo: 1})
   356  	run("^TestF", expect{foo: 1})
   357  
   358  	run("ef", expect{def: 1})
   359  	run("def", expect{def: 1})
   360  	run("ddef", expect{})
   361  	run("testdef", expect{})
   362  	run("test01def", expect{})
   363  	run("test02def", expect{def: 1})
   364  	run("Test02def", expect{def: 1})
   365  	run("test02Def", expect{def: 1})
   366  	run("Test02Def", expect{def: 1})
   367  
   368  	run("z", expect{})
   369  	run("testz", expect{})
   370  	run("Testz", expect{})
   371  
   372  	run("[fa]", expect{foo: 1, bar: 1, abc: 1, def: 1})
   373  	run("[fb]", expect{foo: 1, bar: 1, abc: 1, def: 1})
   374  	run("[fc]", expect{foo: 1, abc: 1, def: 1})
   375  	run("test[fa]", expect{foo: 1})
   376  	run("test[fb]", expect{foo: 1, bar: 1})
   377  	run("test[fc]", expect{foo: 1})
   378  	run("Test[fa]", expect{foo: 1})
   379  	run("Test[fb]", expect{foo: 1, bar: 1})
   380  	run("Test[fc]", expect{foo: 1})
   381  
   382  	run("foo|bar", expect{foo: 1, bar: 1})
   383  	run("FOO|bar", expect{foo: 1, bar: 1})
   384  	run("Testfoo|bar", expect{foo: 1, bar: 1})
   385  	run("TestFOO|bar", expect{foo: 1, bar: 1})
   386  
   387  	run("Testfoo|Testbar", expect{foo: 1, bar: 1})
   388  	run("TestFOO|Testbar", expect{foo: 1, bar: 1})
   389  
   390  	run("footest", expect{})
   391  	run("nothing", expect{})
   392  }