// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "bytes" "strings" "testing" ) func TestAPI_Snapshot(t *testing.T) { t.Parallel() c, s := makeClient(t) defer s.Stop() s.WaitForSerfCheck(t) // Place an initial key into the store. kv := c.KV() key := &KVPair{Key: testKey(), Value: []byte("hello")} if _, err := kv.Put(key, nil); err != nil { t.Fatalf("err: %v", err) } // Make sure it reads back. pair, _, err := kv.Get(key.Key, nil) if err != nil { t.Fatalf("err: %v", err) } if pair == nil { t.Fatalf("expected value: %#v", pair) } if !bytes.Equal(pair.Value, []byte("hello")) { t.Fatalf("unexpected value: %#v", pair) } // Take a snapshot. snapshot := c.Snapshot() snap, qm, err := snapshot.Save(nil) if err != nil { t.Fatalf("err: %v", err) } defer snap.Close() // Sanity check th query metadata. if qm.LastIndex == 0 || !qm.KnownLeader || qm.RequestTime == 0 { t.Fatalf("bad: %v", qm) } // Overwrite the key's value. key.Value = []byte("goodbye") if _, err := kv.Put(key, nil); err != nil { t.Fatalf("err: %v", err) } // Read the key back and look for the new value. pair, _, err = kv.Get(key.Key, nil) if err != nil { t.Fatalf("err: %v", err) } if pair == nil { t.Fatalf("expected value: %#v", pair) } if !bytes.Equal(pair.Value, []byte("goodbye")) { t.Fatalf("unexpected value: %#v", pair) } // Restore the snapshot. if err := snapshot.Restore(nil, snap); err != nil { t.Fatalf("err: %v", err) } // Read the key back and look for the original value. pair, _, err = kv.Get(key.Key, nil) if err != nil { t.Fatalf("err: %v", err) } if pair == nil { t.Fatalf("expected value: %#v", pair) } if !bytes.Equal(pair.Value, []byte("hello")) { t.Fatalf("unexpected value: %#v", pair) } } func TestAPI_Snapshot_Options(t *testing.T) { t.Parallel() c, s := makeACLClient(t) defer s.Stop() // Try to take a snapshot with a bad token. snapshot := c.Snapshot() _, _, err := snapshot.Save(&QueryOptions{Token: "anonymous"}) if err == nil || !strings.Contains(err.Error(), "Permission denied") { t.Fatalf("err: %v", err) } // Now try an unknown DC. _, _, err = snapshot.Save(&QueryOptions{Datacenter: "nope"}) if err == nil || !strings.Contains(err.Error(), "No path to datacenter") { t.Fatalf("err: %v", err) } // This should work with a valid token. snap, _, err := snapshot.Save(&QueryOptions{Token: "root"}) if err != nil { t.Fatalf("err: %v", err) } defer snap.Close() // This should work with a stale snapshot. This doesn't have good feedback // that the stale option was sent, but it makes sure nothing bad happens. snap, _, err = snapshot.Save(&QueryOptions{Token: "root", AllowStale: true}) if err != nil { t.Fatalf("err: %v", err) } defer snap.Close() // Try to restore a snapshot with a bad token. null := bytes.NewReader([]byte("")) err = snapshot.Restore(&WriteOptions{Token: "anonymous"}, null) if err == nil || !strings.Contains(err.Error(), "Permission denied") { t.Fatalf("err: %v", err) } // Now try an unknown DC. null = bytes.NewReader([]byte("")) err = snapshot.Restore(&WriteOptions{Datacenter: "nope"}, null) if err == nil || !strings.Contains(err.Error(), "No path to datacenter") { t.Fatalf("err: %v", err) } // This should work. if err := snapshot.Restore(&WriteOptions{Token: "root"}, snap); err != nil { t.Fatalf("err: %v", err) } }