github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/cmd/get_test.go (about) 1 package cmd 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/google/go-cmp/cmp" 9 "github.com/qri-io/dataset/dstest" 10 ) 11 12 func TestGetComplete(t *testing.T) { 13 run := NewTestRunner(t, "test_peer_get", "qri_test_get_complete") 14 defer run.Delete() 15 16 ctx, cancel := context.WithCancel(context.Background()) 17 defer cancel() 18 19 f, err := NewTestFactory(ctx) 20 if err != nil { 21 t.Errorf("error creating new test factory: %s", err) 22 return 23 } 24 25 cases := []struct { 26 args []string 27 selector string 28 refs []string 29 err string 30 }{ 31 {[]string{}, "", []string{}, ""}, 32 {[]string{"one arg"}, "", []string{"one arg"}, ""}, 33 {[]string{"commit", "peer/ds"}, "commit", []string{"peer/ds"}, ""}, 34 {[]string{"commit.author", "peer/ds"}, "commit.author", []string{"peer/ds"}, ""}, 35 // TODO(dlong): Fix tests when `qri get` can be passed multiple arguments. 36 //{[]string{"peer/ds_two", "peer/ds"}, "", []string{"peer/ds_two", "peer/ds"}, ""}, 37 //{[]string{"foo", "peer/ds"}, "", []string{"foo", "peer/ds"}, ""}, 38 {[]string{"structure"}, "structure", []string{}, ""}, 39 {[]string{"stats", "me/cities"}, "stats", []string{"me/cities"}, ""}, 40 {[]string{"stats", "me/sitemap"}, "stats", []string{"me/sitemap"}, ""}, 41 } 42 43 for i, c := range cases { 44 opt := &GetOptions{ 45 IOStreams: run.Streams, 46 } 47 48 opt.Complete(f, c.args) 49 50 if c.err != run.ErrStream.String() { 51 t.Errorf("case %d, error mismatch. Expected: '%s', Got: '%s'", i, c.err, run.ErrStream.String()) 52 run.IOReset() 53 continue 54 } 55 56 if !testSliceEqual(c.refs, opt.Refs.RefList()) { 57 t.Errorf("case %d, opt.Refs not set correctly. Expected: '%q', Got: '%q'", i, c.refs, opt.Refs.RefList()) 58 run.IOReset() 59 continue 60 } 61 62 if c.selector != opt.Selector { 63 t.Errorf("case %d, opt.Selector not set correctly. Expected: '%s', Got: '%s'", i, c.selector, opt.Selector) 64 run.IOReset() 65 continue 66 } 67 68 if opt.inst == nil { 69 t.Errorf("case %d, opt.inst not set.", i) 70 run.IOReset() 71 continue 72 } 73 run.IOReset() 74 } 75 } 76 77 const ( 78 currHeadRepo = `body:{{ .body }} 79 bodyPath: {{ .bodyPath }} 80 commit: 81 author: 82 id: {{ .profileID }} 83 message: "body:\n\tchanged by 54%" 84 path: {{ .commitPath }} 85 qri: cm:0 86 signature: {{ .signature }} 87 timestamp: "2001-01-01T01:02:01.000000001Z" 88 title: body changed by 54% 89 id: {{ .id }} 90 name: my_ds 91 path: {{ .path }} 92 peername: test_peer_get 93 previousPath: {{ .previousPath }} 94 qri: ds:0 95 stats: 96 path: {{ .statsPath }} 97 qri: sa:0 98 stats: 99 - count: 18 100 frequencies: 101 'Avatar ': 1 102 'Avengers: Age of Ultron ': 1 103 'Batman v Superman: Dawn of Justice ': 1 104 'Harry Potter and the Half-Blood Prince ': 1 105 'John Carter ': 1 106 'Man of Steel ': 1 107 'Pirates of the Caribbean: At World''s End... 41 chars (6)': 1 108 'Pirates of the Caribbean: Dead Man''s Che... 43 chars (7)': 1 109 'Quantum of Solace ': 1 110 'Spectre ': 1 111 'Spider-Man 3 ': 1 112 'Star Wars: Episode VII - The Force Awake... 55 chars (11)': 1 113 'Superman Returns ': 1 114 'Tangled ': 1 115 'The Avengers ': 1 116 'The Chronicles of Narnia: Prince Caspian... 41 chars (15)': 1 117 'The Dark Knight Rises ': 1 118 'The Lone Ranger ': 1 119 maxLength: 55 120 minLength: 7 121 type: string 122 unique: 18 123 - count: 17 124 histogram: 125 bins: 126 - 100 127 - 106 128 - 132 129 - 141 130 - 143 131 - 148 132 - 150 133 - 151 134 - 153 135 - 156 136 - 164 137 - 169 138 - 173 139 - 178 140 - 183 141 - 184 142 frequencies: 143 - 1 144 - 1 145 - 1 146 - 1 147 - 1 148 - 1 149 - 2 150 - 1 151 - 1 152 - 1 153 - 1 154 - 2 155 - 1 156 - 1 157 - 1 158 max: 183 159 mean: 150.94117647058823 160 median: 151 161 min: 100 162 type: numeric 163 structure: 164 checksum: {{ .bodyPath }} 165 depth: 2 166 entries: 18 167 errCount: 1 168 format: csv 169 formatConfig: 170 headerRow: true 171 lazyQuotes: true 172 length: 532 173 path: {{ .structurePath }} 174 qri: st:0 175 schema: 176 items: 177 items: 178 - title: movie_title 179 type: string 180 - title: duration 181 type: integer 182 type: array 183 type: array 184 185 ` 186 187 prevHeadRepo = `body:{{ .body }} 188 bodyPath: {{ .bodyPath }} 189 commit: 190 author: 191 id: {{ .profileID }} 192 message: created dataset from body_ten.csv 193 path: {{ .commitPath }} 194 qri: cm:0 195 signature: {{ .signature }} 196 timestamp: "2001-01-01T01:01:01.000000001Z" 197 title: created dataset from body_ten.csv 198 id: {{ .id }} 199 name: my_ds 200 path: {{ .path }} 201 peername: test_peer_get 202 qri: ds:0 203 stats: 204 path: {{ .statsPath }} 205 qri: sa:0 206 stats: 207 - count: 8 208 frequencies: 209 'Avatar ': 1 210 'John Carter ': 1 211 'Pirates of the Caribbean: At World''s End... 41 chars (2)': 1 212 'Spectre ': 1 213 'Spider-Man 3 ': 1 214 'Star Wars: Episode VII - The Force Awake... 55 chars (5)': 1 215 'Tangled ': 1 216 'The Dark Knight Rises ': 1 217 maxLength: 55 218 minLength: 7 219 type: string 220 unique: 8 221 - count: 7 222 histogram: 223 bins: 224 - 100 225 - 132 226 - 148 227 - 156 228 - 164 229 - 169 230 - 178 231 - 179 232 frequencies: 233 - 1 234 - 1 235 - 1 236 - 1 237 - 1 238 - 1 239 - 1 240 max: 178 241 mean: 149.57142857142858 242 median: 156 243 min: 100 244 type: numeric 245 structure: 246 checksum: {{ .bodyPath }} 247 depth: 2 248 entries: 8 249 errCount: 1 250 format: csv 251 formatConfig: 252 headerRow: true 253 lazyQuotes: true 254 length: 224 255 path: {{ .structurePath }} 256 qri: st:0 257 schema: 258 items: 259 items: 260 - title: movie_title 261 type: string 262 - title: duration 263 type: integer 264 type: array 265 type: array 266 267 ` 268 currBodyRepo = `movie_title,duration 269 Avatar ,178 270 Pirates of the Caribbean: At World's End ,169 271 Spectre ,148 272 The Dark Knight Rises ,164 273 Star Wars: Episode VII - The Force Awakens , 274 John Carter ,132 275 Spider-Man 3 ,156 276 Tangled ,100 277 Avengers: Age of Ultron ,141 278 Harry Potter and the Half-Blood Prince ,153 279 Batman v Superman: Dawn of Justice ,183 280 Superman Returns ,169 281 Quantum of Solace ,106 282 Pirates of the Caribbean: Dead Man's Chest ,151 283 The Lone Ranger ,150 284 Man of Steel ,143 285 The Chronicles of Narnia: Prince Caspian ,150 286 The Avengers ,173 287 288 ` 289 currBodyJSON = `[["Avatar ",178],["Pirates of the Caribbean: At World's End ",169],["Spectre ",148],["The Dark Knight Rises ",164],["Star Wars: Episode VII - The Force Awakens ",""],["John Carter ",132],["Spider-Man 3 ",156],["Tangled ",100],["Avengers: Age of Ultron ",141],["Harry Potter and the Half-Blood Prince ",153],["Batman v Superman: Dawn of Justice ",183],["Superman Returns ",169],["Quantum of Solace ",106],["Pirates of the Caribbean: Dead Man's Chest ",151],["The Lone Ranger ",150],["Man of Steel ",143],["The Chronicles of Narnia: Prince Caspian ",150],["The Avengers ",173]] 290 ` 291 292 currBodyYAML = ` 293 - - 'Avatar ' 294 - 178 295 - - 'Pirates of the Caribbean: At World''s End ' 296 - 169 297 - - 'Spectre ' 298 - 148 299 - - 'The Dark Knight Rises ' 300 - 164 301 - - 'Star Wars: Episode VII - The Force Awakens ' 302 - "" 303 - - 'John Carter ' 304 - 132 305 - - 'Spider-Man 3 ' 306 - 156 307 - - 'Tangled ' 308 - 100 309 - - 'Avengers: Age of Ultron ' 310 - 141 311 - - 'Harry Potter and the Half-Blood Prince ' 312 - 153 313 - - 'Batman v Superman: Dawn of Justice ' 314 - 183 315 - - 'Superman Returns ' 316 - 169 317 - - 'Quantum of Solace ' 318 - 106 319 - - 'Pirates of the Caribbean: Dead Man''s Chest ' 320 - 151 321 - - 'The Lone Ranger ' 322 - 150 323 - - 'Man of Steel ' 324 - 143 325 - - 'The Chronicles of Narnia: Prince Caspian ' 326 - 150 327 - - 'The Avengers ' 328 - 173` 329 330 prevBodyRepo = `movie_title,duration 331 Avatar ,178 332 Pirates of the Caribbean: At World's End ,169 333 Spectre ,148 334 The Dark Knight Rises ,164 335 Star Wars: Episode VII - The Force Awakens , 336 John Carter ,132 337 Spider-Man 3 ,156 338 Tangled ,100 339 340 ` 341 prevBodyJSON = `[["Avatar ",178],["Pirates of the Caribbean: At World's End ",169],["Spectre ",148],["The Dark Knight Rises ",164],["Star Wars: Episode VII - The Force Awakens ",""],["John Carter ",132],["Spider-Man 3 ",156],["Tangled ",100]] 342 ` 343 344 prevBodyYAML = ` 345 - - 'Avatar ' 346 - 178 347 - - 'Pirates of the Caribbean: At World''s End ' 348 - 169 349 - - 'Spectre ' 350 - 148 351 - - 'The Dark Knight Rises ' 352 - 164 353 - - 'Star Wars: Episode VII - The Force Awakens ' 354 - "" 355 - - 'John Carter ' 356 - 132 357 - - 'Spider-Man 3 ' 358 - 156 359 - - 'Tangled ' 360 - 100` 361 ) 362 363 var ( 364 currHeadRepoData = map[string]string{ 365 "id": "nkt3s27sojzsiu7tcs6p5asrwbqf3yd5nhjtotsstd6ub2owecvq", 366 "profileID": "QmeL2mdVka1eahKENjehK6tBxkkpk5dNQ1qMcgWi7Hrb4B", 367 "body": currBodyYAML, 368 "bodyPath": "/ipfs/QmeLmPMNSCxVxCdDmdunBCfiN1crb3C2eUnZex6QgHpFiB", 369 "commitPath": "/ipfs/QmQb3AfjzFn5RWGkrcFHV4GEDWAt97P9q3JhM8qJm69wZ3", 370 "signature": "hK9sMkmsRqH8xKDNxTwQX0IfDsHX8wB08SQA/tz0R8V0QaWfPgjPBhvFvWXKXtM+UqxKDp1YzGLyAcozk7BIgRLPEcQI+TMvjpqf9UKlu7f0pmtnT6w7Vj8hHcVk/yvG+MfpKLWIK+FLWqIj46aeYztjtweN2AC1Xebky7ISzkczaOg0rL6hcbWoxE96Eqw5mvcX3iO9l/zfbF6GkRAhzKVHkNdmwvqPaMRE/XTdR9+F5bIodwpqJGmqM7igewimGQAe/UTyFhOYi7Z7LJxCGKeKJ/7n8mk7CfRQPmhqk8hzcVm5yTNjTUOUueK9Os1g8b3z6FgnWpIaMOV0L/ARqg==", 371 "path": "/ipfs/Qmc75sMYi6fjvcKiRqsFFopjLYDTnuQ8BdesEUYoX5raG5", 372 "previousPath": "/ipfs/QmVmAAVSVewv6HzojRBr2bqJgWwZ8w18vVPqQ6VuTuH7UZ", 373 "statsPath": "/ipfs/Qmc3QsRMdo1rqY3F5Shr2Kd25yib6R4Ktgz3RdXTXwVjDU", 374 "structurePath": "/ipfs/QmcAfMfZ7qTNiCfQxnRJyDxEDM7tqDstvpgviT73PFbabZ", 375 } 376 prevHeadRepoData = map[string]string{ 377 "id": "nkt3s27sojzsiu7tcs6p5asrwbqf3yd5nhjtotsstd6ub2owecvq", 378 "profileID": "QmeL2mdVka1eahKENjehK6tBxkkpk5dNQ1qMcgWi7Hrb4B", 379 "body": prevBodyYAML, 380 "bodyPath": "/ipfs/QmXhsUK6vGZrqarhw9Z8RCXqhmEpvtVByKtaYVarbDZ5zn", 381 "commitPath": "/ipfs/QmRQo5ivNLbQdu1ps3iyEaVknyTYisUwsL152dwSorskJB", 382 "signature": "iGs2R/GWE8f0YqRhTnaw6r/geX+5hSmTxOG68vdYbJ5dkqLXcp7nYkuezvs9aHPTLPgqoshJ6w0va8JthSSGkRkm6ue5iItLqN0Vbi2Ru/b7BAfvpJwoeb/FJCj41bFtqojs9S9flNJB7RmQl03usiaauUw/dkNE7KXZkT0DGA3Fo8cHKeAgyhYdZzPeXKu1RIp+rIMZMJOwj0Rw7oLBXjiWcqttwJQsvx8qAS72xhQZysGGicImdTPzeTK+7wwBnm99f2afjB1v3TD7h5XMmFRiOBtNx3U6snzTcUPvGeL895Q7ZBco9fEAPhgxgrV51b28IS0ci6qXyYfIOKNARg==", 383 "path": "/ipfs/QmVmAAVSVewv6HzojRBr2bqJgWwZ8w18vVPqQ6VuTuH7UZ", 384 "previousPath": "/ipfs/QmRQYDZMgrxE8SLQXKRxJRZRDshQwJBDdb2d27ZNFiVghM", 385 "statsPath": "/ipfs/QmbJeH82n56LBGBsRWxmSctrUy1Urr1epePSpQ8bMgufsG", 386 "structurePath": "/ipfs/QmSxuAVwd9pPf9c7WMu1gjUsHSLBLRuxQcFjyu9mfsA2TQ", 387 } 388 ) 389 390 func TestGetDatasetFromRepo(t *testing.T) { 391 run := NewTestRunner(t, "test_peer_get", "get_dataset_head") 392 defer run.Delete() 393 394 // Save two versions. 395 got := run.MustExecCombinedOutErr(t, "qri save --body=testdata/movies/body_ten.csv me/my_ds") 396 ref := parseRefFromSave(got) 397 run.MustExec(t, "qri save --body=testdata/movies/body_twenty.csv me/my_ds") 398 399 // Get head. 400 output := run.MustExec(t, "qri get me/my_ds") 401 expect := dstest.Template(t, currHeadRepo, currHeadRepoData) 402 if diff := cmp.Diff(expect, output); diff != "" { 403 t.Errorf("unexpected (-want +got):\n%s", diff) 404 } 405 406 // Get one version ago. 407 output = run.MustExec(t, fmt.Sprintf("qri get %s", ref)) 408 expect = dstest.Template(t, prevHeadRepo, prevHeadRepoData) 409 if diff := cmp.Diff(expect, output); diff != "" { 410 t.Errorf("unexpected (-want +got):\n%s", diff) 411 } 412 413 // Get body from current commit in csv format 414 output = run.MustExec(t, "qri get body me/my_ds --format csv") 415 expect = currBodyRepo 416 if diff := cmp.Diff(expect, output); diff != "" { 417 t.Errorf("unexpected (-want +got):\n%s", diff) 418 } 419 420 // Get body from current commit in json format 421 output = run.MustExec(t, "qri get body me/my_ds") 422 expect = currBodyJSON 423 if diff := cmp.Diff(expect, output); diff != "" { 424 t.Errorf("unexpected (-want +got):\n%s", diff) 425 } 426 427 // Get body from one version ago in csv format 428 output = run.MustExec(t, fmt.Sprintf("qri get body %s --format csv", ref)) 429 expect = prevBodyRepo 430 if diff := cmp.Diff(expect, output); diff != "" { 431 t.Errorf("unexpected (-want +got):\n%s", diff) 432 } 433 434 // Get body from one version ago in json format 435 output = run.MustExec(t, fmt.Sprintf("qri get body %s", ref)) 436 expect = prevBodyJSON 437 if diff := cmp.Diff(expect, output); diff != "" { 438 t.Errorf("unexpected (-want +got):\n%s", diff) 439 } 440 441 } 442 443 func TestGetDatasetUsingDscache(t *testing.T) { 444 t.Skip("TODO(dustmop): Need a way to enable Dscache without the Param field") 445 446 run := NewTestRunner(t, "test_peer_get", "get_dataset_head") 447 defer run.Delete() 448 449 // Save two versions, using dscache. 450 got := run.MustExecCombinedOutErr(t, "qri save --use-dscache --body=testdata/movies/body_ten.csv me/my_ds") 451 ref := parseRefFromSave(got) 452 run.MustExec(t, "qri save --use-dscache --body=testdata/movies/body_twenty.csv me/my_ds") 453 454 // Get head. 455 output := run.MustExec(t, "qri get me/my_ds") 456 expect := dstest.Template(t, currHeadRepo, currHeadRepoData) 457 if diff := cmp.Diff(expect, output); diff != "" { 458 t.Errorf("unexpected (-want +got):\n%s", diff) 459 } 460 461 // Get one version ago. 462 output = run.MustExec(t, fmt.Sprintf("qri get %s", ref)) 463 expect = dstest.Template(t, prevHeadRepo, prevHeadRepoData) 464 if diff := cmp.Diff(expect, output); diff != "" { 465 t.Errorf("unexpected (-want +got):\n%s", diff) 466 } 467 468 // Get body from current commit. 469 output = run.MustExec(t, "qri get body me/my_ds") 470 expect = currBodyRepo 471 if diff := cmp.Diff(expect, output); diff != "" { 472 t.Errorf("unexpected (-want +got):\n%s", diff) 473 } 474 475 // Get body from one version ago. 476 output = run.MustExec(t, fmt.Sprintf("qri get body %s", ref)) 477 expect = prevBodyRepo 478 if diff := cmp.Diff(expect, output); diff != "" { 479 t.Errorf("unexpected (-want +got):\n%s", diff) 480 } 481 } 482 483 func TestGetRemoteDataset(t *testing.T) { 484 run := NewTestRunnerWithMockRemoteClient(t, "test_get_remote_dataset", "get_remote_dataset") 485 defer run.Delete() 486 487 expect := "cannot use '--offline' and '--remote' flags together" 488 err := run.ExecCommand("qri get --remote=registry --offline other_peer/their_dataset") 489 if err == nil { 490 t.Fatal("expected to get an error, did not get one") 491 } 492 if expect != err.Error() { 493 t.Errorf("response mismatch\nwant: %q\n got: %q", expect, err) 494 } 495 496 expect = "reference not found" 497 err = run.ExecCommand("qri get --offline other_peer/their_dataset") 498 if err == nil { 499 t.Fatal("expected to get an error, did not get one") 500 } 501 if expect != err.Error() { 502 t.Errorf("response mismatch\nwant: %q\n got: %q", expect, err) 503 } 504 505 // mock remote datasets have empty bodies 506 expect = dstest.Template(t, `body: {} 507 bodyPath: {{ .bodyPath }} 508 commit: 509 message: created dataset 510 path: {{ .commitPath }} 511 qri: cm:0 512 signature: {{ .signature }} 513 timestamp: "2001-01-01T01:01:01.000000001Z" 514 title: created dataset 515 id: {{ .id }} 516 name: their_dataset 517 path: {{ .path }} 518 peername: other_peer 519 qri: ds:0 520 stats: {{ .statsPath }} 521 structure: 522 checksum: {{ .bodyPath }} 523 depth: 1 524 format: json 525 length: 2 526 path: {{ .structurePath }} 527 qri: st:0 528 schema: 529 type: object 530 531 `, map[string]string{ 532 "id": "zgseugtra4h7ekpzfuczupudzyrfrhafx3ucb35kbafb37p2575q", 533 "bodyPath": "/ipfs/QmbJWAESqCsf4RFCqEY7jecCashj8usXiyDNfKtZCwwzGb", 534 "commitPath": "/ipfs/QmTTPd47BD4EGpCpuvRwTRqDRF84iAuJmfUUGcfEBuF7he", 535 "signature": "gySMr/FiT+kz0X2ODXCE5APx/BvPvalw4xlbS8TtSWssEoHlAOdrUNKUfU7j6rjyq7sFJ7hrbIVOn87fx+7arYCvrvikRawd2anzIvIruxfBymS6A0HtAGAOEAvpn3XbDykEjqaomTXS1CyR6wQkwNEgbELCIqwda9UV3ulhUtHMrAyMxvnq3NG6J9wyFB13u133aDVEojJ82mEF5DBFB+VBVbw90S4b/5AxLEUFSt/BCtE1O0lKYCt2x0HK+1fhl85oe3fpqLhLk96qCAR/Ngv4bt0E9NjGi2ltuji8gaDICKe5KRaSXjXlMkwbUq6sXEKgqzfxHXoIAUZnZNwnmg==", 536 "path": "/ipfs/QmUv37uYowTAYx2VTsdBcpgHoqRQppQyrnf5yEZcAwcp9P", 537 "statsPath": "/ipfs/QmQQkQF2KNBZfFiX33jJ9hu6ivfoHrtgcwMRAezS4dcA7c", 538 "structurePath": "/ipfs/QmWoYVZWDdiNauzeP171hKSdo3p2bFaqDcW6cppb9QugUE", 539 }) 540 got := run.MustExec(t, "qri get --remote=registry other_peer/their_dataset") 541 if diff := cmp.Diff(expect, got); diff != "" { 542 t.Errorf("repsonse mismatch (-want +got):\n%s", diff) 543 } 544 }