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  }