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 }