github.com/mckael/restic@v0.8.3/internal/restic/snapshot_policy_test.go (about)

     1  package restic_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"path/filepath"
     8  	"reflect"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/restic/restic/internal/restic"
    13  )
    14  
    15  func parseTimeUTC(s string) time.Time {
    16  	t, err := time.Parse("2006-01-02 15:04:05", s)
    17  	if err != nil {
    18  		panic(err)
    19  	}
    20  
    21  	return t.UTC()
    22  }
    23  
    24  func TestExpireSnapshotOps(t *testing.T) {
    25  	data := []struct {
    26  		expectEmpty bool
    27  		expectSum   int
    28  		p           *restic.ExpirePolicy
    29  	}{
    30  		{true, 0, &restic.ExpirePolicy{}},
    31  		{true, 0, &restic.ExpirePolicy{Tags: []restic.TagList{}}},
    32  		{false, 22, &restic.ExpirePolicy{Daily: 7, Weekly: 2, Monthly: 3, Yearly: 10}},
    33  	}
    34  	for i, d := range data {
    35  		isEmpty := d.p.Empty()
    36  		if isEmpty != d.expectEmpty {
    37  			t.Errorf("empty test %v: wrong result, want:\n  %#v\ngot:\n  %#v", i, d.expectEmpty, isEmpty)
    38  		}
    39  		hasSum := d.p.Sum()
    40  		if hasSum != d.expectSum {
    41  			t.Errorf("sum test %v: wrong result, want:\n  %#v\ngot:\n  %#v", i, d.expectSum, hasSum)
    42  		}
    43  	}
    44  }
    45  
    46  var testExpireSnapshots = restic.Snapshots{
    47  	{Time: parseTimeUTC("2014-09-01 10:20:30")},
    48  	{Time: parseTimeUTC("2014-09-02 10:20:30")},
    49  	{Time: parseTimeUTC("2014-09-05 10:20:30")},
    50  	{Time: parseTimeUTC("2014-09-06 10:20:30")},
    51  	{Time: parseTimeUTC("2014-09-08 10:20:30")},
    52  	{Time: parseTimeUTC("2014-09-09 10:20:30")},
    53  	{Time: parseTimeUTC("2014-09-10 10:20:30")},
    54  	{Time: parseTimeUTC("2014-09-11 10:20:30")},
    55  	{Time: parseTimeUTC("2014-09-20 10:20:30")},
    56  	{Time: parseTimeUTC("2014-09-22 10:20:30")},
    57  	{Time: parseTimeUTC("2014-08-08 10:20:30")},
    58  	{Time: parseTimeUTC("2014-08-10 10:20:30")},
    59  	{Time: parseTimeUTC("2014-08-12 10:20:30")},
    60  	{Time: parseTimeUTC("2014-08-13 10:20:30")},
    61  	{Time: parseTimeUTC("2014-08-13 10:20:30.1")},
    62  	{Time: parseTimeUTC("2014-08-15 10:20:30")},
    63  	{Time: parseTimeUTC("2014-08-18 10:20:30")},
    64  	{Time: parseTimeUTC("2014-08-20 10:20:30")},
    65  	{Time: parseTimeUTC("2014-08-21 10:20:30")},
    66  	{Time: parseTimeUTC("2014-08-22 10:20:30")},
    67  	{Time: parseTimeUTC("2014-10-01 10:20:30"), Tags: []string{"foo"}},
    68  	{Time: parseTimeUTC("2014-10-02 10:20:30"), Tags: []string{"foo"}},
    69  	{Time: parseTimeUTC("2014-10-05 10:20:30"), Tags: []string{"foo"}},
    70  	{Time: parseTimeUTC("2014-10-06 10:20:30"), Tags: []string{"foo"}},
    71  	{Time: parseTimeUTC("2014-10-08 10:20:30"), Tags: []string{"foo"}},
    72  	{Time: parseTimeUTC("2014-10-09 10:20:30"), Tags: []string{"foo"}},
    73  	{Time: parseTimeUTC("2014-10-10 10:20:30"), Tags: []string{"foo"}},
    74  	{Time: parseTimeUTC("2014-10-11 10:20:30"), Tags: []string{"foo"}},
    75  	{Time: parseTimeUTC("2014-10-20 10:20:30"), Tags: []string{"foo"}},
    76  	{Time: parseTimeUTC("2014-10-22 10:20:30"), Tags: []string{"foo"}},
    77  	{Time: parseTimeUTC("2014-11-08 10:20:30"), Tags: []string{"foo"}},
    78  	{Time: parseTimeUTC("2014-11-10 10:20:30"), Tags: []string{"foo"}},
    79  	{Time: parseTimeUTC("2014-11-12 10:20:30"), Tags: []string{"foo"}},
    80  	{Time: parseTimeUTC("2014-11-13 10:20:30"), Tags: []string{"foo"}},
    81  	{Time: parseTimeUTC("2014-11-13 10:20:30.1"), Tags: []string{"bar"}},
    82  	{Time: parseTimeUTC("2014-11-15 10:20:30"), Tags: []string{"foo", "bar"}},
    83  	{Time: parseTimeUTC("2014-11-18 10:20:30")},
    84  	{Time: parseTimeUTC("2014-11-20 10:20:30")},
    85  	{Time: parseTimeUTC("2014-11-21 10:20:30")},
    86  	{Time: parseTimeUTC("2014-11-22 10:20:30")},
    87  	{Time: parseTimeUTC("2015-09-01 10:20:30")},
    88  	{Time: parseTimeUTC("2015-09-02 10:20:30")},
    89  	{Time: parseTimeUTC("2015-09-05 10:20:30")},
    90  	{Time: parseTimeUTC("2015-09-06 10:20:30")},
    91  	{Time: parseTimeUTC("2015-09-08 10:20:30")},
    92  	{Time: parseTimeUTC("2015-09-09 10:20:30")},
    93  	{Time: parseTimeUTC("2015-09-10 10:20:30")},
    94  	{Time: parseTimeUTC("2015-09-11 10:20:30")},
    95  	{Time: parseTimeUTC("2015-09-20 10:20:30")},
    96  	{Time: parseTimeUTC("2015-09-22 10:20:30")},
    97  	{Time: parseTimeUTC("2015-08-08 10:20:30")},
    98  	{Time: parseTimeUTC("2015-08-10 10:20:30")},
    99  	{Time: parseTimeUTC("2015-08-12 10:20:30")},
   100  	{Time: parseTimeUTC("2015-08-13 10:20:30")},
   101  	{Time: parseTimeUTC("2015-08-13 10:20:30.1")},
   102  	{Time: parseTimeUTC("2015-08-15 10:20:30")},
   103  	{Time: parseTimeUTC("2015-08-18 10:20:30")},
   104  	{Time: parseTimeUTC("2015-08-20 10:20:30")},
   105  	{Time: parseTimeUTC("2015-08-21 10:20:30")},
   106  	{Time: parseTimeUTC("2015-08-22 10:20:30")},
   107  	{Time: parseTimeUTC("2015-10-01 10:20:30")},
   108  	{Time: parseTimeUTC("2015-10-02 10:20:30")},
   109  	{Time: parseTimeUTC("2015-10-05 10:20:30")},
   110  	{Time: parseTimeUTC("2015-10-06 10:20:30")},
   111  	{Time: parseTimeUTC("2015-10-08 10:20:30")},
   112  	{Time: parseTimeUTC("2015-10-09 10:20:30")},
   113  	{Time: parseTimeUTC("2015-10-10 10:20:30")},
   114  	{Time: parseTimeUTC("2015-10-11 10:20:30")},
   115  	{Time: parseTimeUTC("2015-10-20 10:20:30")},
   116  	{Time: parseTimeUTC("2015-10-22 10:20:30")},
   117  	{Time: parseTimeUTC("2015-10-22 10:20:30")},
   118  	{Time: parseTimeUTC("2015-10-22 10:20:30"), Tags: []string{"foo", "bar"}},
   119  	{Time: parseTimeUTC("2015-10-22 10:20:30"), Tags: []string{"foo", "bar"}},
   120  	{Time: parseTimeUTC("2015-10-22 10:20:30"), Tags: []string{"foo", "bar"}, Paths: []string{"path1", "path2"}},
   121  	{Time: parseTimeUTC("2015-11-08 10:20:30")},
   122  	{Time: parseTimeUTC("2015-11-10 10:20:30")},
   123  	{Time: parseTimeUTC("2015-11-12 10:20:30")},
   124  	{Time: parseTimeUTC("2015-11-13 10:20:30")},
   125  	{Time: parseTimeUTC("2015-11-13 10:20:30.1")},
   126  	{Time: parseTimeUTC("2015-11-15 10:20:30")},
   127  	{Time: parseTimeUTC("2015-11-18 10:20:30")},
   128  	{Time: parseTimeUTC("2015-11-20 10:20:30")},
   129  	{Time: parseTimeUTC("2015-11-21 10:20:30")},
   130  	{Time: parseTimeUTC("2015-11-22 10:20:30")},
   131  	{Time: parseTimeUTC("2016-01-01 01:02:03")},
   132  	{Time: parseTimeUTC("2016-01-01 01:03:03")},
   133  	{Time: parseTimeUTC("2016-01-01 07:08:03")},
   134  	{Time: parseTimeUTC("2016-01-03 07:02:03")},
   135  	{Time: parseTimeUTC("2016-01-04 10:23:03")},
   136  	{Time: parseTimeUTC("2016-01-04 11:23:03")},
   137  	{Time: parseTimeUTC("2016-01-04 12:23:03")},
   138  	{Time: parseTimeUTC("2016-01-04 12:24:03")},
   139  	{Time: parseTimeUTC("2016-01-04 12:28:03")},
   140  	{Time: parseTimeUTC("2016-01-04 12:30:03")},
   141  	{Time: parseTimeUTC("2016-01-04 16:23:03")},
   142  	{Time: parseTimeUTC("2016-01-05 09:02:03")},
   143  	{Time: parseTimeUTC("2016-01-06 08:02:03")},
   144  	{Time: parseTimeUTC("2016-01-07 10:02:03")},
   145  	{Time: parseTimeUTC("2016-01-08 20:02:03")},
   146  	{Time: parseTimeUTC("2016-01-09 21:02:03")},
   147  	{Time: parseTimeUTC("2016-01-12 21:02:03")},
   148  	{Time: parseTimeUTC("2016-01-12 21:08:03")},
   149  	{Time: parseTimeUTC("2016-01-18 12:02:03")},
   150  }
   151  
   152  var expireTests = []restic.ExpirePolicy{
   153  	{},
   154  	{Last: 10},
   155  	{Last: 15},
   156  	{Last: 99},
   157  	{Last: 200},
   158  	{Hourly: 20},
   159  	{Daily: 3},
   160  	{Daily: 10},
   161  	{Daily: 30},
   162  	{Last: 5, Daily: 5},
   163  	{Last: 2, Daily: 10},
   164  	{Weekly: 2},
   165  	{Weekly: 4},
   166  	{Daily: 3, Weekly: 4},
   167  	{Monthly: 6},
   168  	{Daily: 2, Weekly: 2, Monthly: 6},
   169  	{Yearly: 10},
   170  	{Daily: 7, Weekly: 2, Monthly: 3, Yearly: 10},
   171  	{Tags: []restic.TagList{{"foo"}}},
   172  	{Tags: []restic.TagList{{"foo", "bar"}}},
   173  	{Tags: []restic.TagList{{"foo"}, {"bar"}}},
   174  }
   175  
   176  func TestApplyPolicy(t *testing.T) {
   177  	for i, p := range expireTests {
   178  		keep, remove := restic.ApplyPolicy(testExpireSnapshots, p)
   179  
   180  		t.Logf("test %d: returned keep %v, remove %v (of %v) expired snapshots for policy %v",
   181  			i, len(keep), len(remove), len(testExpireSnapshots), p)
   182  
   183  		if len(keep)+len(remove) != len(testExpireSnapshots) {
   184  			t.Errorf("test %d: len(keep)+len(remove) = %d != len(testExpireSnapshots) = %d",
   185  				i, len(keep)+len(remove), len(testExpireSnapshots))
   186  		}
   187  
   188  		if p.Sum() > 0 && len(keep) > p.Sum() {
   189  			t.Errorf("not enough snapshots removed: policy allows %v snapshots to remain, but ended up with %v",
   190  				p.Sum(), len(keep))
   191  		}
   192  
   193  		for _, sn := range keep {
   194  			t.Logf("test %d:     keep snapshot at %v %s\n", i, sn.Time, sn.Tags)
   195  		}
   196  		for _, sn := range remove {
   197  			t.Logf("test %d:   forget snapshot at %v %s\n", i, sn.Time, sn.Tags)
   198  		}
   199  
   200  		goldenFilename := filepath.Join("testdata", fmt.Sprintf("policy_keep_snapshots_%d", i))
   201  
   202  		if *updateGoldenFiles {
   203  			buf, err := json.MarshalIndent(keep, "", "  ")
   204  			if err != nil {
   205  				t.Fatalf("error marshaling result: %v", err)
   206  			}
   207  
   208  			if err = ioutil.WriteFile(goldenFilename, buf, 0644); err != nil {
   209  				t.Fatalf("unable to update golden file: %v", err)
   210  			}
   211  		}
   212  
   213  		buf, err := ioutil.ReadFile(goldenFilename)
   214  		if err != nil {
   215  			t.Errorf("error loading golden file %v: %v", goldenFilename, err)
   216  			continue
   217  		}
   218  
   219  		var want restic.Snapshots
   220  		err = json.Unmarshal(buf, &want)
   221  		if err != nil {
   222  			t.Errorf("error unmarshalling golden file %v: %v", goldenFilename, err)
   223  			continue
   224  		}
   225  
   226  		if !reflect.DeepEqual(keep, want) {
   227  			t.Errorf("test %v: wrong result, want:\n  %v\ngot:\n  %v", i, want, keep)
   228  			continue
   229  		}
   230  	}
   231  }