1/* 2Copyright 2011 The Perkeep Authors 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package localdisk 18 19import ( 20 "context" 21 "fmt" 22 "os" 23 "strconv" 24 "sync" 25 "testing" 26 27 "perkeep.org/pkg/blob" 28 "perkeep.org/pkg/blobserver" 29 "perkeep.org/pkg/blobserver/storagetest" 30 "perkeep.org/pkg/test" 31) 32 33func cleanUp(ds *DiskStorage) { 34 os.RemoveAll(ds.root) 35} 36 37var ( 38 epochLock sync.Mutex 39 rootEpoch = 0 40) 41 42func NewStorage(t *testing.T) *DiskStorage { 43 epochLock.Lock() 44 rootEpoch++ 45 path := fmt.Sprintf("%s/camli-testroot-%d-%d", os.TempDir(), os.Getpid(), rootEpoch) 46 epochLock.Unlock() 47 if err := os.Mkdir(path, 0755); err != nil { 48 t.Fatalf("Failed to create temp directory %q: %v", path, err) 49 } 50 ds, err := New(path) 51 if err != nil { 52 t.Fatalf("Failed to run New: %v", err) 53 } 54 return ds 55} 56 57func TestUploadDup(t *testing.T) { 58 ds := NewStorage(t) 59 defer cleanUp(ds) 60 tb := &test.Blob{"Foo"} 61 tb.MustUpload(t, ds) 62 tb.MustUpload(t, ds) 63} 64 65func TestReceiveStat(t *testing.T) { 66 ds := NewStorage(t) 67 defer cleanUp(ds) 68 69 tb := &test.Blob{"Foo"} 70 tb.MustUpload(t, ds) 71 72 ctx := context.Background() 73 got, err := blobserver.StatBlobs(ctx, ds, tb.BlobRefSlice()) 74 if err != nil { 75 t.Fatalf("StatBlobs: %v", err) 76 } 77 if len(got) != 1 { 78 t.Errorf("got %d stat blobs; expected 1", len(got)) 79 } 80 sb, ok := got[tb.BlobRef()] 81 if !ok { 82 t.Fatalf("stat response lacked information for %v", tb.BlobRef()) 83 } 84 tb.AssertMatches(t, sb) 85} 86 87func TestMultiStat(t *testing.T) { 88 ds := NewStorage(t) 89 defer cleanUp(ds) 90 91 blobfoo := &test.Blob{"foo"} 92 blobbar := &test.Blob{"bar!"} 93 blobfoo.MustUpload(t, ds) 94 blobbar.MustUpload(t, ds) 95 96 need := make(map[blob.Ref]bool) 97 need[blobfoo.BlobRef()] = true 98 need[blobbar.BlobRef()] = true 99 100 blobs := []blob.Ref{blobfoo.BlobRef(), blobbar.BlobRef()} 101 102 // In addition to the two "foo" and "bar" blobs, add 103 // maxParallelStats other dummy blobs, to exercise the stat 104 // rate-limiting (which had a deadlock once after a cleanup) 105 const maxParallelStats = 20 106 for i := 0; i < maxParallelStats; i++ { 107 blobs = append(blobs, blob.RefFromString(strconv.Itoa(i))) 108 } 109 110 ctx := context.Background() 111 gotStat, err := blobserver.StatBlobs(ctx, ds, blobs) 112 if err != nil { 113 t.Fatalf("StatBlobs: %v", err) 114 } 115 got := 0 116 for _, sb := range gotStat { 117 got++ 118 if !need[sb.Ref] { 119 t.Errorf("didn't need %s", sb.Ref) 120 } 121 delete(need, sb.Ref) 122 } 123 if want := 2; got != want { 124 t.Errorf("number stats = %d; want %d", got, want) 125 } 126 if len(need) != 0 { 127 t.Errorf("Not all stat results returned; still need %d", len(need)) 128 } 129} 130 131func TestMissingGetReturnsNoEnt(t *testing.T) { 132 ds := NewStorage(t) 133 defer cleanUp(ds) 134 foo := &test.Blob{"foo"} 135 136 blob, _, err := ds.Fetch(context.Background(), foo.BlobRef()) 137 if err != os.ErrNotExist { 138 t.Errorf("expected ErrNotExist; got %v", err) 139 } 140 if blob != nil { 141 t.Errorf("expected nil blob; got a value") 142 } 143} 144 145type file struct { 146 name string 147 contents string 148} 149 150func TestLocaldisk(t *testing.T) { 151 storagetest.Test(t, func(t *testing.T) (blobserver.Storage, func()) { 152 ds := NewStorage(t) 153 return ds, func() { cleanUp(ds) } 154 }) 155} 156