github.com/fipar/percona-agent@v1.0.13/pct/update_test.go (about)

     1  /*
     2     Copyright (c) 2014-2015, Percona LLC and/or its affiliates. All rights reserved.
     3  
     4     This program is free software: you can redistribute it and/or modify
     5     it under the terms of the GNU Affero General Public License as published by
     6     the Free Software Foundation, either version 3 of the License, or
     7     (at your option) any later version.
     8  
     9     This program is distributed in the hope that it will be useful,
    10     but WITHOUT ANY WARRANTY; without even the implied warranty of
    11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12     GNU Affero General Public License for more details.
    13  
    14     You should have received a copy of the GNU Affero General Public License
    15     along with this program.  If not, see <http://www.gnu.org/licenses/>
    16  */
    17  
    18  package pct_test
    19  
    20  import (
    21  	"bytes"
    22  	"github.com/percona/cloud-protocol/proto/v1"
    23  	"github.com/percona/percona-agent/pct"
    24  	"github.com/percona/percona-agent/test"
    25  	"github.com/percona/percona-agent/test/mock"
    26  	. "gopkg.in/check.v1"
    27  	"io/ioutil"
    28  	"os"
    29  	"os/exec"
    30  	"path/filepath"
    31  	"strings"
    32  )
    33  
    34  type UpdateTestSuite struct {
    35  	tmpDir  string
    36  	logChan chan *proto.LogEntry
    37  	logger  *pct.Logger
    38  	api     *mock.API
    39  	pubKey  []byte
    40  	bin     []byte
    41  	sig     []byte
    42  }
    43  
    44  var _ = Suite(&UpdateTestSuite{})
    45  
    46  func (s *UpdateTestSuite) SetUpSuite(t *C) {
    47  	var err error
    48  	s.tmpDir, err = ioutil.TempDir("/tmp", "percona-agent-test-pct-update")
    49  	t.Assert(err, IsNil)
    50  
    51  	s.logChan = make(chan *proto.LogEntry, 1000)
    52  	s.logger = pct.NewLogger(s.logChan, "qan-test")
    53  
    54  	links := map[string]string{
    55  		"agent":     "http://localhost/agent",
    56  		"instances": "http://localhost/instances",
    57  		"update":    "http://localhost/update",
    58  	}
    59  	s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links)
    60  
    61  	test.CopyFile(test.RootDir+"/pct/fake-percona-agent-1.0.1.go", s.tmpDir)
    62  
    63  	cwd, err := os.Getwd()
    64  	t.Assert(err, IsNil)
    65  	defer os.Chdir(cwd)
    66  
    67  	err = os.Chdir(s.tmpDir)
    68  	t.Assert(err, IsNil)
    69  
    70  	out, err := exec.Command("go", "build", "fake-percona-agent-1.0.1.go").Output()
    71  	if err != nil {
    72  		t.Logf("%s", out)
    73  		t.Fatal(err)
    74  	}
    75  	s.bin, s.sig, err = test.Sign(filepath.Join(s.tmpDir, "fake-percona-agent-1.0.1"))
    76  	t.Assert(err, IsNil)
    77  
    78  	s.pubKey, err = ioutil.ReadFile(filepath.Join(test.RootDir, "pct", "key.pub"))
    79  	t.Assert(err, IsNil)
    80  }
    81  
    82  func (s *UpdateTestSuite) TearDownSuite(t *C) {
    83  	if err := os.RemoveAll(s.tmpDir); err != nil {
    84  		t.Error(err)
    85  	}
    86  }
    87  
    88  // --------------------------------------------------------------------------
    89  
    90  func (s *UpdateTestSuite) TestCheck(t *C) {
    91  	// First make a very fake percona-agent "binary": just a file containing "A".
    92  	// Later we'll check that the update process overwrites this with the updated binary.
    93  	curBin := filepath.Join(s.tmpDir + "/percona-agent")
    94  	if err := ioutil.WriteFile(curBin, []byte{0x41}, os.FileMode(0655)); err != nil {
    95  		t.Fatal(err)
    96  	}
    97  
    98  	// Create an updater.  Normally we'd pass in hard-coded pct.PublicKey and os.Args[0].
    99  	u := pct.NewUpdater(s.logger, s.api, s.pubKey, curBin, "1.0.0")
   100  	t.Assert(u, NotNil)
   101  
   102  	// Updater.Update() makes 2 API calls: first to get percona-agent-VERSION-ARCH.gz,
   103  	// second to get the corresponding .sig file.  The bin and sig here are "real" in
   104  	// the sense that in SetUpSuite() we compiled a fake percona-agent bin and signed
   105  	// it with the test private key (test/pct/key.pem).
   106  	s.api.GetCode = []int{200, 200}
   107  	s.api.GetData = [][]byte{s.bin, s.sig}
   108  	s.api.GetError = []error{nil, nil}
   109  
   110  	// Run the update process.  It thinks it's getting percona-agent 1.0.1 from the real API.
   111  	err := u.Update("1.0.1")
   112  	t.Assert(err, IsNil)
   113  
   114  	// The update process should have fetched and verified the test bin and sig, then
   115  	// write the bin to disk and copied it over the very fake percona-agent "binary"
   116  	// we created first.  So the whole process looks like:
   117  	//   1. Test writes percona-agent (very fake binary)
   118  	//   2. Test compiles fake-percona-agent-1.0.1.go to fake-percona-agent-1.0.1 (bin)
   119  	//   3. Test queues bytes of fake-percona-agent-go-1.0.1 (bin) and sig in fake API
   120  	//   4. Updater gets those ^ bytes, verifies bin with sig
   121  	//   5. Updater writes bin bytes as percona-agent-1.0.1-ARCH
   122  	//   6. Updater runs "percona-agent-1.0.1-ARCH -version", expects output to be "1.0.1"
   123  	//   7. Update does "mv percona-agent-1.0.1-ARCH percona-agent"
   124  	// Therefore, fake-percona-agent-1.0.1 (bin) == percona-agent at the byte level.
   125  	newBin, err := ioutil.ReadFile(curBin)
   126  	t.Assert(err, IsNil)
   127  	if bytes.Compare(s.bin, newBin) != 0 {
   128  		t.Error("percona-agent binary != fake-percona-agent-1.0.1 binary")
   129  	}
   130  
   131  	// And if percona-agent is *really* fake-percona-agent-1.0.1, then we too should
   132  	// get "1.0.1" if we run it with -version:
   133  	out, err := exec.Command(curBin, "-version").Output()
   134  	t.Assert(err, IsNil)
   135  	t.Check(strings.TrimSpace(string(out)), Equals, "percona-agent 1.0.1 rev 19b6b2ede12bfd2a012d40ac572a660be7aff1e7")
   136  }