github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/gridfs_test.go (about) 1 // mgo - MongoDB driver for Go 2 // 3 // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // 1. Redistributions of source code must retain the above copyright notice, this 11 // list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright notice, 13 // this list of conditions and the following disclaimer in the documentation 14 // and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 package mgo_test 28 29 import ( 30 "camlistore.org/third_party/labix.org/v2/mgo" 31 "camlistore.org/third_party/labix.org/v2/mgo/bson" 32 . "camlistore.org/third_party/launchpad.net/gocheck" 33 "io" 34 "os" 35 "time" 36 ) 37 38 func (s *S) TestGridFSCreate(c *C) { 39 session, err := mgo.Dial("localhost:40011") 40 c.Assert(err, IsNil) 41 defer session.Close() 42 43 db := session.DB("mydb") 44 45 before := bson.Now() 46 47 gfs := db.GridFS("fs") 48 file, err := gfs.Create("") 49 c.Assert(err, IsNil) 50 51 n, err := file.Write([]byte("some data")) 52 c.Assert(err, IsNil) 53 c.Assert(n, Equals, 9) 54 55 err = file.Close() 56 c.Assert(err, IsNil) 57 58 after := bson.Now() 59 60 // Check the file information. 61 result := M{} 62 err = db.C("fs.files").Find(nil).One(result) 63 c.Assert(err, IsNil) 64 65 fileId, ok := result["_id"].(bson.ObjectId) 66 c.Assert(ok, Equals, true) 67 c.Assert(fileId.Valid(), Equals, true) 68 result["_id"] = "<id>" 69 70 ud, ok := result["uploadDate"].(time.Time) 71 c.Assert(ok, Equals, true) 72 c.Assert(ud.After(before) && ud.Before(after), Equals, true) 73 result["uploadDate"] = "<timestamp>" 74 75 expected := M{ 76 "_id": "<id>", 77 "length": 9, 78 "chunkSize": 262144, 79 "uploadDate": "<timestamp>", 80 "md5": "1e50210a0202497fb79bc38b6ade6c34", 81 } 82 c.Assert(result, DeepEquals, expected) 83 84 // Check the chunk. 85 result = M{} 86 err = db.C("fs.chunks").Find(nil).One(result) 87 c.Assert(err, IsNil) 88 89 chunkId, ok := result["_id"].(bson.ObjectId) 90 c.Assert(ok, Equals, true) 91 c.Assert(chunkId.Valid(), Equals, true) 92 result["_id"] = "<id>" 93 94 expected = M{ 95 "_id": "<id>", 96 "files_id": fileId, 97 "n": 0, 98 "data": []byte("some data"), 99 } 100 c.Assert(result, DeepEquals, expected) 101 102 // Check that an index was created. 103 indexes, err := db.C("fs.chunks").Indexes() 104 c.Assert(err, IsNil) 105 c.Assert(len(indexes), Equals, 2) 106 c.Assert(indexes[1].Key, DeepEquals, []string{"files_id", "n"}) 107 } 108 109 func (s *S) TestGridFSFileDetails(c *C) { 110 session, err := mgo.Dial("localhost:40011") 111 c.Assert(err, IsNil) 112 defer session.Close() 113 114 db := session.DB("mydb") 115 116 gfs := db.GridFS("fs") 117 118 file, err := gfs.Create("myfile1.txt") 119 c.Assert(err, IsNil) 120 121 n, err := file.Write([]byte("some")) 122 c.Assert(err, IsNil) 123 c.Assert(n, Equals, 4) 124 125 c.Assert(file.Size(), Equals, int64(4)) 126 127 n, err = file.Write([]byte(" data")) 128 c.Assert(err, IsNil) 129 c.Assert(n, Equals, 5) 130 131 c.Assert(file.Size(), Equals, int64(9)) 132 133 id, _ := file.Id().(bson.ObjectId) 134 c.Assert(id.Valid(), Equals, true) 135 c.Assert(file.Name(), Equals, "myfile1.txt") 136 c.Assert(file.ContentType(), Equals, "") 137 138 var info interface{} 139 err = file.GetMeta(&info) 140 c.Assert(err, IsNil) 141 c.Assert(info, IsNil) 142 143 file.SetId("myid") 144 file.SetName("myfile2.txt") 145 file.SetContentType("text/plain") 146 file.SetMeta(M{"any": "thing"}) 147 148 c.Assert(file.Id(), Equals, "myid") 149 c.Assert(file.Name(), Equals, "myfile2.txt") 150 c.Assert(file.ContentType(), Equals, "text/plain") 151 152 err = file.GetMeta(&info) 153 c.Assert(err, IsNil) 154 c.Assert(info, DeepEquals, bson.M{"any": "thing"}) 155 156 err = file.Close() 157 c.Assert(err, IsNil) 158 159 c.Assert(file.MD5(), Equals, "1e50210a0202497fb79bc38b6ade6c34") 160 161 ud := file.UploadDate() 162 now := time.Now() 163 c.Assert(ud.Before(now), Equals, true) 164 c.Assert(ud.After(now.Add(-3*time.Second)), Equals, true) 165 166 result := M{} 167 err = db.C("fs.files").Find(nil).One(result) 168 c.Assert(err, IsNil) 169 170 result["uploadDate"] = "<timestamp>" 171 172 expected := M{ 173 "_id": "myid", 174 "length": 9, 175 "chunkSize": 262144, 176 "uploadDate": "<timestamp>", 177 "md5": "1e50210a0202497fb79bc38b6ade6c34", 178 "filename": "myfile2.txt", 179 "contentType": "text/plain", 180 "metadata": M{"any": "thing"}, 181 } 182 c.Assert(result, DeepEquals, expected) 183 } 184 185 func (s *S) TestGridFSCreateWithChunking(c *C) { 186 session, err := mgo.Dial("localhost:40011") 187 c.Assert(err, IsNil) 188 defer session.Close() 189 190 db := session.DB("mydb") 191 192 gfs := db.GridFS("fs") 193 194 file, err := gfs.Create("") 195 c.Assert(err, IsNil) 196 197 file.SetChunkSize(5) 198 199 // Smaller than the chunk size. 200 n, err := file.Write([]byte("abc")) 201 c.Assert(err, IsNil) 202 c.Assert(n, Equals, 3) 203 204 // Boundary in the middle. 205 n, err = file.Write([]byte("defg")) 206 c.Assert(err, IsNil) 207 c.Assert(n, Equals, 4) 208 209 // Boundary at the end. 210 n, err = file.Write([]byte("hij")) 211 c.Assert(err, IsNil) 212 c.Assert(n, Equals, 3) 213 214 // Larger than the chunk size, with 3 chunks. 215 n, err = file.Write([]byte("klmnopqrstuv")) 216 c.Assert(err, IsNil) 217 c.Assert(n, Equals, 12) 218 219 err = file.Close() 220 c.Assert(err, IsNil) 221 222 // Check the file information. 223 result := M{} 224 err = db.C("fs.files").Find(nil).One(result) 225 c.Assert(err, IsNil) 226 227 fileId, _ := result["_id"].(bson.ObjectId) 228 c.Assert(fileId.Valid(), Equals, true) 229 result["_id"] = "<id>" 230 result["uploadDate"] = "<timestamp>" 231 232 expected := M{ 233 "_id": "<id>", 234 "length": 22, 235 "chunkSize": 5, 236 "uploadDate": "<timestamp>", 237 "md5": "44a66044834cbe55040089cabfc102d5", 238 } 239 c.Assert(result, DeepEquals, expected) 240 241 // Check the chunks. 242 iter := db.C("fs.chunks").Find(nil).Sort("n").Iter() 243 dataChunks := []string{"abcde", "fghij", "klmno", "pqrst", "uv"} 244 for i := 0; ; i++ { 245 result = M{} 246 if !iter.Next(result) { 247 if i != 5 { 248 c.Fatalf("Expected 5 chunks, got %d", i) 249 } 250 break 251 } 252 c.Assert(iter.Close(), IsNil) 253 254 result["_id"] = "<id>" 255 256 expected = M{ 257 "_id": "<id>", 258 "files_id": fileId, 259 "n": i, 260 "data": []byte(dataChunks[i]), 261 } 262 c.Assert(result, DeepEquals, expected) 263 } 264 } 265 266 func (s *S) TestGridFSOpenNotFound(c *C) { 267 session, err := mgo.Dial("localhost:40011") 268 c.Assert(err, IsNil) 269 defer session.Close() 270 271 db := session.DB("mydb") 272 273 gfs := db.GridFS("fs") 274 file, err := gfs.OpenId("non-existent") 275 c.Assert(err == mgo.ErrNotFound, Equals, true) 276 c.Assert(file, IsNil) 277 278 file, err = gfs.Open("non-existent") 279 c.Assert(err == mgo.ErrNotFound, Equals, true) 280 c.Assert(file, IsNil) 281 } 282 283 func (s *S) TestGridFSReadAll(c *C) { 284 session, err := mgo.Dial("localhost:40011") 285 c.Assert(err, IsNil) 286 defer session.Close() 287 288 db := session.DB("mydb") 289 290 gfs := db.GridFS("fs") 291 file, err := gfs.Create("") 292 c.Assert(err, IsNil) 293 id := file.Id() 294 295 file.SetChunkSize(5) 296 297 n, err := file.Write([]byte("abcdefghijklmnopqrstuv")) 298 c.Assert(err, IsNil) 299 c.Assert(n, Equals, 22) 300 301 err = file.Close() 302 c.Assert(err, IsNil) 303 304 file, err = gfs.OpenId(id) 305 c.Assert(err, IsNil) 306 307 b := make([]byte, 30) 308 n, err = file.Read(b) 309 c.Assert(n, Equals, 22) 310 c.Assert(err, IsNil) 311 312 n, err = file.Read(b) 313 c.Assert(n, Equals, 0) 314 c.Assert(err == io.EOF, Equals, true) 315 316 err = file.Close() 317 c.Assert(err, IsNil) 318 } 319 320 func (s *S) TestGridFSReadChunking(c *C) { 321 session, err := mgo.Dial("localhost:40011") 322 c.Assert(err, IsNil) 323 defer session.Close() 324 325 db := session.DB("mydb") 326 327 gfs := db.GridFS("fs") 328 329 file, err := gfs.Create("") 330 c.Assert(err, IsNil) 331 332 id := file.Id() 333 334 file.SetChunkSize(5) 335 336 n, err := file.Write([]byte("abcdefghijklmnopqrstuv")) 337 c.Assert(err, IsNil) 338 c.Assert(n, Equals, 22) 339 340 err = file.Close() 341 c.Assert(err, IsNil) 342 343 file, err = gfs.OpenId(id) 344 c.Assert(err, IsNil) 345 346 b := make([]byte, 30) 347 348 // Smaller than the chunk size. 349 n, err = file.Read(b[:3]) 350 c.Assert(err, IsNil) 351 c.Assert(n, Equals, 3) 352 c.Assert(b[:3], DeepEquals, []byte("abc")) 353 354 // Boundary in the middle. 355 n, err = file.Read(b[:4]) 356 c.Assert(err, IsNil) 357 c.Assert(n, Equals, 4) 358 c.Assert(b[:4], DeepEquals, []byte("defg")) 359 360 // Boundary at the end. 361 n, err = file.Read(b[:3]) 362 c.Assert(err, IsNil) 363 c.Assert(n, Equals, 3) 364 c.Assert(b[:3], DeepEquals, []byte("hij")) 365 366 // Larger than the chunk size, with 3 chunks. 367 n, err = file.Read(b) 368 c.Assert(err, IsNil) 369 c.Assert(n, Equals, 12) 370 c.Assert(b[:12], DeepEquals, []byte("klmnopqrstuv")) 371 372 n, err = file.Read(b) 373 c.Assert(n, Equals, 0) 374 c.Assert(err == io.EOF, Equals, true) 375 376 err = file.Close() 377 c.Assert(err, IsNil) 378 } 379 380 func (s *S) TestGridFSOpen(c *C) { 381 session, err := mgo.Dial("localhost:40011") 382 c.Assert(err, IsNil) 383 defer session.Close() 384 385 db := session.DB("mydb") 386 387 gfs := db.GridFS("fs") 388 389 file, err := gfs.Create("myfile.txt") 390 c.Assert(err, IsNil) 391 file.Write([]byte{'1'}) 392 file.Close() 393 394 file, err = gfs.Create("myfile.txt") 395 c.Assert(err, IsNil) 396 file.Write([]byte{'2'}) 397 file.Close() 398 399 file, err = gfs.Open("myfile.txt") 400 c.Assert(err, IsNil) 401 defer file.Close() 402 403 var b [1]byte 404 405 _, err = file.Read(b[:]) 406 c.Assert(err, IsNil) 407 c.Assert(string(b[:]), Equals, "2") 408 } 409 410 func (s *S) TestGridFSSeek(c *C) { 411 session, err := mgo.Dial("localhost:40011") 412 c.Assert(err, IsNil) 413 defer session.Close() 414 415 db := session.DB("mydb") 416 417 gfs := db.GridFS("fs") 418 file, err := gfs.Create("") 419 c.Assert(err, IsNil) 420 id := file.Id() 421 422 file.SetChunkSize(5) 423 424 n, err := file.Write([]byte("abcdefghijklmnopqrstuv")) 425 c.Assert(err, IsNil) 426 c.Assert(n, Equals, 22) 427 428 err = file.Close() 429 c.Assert(err, IsNil) 430 431 b := make([]byte, 5) 432 433 file, err = gfs.OpenId(id) 434 c.Assert(err, IsNil) 435 436 o, err := file.Seek(3, os.SEEK_SET) 437 c.Assert(err, IsNil) 438 c.Assert(o, Equals, int64(3)) 439 _, err = file.Read(b) 440 c.Assert(err, IsNil) 441 c.Assert(b, DeepEquals, []byte("defgh")) 442 443 o, err = file.Seek(5, os.SEEK_CUR) 444 c.Assert(err, IsNil) 445 c.Assert(o, Equals, int64(13)) 446 _, err = file.Read(b) 447 c.Assert(err, IsNil) 448 c.Assert(b, DeepEquals, []byte("nopqr")) 449 450 o, err = file.Seek(-10, os.SEEK_END) 451 c.Assert(err, IsNil) 452 c.Assert(o, Equals, int64(12)) 453 _, err = file.Read(b) 454 c.Assert(err, IsNil) 455 c.Assert(b, DeepEquals, []byte("mnopq")) 456 457 o, err = file.Seek(8, os.SEEK_SET) 458 c.Assert(err, IsNil) 459 c.Assert(o, Equals, int64(8)) 460 _, err = file.Read(b) 461 c.Assert(err, IsNil) 462 c.Assert(b, DeepEquals, []byte("ijklm")) 463 464 // Trivial seek forward within same chunk. Already 465 // got the data, shouldn't touch the database. 466 sent := mgo.GetStats().SentOps 467 o, err = file.Seek(1, os.SEEK_CUR) 468 c.Assert(err, IsNil) 469 c.Assert(o, Equals, int64(14)) 470 c.Assert(mgo.GetStats().SentOps, Equals, sent) 471 _, err = file.Read(b) 472 c.Assert(err, IsNil) 473 c.Assert(b, DeepEquals, []byte("opqrs")) 474 475 // Try seeking past end of file. 476 file.Seek(3, os.SEEK_SET) 477 o, err = file.Seek(23, os.SEEK_SET) 478 c.Assert(err, ErrorMatches, "Seek past end of file") 479 c.Assert(o, Equals, int64(3)) 480 } 481 482 func (s *S) TestGridFSRemoveId(c *C) { 483 session, err := mgo.Dial("localhost:40011") 484 c.Assert(err, IsNil) 485 defer session.Close() 486 487 db := session.DB("mydb") 488 489 gfs := db.GridFS("fs") 490 491 file, err := gfs.Create("myfile.txt") 492 c.Assert(err, IsNil) 493 file.Write([]byte{'1'}) 494 file.Close() 495 496 file, err = gfs.Create("myfile.txt") 497 c.Assert(err, IsNil) 498 file.Write([]byte{'2'}) 499 id := file.Id() 500 file.Close() 501 502 err = gfs.RemoveId(id) 503 c.Assert(err, IsNil) 504 505 file, err = gfs.Open("myfile.txt") 506 c.Assert(err, IsNil) 507 defer file.Close() 508 509 var b [1]byte 510 511 _, err = file.Read(b[:]) 512 c.Assert(err, IsNil) 513 c.Assert(string(b[:]), Equals, "1") 514 515 n, err := db.C("fs.chunks").Find(M{"files_id": id}).Count() 516 c.Assert(err, IsNil) 517 c.Assert(n, Equals, 0) 518 } 519 520 func (s *S) TestGridFSRemove(c *C) { 521 session, err := mgo.Dial("localhost:40011") 522 c.Assert(err, IsNil) 523 defer session.Close() 524 525 db := session.DB("mydb") 526 527 gfs := db.GridFS("fs") 528 529 file, err := gfs.Create("myfile.txt") 530 c.Assert(err, IsNil) 531 file.Write([]byte{'1'}) 532 file.Close() 533 534 file, err = gfs.Create("myfile.txt") 535 c.Assert(err, IsNil) 536 file.Write([]byte{'2'}) 537 file.Close() 538 539 err = gfs.Remove("myfile.txt") 540 c.Assert(err, IsNil) 541 542 _, err = gfs.Open("myfile.txt") 543 c.Assert(err == mgo.ErrNotFound, Equals, true) 544 545 n, err := db.C("fs.chunks").Find(nil).Count() 546 c.Assert(err, IsNil) 547 c.Assert(n, Equals, 0) 548 } 549 550 func (s *S) TestGridFSOpenNext(c *C) { 551 session, err := mgo.Dial("localhost:40011") 552 c.Assert(err, IsNil) 553 defer session.Close() 554 555 db := session.DB("mydb") 556 557 gfs := db.GridFS("fs") 558 559 file, err := gfs.Create("myfile1.txt") 560 c.Assert(err, IsNil) 561 file.Write([]byte{'1'}) 562 file.Close() 563 564 file, err = gfs.Create("myfile2.txt") 565 c.Assert(err, IsNil) 566 file.Write([]byte{'2'}) 567 file.Close() 568 569 var f *mgo.GridFile 570 var b [1]byte 571 572 iter := gfs.Find(nil).Sort("-filename").Iter() 573 574 ok := gfs.OpenNext(iter, &f) 575 c.Assert(ok, Equals, true) 576 c.Check(f.Name(), Equals, "myfile2.txt") 577 578 _, err = f.Read(b[:]) 579 c.Assert(err, IsNil) 580 c.Assert(string(b[:]), Equals, "2") 581 582 ok = gfs.OpenNext(iter, &f) 583 c.Assert(ok, Equals, true) 584 c.Check(f.Name(), Equals, "myfile1.txt") 585 586 _, err = f.Read(b[:]) 587 c.Assert(err, IsNil) 588 c.Assert(string(b[:]), Equals, "1") 589 590 ok = gfs.OpenNext(iter, &f) 591 c.Assert(ok, Equals, false) 592 c.Assert(iter.Close(), IsNil) 593 c.Assert(f, IsNil) 594 595 // Do it again with a more restrictive query to make sure 596 // it's actually taken into account. 597 iter = gfs.Find(bson.M{"filename": "myfile1.txt"}).Iter() 598 599 ok = gfs.OpenNext(iter, &f) 600 c.Assert(ok, Equals, true) 601 c.Check(f.Name(), Equals, "myfile1.txt") 602 603 ok = gfs.OpenNext(iter, &f) 604 c.Assert(ok, Equals, false) 605 c.Assert(iter.Close(), IsNil) 606 c.Assert(f, IsNil) 607 }