github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/cmd/noms/splore/noms_splore_test.go (about) 1 // Copyright 2017 Attic Labs, Inc. All rights reserved. 2 // Licensed under the Apache License, version 2.0: 3 // http://www.apache.org/licenses/LICENSE-2.0 4 5 package splore 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "net" 11 "net/http" 12 "os" 13 "strings" 14 "testing" 15 16 "github.com/attic-labs/noms/go/chunks" 17 "github.com/attic-labs/noms/go/d" 18 "github.com/attic-labs/noms/go/datas" 19 "github.com/attic-labs/noms/go/spec" 20 "github.com/attic-labs/noms/go/types" 21 "github.com/attic-labs/noms/go/util/verbose" 22 "github.com/stretchr/testify/assert" 23 ) 24 25 func TestNomsSplore(t *testing.T) { 26 assert := assert.New(t) 27 28 dir, err := ioutil.TempDir("", "TestNomsSplore") 29 d.PanicIfError(err) 30 defer os.RemoveAll(dir) 31 32 quiet := verbose.Quiet() 33 defer verbose.SetQuiet(quiet) 34 verbose.SetQuiet(true) 35 36 getNode := func(id string) string { 37 lchan := make(chan net.Listener) 38 httpServe = func(l net.Listener, h http.Handler) error { 39 lchan <- l 40 http.Serve(l, h) // this will error because of the l.Close() below 41 return nil 42 } 43 44 go func() { run(&http.ServeMux{}, 0, false, "nbs:"+dir) }() 45 l := <-lchan 46 defer l.Close() 47 48 r, err := http.Get(fmt.Sprintf("http://%s/getNode?id=%s", l.Addr().String(), id)) 49 assert.NoError(err) 50 defer r.Body.Close() 51 body, err := ioutil.ReadAll(r.Body) 52 return string(body) 53 } 54 55 // No data yet: 56 assert.JSONEq(`{ 57 "children": [], 58 "hasChildren": false, 59 "id": "", 60 "name": "Map(0)" 61 }`, getNode("")) 62 63 // Path not found: 64 assert.JSONEq(`{"error": "not found"}`, getNode(".notfound")) 65 66 // Test with real data: 67 sp, err := spec.ForDataset(fmt.Sprintf("nbs:%s::ds", dir)) 68 d.PanicIfError(err) 69 defer sp.Close() 70 db := sp.GetDatabase() 71 strct := types.NewStruct("StructName", types.StructData{ 72 "blob": types.NewBlob(db), 73 "bool": types.Bool(true), 74 "list": types.NewList(db, types.Number(1), types.Number(2)), 75 "map": types.NewMap(db, types.String("a"), types.String("b"), types.String("c"), types.String("d")), 76 "number": types.Number(42), 77 "ref": db.WriteValue(types.Bool(true)), 78 "set": types.NewSet(db, types.Number(3), types.Number(4)), 79 "string": types.String("hello world"), 80 "typeCompound": types.MakeMapType(types.StringType, types.MakeListType(types.BoolType)), 81 "typePrimitive": types.NumberType, 82 "typeStruct": types.MakeStructType("StructType", types.StructField{Name: "x", Type: types.StringType}, types.StructField{Name: "y", Type: types.MakeStructType("")}), 83 }) 84 sp.GetDatabase().CommitValue(sp.GetDataset(), strct) 85 86 // The dataset head hash changes whenever the test data changes, so instead 87 // of updating it all the time, use string replacement. 88 dsHash := sp.GetDataset().HeadRef().TargetHash().String() 89 test := func(expectJSON string, id string) { 90 expectJSON = strings.Replace(expectJSON, "{{dsHash}}", dsHash, -1) 91 assert.JSONEq(expectJSON, getNode(id)) 92 } 93 94 // Root => datasets: 95 test(`{ 96 "children": [ 97 { 98 "key": { 99 "hasChildren": false, 100 "id": "@at(0)@key", 101 "name": "\"ds\"" 102 }, 103 "label": "", 104 "value": { 105 "hasChildren": true, 106 "id": "@at(0)", 107 "name": "Value#{{dsHash}}" 108 } 109 } 110 ], 111 "hasChildren": true, 112 "id": "", 113 "name": "Map(1)" 114 }`, "") 115 116 // Dataset 0 (ds) => dataset head ref. 117 test(`{ 118 "children": [ 119 { 120 "key": { 121 "hasChildren": false, 122 "id": "", 123 "name": "" 124 }, 125 "label": "", 126 "value": { 127 "hasChildren": true, 128 "id": "@at(0)@target", 129 "name": "Value#{{dsHash}}" 130 } 131 } 132 ], 133 "hasChildren": true, 134 "id": "@at(0)", 135 "name": "Value#{{dsHash}}" 136 }`, "@at(0)") 137 138 // ds head ref => ds head: 139 // There is a %s replacement here for the ID root, because this expectation 140 // is used both for fetching via @at(0)@target and as an absolute ref. 141 expectDSHeadFmt := `{ 142 "children": [ 143 { 144 "key": { 145 "hasChildren": false, 146 "id": "", 147 "name": "" 148 }, 149 "label": "meta", 150 "value": { 151 "hasChildren": false, 152 "id": "%[1]s.meta", 153 "name": "{}" 154 } 155 }, 156 { 157 "key": { 158 "hasChildren": false, 159 "id": "", 160 "name": "" 161 }, 162 "label": "parents", 163 "value": { 164 "hasChildren": false, 165 "id": "%[1]s.parents", 166 "name": "Set(0)" 167 } 168 }, 169 { 170 "key": { 171 "hasChildren": false, 172 "id": "", 173 "name": "" 174 }, 175 "label": "value", 176 "value": { 177 "hasChildren": true, 178 "id": "%[1]s.value", 179 "name": "StructName" 180 } 181 } 182 ], 183 "hasChildren": true, 184 "id": "%[1]s", 185 "name": "Commit" 186 }` 187 188 test(fmt.Sprintf(expectDSHeadFmt, "@at(0)@target"), "@at(0)@target") 189 test(fmt.Sprintf(expectDSHeadFmt, "#"+dsHash), "%23"+dsHash) 190 191 // ds head value => strct. 192 test(`{ 193 "children": [ 194 { 195 "key": { 196 "hasChildren": false, 197 "id": "", 198 "name": "" 199 }, 200 "label": "blob", 201 "value": { 202 "hasChildren": false, 203 "id": "@at(0)@target.value.blob", 204 "name": "Blob(0 B)" 205 } 206 }, 207 { 208 "key": { 209 "hasChildren": false, 210 "id": "", 211 "name": "" 212 }, 213 "label": "bool", 214 "value": { 215 "hasChildren": false, 216 "id": "@at(0)@target.value.bool", 217 "name": "true" 218 } 219 }, 220 { 221 "key": { 222 "hasChildren": false, 223 "id": "", 224 "name": "" 225 }, 226 "label": "list", 227 "value": { 228 "hasChildren": true, 229 "id": "@at(0)@target.value.list", 230 "name": "List(2)" 231 } 232 }, 233 { 234 "key": { 235 "hasChildren": false, 236 "id": "", 237 "name": "" 238 }, 239 "label": "map", 240 "value": { 241 "hasChildren": true, 242 "id": "@at(0)@target.value.map", 243 "name": "Map(2)" 244 } 245 }, 246 { 247 "key": { 248 "hasChildren": false, 249 "id": "", 250 "name": "" 251 }, 252 "label": "number", 253 "value": { 254 "hasChildren": false, 255 "id": "@at(0)@target.value.number", 256 "name": "42" 257 } 258 }, 259 { 260 "key": { 261 "hasChildren": false, 262 "id": "", 263 "name": "" 264 }, 265 "label": "ref", 266 "value": { 267 "hasChildren": true, 268 "id": "@at(0)@target.value.ref", 269 "name": "Bool#g19moobgrm32dn083bokhksuobulq28c" 270 } 271 }, 272 { 273 "key": { 274 "hasChildren": false, 275 "id": "", 276 "name": "" 277 }, 278 "label": "set", 279 "value": { 280 "hasChildren": true, 281 "id": "@at(0)@target.value.set", 282 "name": "Set(2)" 283 } 284 }, 285 { 286 "key": { 287 "hasChildren": false, 288 "id": "", 289 "name": "" 290 }, 291 "label": "string", 292 "value": { 293 "hasChildren": false, 294 "id": "@at(0)@target.value.string", 295 "name": "\"hello world\"" 296 } 297 }, 298 { 299 "key": { 300 "hasChildren": false, 301 "id": "", 302 "name": "" 303 }, 304 "label": "typeCompound", 305 "value": { 306 "hasChildren": true, 307 "id": "@at(0)@target.value.typeCompound", 308 "name": "Map" 309 } 310 }, 311 { 312 "key": { 313 "hasChildren": false, 314 "id": "", 315 "name": "" 316 }, 317 "label": "typePrimitive", 318 "value": { 319 "hasChildren": false, 320 "id": "@at(0)@target.value.typePrimitive", 321 "name": "Number" 322 } 323 }, 324 { 325 "key": { 326 "hasChildren": false, 327 "id": "", 328 "name": "" 329 }, 330 "label": "typeStruct", 331 "value": { 332 "hasChildren": true, 333 "id": "@at(0)@target.value.typeStruct", 334 "name": "struct StructType" 335 } 336 } 337 ], 338 "hasChildren": true, 339 "id": "@at(0)@target.value", 340 "name": "StructName" 341 }`, "@at(0)@target.value") 342 343 // strct.blob: 344 test(`{ 345 "children": [], 346 "hasChildren": false, 347 "id": "@at(0)@target.value.blob", 348 "name": "Blob(0 B)" 349 }`, "@at(0)@target.value.blob") 350 351 // strct.bool: 352 test(`{ 353 "children": [], 354 "hasChildren": false, 355 "id": "@at(0)@target.value.bool", 356 "name": "true" 357 }`, "@at(0)@target.value.bool") 358 359 // strct.list: 360 test(`{ 361 "children": [ 362 { 363 "key": { 364 "hasChildren": false, 365 "id": "", 366 "name": "" 367 }, 368 "label": "", 369 "value": { 370 "hasChildren": false, 371 "id": "@at(0)@target.value.list[0]", 372 "name": "1" 373 } 374 }, 375 { 376 "key": { 377 "hasChildren": false, 378 "id": "", 379 "name": "" 380 }, 381 "label": "", 382 "value": { 383 "hasChildren": false, 384 "id": "@at(0)@target.value.list[1]", 385 "name": "2" 386 } 387 } 388 ], 389 "hasChildren": true, 390 "id": "@at(0)@target.value.list", 391 "name": "List(2)" 392 }`, "@at(0)@target.value.list") 393 394 // strct.map: 395 test(`{ 396 "children": [ 397 { 398 "key": { 399 "hasChildren": false, 400 "id": "@at(0)@target.value.map@at(0)@key", 401 "name": "\"a\"" 402 }, 403 "label": "", 404 "value": { 405 "hasChildren": false, 406 "id": "@at(0)@target.value.map@at(0)", 407 "name": "\"b\"" 408 } 409 }, 410 { 411 "key": { 412 "hasChildren": false, 413 "id": "@at(0)@target.value.map@at(1)@key", 414 "name": "\"c\"" 415 }, 416 "label": "", 417 "value": { 418 "hasChildren": false, 419 "id": "@at(0)@target.value.map@at(1)", 420 "name": "\"d\"" 421 } 422 } 423 ], 424 "hasChildren": true, 425 "id": "@at(0)@target.value.map", 426 "name": "Map(2)" 427 }`, "@at(0)@target.value.map") 428 429 // strct.number: 430 test(`{ 431 "children": [], 432 "hasChildren": false, 433 "id": "@at(0)@target.value.number", 434 "name": "42" 435 }`, "@at(0)@target.value.number") 436 437 // strct.ref: 438 test(`{ 439 "children": [ 440 { 441 "key": { 442 "hasChildren": false, 443 "id": "", 444 "name": "" 445 }, 446 "label": "", 447 "value": { 448 "hasChildren": true, 449 "id": "@at(0)@target.value.ref@target", 450 "name": "Bool#g19moobgrm32dn083bokhksuobulq28c" 451 } 452 } 453 ], 454 "hasChildren": true, 455 "id": "@at(0)@target.value.ref", 456 "name": "Bool#g19moobgrm32dn083bokhksuobulq28c" 457 }`, "@at(0)@target.value.ref") 458 459 // strct.set: 460 test(`{ 461 "children": [ 462 { 463 "key": { 464 "hasChildren": false, 465 "id": "", 466 "name": "" 467 }, 468 "label": "", 469 "value": { 470 "hasChildren": false, 471 "id": "@at(0)@target.value.set@at(0)", 472 "name": "3" 473 } 474 }, 475 { 476 "key": { 477 "hasChildren": false, 478 "id": "", 479 "name": "" 480 }, 481 "label": "", 482 "value": { 483 "hasChildren": false, 484 "id": "@at(0)@target.value.set@at(1)", 485 "name": "4" 486 } 487 } 488 ], 489 "hasChildren": true, 490 "id": "@at(0)@target.value.set", 491 "name": "Set(2)" 492 }`, "@at(0)@target.value.set") 493 494 // strct.string: 495 test(`{ 496 "children": [], 497 "hasChildren": false, 498 "id": "@at(0)@target.value.string", 499 "name": "\"hello world\"" 500 }`, "@at(0)@target.value.string") 501 502 // strct.typeCompound: 503 test(`{ 504 "children": [ 505 { 506 "key": { 507 "hasChildren": false, 508 "id": "", 509 "name": "" 510 }, 511 "label": "", 512 "value": { 513 "hasChildren": false, 514 "id": "@at(0)@target.value.typeCompound[0]", 515 "name": "String" 516 } 517 }, 518 { 519 "key": { 520 "hasChildren": false, 521 "id": "", 522 "name": "" 523 }, 524 "label": "", 525 "value": { 526 "hasChildren": true, 527 "id": "@at(0)@target.value.typeCompound[1]", 528 "name": "List" 529 } 530 } 531 ], 532 "hasChildren": true, 533 "id": "@at(0)@target.value.typeCompound", 534 "name": "Map" 535 }`, "@at(0)@target.value.typeCompound") 536 537 // strct.typePrimitive: 538 test(`{ 539 "children": [], 540 "hasChildren": false, 541 "id": "@at(0)@target.value.typePrimitive", 542 "name": "Number" 543 }`, "@at(0)@target.value.typePrimitive") 544 545 // strct.typeStruct: 546 test(`{ 547 "children": [ 548 { 549 "key": { 550 "hasChildren": false, 551 "id": "", 552 "name": "" 553 }, 554 "label": "x", 555 "value": { 556 "hasChildren": false, 557 "id": "@at(0)@target.value.typeStruct.x", 558 "name": "String" 559 } 560 }, 561 { 562 "key": { 563 "hasChildren": false, 564 "id": "", 565 "name": "" 566 }, 567 "label": "y", 568 "value": { 569 "hasChildren": false, 570 "id": "@at(0)@target.value.typeStruct.y", 571 "name": "struct {}" 572 } 573 } 574 ], 575 "hasChildren": true, 576 "id": "@at(0)@target.value.typeStruct", 577 "name": "struct StructType" 578 }`, "@at(0)@target.value.typeStruct") 579 } 580 581 func TestNomsSploreGetMetaChildren(t *testing.T) { 582 assert := assert.New(t) 583 584 storage := &chunks.TestStorage{} 585 db := datas.NewDatabase(storage.NewView()) 586 defer db.Close() 587 588 // A bunch of lists with just numbers or ref<number>s in them. None of these 589 // should be detected as meta sequences: 590 591 l1 := types.NewList(db) 592 assert.Nil(getMetaChildren(l1)) 593 594 l2 := types.NewList(db, types.Number(1)) 595 assert.Nil(getMetaChildren(l2)) 596 597 l3 := types.NewList(db, types.Number(1), types.Number(2)) 598 assert.Nil(getMetaChildren(l3)) 599 600 l4 := types.NewList(db, db.WriteValue(types.Number(1))) 601 assert.Nil(getMetaChildren(l4)) 602 603 l5 := types.NewList(db, db.WriteValue(types.Number(1)), types.Number(2)) 604 assert.Nil(getMetaChildren(l5)) 605 606 l6 := types.NewList(db, db.WriteValue(types.Number(1)), db.WriteValue(types.Number(2))) 607 assert.Nil(getMetaChildren(l6)) 608 609 l7 := types.NewList(db, l1) 610 assert.Nil(getMetaChildren(l7)) 611 612 l8 := types.NewList(db, l4) 613 assert.Nil(getMetaChildren(l8)) 614 615 // List with more or equal ref<list> than elements. This can't possibly be a meta 616 // sequence, because there are no empty leaf sequences: 617 618 l1Ref := db.WriteValue(l1) 619 l2Ref := db.WriteValue(l2) 620 l3Ref := db.WriteValue(l3) 621 listRefList := types.NewList(db, l1Ref, l2Ref, l3Ref) 622 623 l9 := types.NewList(db, listRefList) 624 assert.Nil(getMetaChildren(l9)) 625 626 l10 := types.NewList(db, types.Number(1), listRefList) 627 assert.Nil(getMetaChildren(l10)) 628 629 l11 := listRefList 630 assert.Nil(getMetaChildren(l11)) 631 632 l12 := types.NewList(db, types.Number(1), types.Number(2), listRefList) 633 assert.Nil(getMetaChildren(l12)) 634 635 l13 := types.NewList(db, types.Number(1), db.WriteValue(types.Number(2)), listRefList) 636 assert.Nil(getMetaChildren(l13)) 637 638 // List with fewer ref<list> as children. For now this is the closet 639 // approximation for detecting meta sequences: 640 641 l1Hash := "#" + l1Ref.TargetHash().String() 642 l2Hash := "#" + l2Ref.TargetHash().String() 643 l3Hash := "#" + l3Ref.TargetHash().String() 644 expectNodeChildren := []nodeChild{ 645 {Value: nodeInfo{HasChildren: true, ID: l1Hash, Name: "List" + l1Hash}}, 646 {Value: nodeInfo{HasChildren: true, ID: l2Hash, Name: "List" + l2Hash}}, 647 {Value: nodeInfo{HasChildren: true, ID: l3Hash, Name: "List" + l3Hash}}, 648 } 649 650 l14 := types.NewList(db, types.Number(1), types.Number(2), types.Number(3), listRefList) 651 assert.Equal(expectNodeChildren, getMetaChildren(l14)) 652 653 l15 := types.NewList(db, types.Number(1), types.Number(2), db.WriteValue(types.Number(3)), listRefList) 654 assert.Equal(expectNodeChildren, getMetaChildren(l15)) 655 656 l16 := types.NewList(db, types.Number(1), types.Number(2), types.Number(3), types.Number(4), listRefList) 657 assert.Equal(expectNodeChildren, getMetaChildren(l16)) 658 659 l17 := types.NewList(db, types.Number(1), types.Number(2), db.WriteValue(types.Number(3)), db.WriteValue(types.Number(4)), listRefList) 660 assert.Equal(expectNodeChildren, getMetaChildren(l17)) 661 }