github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/client/snapshot_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package client_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"net/http"
    25  	"net/url"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	"gopkg.in/check.v1"
    31  
    32  	"github.com/snapcore/snapd/client"
    33  	"github.com/snapcore/snapd/snap"
    34  )
    35  
    36  func (cs *clientSuite) TestClientSnapshotIsValid(c *check.C) {
    37  	now := time.Now()
    38  	revno := snap.R(1)
    39  	sums := map[string]string{"user/foo.tgz": "some long hash"}
    40  	c.Check((&client.Snapshot{
    41  		SetID:    42,
    42  		Time:     now,
    43  		Snap:     "asnap",
    44  		Revision: revno,
    45  		SHA3_384: sums,
    46  	}).IsValid(), check.Equals, true)
    47  
    48  	for desc, snapshot := range map[string]*client.Snapshot{
    49  		"nil":     nil,
    50  		"empty":   {},
    51  		"no id":   { /*SetID: 42,*/ Time: now, Snap: "asnap", Revision: revno, SHA3_384: sums},
    52  		"no time": {SetID: 42 /*Time: now,*/, Snap: "asnap", Revision: revno, SHA3_384: sums},
    53  		"no snap": {SetID: 42, Time: now /*Snap: "asnap",*/, Revision: revno, SHA3_384: sums},
    54  		"no rev":  {SetID: 42, Time: now, Snap: "asnap" /*Revision: revno,*/, SHA3_384: sums},
    55  		"no sums": {SetID: 42, Time: now, Snap: "asnap", Revision: revno /*SHA3_384: sums*/},
    56  	} {
    57  		c.Check(snapshot.IsValid(), check.Equals, false, check.Commentf("%s", desc))
    58  	}
    59  
    60  }
    61  
    62  func (cs *clientSuite) TestClientSnapshotSetTime(c *check.C) {
    63  	// if set is empty, it doesn't explode (and returns the zero time)
    64  	c.Check(client.SnapshotSet{}.Time().IsZero(), check.Equals, true)
    65  	// if not empty, returns the earliest one
    66  	c.Check(client.SnapshotSet{Snapshots: []*client.Snapshot{
    67  		{Time: time.Unix(3, 0)},
    68  		{Time: time.Unix(1, 0)},
    69  		{Time: time.Unix(2, 0)},
    70  	}}.Time(), check.DeepEquals, time.Unix(1, 0))
    71  }
    72  
    73  func (cs *clientSuite) TestClientSnapshotSetSize(c *check.C) {
    74  	// if set is empty, doesn't explode (and returns 0)
    75  	c.Check(client.SnapshotSet{}.Size(), check.Equals, int64(0))
    76  	// if not empty, returns the sum
    77  	c.Check(client.SnapshotSet{Snapshots: []*client.Snapshot{
    78  		{Size: 1},
    79  		{Size: 2},
    80  		{Size: 3},
    81  	}}.Size(), check.DeepEquals, int64(6))
    82  }
    83  
    84  func (cs *clientSuite) TestClientSnapshotSets(c *check.C) {
    85  	cs.rsp = `{
    86  		"type": "sync",
    87  		"result": [{"id": 1}, {"id":2}]
    88  }`
    89  	sets, err := cs.cli.SnapshotSets(42, []string{"foo", "bar"})
    90  	c.Assert(err, check.IsNil)
    91  	c.Check(sets, check.DeepEquals, []client.SnapshotSet{{ID: 1}, {ID: 2}})
    92  	c.Check(cs.req.Method, check.Equals, "GET")
    93  	c.Check(cs.req.URL.Path, check.Equals, "/v2/snapshots")
    94  	c.Check(cs.req.URL.Query(), check.DeepEquals, url.Values{
    95  		"set":   []string{"42"},
    96  		"snaps": []string{"foo,bar"},
    97  	})
    98  }
    99  
   100  func (cs *clientSuite) testClientSnapshotActionFull(c *check.C, action string, users []string, f func() (string, error)) {
   101  	cs.status = 202
   102  	cs.rsp = `{
   103  		"status-code": 202,
   104  		"type": "async",
   105  		"change": "1too3"
   106  	}`
   107  	id, err := f()
   108  	c.Assert(err, check.IsNil)
   109  	c.Check(id, check.Equals, "1too3")
   110  
   111  	c.Assert(cs.req.Header.Get("Content-Type"), check.Equals, "application/json")
   112  
   113  	act, err := client.UnmarshalSnapshotAction(cs.req.Body)
   114  	c.Assert(err, check.IsNil)
   115  	c.Check(act.SetID, check.Equals, uint64(42))
   116  	c.Check(act.Action, check.Equals, action)
   117  	c.Check(act.Snaps, check.DeepEquals, []string{"asnap", "bsnap"})
   118  	c.Check(act.Users, check.DeepEquals, users)
   119  
   120  	c.Check(cs.req.Method, check.Equals, "POST")
   121  	c.Check(cs.req.URL.Path, check.Equals, "/v2/snapshots")
   122  	c.Check(cs.req.URL.Query(), check.HasLen, 0)
   123  }
   124  
   125  func (cs *clientSuite) TestClientForgetSnapshot(c *check.C) {
   126  	cs.testClientSnapshotActionFull(c, "forget", nil, func() (string, error) {
   127  		return cs.cli.ForgetSnapshots(42, []string{"asnap", "bsnap"})
   128  	})
   129  }
   130  
   131  func (cs *clientSuite) testClientSnapshotAction(c *check.C, action string, f func(uint64, []string, []string) (string, error)) {
   132  	cs.testClientSnapshotActionFull(c, action, []string{"auser", "buser"}, func() (string, error) {
   133  		return f(42, []string{"asnap", "bsnap"}, []string{"auser", "buser"})
   134  	})
   135  }
   136  
   137  func (cs *clientSuite) TestClientCheckSnapshots(c *check.C) {
   138  	cs.testClientSnapshotAction(c, "check", cs.cli.CheckSnapshots)
   139  }
   140  
   141  func (cs *clientSuite) TestClientRestoreSnapshots(c *check.C) {
   142  	cs.testClientSnapshotAction(c, "restore", cs.cli.RestoreSnapshots)
   143  }
   144  
   145  func (cs *clientSuite) TestClientExportSnapshot(c *check.C) {
   146  	type tableT struct {
   147  		content     string
   148  		contentType string
   149  		status      int
   150  	}
   151  
   152  	table := []tableT{
   153  		{"dummy-export", client.SnapshotExportMediaType, 200},
   154  		{"dummy-export", "application/x-tar", 400},
   155  		{"", "", 400},
   156  	}
   157  
   158  	for i, t := range table {
   159  		comm := check.Commentf("%d: %q", i, t.content)
   160  
   161  		cs.contentLength = int64(len(t.content))
   162  		cs.header = http.Header{"Content-Type": []string{t.contentType}}
   163  		cs.rsp = t.content
   164  		cs.status = t.status
   165  
   166  		r, size, err := cs.cli.SnapshotExport(42)
   167  		if t.status == 200 {
   168  			c.Assert(err, check.IsNil, comm)
   169  			c.Assert(cs.countingCloser.closeCalled, check.Equals, 0)
   170  			c.Assert(size, check.Equals, int64(len(t.content)), comm)
   171  		} else {
   172  			c.Assert(err.Error(), check.Equals, "unexpected status code: ")
   173  			c.Assert(cs.countingCloser.closeCalled, check.Equals, 1)
   174  		}
   175  
   176  		if t.status == 200 {
   177  			buf, err := ioutil.ReadAll(r)
   178  			c.Assert(err, check.IsNil)
   179  			c.Assert(string(buf), check.Equals, t.content)
   180  		}
   181  	}
   182  }
   183  
   184  func (cs *clientSuite) TestClientSnapshotImport(c *check.C) {
   185  	type tableT struct {
   186  		rsp    string
   187  		status int
   188  		setID  uint64
   189  		error  string
   190  	}
   191  	table := []tableT{
   192  		{`{"type": "sync", "result": {"set-id": 42, "snaps": ["baz", "bar", "foo"]}}`, 200, 42, ""},
   193  		{`{"type": "error"}`, 400, 0, "server error: \"Bad Request\""},
   194  	}
   195  
   196  	for i, t := range table {
   197  		comm := check.Commentf("%d: %s", i, t.rsp)
   198  
   199  		cs.rsp = t.rsp
   200  		cs.status = t.status
   201  
   202  		fakeSnapshotData := "fake"
   203  		r := strings.NewReader(fakeSnapshotData)
   204  		importSet, err := cs.cli.SnapshotImport(r, int64(len(fakeSnapshotData)))
   205  		if t.error != "" {
   206  			c.Assert(err, check.NotNil, comm)
   207  			c.Check(err.Error(), check.Equals, t.error, comm)
   208  			continue
   209  		}
   210  		c.Assert(err, check.IsNil, comm)
   211  		c.Assert(cs.req.Header.Get("Content-Type"), check.Equals, client.SnapshotExportMediaType)
   212  		c.Assert(cs.req.Header.Get("Content-Length"), check.Equals, strconv.Itoa(len(fakeSnapshotData)))
   213  		c.Check(importSet.ID, check.Equals, t.setID, comm)
   214  		c.Check(importSet.Snaps, check.DeepEquals, []string{"baz", "bar", "foo"}, comm)
   215  		d, err := ioutil.ReadAll(cs.req.Body)
   216  		c.Assert(err, check.IsNil)
   217  		c.Check(string(d), check.Equals, fakeSnapshotData)
   218  	}
   219  }