1package storagepacker 2 3import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/golang/protobuf/proto" 9 "github.com/golang/protobuf/ptypes" 10 log "github.com/hashicorp/go-hclog" 11 uuid "github.com/hashicorp/go-uuid" 12 "github.com/hashicorp/vault/helper/identity" 13 "github.com/hashicorp/vault/sdk/logical" 14) 15 16func BenchmarkStoragePacker(b *testing.B) { 17 storagePacker, err := NewStoragePacker(&logical.InmemStorage{}, log.New(&log.LoggerOptions{Name: "storagepackertest"}), "") 18 if err != nil { 19 b.Fatal(err) 20 } 21 22 ctx := context.Background() 23 24 for i := 0; i < b.N; i++ { 25 itemID, err := uuid.GenerateUUID() 26 if err != nil { 27 b.Fatal(err) 28 } 29 30 item := &Item{ 31 ID: itemID, 32 } 33 34 err = storagePacker.PutItem(ctx, item) 35 if err != nil { 36 b.Fatal(err) 37 } 38 39 fetchedItem, err := storagePacker.GetItem(itemID) 40 if err != nil { 41 b.Fatal(err) 42 } 43 44 if fetchedItem == nil { 45 b.Fatalf("failed to read stored item with ID: %q, iteration: %d", item.ID, i) 46 } 47 48 if fetchedItem.ID != item.ID { 49 b.Fatalf("bad: item ID; expected: %q\n actual: %q", item.ID, fetchedItem.ID) 50 } 51 52 err = storagePacker.DeleteItem(ctx, item.ID) 53 if err != nil { 54 b.Fatal(err) 55 } 56 57 fetchedItem, err = storagePacker.GetItem(item.ID) 58 if err != nil { 59 b.Fatal(err) 60 } 61 if fetchedItem != nil { 62 b.Fatalf("failed to delete item") 63 } 64 } 65} 66 67func TestStoragePacker(t *testing.T) { 68 storagePacker, err := NewStoragePacker(&logical.InmemStorage{}, log.New(&log.LoggerOptions{Name: "storagepackertest"}), "") 69 if err != nil { 70 t.Fatal(err) 71 } 72 73 ctx := context.Background() 74 75 // Persist a storage entry 76 item1 := &Item{ 77 ID: "item1", 78 } 79 80 err = storagePacker.PutItem(ctx, item1) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 // Verify that it can be read 86 fetchedItem, err := storagePacker.GetItem(item1.ID) 87 if err != nil { 88 t.Fatal(err) 89 } 90 if fetchedItem == nil { 91 t.Fatalf("failed to read the stored item") 92 } 93 94 if item1.ID != fetchedItem.ID { 95 t.Fatalf("bad: item ID; expected: %q\n actual: %q\n", item1.ID, fetchedItem.ID) 96 } 97 98 // Delete item1 99 err = storagePacker.DeleteItem(ctx, item1.ID) 100 if err != nil { 101 t.Fatal(err) 102 } 103 104 // Check that the deletion was successful 105 fetchedItem, err = storagePacker.GetItem(item1.ID) 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 if fetchedItem != nil { 111 t.Fatalf("failed to delete item") 112 } 113} 114 115func TestStoragePacker_SerializeDeserializeComplexItem(t *testing.T) { 116 storagePacker, err := NewStoragePacker(&logical.InmemStorage{}, log.New(&log.LoggerOptions{Name: "storagepackertest"}), "") 117 if err != nil { 118 t.Fatal(err) 119 } 120 121 ctx := context.Background() 122 123 timeNow := ptypes.TimestampNow() 124 125 alias1 := &identity.Alias{ 126 ID: "alias_id", 127 CanonicalID: "canonical_id", 128 MountType: "mount_type", 129 MountAccessor: "mount_accessor", 130 Metadata: map[string]string{ 131 "aliasmkey": "aliasmvalue", 132 }, 133 Name: "alias_name", 134 CreationTime: timeNow, 135 LastUpdateTime: timeNow, 136 MergedFromCanonicalIDs: []string{"merged_from_canonical_id"}, 137 } 138 139 entity := &identity.Entity{ 140 Aliases: []*identity.Alias{alias1}, 141 ID: "entity_id", 142 Name: "entity_name", 143 Metadata: map[string]string{ 144 "testkey1": "testvalue1", 145 "testkey2": "testvalue2", 146 }, 147 CreationTime: timeNow, 148 LastUpdateTime: timeNow, 149 BucketKey: "entity_hash", 150 MergedEntityIDs: []string{"merged_entity_id1", "merged_entity_id2"}, 151 Policies: []string{"policy1", "policy2"}, 152 } 153 154 marshaledEntity, err := ptypes.MarshalAny(entity) 155 if err != nil { 156 t.Fatal(err) 157 } 158 err = storagePacker.PutItem(ctx, &Item{ 159 ID: entity.ID, 160 Message: marshaledEntity, 161 }) 162 if err != nil { 163 t.Fatal(err) 164 } 165 166 itemFetched, err := storagePacker.GetItem(entity.ID) 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 var itemDecoded identity.Entity 172 err = ptypes.UnmarshalAny(itemFetched.Message, &itemDecoded) 173 if err != nil { 174 t.Fatal(err) 175 } 176 177 if !proto.Equal(&itemDecoded, entity) { 178 t.Fatalf("bad: expected: %#v\nactual: %#v\n", entity, itemDecoded) 179 } 180} 181 182func TestStoragePacker_DeleteMultiple(t *testing.T) { 183 storagePacker, err := NewStoragePacker(&logical.InmemStorage{}, log.New(&log.LoggerOptions{Name: "storagepackertest"}), "") 184 if err != nil { 185 t.Fatal(err) 186 } 187 188 ctx := context.Background() 189 190 // Persist a storage entry 191 for i := 0; i < 100; i++ { 192 item := &Item{ 193 ID: fmt.Sprintf("item%d", i), 194 } 195 196 err = storagePacker.PutItem(ctx, item) 197 if err != nil { 198 t.Fatal(err) 199 } 200 201 // Verify that it can be read 202 fetchedItem, err := storagePacker.GetItem(item.ID) 203 if err != nil { 204 t.Fatal(err) 205 } 206 if fetchedItem == nil { 207 t.Fatalf("failed to read the stored item") 208 } 209 210 if item.ID != fetchedItem.ID { 211 t.Fatalf("bad: item ID; expected: %q\n actual: %q\n", item.ID, fetchedItem.ID) 212 } 213 } 214 215 itemsToDelete := make([]string, 0, 50) 216 for i := 1; i < 100; i += 2 { 217 itemsToDelete = append(itemsToDelete, fmt.Sprintf("item%d", i)) 218 } 219 220 err = storagePacker.DeleteMultipleItems(ctx, nil, itemsToDelete) 221 if err != nil { 222 t.Fatal(err) 223 } 224 225 // Check that the deletion was successful 226 for i := 0; i < 100; i++ { 227 fetchedItem, err := storagePacker.GetItem(fmt.Sprintf("item%d", i)) 228 if err != nil { 229 t.Fatal(err) 230 } 231 232 if i%2 == 0 && fetchedItem == nil { 233 t.Fatal("expected item not found") 234 } 235 if i%2 == 1 && fetchedItem != nil { 236 t.Fatalf("failed to delete item") 237 } 238 } 239} 240 241func TestStoragePacker_DeleteMultiple_ALL(t *testing.T) { 242 storagePacker, err := NewStoragePacker(&logical.InmemStorage{}, log.New(&log.LoggerOptions{Name: "storagepackertest"}), "") 243 if err != nil { 244 t.Fatal(err) 245 } 246 247 ctx := context.Background() 248 249 // Persist a storage entry 250 itemsToDelete := make([]string, 0, 10000) 251 for i := 0; i < 10000; i++ { 252 item := &Item{ 253 ID: fmt.Sprintf("item%d", i), 254 } 255 256 err = storagePacker.PutItem(ctx, item) 257 if err != nil { 258 t.Fatal(err) 259 } 260 261 // Verify that it can be read 262 fetchedItem, err := storagePacker.GetItem(item.ID) 263 if err != nil { 264 t.Fatal(err) 265 } 266 if fetchedItem == nil { 267 t.Fatalf("failed to read the stored item") 268 } 269 270 if item.ID != fetchedItem.ID { 271 t.Fatalf("bad: item ID; expected: %q\n actual: %q\n", item.ID, fetchedItem.ID) 272 } 273 274 itemsToDelete = append(itemsToDelete, fmt.Sprintf("item%d", i)) 275 } 276 277 err = storagePacker.DeleteMultipleItems(ctx, nil, itemsToDelete) 278 if err != nil { 279 t.Fatal(err) 280 } 281 282 // Check that the deletion was successful 283 for _, item := range itemsToDelete { 284 fetchedItem, err := storagePacker.GetItem(item) 285 if err != nil { 286 t.Fatal(err) 287 } 288 if fetchedItem != nil { 289 t.Fatal("item not deleted") 290 } 291 } 292} 293