Merge lp:~elopio/snappy/fix1496515-go_vet_missing_return into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by Leo Arias
Status: Superseded
Proposed branch: lp:~elopio/snappy/fix1496515-go_vet_missing_return
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Diff against target: 6958 lines (+5442/-67) (has conflicts)
75 files modified
_integration-tests/README.md (+117/-0)
_integration-tests/data/snaps/basic/meta/package.yaml (+4/-0)
_integration-tests/data/snaps/basic/meta/readme.md (+3/-0)
_integration-tests/data/snaps/missing-readme/meta/package.yaml (+4/-0)
_integration-tests/data/snaps/wrong-yaml/meta/package.yaml (+5/-0)
_integration-tests/data/snaps/wrong-yaml/meta/readme.md (+3/-0)
_integration-tests/data/tpl/control (+4/-0)
_integration-tests/main.go (+105/-0)
_integration-tests/reboot-wrapper (+35/-0)
_integration-tests/tests/apt_test.go (+39/-0)
_integration-tests/tests/base_test.go (+29/-0)
_integration-tests/tests/build_test.go (+90/-0)
_integration-tests/tests/failover_rclocal_crash_test.go (+54/-0)
_integration-tests/tests/failover_systemd_loop_test.go (+114/-0)
_integration-tests/tests/failover_test.go (+58/-0)
_integration-tests/tests/failover_zero_size_file_test.go (+258/-0)
_integration-tests/tests/info_test.go (+79/-0)
_integration-tests/tests/installApp_test.go (+128/-0)
_integration-tests/tests/installFramework_test.go (+93/-0)
_integration-tests/tests/list_test.go (+78/-0)
_integration-tests/tests/rollback_test.go (+53/-0)
_integration-tests/tests/search_test.go (+44/-0)
_integration-tests/tests/update_test.go (+51/-0)
_integration-tests/tests/writablePaths_test.go (+106/-0)
_integration-tests/testutils/autopkgtest/autopkgtest.go (+111/-0)
_integration-tests/testutils/autopkgtest/ssh.go (+46/-0)
_integration-tests/testutils/build/build.go (+76/-0)
_integration-tests/testutils/common/common.go (+379/-0)
_integration-tests/testutils/common/common_test.go (+68/-0)
_integration-tests/testutils/config/config.go (+75/-0)
_integration-tests/testutils/config/config_test.go (+121/-0)
_integration-tests/testutils/image/image.go (+86/-0)
_integration-tests/testutils/testutils.go (+61/-0)
cmd/snappy/cmd_internal_unpack.go (+4/-0)
cmd/snappy/cmd_internal_unpack_test.go (+20/-0)
cmd/snappy/cmd_rollback.go (+9/-0)
cmd/snappy/cmd_set.go (+14/-0)
cmd/snappy/cmd_set_test.go (+18/-1)
cmd/snappy/main.go (+4/-0)
coreconfig/config_test.go (+38/-0)
debian/control (+9/-0)
debian/rules (+20/-0)
debian/snappy-wait4network.service (+10/-0)
dependencies.tsv (+8/-0)
etc/grub.d/09_snappy (+441/-0)
helpers/helpers.go (+170/-8)
helpers/helpers_test.go (+104/-0)
logger/logger_test.go (+331/-0)
partition/bootloader_grub.go (+20/-0)
partition/bootloader_grub_test.go (+5/-0)
partition/bootloader_uboot.go (+343/-0)
partition/bootloader_uboot_test.go (+90/-0)
partition/partition.go (+20/-0)
run-checks (+19/-0)
snappy/auth_test.go (+12/-12)
snappy/build_test.go (+5/-0)
snappy/click.go (+353/-1)
snappy/click_test.go (+119/-2)
snappy/common_test.go (+7/-1)
snappy/dirs.go (+9/-0)
snappy/errors.go (+41/-0)
snappy/firstboot_test.go (+4/-0)
snappy/install_test.go (+5/-0)
snappy/parts.go (+47/-1)
snappy/remove_test.go (+4/-0)
snappy/rollback_test.go (+4/-0)
snappy/security.go (+7/-0)
snappy/security_test.go (+4/-0)
snappy/snapp.go (+127/-2)
snappy/snapp_test.go (+146/-17)
snappy/sort_test.go (+4/-0)
snappy/systemimage.go (+36/-0)
snappy/systemimage_test.go (+58/-0)
snappy/udev_test.go.OTHER (+49/-0)
systemd/systemd.go (+127/-22)
Conflict adding file _integration-tests.  Moved existing file to _integration-tests.moved.
Text conflict in cmd/snappy/cmd_internal_unpack.go
Text conflict in cmd/snappy/cmd_internal_unpack_test.go
Text conflict in cmd/snappy/cmd_set.go
Text conflict in cmd/snappy/cmd_set_test.go
Text conflict in cmd/snappy/main.go
Text conflict in coreconfig/config_test.go
Text conflict in debian/control
Text conflict in debian/rules
Conflict adding file debian/snappy-wait4network.service.  Moved existing file to debian/snappy-wait4network.service.moved.
Text conflict in dependencies.tsv
Conflict adding files to etc.  Created directory.
Conflict because etc is not versioned, but has versioned children.  Versioned directory.
Conflict adding file etc.  Moved existing file to etc.moved.
Conflict adding files to etc/grub.d.  Created directory.
Conflict because etc/grub.d is not versioned, but has versioned children.  Versioned directory.
Text conflict in helpers/helpers.go
Text conflict in helpers/helpers_test.go
Conflict adding files to logger.  Created directory.
Conflict because logger is not versioned, but has versioned children.  Versioned directory.
Conflict adding file logger.  Moved existing file to logger.moved.
Text conflict in partition/bootloader_grub.go
Text conflict in partition/bootloader_grub_test.go
Text conflict in partition/bootloader_uboot.go
Text conflict in partition/partition.go
Text conflict in run-checks
Text conflict in snappy/build_test.go
Text conflict in snappy/click.go
Text conflict in snappy/click_test.go
Text conflict in snappy/common_test.go
Text conflict in snappy/dirs.go
Text conflict in snappy/errors.go
Text conflict in snappy/firstboot_test.go
Text conflict in snappy/install_test.go
Text conflict in snappy/parts.go
Text conflict in snappy/remove_test.go
Text conflict in snappy/rollback_test.go
Text conflict in snappy/security.go
Text conflict in snappy/security_test.go
Text conflict in snappy/snapp.go
Text conflict in snappy/snapp_test.go
Text conflict in snappy/sort_test.go
Text conflict in snappy/systemimage.go
Contents conflict in snappy/udev_test.go
Text conflict in systemd/systemd.go
To merge this branch: bzr merge lp:~elopio/snappy/fix1496515-go_vet_missing_return
Reviewer Review Type Date Requested Status
Snappy Developers Pending
Review via email: mp+271351@code.launchpad.net

This proposal has been superseded by a proposal from 2015-09-16.

Commit message

Fixed the vet check: added the missing return of the error in rsync helper.

To post a comment you must log in.

Unmerged revisions

480. By Leo Arias

Fixed the vet check: added the missing return of the error in rsync helper.

479. By Michael Vogt

reorganizes the ubuntu-core network config by mvo approved by mvo,sergiusens

478. By Michael Vogt

Add support for "forking" by mvo approved by mvo,chipaca

477. By Michael Vogt

Fix off-by-one error in the path handlng by mvo approved by sergiusens

476. By Michael Vogt

Enable watchdog configuration via ubuntu-core-config by mvo approved by mvo

475. By Michael Vogt

Add configuration for ppp via ubuntu-core-config by mvo approved by mvo

474. By Michael Vogt

Unblock network configuration with pass-through networking suppport by mvo approved by mvo

473. By Michael Vogt

Add support for ubuntu-core.modprobe configuration. by mvo approved by mvo,chipaca

472. By Michael Vogt

Fix typo (USer -> User) by mvo approved by sergiusens

471. By Michael Vogt

snappy/hwaccess.go: make valid gpio access broader by mvo approved by sergiusens

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory '_integration-tests'
=== renamed directory '_integration-tests' => '_integration-tests.moved'
=== added file '_integration-tests/README.md'
--- _integration-tests/README.md 1970-01-01 00:00:00 +0000
+++ _integration-tests/README.md 2015-09-16 17:51:11 +0000
@@ -0,0 +1,117 @@
1# Integration testing for snappy
2
3## Requirements
4
5 * autopkgtest (>= 3.15.1)
6
7 Get the latest autopkgtest deb from
8 https://packages.debian.org/sid/all/autopkgtest/download
9
10 * Internet access in the test bed.
11
12## Setting up the project
13
14First you need to set up the GOPATH, get the snappy sources and the
15dependencies as explained in the `README.md` that is located at the root of the
16branch.
17
18## Testing a virtual machine
19
20You can execute the full integration suite in a local virtual machine with:
21
22 go run _integration-tests/main.go
23
24The test runner will create the snappy images with `ubuntu-device-flash`, so it
25will ask for your password to run this command with `sudo`.
26
27You can also especify more options to customize the image being created, including
28the release, the channel and the revision to use. This parameters will be passed
29to `ubuntu-device-flash`:
30
31 go run _integration-tests/main.go -release 15.04 -channel stable -revision 3
32
33The default values are suited to testing the most recent version, `rolling` for
34release, `edge` for channel and an empty revision, which picks the latest
35available.
36
37## Testing snappy from a branch
38
39With the --snappy-from-branch flag, the snappy CLI command will be compiled
40from the current branch, copied to the test bed and used during the integration
41tests:
42
43 go run _integration-tests/main.go --snappy-from-branch
44
45You can use this flag to test in a remote machine too.
46
47## Filtering the tests to run
48
49With the --filter flag you can select the tests to run. For instance you can
50pass MyTestSuite, MyTestSuite.FirstCustomTest or MyTestSuite.*CustomTest:
51
52 go run _integration-tests/main.go --filter MyTestSuite.FirstCustomTest
53
54## Testing a remote machine
55
56You can execute the integration suite in a remote snappy machine with:
57
58 go run _integration-tests/main.go --ip {testbed-ip} --port {testbed-port} \
59 --arch {testbed-arch}
60
61The test runner will use `ssh-copy-id` to send your identity file to the
62testbed, so it will ask for the password of the ubuntu user in the test bed.
63
64When running in a remote machine, the test runner assumes the test bed is in
65the latest rolling edge version, and it will skip all the tests that
66require a different version. See the following section for instructions for
67setting up a BeagleBone Black as the test bed.
68
69## Testing a BeagleBone Black
70
71First flash the latest 15.04 edge version into the sd card
72(replacing /dev/sdX with the path to your card):
73
74 sudo ubuntu-device-flash core 15.04 --channel edge --oem beagleblack \
75 --developer-mode --enable-ssh -o ubuntu-15.04-edge-armhf-bbb.img
76
77 sudo dd if=ubuntu-15.04-edge-armhf-bbb.img of=/dev/sdX bs=32M
78 sync
79
80Then boot the board with the sd card, make sure that it is connected to the
81same network as the test runner host, and find the {beaglebone-ip}.
82
83Run the tests with:
84
85 go run _integration-tests/main.go --ip {beaglebone-ip} --arch arm
86
87## Testing an update
88
89With the --update flag you can flash an old image, update to the latest and
90then run the whole suite on the updated system. The release, the channel and
91the revision flags specify the image that will be flashed, and the
92target-release and target-channel flags specify the values to be used in the
93update if they are different from the flashed values.
94
95For example, to update from 15.04 edge -1 to the latest and then run the
96integration tests:
97
98 go run _integration-tests/main.go --snappy-from-branch \
99 --release=15.04 --revision=-1 --update
100
101To update from 15.04 alpha to 15.04 edge and then run the integration tests:
102
103 go run _integration-tests/main.go --snappy-from-branch \
104 --release=15.04 --channel=alpha \
105 --update --target-channel=edge
106
107## Testing a rollback
108
109With the --rollback flag you can flash an old image, update to the latest,
110rollback again to the old image and then run the whole suite on the rolled
111back system. You should use the release, channel, revision, target-release and
112target-channel flags as when testing an update.
113
114For example, to test a rollback from latest 15.04 edge to 15.04 edge -1:
115
116 go run _integration-tests/main.go \
117 --release=15.04 --revision=-1 --rollback
0118
=== added directory '_integration-tests/data'
=== added directory '_integration-tests/data/snaps'
=== added directory '_integration-tests/data/snaps/basic'
=== added directory '_integration-tests/data/snaps/basic/meta'
=== added file '_integration-tests/data/snaps/basic/meta/package.yaml'
--- _integration-tests/data/snaps/basic/meta/package.yaml 1970-01-01 00:00:00 +0000
+++ _integration-tests/data/snaps/basic/meta/package.yaml 2015-09-16 17:51:11 +0000
@@ -0,0 +1,4 @@
1name: basic
2version: 1.0
3vendor: Snappy Developers <snappy-devel@lists.ubuntu.com>
4icon: meta/snappy64.png
05
=== added file '_integration-tests/data/snaps/basic/meta/readme.md'
--- _integration-tests/data/snaps/basic/meta/readme.md 1970-01-01 00:00:00 +0000
+++ _integration-tests/data/snaps/basic/meta/readme.md 2015-09-16 17:51:11 +0000
@@ -0,0 +1,3 @@
1Basic snap
2
3A basic buildable snap
04
=== added file '_integration-tests/data/snaps/basic/meta/snappy64.png'
1Binary files _integration-tests/data/snaps/basic/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/basic/meta/snappy64.png 2015-09-16 17:51:11 +0000 differ5Binary files _integration-tests/data/snaps/basic/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/basic/meta/snappy64.png 2015-09-16 17:51:11 +0000 differ
=== added directory '_integration-tests/data/snaps/missing-readme'
=== added directory '_integration-tests/data/snaps/missing-readme/meta'
=== added file '_integration-tests/data/snaps/missing-readme/meta/package.yaml'
--- _integration-tests/data/snaps/missing-readme/meta/package.yaml 1970-01-01 00:00:00 +0000
+++ _integration-tests/data/snaps/missing-readme/meta/package.yaml 2015-09-16 17:51:11 +0000
@@ -0,0 +1,4 @@
1name: missing-readme
2version: 1.0
3vendor: Snappy Developers <snappy-devel@lists.ubuntu.com>
4icon: meta/snappy64.png
05
=== added file '_integration-tests/data/snaps/missing-readme/meta/snappy64.png'
1Binary files _integration-tests/data/snaps/missing-readme/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/missing-readme/meta/snappy64.png 2015-09-16 17:51:11 +0000 differ6Binary files _integration-tests/data/snaps/missing-readme/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/missing-readme/meta/snappy64.png 2015-09-16 17:51:11 +0000 differ
=== added directory '_integration-tests/data/snaps/wrong-yaml'
=== added directory '_integration-tests/data/snaps/wrong-yaml/meta'
=== added file '_integration-tests/data/snaps/wrong-yaml/meta/package.yaml'
--- _integration-tests/data/snaps/wrong-yaml/meta/package.yaml 1970-01-01 00:00:00 +0000
+++ _integration-tests/data/snaps/wrong-yaml/meta/package.yaml 2015-09-16 17:51:11 +0000
@@ -0,0 +1,5 @@
1# This is an invalid yaml, there's a missing colon after the 'name' field
2name wrong-yaml
3version: 1.0
4vendor: Snappy Developers <snappy-devel@lists.ubuntu.com>
5icon: meta/snappy64.png
06
=== added file '_integration-tests/data/snaps/wrong-yaml/meta/readme.md'
--- _integration-tests/data/snaps/wrong-yaml/meta/readme.md 1970-01-01 00:00:00 +0000
+++ _integration-tests/data/snaps/wrong-yaml/meta/readme.md 2015-09-16 17:51:11 +0000
@@ -0,0 +1,3 @@
1Wrong metadata snap
2
3A snap with an invalid meta/package.yaml
04
=== added file '_integration-tests/data/snaps/wrong-yaml/meta/snappy64.png'
1Binary files _integration-tests/data/snaps/wrong-yaml/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/wrong-yaml/meta/snappy64.png 2015-09-16 17:51:11 +0000 differ5Binary files _integration-tests/data/snaps/wrong-yaml/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/wrong-yaml/meta/snappy64.png 2015-09-16 17:51:11 +0000 differ
=== added directory '_integration-tests/data/tpl'
=== added file '_integration-tests/data/tpl/control'
--- _integration-tests/data/tpl/control 1970-01-01 00:00:00 +0000
+++ _integration-tests/data/tpl/control 2015-09-16 17:51:11 +0000
@@ -0,0 +1,4 @@
1{{ $filter := .Filter }}
2{{ $test := .Test }}
3Test-Command: ./_integration-tests/reboot-wrapper {{ $test }} {{ if $filter }}-gocheck.f {{ $filter }}{{ end }}
4Restrictions: allow-stderr
05
=== added file '_integration-tests/main.go'
--- _integration-tests/main.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/main.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,105 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package main
21
22import (
23 "flag"
24 "log"
25 "os"
26 "path/filepath"
27 "strconv"
28
29 "launchpad.net/snappy/_integration-tests/testutils"
30 "launchpad.net/snappy/_integration-tests/testutils/autopkgtest"
31 "launchpad.net/snappy/_integration-tests/testutils/build"
32 "launchpad.net/snappy/_integration-tests/testutils/config"
33 "launchpad.net/snappy/_integration-tests/testutils/image"
34)
35
36const (
37 baseDir = "/tmp/snappy-test"
38 defaultRelease = "rolling"
39 defaultChannel = "edge"
40 defaultSSHPort = 22
41 dataOutputDir = "_integration-tests/data/output/"
42)
43
44var configFileName = filepath.Join(dataOutputDir, "testconfig.json")
45
46func main() {
47 var (
48 useSnappyFromBranch = flag.Bool("snappy-from-branch", false,
49 "If this flag is used, snappy will be compiled from this branch, copied to the testbed and used for the tests. Otherwise, the snappy installed with the image will be used.")
50 arch = flag.String("arch", "",
51 "Architecture of the test bed. Defaults to use the same architecture as the host.")
52 testbedIP = flag.String("ip", "",
53 "IP of the testbed. If no IP is passed, a virtual machine will be created for the test.")
54 testbedPort = flag.Int("port", defaultSSHPort,
55 "SSH port of the testbed. Defaults to use port "+strconv.Itoa(defaultSSHPort))
56 testFilter = flag.String("filter", "",
57 "Suites or tests to run, for instance MyTestSuite, MyTestSuite.FirstCustomTest or MyTestSuite.*CustomTest")
58 imgRelease = flag.String("release", defaultRelease,
59 "Release of the image to be built, defaults to "+defaultRelease)
60 imgChannel = flag.String("channel", defaultChannel,
61 "Channel of the image to be built, defaults to "+defaultChannel)
62 imgRevision = flag.String("revision", "",
63 "Revision of the image to be built (can be relative to the latest available revision in the given release and channel as in -1), defaults to the empty string")
64 update = flag.Bool("update", false,
65 "If this flag is used, the image will be updated before running the tests.")
66 targetRelease = flag.String("target-release", "",
67 "If the update flag is used, the image will be updated to this release before running the tests.")
68 targetChannel = flag.String("target-channel", "",
69 "If the update flag is used, the image will be updated to this channel before running the tests.")
70 rollback = flag.Bool("rollback", false,
71 "If this flag is used, the image will be updated and then rolled back before running the tests.")
72 )
73
74 flag.Parse()
75
76 build.Assets(*useSnappyFromBranch, *arch)
77
78 // TODO: generate the files out of the source tree. --elopio - 2015-07-15
79 testutils.PrepareTargetDir(dataOutputDir)
80 defer os.RemoveAll(dataOutputDir)
81
82 remoteTestbed := *testbedIP != ""
83
84 // TODO: pass the config as arguments to the test binaries.
85 // --elopio - 2015-07-15
86 cfg := config.NewConfig(
87 configFileName, *imgRelease, *imgChannel, *targetRelease, *targetChannel,
88 remoteTestbed, *update, *rollback)
89 cfg.Write()
90
91 rootPath := testutils.RootPath()
92
93 test := autopkgtest.NewAutopkgtest(rootPath, baseDir, *testFilter, build.IntegrationTestName)
94 if !remoteTestbed {
95 img := image.NewImage(*imgRelease, *imgChannel, *imgRevision, baseDir)
96
97 if imagePath, err := img.UdfCreate(); err == nil {
98 test.AdtRunLocal(imagePath)
99 } else {
100 log.Panic(err.Error())
101 }
102 } else {
103 test.AdtRunRemote(*testbedIP, *testbedPort)
104 }
105}
0106
=== added file '_integration-tests/reboot-wrapper'
--- _integration-tests/reboot-wrapper 1970-01-01 00:00:00 +0000
+++ _integration-tests/reboot-wrapper 2015-09-16 17:51:11 +0000
@@ -0,0 +1,35 @@
1#!/bin/sh
2
3# Copyright (C) 2015 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
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 General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17# This runs the $1 go test binary and reboots if necessary.
18
19set -e
20
21TEST=$1
22NEEDS_REBOOT=/tmp/needs-reboot
23
24export PATH=$(pwd)/_integration-tests/bin:$PATH
25
26# shift to remove the test binary name (first argument) and be able to pass the rest
27# of them to it
28shift
29${TEST} -check.vv -test.outputdir=$ADT_ARTIFACTS-$ADT_REBOOT_MARK "$@"
30
31if [ -e ${NEEDS_REBOOT} ]; then
32 mark=`cat ${NEEDS_REBOOT}`
33 echo "Rebooting..."
34 sudo /tmp/autopkgtest-reboot "$mark"
35fi
036
=== added directory '_integration-tests/tests'
=== added file '_integration-tests/tests/apt_test.go'
--- _integration-tests/tests/apt_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/apt_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,39 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 . "launchpad.net/snappy/_integration-tests/testutils/common"
24
25 check "gopkg.in/check.v1"
26)
27
28var _ = check.Suite(&aptSuite{})
29
30type aptSuite struct {
31 SnappySuite
32}
33
34func (s *aptSuite) TestAptGetMustPrintError(c *check.C) {
35 aptOutput := ExecCommand(c, "apt-get", "update")
36
37 expected := "Ubuntu Core does not use apt-get, see 'snappy --help'!\n"
38 c.Assert(aptOutput, check.Equals, expected)
39}
040
=== added file '_integration-tests/tests/base_test.go'
--- _integration-tests/tests/base_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/base_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,29 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "testing"
24
25 . "gopkg.in/check.v1"
26)
27
28// Hook up gocheck into the "go test" runner.
29func Test(t *testing.T) { TestingT(t) }
030
=== added file '_integration-tests/tests/build_test.go'
--- _integration-tests/tests/build_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/build_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,90 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24 "os"
25 "os/exec"
26
27 . "launchpad.net/snappy/_integration-tests/testutils/common"
28
29 . "gopkg.in/check.v1"
30)
31
32const (
33 baseSnapPath = "_integration-tests/data/snaps"
34 basicSnapName = "basic"
35 wrongYamlSnapName = "wrong-yaml"
36 missingReadmeSnapName = "missing-readme"
37)
38
39var _ = Suite(&buildSuite{})
40
41type buildSuite struct {
42 SnappySuite
43}
44
45func buildSnap(c *C, snapPath string) string {
46 return ExecCommand(c, "snappy", "build", snapPath)
47}
48
49func (s *buildSuite) TestBuildBasicSnapOnSnappy(c *C) {
50 // build basic snap and check output
51 snapPath := baseSnapPath + "/" + basicSnapName
52 buildOutput := buildSnap(c, snapPath)
53 snapName := basicSnapName + "_1.0_all.snap"
54 expected := fmt.Sprintf("Generated '%s' snap\n", snapName)
55 c.Check(buildOutput, Equals, expected)
56 defer os.Remove(snapPath + "/" + snapName)
57
58 // install built snap and check output
59 installOutput := InstallSnap(c, snapName)
60 defer RemoveSnap(c, basicSnapName)
61 expected = "(?ms)" +
62 "Installing " + snapName + "\n" +
63 ".*Signature check failed, but installing anyway as requested\n" +
64 "Name +Date +Version +Developer \n" +
65 ".*\n" +
66 basicSnapName + " +.* +.* +sideload \n" +
67 ".*\n"
68
69 c.Check(installOutput, Matches, expected)
70
71 // teardown, remove snap file
72 c.Assert(os.Remove(snapName), IsNil, Commentf("Error removing %s", snapName))
73}
74
75func (s *buildSuite) TestBuildWrongYamlSnapOnSnappy(c *C) {
76 commonWrongTest(c, wrongYamlSnapName, "(?msi).*Can not parse.*yaml: line 2: mapping values are not allowed in this context.*")
77}
78
79func (s *buildSuite) TestBuildMissingReadmeSnapOnSnappy(c *C) {
80 commonWrongTest(c, missingReadmeSnapName, ".*readme.md: no such file or directory\n")
81}
82
83func commonWrongTest(c *C, testName, expected string) {
84 // build wrong snap and check output
85 cmd := exec.Command("snappy", "build", fmt.Sprintf("%s/%s", baseSnapPath, testName))
86 echoOutput, err := cmd.CombinedOutput()
87 c.Assert(err, NotNil, Commentf("%s should not be built", testName))
88
89 c.Assert(string(echoOutput), Matches, expected)
90}
091
=== added file '_integration-tests/tests/failover_rclocal_crash_test.go'
--- _integration-tests/tests/failover_rclocal_crash_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/failover_rclocal_crash_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,54 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24
25 . "launchpad.net/snappy/_integration-tests/testutils/common"
26
27 check "gopkg.in/check.v1"
28)
29
30type rcLocalCrash struct{}
31
32func (rcLocalCrash) set(c *check.C) {
33 MakeWritable(c, BaseAltPartitionPath)
34 defer MakeReadonly(c, BaseAltPartitionPath)
35 targetFile := fmt.Sprintf("%s/etc/rc.local", BaseAltPartitionPath)
36 ExecCommand(c, "sudo", "chmod", "a+xw", targetFile)
37 ExecCommandToFile(c, targetFile,
38 "sudo", "echo", "#!bin/sh\nprintf c > /proc/sysrq-trigger")
39}
40
41func (rcLocalCrash) unset(c *check.C) {
42 MakeWritable(c, BaseAltPartitionPath)
43 defer MakeReadonly(c, BaseAltPartitionPath)
44 ExecCommand(c, "sudo", "rm", fmt.Sprintf("%s/etc/rc.local", BaseAltPartitionPath))
45}
46
47/*
48TODO: uncomment when bug https://bugs.launchpad.net/snappy/+bug/1476129 is fixed
49(fgimenez 20150728)
50
51func (s *failoverSuite) TestRCLocalCrash(c *check.C) {
52 commonFailoverTest(c, rcLocalCrash{})
53}
54*/
055
=== added file '_integration-tests/tests/failover_systemd_loop_test.go'
--- _integration-tests/tests/failover_systemd_loop_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/failover_systemd_loop_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,114 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24
25 . "launchpad.net/snappy/_integration-tests/testutils/common"
26
27 check "gopkg.in/check.v1"
28)
29
30const (
31 deadlockService = `[Unit]
32Before=sysinit.target
33DefaultDependencies=no
34
35[Service]
36Type=oneshot
37ExecStartPre=-/bin/sh -c "echo 'DEBUG: $(date): deadlocked system' >/dev/console"
38ExecStartPre=-/bin/sh -c "echo 'DEBUG: $(date): deadlocked system' >/dev/ttyS0"
39ExecStart=/bin/systemctl start deadlock.service
40RemainAfterExit=yes
41
42[Install]
43RequiredBy=sysinit.target
44`
45 rebootService = `[Unit]
46DefaultDependencies=no
47Description=Hack to force reboot if booting did not finish after 20s
48
49[Service]
50Type=oneshot
51ExecStartPre=/bin/sleep 20
52ExecStart=-/bin/sh -c 'if ! systemctl is-active default.target; then wall "EMERGENCY REBOOT"; reboot -f; fi'
53
54[Install]
55RequiredBy=sysinit.target
56`
57 baseSystemdPath = "/lib/systemd/system"
58 systemdTargetRequiresDir = "sysinit.target.requires"
59)
60
61type systemdDependencyLoop struct{}
62
63func (systemdDependencyLoop) set(c *check.C) {
64 installService(c, "deadlock", deadlockService, BaseAltPartitionPath)
65 installService(c, "emerg-reboot", rebootService, BaseAltPartitionPath)
66}
67
68func (systemdDependencyLoop) unset(c *check.C) {
69 unInstallService(c, "deadlock", BaseAltPartitionPath)
70 unInstallService(c, "emerg-reboot", BaseAltPartitionPath)
71}
72
73func installService(c *check.C, serviceName, serviceCfg, basePath string) {
74 MakeWritable(c, basePath)
75 defer MakeReadonly(c, basePath)
76
77 // Create service file
78 serviceFile := fmt.Sprintf("%s%s/%s.service", basePath, baseSystemdPath, serviceName)
79 ExecCommand(c, "sudo", "chmod", "a+w", fmt.Sprintf("%s%s", basePath, baseSystemdPath))
80 ExecCommandToFile(c, serviceFile, "sudo", "echo", serviceCfg)
81
82 // Create requires directory
83 requiresDirPart := fmt.Sprintf("%s/%s", baseSystemdPath, systemdTargetRequiresDir)
84 requiresDir := fmt.Sprintf("%s%s", basePath, requiresDirPart)
85 ExecCommand(c, "sudo", "mkdir", "-p", requiresDir)
86
87 // Symlink from the requires dir to the service file (with chroot for being
88 // usable in the other partition)
89 ExecCommand(c, "sudo", "chroot", basePath, "ln", "-s",
90 fmt.Sprintf("%s/%s.service", baseSystemdPath, serviceName),
91 fmt.Sprintf("%s/%s.service", requiresDirPart, serviceName),
92 )
93}
94
95func unInstallService(c *check.C, serviceName, basePath string) {
96 MakeWritable(c, basePath)
97 defer MakeReadonly(c, basePath)
98
99 // Disable the service
100 ExecCommand(c, "sudo", "chroot", basePath,
101 "systemctl", "disable", fmt.Sprintf("%s.service", serviceName))
102
103 // Remove the service file
104 ExecCommand(c, "sudo", "rm",
105 fmt.Sprintf("%s%s/%s.service", basePath, baseSystemdPath, serviceName))
106
107 // Remove the requires symlink
108 ExecCommand(c, "sudo", "rm",
109 fmt.Sprintf("%s%s/%s/%s.service", basePath, baseSystemdPath, systemdTargetRequiresDir, serviceName))
110}
111
112func (s *failoverSuite) TestSystemdDependencyLoop(c *check.C) {
113 commonFailoverTest(c, systemdDependencyLoop{})
114}
0115
=== added file '_integration-tests/tests/failover_test.go'
--- _integration-tests/tests/failover_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/failover_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,58 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 check "gopkg.in/check.v1"
24
25 . "launchpad.net/snappy/_integration-tests/testutils/common"
26)
27
28var _ = check.Suite(&failoverSuite{})
29
30type failoverSuite struct {
31 SnappySuite
32}
33
34// The types that implement this interface can be used in the test logic
35type failer interface {
36 // Sets the failure conditions
37 set(c *check.C)
38 // Unsets the failure conditions
39 unset(c *check.C)
40}
41
42// This is the logic common to all the failover tests. Each of them has define a
43// type implementing the failer interface and call this function with an instance
44// of it
45func commonFailoverTest(c *check.C, f failer) {
46 currentVersion := GetCurrentUbuntuCoreVersion(c)
47
48 if AfterReboot(c) {
49 RemoveRebootMark(c)
50 f.unset(c)
51 c.Assert(GetSavedVersion(c), check.Equals, currentVersion)
52 } else {
53 SetSavedVersion(c, currentVersion-1)
54 CallFakeUpdate(c)
55 f.set(c)
56 Reboot(c)
57 }
58}
059
=== added file '_integration-tests/tests/failover_zero_size_file_test.go'
--- _integration-tests/tests/failover_zero_size_file_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/failover_zero_size_file_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,258 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "bufio"
24 "fmt"
25 "os"
26 "path/filepath"
27 "strings"
28
29 . "launchpad.net/snappy/_integration-tests/testutils/common"
30
31 check "gopkg.in/check.v1"
32)
33
34const (
35 origBootFilenamePattern = "boot/%s%s*"
36 origSystemdFilenamePattern = "lib/systemd/%s%s"
37 kernelFilename = "vmlinuz"
38 initrdFilename = "initrd"
39 systemdFilename = "systemd"
40 destFilenamePrefix = "snappy-selftest-"
41 bootBase = "/boot"
42 ubootDir = bootBase + "/uboot"
43 grubDir = bootBase + "/grub"
44 ubootConfigFile = ubootDir + "/snappy-system.txt"
45 grubConfigFile = grubDir + "/grubenv"
46)
47
48type zeroSizeKernel struct{}
49type zeroSizeInitrd struct{}
50type zeroSizeSystemd struct{}
51
52func (zeroSizeKernel) set(c *check.C) {
53 commonSet(c, BaseAltPartitionPath, origBootFilenamePattern, kernelFilename)
54}
55
56func (zeroSizeKernel) unset(c *check.C) {
57 commonUnset(c, BaseAltPartitionPath, origBootFilenamePattern, kernelFilename)
58}
59
60func (zeroSizeInitrd) set(c *check.C) {
61 if classicKernelFiles(c) {
62 commonSet(c, BaseAltPartitionPath, origBootFilenamePattern, initrdFilename)
63 } else {
64 boot := bootSystem(c)
65 dir := bootDirectory(boot)
66 bootFileNamePattern := newKernelFilenamePattern(c, boot, true)
67 commonSet(c, dir, bootFileNamePattern, initrdFilename)
68 }
69}
70
71func (zeroSizeInitrd) unset(c *check.C) {
72 if classicKernelFiles(c) {
73 commonUnset(c, BaseAltPartitionPath, origBootFilenamePattern, initrdFilename)
74 } else {
75 boot := bootSystem(c)
76 dir := bootDirectory(boot)
77 bootFileNamePattern := newKernelFilenamePattern(c, boot, false)
78 commonUnset(c, dir, bootFileNamePattern, initrdFilename)
79 }
80}
81
82func (zeroSizeSystemd) set(c *check.C) {
83 commonSet(c, BaseAltPartitionPath, origSystemdFilenamePattern, systemdFilename)
84}
85
86func (zeroSizeSystemd) unset(c *check.C) {
87 commonUnset(c, BaseAltPartitionPath, origSystemdFilenamePattern, systemdFilename)
88}
89
90func commonSet(c *check.C, baseOtherPath, origPattern, filename string) {
91 filenamePattern := fmt.Sprintf(origPattern, "", filename)
92 completePattern := filepath.Join(
93 baseOtherPath,
94 filenamePattern)
95 oldFilename := getSingleFilename(c, completePattern)
96 filenameSuffix := fmt.Sprintf(
97 strings.Replace(origPattern, "*", "", 1), destFilenamePrefix, filepath.Base(oldFilename))
98 newFilename := fmt.Sprintf(
99 "%s/%s", baseOtherPath, filenameSuffix)
100
101 renameFile(c, baseOtherPath, oldFilename, newFilename, true)
102}
103
104func commonUnset(c *check.C, baseOtherPath, origPattern, filename string) {
105 completePattern := filepath.Join(
106 baseOtherPath,
107 fmt.Sprintf(origPattern, destFilenamePrefix, filename))
108 oldFilename := getSingleFilename(c, completePattern)
109 newFilename := strings.Replace(oldFilename, destFilenamePrefix, "", 1)
110
111 renameFile(c, baseOtherPath, oldFilename, newFilename, false)
112}
113
114func renameFile(c *check.C, basePath, oldFilename, newFilename string, keepOld bool) {
115 // Only need to make writable and revert for BaseAltPartitionPath,
116 // kernel files' boot directory is writable
117 if basePath == BaseAltPartitionPath {
118 MakeWritable(c, basePath)
119 defer MakeReadonly(c, basePath)
120 }
121
122 ExecCommand(c, "sudo", "mv", oldFilename, newFilename)
123
124 if keepOld {
125 ExecCommand(c, "sudo", "touch", oldFilename)
126 mode := getFileMode(c, newFilename)
127 ExecCommand(c, "sudo", "chmod", fmt.Sprintf("%o", mode), oldFilename)
128 }
129}
130
131func getFileMode(c *check.C, filePath string) os.FileMode {
132 info, err := os.Stat(filePath)
133 c.Check(err, check.IsNil, check.Commentf("Error getting Stat of %s", filePath))
134
135 return info.Mode()
136}
137
138func getSingleFilename(c *check.C, pattern string) string {
139 matches, err := filepath.Glob(pattern)
140
141 c.Assert(err, check.IsNil, check.Commentf("Error: %v", err))
142 c.Assert(len(matches), check.Equals, 1,
143 check.Commentf("%d files matching %s, 1 expected", len(matches), pattern))
144
145 return matches[0]
146}
147
148func classicKernelFiles(c *check.C) bool {
149 initrdClassicFilenamePattern := fmt.Sprintf("/boot/%s*-generic", initrdFilename)
150 matches, err := filepath.Glob(initrdClassicFilenamePattern)
151
152 c.Assert(err, check.IsNil, check.Commentf("Error: %v", err))
153
154 return len(matches) == 1
155}
156
157func bootSystem(c *check.C) string {
158 matches, err := filepath.Glob(bootBase + "/grub")
159
160 c.Assert(err, check.IsNil, check.Commentf("Error: %v", err))
161
162 if len(matches) == 1 {
163 return "grub"
164 }
165 return "uboot"
166}
167
168func bootDirectory(bootSystem string) string {
169 if bootSystem == "grub" {
170 return grubDir
171 }
172 return ubootDir
173}
174
175func bootConfigFile(bootSystem string) string {
176 if bootSystem == "grub" {
177 return grubConfigFile
178 }
179 return ubootConfigFile
180}
181
182func currentPartition(c *check.C, bootSystem string) (partition string) {
183 bootConfigFile := bootConfigFile(bootSystem)
184 file, err := os.Open(bootConfigFile)
185
186 c.Assert(err, check.IsNil,
187 check.Commentf("Error reading boot config file %s", bootConfigFile))
188
189 defer file.Close()
190
191 reader := bufio.NewReader(file)
192 scanner := bufio.NewScanner(reader)
193
194 scanner.Split(bufio.ScanLines)
195
196 for scanner.Scan() {
197 if strings.HasPrefix(scanner.Text(), "snappy_ab") {
198 fields := strings.Split(scanner.Text(), "=")
199 if len(fields) > 1 {
200 if bootSystem == "grub" {
201 partition = fields[1]
202 } else {
203 partition = otherPart(fields[1])
204 }
205 }
206 return
207 }
208 }
209 return
210}
211
212func otherPart(current string) string {
213 if current == "a" {
214 return "b"
215 }
216 return "a"
217}
218
219// newKernelFilenamePattern returns the filename pattern to modify files
220// in the partition declared in the boot config file.
221//
222// After the update, the config file is already changed to point to the new partition.
223// If we are on a and update, the config file would point to b
224// and this function would return "b/%s%s*"
225// If we are not in an update process (ie. we are unsetting the failover conditions)
226// we want to change the files in the other partition
227func newKernelFilenamePattern(c *check.C, bootSystem string, afterUpdate bool) string {
228 var actualPartition string
229 partition := currentPartition(c, bootSystem)
230 if afterUpdate {
231 actualPartition = partition
232 } else {
233 actualPartition = otherPart(partition)
234 }
235 return filepath.Join(actualPartition, "%s%s*")
236}
237
238/*
239TODO: uncomment when bug https://bugs.launchpad.net/snappy/+bug/1467553 is fixed
240(fgimenez 20150729)
241
242func (s *failoverSuite) TestZeroSizeKernel(c *check.C) {
243 commonFailoverTest(c, zeroSizeKernel{})
244}
245*/
246
247func (s *failoverSuite) TestZeroSizeInitrd(c *check.C) {
248 // Skip if on uboot due to https://bugs.launchpad.net/snappy/+bug/1480248
249 // (fgimenez 20150731)
250 if bootSystem(c) == "uboot" {
251 c.Skip("Failover for empty initrd not working in uboot")
252 }
253 commonFailoverTest(c, zeroSizeInitrd{})
254}
255
256func (s *failoverSuite) TestZeroSizeSystemd(c *check.C) {
257 commonFailoverTest(c, zeroSizeSystemd{})
258}
0259
=== added file '_integration-tests/tests/info_test.go'
--- _integration-tests/tests/info_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/info_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,79 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24
25 . "launchpad.net/snappy/_integration-tests/testutils/common"
26
27 check "gopkg.in/check.v1"
28)
29
30var _ = check.Suite(&infoSuite{})
31
32type infoSuite struct {
33 SnappySuite
34}
35
36func (s *infoSuite) TestInfoMustPrintReleaseAndChannel(c *check.C) {
37 // skip test when having a remote testbed (we can't know which the
38 // release and channels are)
39 if Cfg.RemoteTestbed {
40 c.Skip(fmt.Sprintf(
41 "Skipping %s while testing in remote testbed",
42 c.TestName()))
43 }
44
45 infoOutput := ExecCommand(c, "snappy", "info")
46
47 expected := "(?ms)" +
48 fmt.Sprintf("^release: ubuntu-core/%s/%s\n", Cfg.Release, Cfg.Channel) +
49 ".*"
50
51 c.Assert(infoOutput, check.Matches, expected)
52}
53
54func (s *infoSuite) TestInfoMustPrintInstalledApps(c *check.C) {
55 InstallSnap(c, "hello-world")
56 s.AddCleanup(func() {
57 RemoveSnap(c, "hello-world")
58 })
59 infoOutput := ExecCommand(c, "snappy", "info")
60
61 expected := "(?ms)" +
62 ".*" +
63 "^apps: .*hello-world.*\n"
64 c.Assert(infoOutput, check.Matches, expected)
65}
66
67func (s *infoSuite) TestInfoMustPrintInstalledFrameworks(c *check.C) {
68 InstallSnap(c, "hello-dbus-fwk.canonical")
69 s.AddCleanup(func() {
70 RemoveSnap(c, "hello-dbus-fwk.canonical")
71 })
72 infoOutput := ExecCommand(c, "snappy", "info")
73
74 expected := "(?ms)" +
75 ".*" +
76 "^frameworks: .*hello-dbus-fwk.*\n" +
77 ".*"
78 c.Assert(infoOutput, check.Matches, expected)
79}
080
=== added file '_integration-tests/tests/installApp_test.go'
--- _integration-tests/tests/installApp_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/installApp_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,128 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24 "net/http"
25 "os/exec"
26 "time"
27
28 . "launchpad.net/snappy/_integration-tests/testutils/common"
29
30 check "gopkg.in/check.v1"
31)
32
33var _ = check.Suite(&installAppSuite{})
34
35type installAppSuite struct {
36 SnappySuite
37}
38
39func (s *installAppSuite) TestInstallAppMustPrintPackageInformation(c *check.C) {
40 installOutput := InstallSnap(c, "hello-world")
41 s.AddCleanup(func() {
42 RemoveSnap(c, "hello-world")
43 })
44
45 expected := "(?ms)" +
46 "Installing hello-world\n" +
47 "Name +Date +Version +Developer \n" +
48 ".*" +
49 "^hello-world +.* +.* +canonical \n" +
50 ".*"
51
52 c.Assert(installOutput, check.Matches, expected)
53}
54
55func (s *installAppSuite) TestCallBinaryFromInstalledSnap(c *check.C) {
56 InstallSnap(c, "hello-world")
57 s.AddCleanup(func() {
58 RemoveSnap(c, "hello-world")
59 })
60
61 echoOutput := ExecCommand(c, "hello-world.echo")
62
63 c.Assert(echoOutput, check.Equals, "Hello World!\n")
64}
65
66func (s *installAppSuite) TestCallBinaryWithPermissionDeniedMustPrintError(c *check.C) {
67 InstallSnap(c, "hello-world")
68 s.AddCleanup(func() {
69 RemoveSnap(c, "hello-world")
70 })
71
72 cmd := exec.Command("hello-world.evil")
73 echoOutput, err := cmd.CombinedOutput()
74 c.Assert(err, check.NotNil, check.Commentf("hello-world.evil did not fail"))
75
76 expected := "" +
77 "Hello Evil World!\n" +
78 "This example demonstrates the app confinement\n" +
79 "You should see a permission denied error next\n" +
80 "/apps/hello-world.canonical/.*/bin/evil: \\d+: " +
81 "/apps/hello-world.canonical/.*/bin/evil: " +
82 "cannot create /var/tmp/myevil.txt: Permission denied\n"
83
84 c.Assert(string(echoOutput), check.Matches, expected)
85}
86
87func (s *installAppSuite) TestInfoMustPrintInstalledPackageInformation(c *check.C) {
88 InstallSnap(c, "hello-world")
89 s.AddCleanup(func() {
90 RemoveSnap(c, "hello-world")
91 })
92
93 infoOutput := ExecCommand(c, "snappy", "info")
94
95 expected := "(?ms).*^apps: hello-world\n"
96 c.Assert(infoOutput, check.Matches, expected)
97}
98
99func (s *installAppSuite) TestAppNetworkingServiceMustBeStarted(c *check.C) {
100 baseAppName := "xkcd-webserver"
101 appName := baseAppName + ".canonical"
102 InstallSnap(c, appName)
103 s.AddCleanup(func() {
104 RemoveSnap(c, appName)
105 })
106
107 appVersion := GetCurrentVersion(c, baseAppName)
108 appService := fmt.Sprintf("%s_%s_%s.service", baseAppName, baseAppName, appVersion)
109
110 err := WaitForActiveService(c, appService)
111 c.Assert(err, check.IsNil)
112
113 time.Sleep(1 * time.Second)
114 resp, err := http.Get("http://localhost")
115 c.Assert(err, check.IsNil)
116 c.Check(resp.Status, check.Equals, "200 OK")
117 c.Assert(resp.Proto, check.Equals, "HTTP/1.0")
118}
119
120func (s *installAppSuite) TestInstallUnexistingAppMustPrintError(c *check.C) {
121 cmd := exec.Command("sudo", "snappy", "install", "unexisting.canonical")
122 output, err := cmd.CombinedOutput()
123
124 c.Assert(err, check.NotNil)
125 c.Assert(string(output), check.Equals,
126 "Installing unexisting.canonical\n"+
127 "unexisting.canonical failed to install: snappy package not found\n")
128}
0129
=== added file '_integration-tests/tests/installFramework_test.go'
--- _integration-tests/tests/installFramework_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/installFramework_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,93 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24 "regexp"
25
26 . "launchpad.net/snappy/_integration-tests/testutils/common"
27
28 check "gopkg.in/check.v1"
29)
30
31var _ = check.Suite(&installFrameworkSuite{})
32
33type installFrameworkSuite struct {
34 SnappySuite
35}
36
37func (s *installFrameworkSuite) TearDownTest(c *check.C) {
38 if !NeedsReboot() && CheckRebootMark("") {
39 RemoveSnap(c, "docker")
40 }
41 // run cleanup last
42 s.SnappySuite.TearDownTest(c)
43}
44
45func isDockerServiceRunning(c *check.C) bool {
46 dockerVersion := GetCurrentVersion(c, "docker")
47 dockerService := fmt.Sprintf("docker_docker-daemon_%s.service", dockerVersion)
48
49 err := WaitForActiveService(c, dockerService)
50 c.Assert(err, check.IsNil)
51
52 statusOutput := ExecCommand(
53 c, "systemctl", "status",
54 dockerService)
55
56 expected := "(?ms)" +
57 ".* docker_docker-daemon_.*\\.service .*\n" +
58 ".*Loaded: loaded .*\n" +
59 ".*Active: active \\(running\\) .*\n" +
60 ".*"
61
62 matched, err := regexp.MatchString(expected, statusOutput)
63 c.Assert(err, check.IsNil)
64 return matched
65}
66
67func (s *installFrameworkSuite) TestInstallFrameworkMustPrintPackageInformation(c *check.C) {
68 installOutput := InstallSnap(c, "docker")
69
70 expected := "(?ms)" +
71 "Installing docker\n" +
72 "Name +Date +Version +Developer \n" +
73 ".*" +
74 "^docker +.* +.* +canonical \n" +
75 ".*"
76
77 c.Assert(installOutput, check.Matches, expected)
78}
79
80func (s *installFrameworkSuite) TestInstalledFrameworkServiceMustBeStarted(c *check.C) {
81 InstallSnap(c, "docker")
82 c.Assert(isDockerServiceRunning(c), check.Equals, true)
83}
84
85func (s *installFrameworkSuite) TestFrameworkServiceMustBeStartedAfterReboot(c *check.C) {
86 if BeforeReboot() {
87 InstallSnap(c, "docker")
88 Reboot(c)
89 } else if AfterReboot(c) {
90 RemoveRebootMark(c)
91 c.Assert(isDockerServiceRunning(c), check.Equals, true)
92 }
93}
094
=== added file '_integration-tests/tests/list_test.go'
--- _integration-tests/tests/list_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/list_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,78 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "fmt"
24 "os"
25
26 . "launchpad.net/snappy/_integration-tests/testutils/common"
27
28 "github.com/mvo5/goconfigparser"
29 check "gopkg.in/check.v1"
30)
31
32var _ = check.Suite(&listSuite{})
33
34type listSuite struct {
35 SnappySuite
36}
37
38func getVersionFromConfig(c *check.C) string {
39 cfg := goconfigparser.New()
40 f, err := os.Open("/etc/system-image/channel.ini")
41 c.Assert(err, check.IsNil,
42 check.Commentf("Error opening the config file: %v:", err))
43 defer f.Close()
44 err = cfg.Read(f)
45 c.Assert(err, check.IsNil,
46 check.Commentf("Error parsing the config file: %v", err))
47 version, err := cfg.Get("service", "build_number")
48 c.Assert(err, check.IsNil,
49 check.Commentf("Error getting the build number: %v", err))
50 return version
51}
52
53func (s *listSuite) TestListMustPrintCoreVersion(c *check.C) {
54 listOutput := ExecCommand(c, "snappy", "list")
55
56 expected := "(?ms)" +
57 "Name +Date +Version +Developer *\n" +
58 ".*" +
59 fmt.Sprintf("^ubuntu-core +.* +%s +ubuntu *\n", getVersionFromConfig(c)) +
60 ".*"
61 c.Assert(listOutput, check.Matches, expected)
62}
63
64func (s *listSuite) TestListMustPrintAppVersion(c *check.C) {
65 InstallSnap(c, "hello-world")
66 s.AddCleanup(func() {
67 RemoveSnap(c, "hello-world")
68 })
69
70 listOutput := ExecCommand(c, "snappy", "list")
71 expected := "(?ms)" +
72 "Name +Date +Version +Developer *\n" +
73 ".*" +
74 "^hello-world +.* +(\\d+)(\\.\\d+)* +.* +.* *\n" +
75 ".*"
76
77 c.Assert(listOutput, check.Matches, expected)
78}
079
=== added file '_integration-tests/tests/rollback_test.go'
--- _integration-tests/tests/rollback_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/rollback_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,53 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "strconv"
24
25 . "launchpad.net/snappy/_integration-tests/testutils/common"
26
27 check "gopkg.in/check.v1"
28)
29
30var _ = check.Suite(&rollbackSuite{})
31
32type rollbackSuite struct {
33 SnappySuite
34}
35
36func (s *rollbackSuite) TestRollbackMustRebootToOtherVersion(c *check.C) {
37 if BeforeReboot() {
38 CallFakeUpdate(c)
39 Reboot(c)
40 } else if CheckRebootMark(c.TestName()) {
41 RemoveRebootMark(c)
42 currentVersion := GetCurrentUbuntuCoreVersion(c)
43 c.Assert(currentVersion > GetSavedVersion(c), check.Equals, true)
44 ExecCommand(c, "sudo", "snappy", "rollback", "ubuntu-core",
45 strconv.Itoa(GetSavedVersion(c)))
46 SetSavedVersion(c, currentVersion)
47 RebootWithMark(c, c.TestName()+"-rollback")
48 } else if CheckRebootMark(c.TestName() + "-rollback") {
49 RemoveRebootMark(c)
50 c.Assert(
51 GetCurrentUbuntuCoreVersion(c) < GetSavedVersion(c), check.Equals, true)
52 }
53}
054
=== added file '_integration-tests/tests/search_test.go'
--- _integration-tests/tests/search_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/search_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,44 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 . "launchpad.net/snappy/_integration-tests/testutils/common"
24
25 . "gopkg.in/check.v1"
26)
27
28var _ = Suite(&searchSuite{})
29
30type searchSuite struct {
31 SnappySuite
32}
33
34func (s *searchSuite) TestSearchFrameworkMustPrintMatch(c *C) {
35 searchOutput := ExecCommand(c, "snappy", "search", "hello-dbus-fwk")
36
37 expected := "(?ms)" +
38 "Name +Version +Summary *\n" +
39 ".*" +
40 "^hello-dbus-fwk +.* +hello-dbus-fwk *\n" +
41 ".*"
42
43 c.Assert(searchOutput, Matches, expected)
44}
045
=== added file '_integration-tests/tests/update_test.go'
--- _integration-tests/tests/update_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/update_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,51 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 . "launchpad.net/snappy/_integration-tests/testutils/common"
24
25 check "gopkg.in/check.v1"
26)
27
28var _ = check.Suite(&updateSuite{})
29
30type updateSuite struct {
31 SnappySuite
32}
33
34// Test that the update to the same release and channel must install a newer
35// version. If there is no update available, the channel version will be
36// modified to fake an update. If there is a version available, the image will
37// be up-to-date after running this test.
38func (s *updateSuite) TestUpdateToSameReleaseAndChannel(c *check.C) {
39 if BeforeReboot() {
40 updateOutput := CallFakeUpdate(c)
41 expected := "(?ms)" +
42 ".*" +
43 "^Reboot to use .*ubuntu-core.\n"
44 c.Assert(updateOutput, check.Matches, expected)
45 Reboot(c)
46 } else if AfterReboot(c) {
47 RemoveRebootMark(c)
48 c.Assert(GetCurrentUbuntuCoreVersion(c) > GetSavedVersion(c),
49 check.Equals, true)
50 }
51}
052
=== added file '_integration-tests/tests/writablePaths_test.go'
--- _integration-tests/tests/writablePaths_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/tests/writablePaths_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,106 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package tests
21
22import (
23 "bufio"
24 "fmt"
25 "os"
26 "os/exec"
27 "path/filepath"
28 "strings"
29
30 . "launchpad.net/snappy/_integration-tests/testutils/common"
31
32 check "gopkg.in/check.v1"
33)
34
35const writablePathsListFile = "/etc/system-image/writable-paths"
36
37var _ = check.Suite(&writablePathsSuite{})
38
39type writablePathsSuite struct {
40 SnappySuite
41}
42
43var IsWritable check.Checker = &isWritable{}
44
45type isWritable struct {
46}
47
48func (is *isWritable) Info() *check.CheckerInfo {
49 return &check.CheckerInfo{Name: "IsWritable", Params: []string{"path"}}
50}
51
52func (is *isWritable) Check(params []interface{}, names []string) (result bool, error string) {
53 if path, ok := params[0].(string); ok {
54 filename := filepath.Join(path, "tmpfile")
55
56 cmd := exec.Command("sudo", "touch", filename)
57 rmCmd := exec.Command("sudo", "rm", filename)
58 defer rmCmd.Run()
59
60 if _, err := cmd.CombinedOutput(); err == nil {
61 result = true
62 } else {
63 error = fmt.Sprintf("Error creating file %s", filename)
64 }
65 } else {
66 error = fmt.Sprintf("First param of checker %v is of type %T and it should be a string", params[0], params[0])
67 }
68 return result, error
69}
70
71func (s *writablePathsSuite) TestWritablePathsAreWritable(c *check.C) {
72 for writablePath := range generateWritablePaths(c) {
73 c.Logf("Checking if %s is writable", writablePath)
74 c.Check(writablePath, IsWritable)
75 }
76}
77
78func generateWritablePaths(c *check.C) chan string {
79 ch := make(chan string)
80
81 go func() {
82 file, err := os.Open(writablePathsListFile)
83
84 c.Assert(err, check.IsNil,
85 check.Commentf("Error reading writable files list %s", writablePathsListFile))
86
87 defer file.Close()
88
89 reader := bufio.NewReader(file)
90 scanner := bufio.NewScanner(reader)
91
92 scanner.Split(bufio.ScanLines)
93
94 for scanner.Scan() {
95 fields := strings.Fields(scanner.Text())
96 if len(fields) > 0 && fields[0] != "#" {
97 if src, err := os.Stat(fields[0]); err == nil && src.IsDir() {
98 ch <- fields[0]
99 }
100 }
101 }
102 close(ch)
103 }()
104
105 return ch
106}
0107
=== added directory '_integration-tests/testutils'
=== added directory '_integration-tests/testutils/autopkgtest'
=== added file '_integration-tests/testutils/autopkgtest/autopkgtest.go'
--- _integration-tests/testutils/autopkgtest/autopkgtest.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/autopkgtest/autopkgtest.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,111 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package autopkgtest
21
22import (
23 "fmt"
24 "os"
25 "path/filepath"
26 "strconv"
27 "text/template"
28
29 "log"
30
31 "launchpad.net/snappy/_integration-tests/testutils"
32)
33
34const (
35 controlTpl = "_integration-tests/data/tpl/control"
36 dataOutputDir = "_integration-tests/data/output/"
37)
38
39var controlFile = filepath.Join(dataOutputDir, "control")
40
41// Autopkgtest is the type that knows how to call adt-run
42type Autopkgtest struct {
43 sourceCodePath string // location of the source code on the host
44 testArtifactsPath string // location of the test artifacts on the host
45 testFilter string
46 integrationTestName string
47}
48
49// NewAutopkgtest is the Autopkgtest constructor
50func NewAutopkgtest(sourceCodePath, testArtifactsPath, testFilter, integrationTestName string) *Autopkgtest {
51 return &Autopkgtest{
52 sourceCodePath: sourceCodePath,
53 testArtifactsPath: testArtifactsPath,
54 testFilter: testFilter,
55 integrationTestName: integrationTestName}
56}
57
58// AdtRunLocal starts a kvm running the image passed as argument and runs the
59// autopkgtests using it as the testbed.
60func (a *Autopkgtest) AdtRunLocal(imgPath string) {
61 // Run the tests on the latest rolling edge image.
62 a.adtRun(kvmSSHOptions(imgPath))
63}
64
65// AdtRunRemote runs the autopkgtests using a remote machine as the testbed.
66func (a *Autopkgtest) AdtRunRemote(testbedIP string, testbedPort int) {
67 testutils.ExecCommand("ssh-copy-id", "-p", strconv.Itoa(testbedPort),
68 "ubuntu@"+testbedIP)
69 a.adtRun(remoteTestbedSSHOptions(testbedIP, testbedPort))
70}
71
72func (a *Autopkgtest) adtRun(testbedOptions []string) {
73 a.createControlFile()
74
75 fmt.Println("Calling adt-run...")
76 outputDir := filepath.Join(a.testArtifactsPath, "output")
77 testutils.PrepareTargetDir(outputDir)
78
79 cmd := []string{
80 "adt-run", "-B",
81 "--setup-commands", "touch /run/autopkgtest_no_reboot.stamp",
82 "--override-control", controlFile,
83 "--built-tree", a.sourceCodePath,
84 "--output-dir", outputDir}
85
86 testutils.ExecCommand(append(cmd, testbedOptions...)...)
87}
88
89func (a *Autopkgtest) createControlFile() {
90 type controlData struct {
91 Filter string
92 Test string
93 }
94
95 tpl, err := template.ParseFiles(controlTpl)
96 if err != nil {
97 log.Panicf("Error reading adt-run control template %s", controlTpl)
98 }
99
100 outputFile, err := os.Create(controlFile)
101 if err != nil {
102 log.Panicf("Error creating control file %s", controlFile)
103 }
104 defer outputFile.Close()
105
106 err = tpl.Execute(outputFile,
107 controlData{Test: a.integrationTestName, Filter: a.testFilter})
108 if err != nil {
109 log.Panicf("execution: %s", err)
110 }
111}
0112
=== added file '_integration-tests/testutils/autopkgtest/ssh.go'
--- _integration-tests/testutils/autopkgtest/ssh.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/autopkgtest/ssh.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,46 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package autopkgtest
21
22import (
23 "os"
24 "path/filepath"
25 "strconv"
26)
27
28var commonSSHOptions = []string{"---", "ssh"}
29
30func kvmSSHOptions(imagePath string) []string {
31 return append(
32 commonSSHOptions,
33 []string{
34 "-s", "/usr/share/autopkgtest/ssh-setup/snappy",
35 "--", "-i", imagePath}...)
36}
37
38func remoteTestbedSSHOptions(testbedIP string, testbedPort int) []string {
39 options := []string{
40 "-H", testbedIP,
41 "-p", strconv.Itoa(testbedPort),
42 "-l", "ubuntu",
43 "-i", filepath.Join(os.Getenv("HOME"), ".ssh", "id_rsa"),
44 "--reboot"}
45 return append(commonSSHOptions, options...)
46}
047
=== added directory '_integration-tests/testutils/build'
=== added file '_integration-tests/testutils/build/build.go'
--- _integration-tests/testutils/build/build.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/build/build.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,76 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package build
21
22import (
23 "fmt"
24 "os"
25
26 "launchpad.net/snappy/_integration-tests/testutils"
27)
28
29const (
30 // IntegrationTestName is the name of the test binary.
31 IntegrationTestName = "integration.test"
32 defaultGoArm = "7"
33 testsBinDir = "_integration-tests/bin/"
34)
35
36// Assets builds the snappy and integration tests binaries for the target
37// architecture.
38func Assets(useSnappyFromBranch bool, arch string) {
39 testutils.PrepareTargetDir(testsBinDir)
40
41 if useSnappyFromBranch {
42 // FIXME We need to build an image that has the snappy from the branch
43 // installed. --elopio - 2015-06-25.
44 buildSnappyCLI(arch)
45 }
46 buildTests(arch)
47}
48
49func buildSnappyCLI(arch string) {
50 fmt.Println("Building snappy CLI...")
51 // On the root of the project we have a directory called snappy, so we
52 // output the binary for the tests in the tests directory.
53 goCall(arch, "build", "-o", testsBinDir+"snappy", "./cmd/snappy")
54}
55
56func buildTests(arch string) {
57 fmt.Println("Building tests...")
58
59 goCall(arch, "test", "-c", "./_integration-tests/tests")
60 // XXX Go test 1.3 does not have the output flag, so we move the
61 // binaries after they are generated.
62 os.Rename("tests.test", testsBinDir+IntegrationTestName)
63}
64
65func goCall(arch string, cmds ...string) {
66 if arch != "" {
67 defer os.Setenv("GOARCH", os.Getenv("GOARCH"))
68 os.Setenv("GOARCH", arch)
69 if arch == "arm" {
70 defer os.Setenv("GOARM", os.Getenv("GOARM"))
71 os.Setenv("GOARM", defaultGoArm)
72 }
73 }
74 goCmd := append([]string{"go"}, cmds...)
75 testutils.ExecCommand(goCmd...)
76}
077
=== added directory '_integration-tests/testutils/common'
=== added file '_integration-tests/testutils/common/common.go'
--- _integration-tests/testutils/common/common.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/common/common.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,379 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package common
21
22import (
23 "fmt"
24 "io/ioutil"
25 "os"
26 "os/exec"
27 "path/filepath"
28 "regexp"
29 "strconv"
30 "strings"
31 "time"
32
33 check "gopkg.in/check.v1"
34
35 "launchpad.net/snappy/_integration-tests/testutils/config"
36)
37
38const (
39 // BaseAltPartitionPath is the path to the B system partition.
40 BaseAltPartitionPath = "/writable/cache/system"
41 needsRebootFile = "/tmp/needs-reboot"
42 channelCfgFile = "/etc/system-image/channel.ini"
43)
44
45// Cfg is a struct that contains the configuration values passed from the
46// host to the testbed.
47var Cfg *config.Config
48
49// SnappySuite is a structure used as a base test suite for all the snappy
50// integration tests.
51type SnappySuite struct {
52 cleanupHandlers []func()
53}
54
55// SetUpSuite disables the snappy autopilot. It will run before all the
56// integration suites.
57func (s *SnappySuite) SetUpSuite(c *check.C) {
58 ExecCommand(c, "sudo", "systemctl", "stop", "snappy-autopilot.timer")
59 ExecCommand(c, "sudo", "systemctl", "disable", "snappy-autopilot.timer")
60 if !isInRebootProcess() {
61 var err error
62 Cfg, err = config.ReadConfig(
63 "_integration-tests/data/output/testconfig.json")
64 c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
65 if Cfg.Update || Cfg.Rollback {
66 switchSystemImageConf(c, Cfg.TargetRelease, Cfg.TargetChannel, "0")
67 // Always use the installed snappy because we are updating from an old
68 // image, so we should not use the snappy from the branch.
69 output := ExecCommand(c, "sudo", "/usr/bin/snappy", "update")
70 if output != "" {
71 RebootWithMark(c, "setupsuite-update")
72 }
73 }
74 } else if CheckRebootMark("setupsuite-update") {
75 RemoveRebootMark(c)
76 if Cfg.Rollback {
77 ExecCommand(c, "sudo", "snappy", "rollback", "ubuntu-core")
78 RebootWithMark(c, "setupsuite-rollback")
79 }
80 } else if CheckRebootMark("setupsuite-rollback") {
81 RemoveRebootMark(c)
82 }
83}
84
85// SetUpTest handles reboots and stores version information. It will run before
86// all the integration tests. Before running a test, it will save the
87// ubuntu-core version. If a reboot was requested by a previous test, it
88// will skip all the following tests. If the suite is being called after the
89// test bed was rebooted, it will resume the test that requested the reboot.
90func (s *SnappySuite) SetUpTest(c *check.C) {
91 if NeedsReboot() {
92 contents, err := ioutil.ReadFile(needsRebootFile)
93 c.Assert(err, check.IsNil, check.Commentf("Error reading needs-reboot file %v", err))
94 c.Skip(fmt.Sprintf("****** Skipped %s during reboot caused by %s",
95 c.TestName(), contents))
96 } else {
97 if CheckRebootMark("") {
98 c.Logf("****** Running %s", c.TestName())
99 SetSavedVersion(c, GetCurrentUbuntuCoreVersion(c))
100 } else {
101 if AfterReboot(c) {
102 c.Logf("****** Resuming %s after reboot", c.TestName())
103 } else {
104 c.Skip(fmt.Sprintf("****** Skipped %s after reboot caused by %s",
105 c.TestName(), os.Getenv("ADT_REBOOT_MARK")))
106 }
107 }
108 }
109 // clear slice
110 s.cleanupHandlers = nil
111}
112
113// TearDownTest cleans up the channel.ini files in case they were changed by
114// the test.
115// It also runs the cleanup handlers
116func (s *SnappySuite) TearDownTest(c *check.C) {
117 if !NeedsReboot() && CheckRebootMark("") {
118 // Only restore the channel config files if the reboot has been handled.
119 m := make(map[string]string)
120 m[channelCfgBackupFile()] = "/"
121 m[channelCfgOtherBackupFile()] = BaseAltPartitionPath
122 for backup, target := range m {
123 if _, err := os.Stat(backup); err == nil {
124 MakeWritable(c, target)
125 defer MakeReadonly(c, target)
126 original := filepath.Join(target, channelCfgFile)
127 c.Logf("Restoring %s...", original)
128 ExecCommand(c, "sudo", "mv", backup, original)
129 }
130 }
131 }
132
133 // run cleanup handlers and clear the slice
134 for _, f := range s.cleanupHandlers {
135 f()
136 }
137 s.cleanupHandlers = nil
138}
139
140// AddCleanup adds a new cleanup function to the test
141func (s *SnappySuite) AddCleanup(f func()) {
142 s.cleanupHandlers = append(s.cleanupHandlers, f)
143}
144
145func switchSystemImageConf(c *check.C, release, channel, version string) {
146 targets := []string{"/", BaseAltPartitionPath}
147 for _, target := range targets {
148 file := filepath.Join(target, channelCfgFile)
149 if _, err := os.Stat(file); err == nil {
150 MakeWritable(c, target)
151 defer MakeReadonly(c, target)
152 replaceSystemImageValues(c, file, release, channel, version)
153 }
154 }
155}
156
157func replaceSystemImageValues(c *check.C, file, release, channel, version string) {
158 c.Log("Switching the system image conf...")
159 replaceRegex := map[string]string{
160 release: `s#channel: ubuntu-core/.*/\(.*\)#channel: ubuntu-core/%s/\1#`,
161 channel: `s#channel: ubuntu-core/\(.*\)/.*#channel: ubuntu-core/\1/%s#`,
162 version: `s/build_number: .*/build_number: %s/`,
163 }
164 for value, regex := range replaceRegex {
165 if value != "" {
166 ExecCommand(c,
167 "sudo", "sed", "-i", fmt.Sprintf(regex, value), file)
168 }
169 }
170 // Leave the new file in the test log.
171 ExecCommand(c, "cat", file)
172}
173
174func channelCfgBackupFile() string {
175 return filepath.Join(os.Getenv("ADT_ARTIFACTS"), "channel.ini")
176}
177
178func channelCfgOtherBackupFile() string {
179 return filepath.Join(os.Getenv("ADT_ARTIFACTS"), "channel.ini.other")
180}
181
182// ExecCommand executes a shell command and returns a string with the output
183// of the command. In case of error, it will fail the test.
184func ExecCommand(c *check.C, cmds ...string) string {
185 fmt.Println(strings.Join(cmds, " "))
186 cmd := exec.Command(cmds[0], cmds[1:len(cmds)]...)
187 output, err := cmd.CombinedOutput()
188 stringOutput := string(output)
189 fmt.Print(stringOutput)
190 c.Assert(err, check.IsNil, check.Commentf("Error: %v", stringOutput))
191 return stringOutput
192}
193
194// ExecCommandToFile executes a shell command and saves the output of the
195// command to a file. In case of error, it will fail the test.
196func ExecCommandToFile(c *check.C, filename string, cmds ...string) {
197 cmd := exec.Command(cmds[0], cmds[1:len(cmds)]...)
198 outfile, err := os.Create(filename)
199 c.Assert(err, check.IsNil, check.Commentf("Error creating output file %s", filename))
200
201 defer outfile.Close()
202 cmd.Stdout = outfile
203
204 err = cmd.Run()
205 c.Assert(err, check.IsNil, check.Commentf("Error executing command '%v': %v", cmds, err))
206}
207
208// GetCurrentVersion returns the version of the installed and active package.
209func GetCurrentVersion(c *check.C, packageName string) string {
210 output := ExecCommand(c, "snappy", "list")
211 pattern := "(?mU)^" + packageName + " +(.*)$"
212 re := regexp.MustCompile(pattern)
213 match := re.FindStringSubmatch(string(output))
214 c.Assert(match, check.NotNil, check.Commentf("Version not found in %s", output))
215
216 // match is like "ubuntu-core 2015-06-18 93 ubuntu"
217 items := strings.Fields(match[0])
218 return items[2]
219}
220
221// GetCurrentUbuntuCoreVersion returns the version number of the installed and
222// active ubuntu-core.
223func GetCurrentUbuntuCoreVersion(c *check.C) int {
224 versionString := GetCurrentVersion(c, "ubuntu-core")
225 version, err := strconv.Atoi(versionString)
226 c.Assert(err, check.IsNil, check.Commentf("Error converting version to int %v", version))
227 return version
228}
229
230// CallFakeUpdate calls snappy update after faking the current version
231func CallFakeUpdate(c *check.C) string {
232 c.Log("Preparing fake and calling update.")
233 fakeAvailableUpdate(c)
234 return ExecCommand(c, "sudo", "snappy", "update")
235}
236
237func fakeAvailableUpdate(c *check.C) {
238 c.Log("Faking an available update...")
239 currentVersion := GetCurrentUbuntuCoreVersion(c)
240 switchChannelVersionWithBackup(c, currentVersion-1)
241 SetSavedVersion(c, currentVersion-1)
242}
243
244func switchChannelVersionWithBackup(c *check.C, newVersion int) {
245 m := make(map[string]string)
246 m["/"] = channelCfgBackupFile()
247 m[BaseAltPartitionPath] = channelCfgOtherBackupFile()
248 for target, backup := range m {
249 file := filepath.Join(target, channelCfgFile)
250 if _, err := os.Stat(file); err == nil {
251 MakeWritable(c, target)
252 defer MakeReadonly(c, target)
253 // Back up the file. It will be restored during the test tear down.
254 ExecCommand(c, "cp", file, backup)
255 replaceSystemImageValues(c, file, "", "", strconv.Itoa(newVersion))
256 }
257 }
258}
259
260// MakeWritable remounts a path with read and write permissions.
261func MakeWritable(c *check.C, path string) {
262 ExecCommand(c, "sudo", "mount", "-o", "remount,rw", path)
263}
264
265// MakeReadonly remounts a path with only read permissions.
266func MakeReadonly(c *check.C, path string) {
267 ExecCommand(c, "sudo", "mount", "-o", "remount,ro", path)
268}
269
270// Reboot requests a reboot using the test name as the mark.
271func Reboot(c *check.C) {
272 RebootWithMark(c, c.TestName())
273}
274
275// RebootWithMark requests a reboot using a specified mark.
276func RebootWithMark(c *check.C, mark string) {
277 c.Log("Preparing reboot with mark " + mark)
278 err := ioutil.WriteFile(needsRebootFile, []byte(mark), 0777)
279 c.Assert(err, check.IsNil, check.Commentf("Error writing needs-reboot file: %v", err))
280}
281
282// NeedsReboot returns True if a reboot has been requested by a test.
283func NeedsReboot() bool {
284 _, err := os.Stat(needsRebootFile)
285 return err == nil
286}
287
288// BeforeReboot returns True if the test is running before the test bed has
289// been rebooted, or after the test that requested the reboot handled it.
290func BeforeReboot() bool {
291 return CheckRebootMark("")
292}
293
294// AfterReboot returns True if the test is running after the test bed has been
295// rebooted.
296func AfterReboot(c *check.C) bool {
297 // $ADT_REBOOT_MARK contains the reboot mark, if we have rebooted it'll be the test name
298 return strings.HasPrefix(os.Getenv("ADT_REBOOT_MARK"), c.TestName())
299}
300
301// CheckRebootMark returns True if the reboot mark matches the string passed as
302// argument.
303func CheckRebootMark(mark string) bool {
304 return os.Getenv("ADT_REBOOT_MARK") == mark
305}
306
307func isInRebootProcess() bool {
308 return !CheckRebootMark("") || NeedsReboot()
309}
310
311// RemoveRebootMark removes the reboot mark to signal that the reboot has been
312// handled.
313func RemoveRebootMark(c *check.C) {
314 os.Setenv("ADT_REBOOT_MARK", "")
315}
316
317// SetSavedVersion saves a version number into a file so it can be used on
318// tests after reboots.
319func SetSavedVersion(c *check.C, version int) {
320 versionFile := getVersionFile()
321 err := ioutil.WriteFile(versionFile, []byte(strconv.Itoa(version)), 0777)
322 c.Assert(err, check.IsNil, check.Commentf("Error writing version file %s with %s", versionFile, version))
323}
324
325// GetSavedVersion returns the saved version number.
326func GetSavedVersion(c *check.C) int {
327 versionFile := getVersionFile()
328 contents, err := ioutil.ReadFile(versionFile)
329 c.Assert(err, check.IsNil, check.Commentf("Error reading version file %s", versionFile))
330
331 version, err := strconv.Atoi(string(contents))
332 c.Assert(err, check.IsNil, check.Commentf("Error converting version %v", contents))
333
334 return version
335}
336
337func getVersionFile() string {
338 return filepath.Join(os.Getenv("ADT_ARTIFACTS"), "version")
339}
340
341// InstallSnap executes the required command to install the specified snap
342func InstallSnap(c *check.C, packageName string) string {
343 return ExecCommand(c, "sudo", "snappy", "install", packageName, "--allow-unauthenticated")
344}
345
346// RemoveSnap executes the required command to remove the specified snap
347func RemoveSnap(c *check.C, packageName string) string {
348 return ExecCommand(c, "sudo", "snappy", "remove", packageName)
349}
350
351// WaitForActiveService keeps asking for the active state of the given service until
352// it is active or the maximun waiting time expires, in which case an error is returned
353func WaitForActiveService(c *check.C, serviceName string) error {
354 maxWait := time.Second * 10
355 checkInterval := time.Millisecond * 500
356
357 timer := time.NewTimer(maxWait)
358 timeChan := timer.C
359
360 ticker := time.NewTicker(checkInterval)
361 tickChan := ticker.C
362
363 for {
364 select {
365 case <-timeChan:
366 ticker.Stop()
367 journalctlOutput := ExecCommand(c, "sudo", "journalctl", "-u", serviceName)
368 return fmt.Errorf("Service %s not active after %s, journalctl output: %s",
369 serviceName, maxWait, journalctlOutput)
370 case <-tickChan:
371 statusOutput := ExecCommand(
372 c, "systemctl", "show", "-p", "ActiveState", serviceName)
373 if statusOutput == "ActiveState=active\n" {
374 timer.Stop()
375 return nil
376 }
377 }
378 }
379}
0380
=== added file '_integration-tests/testutils/common/common_test.go'
--- _integration-tests/testutils/common/common_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/common/common_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,68 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2014-2015 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
20package common
21
22import (
23 "testing"
24
25 . "gopkg.in/check.v1"
26)
27
28// Hook up check.v1 into the "go test" runner
29func Test(t *testing.T) { TestingT(t) }
30
31// testing a testsuite - thats so meta
32type MetaTestSuite struct {
33}
34
35var _ = Suite(&MetaTestSuite{})
36
37// test trivial cleanup
38func (m *MetaTestSuite) TestCleanupSimple(c *C) {
39 canary := "not-called"
40 s := SnappySuite{}
41
42 s.AddCleanup(func() {
43 canary = "was-called"
44 })
45 s.TearDownTest(c)
46
47 c.Assert(canary, Equals, "was-called")
48}
49
50// a mock method that takes a parameter
51func mockCleanupMethodWithParameters(s *string) {
52 *s = "was-called"
53}
54
55// test that whle AddCleanup() does not take any parameters itself,
56// functions that need parameters can be passed by creating an
57// anonymous function as a wrapper
58func (m *MetaTestSuite) TestCleanupWithParameters(c *C) {
59 canary := "not-called"
60 s := SnappySuite{}
61
62 s.AddCleanup(func() {
63 mockCleanupMethodWithParameters(&canary)
64 })
65 s.TearDownTest(c)
66
67 c.Assert(canary, Equals, "was-called")
68}
069
=== added directory '_integration-tests/testutils/config'
=== added file '_integration-tests/testutils/config/config.go'
--- _integration-tests/testutils/config/config.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/config/config.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,75 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package config
21
22import (
23 "encoding/json"
24 "fmt"
25 "io/ioutil"
26 "log"
27)
28
29// Config contains the values to pass to the test bed from the host.
30type Config struct {
31 FileName string
32 Release string
33 Channel string
34 TargetRelease string
35 TargetChannel string
36 RemoteTestbed bool
37 Update bool
38 Rollback bool
39}
40
41// NewConfig is the Config constructor
42func NewConfig(fileName, release, channel, targetRelease, targetChannel string, remoteTestbed, update, rollback bool) *Config {
43 return &Config{
44 FileName: fileName, Release: release, Channel: channel,
45 TargetRelease: targetRelease, TargetChannel: targetChannel,
46 RemoteTestbed: remoteTestbed, Update: update, Rollback: rollback,
47 }
48}
49
50// Write writes the config to a file that will be copied to the test bed.
51func (cfg Config) Write() {
52 fmt.Println("Writing test config...")
53 fmt.Println(cfg)
54 encoded, err := json.Marshal(cfg)
55 if err != nil {
56 log.Panicf("Error encoding the test config: %v", err)
57 }
58 err = ioutil.WriteFile(cfg.FileName, encoded, 0644)
59 if err != nil {
60 log.Panicf("Error writing the test config: %v", err)
61 }
62}
63
64// ReadConfig the config from a file
65func ReadConfig(fileName string) (*Config, error) {
66 b, err := ioutil.ReadFile(fileName)
67 if err != nil {
68 return nil, err
69 }
70 var decoded Config
71 if err = json.Unmarshal(b, &decoded); err != nil {
72 return nil, err
73 }
74 return &decoded, nil
75}
076
=== added file '_integration-tests/testutils/config/config.test'
1Binary files _integration-tests/testutils/config/config.test 1970-01-01 00:00:00 +0000 and _integration-tests/testutils/config/config.test 2015-09-16 17:51:11 +0000 differ77Binary files _integration-tests/testutils/config/config.test 1970-01-01 00:00:00 +0000 and _integration-tests/testutils/config/config.test 2015-09-16 17:51:11 +0000 differ
=== added file '_integration-tests/testutils/config/config_test.go'
--- _integration-tests/testutils/config/config_test.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/config/config_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,121 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2014-2015 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
20package config
21
22import (
23 "fmt"
24 "io/ioutil"
25 "os"
26 "path/filepath"
27 "testing"
28
29 check "gopkg.in/check.v1"
30)
31
32// Hook up check.v1 into the "go test" runner
33func Test(t *testing.T) { check.TestingT(t) }
34
35type ConfigSuite struct{}
36
37var _ = check.Suite(&ConfigSuite{})
38
39func testConfigFileName(c *check.C) string {
40 tmpDir, err := ioutil.TempDir("", "")
41 c.Assert(err, check.IsNil, check.Commentf(
42 "Error creating a temporary directory: %v", err))
43 return filepath.Join(tmpDir, "test.config")
44}
45
46func testConfigStruct(fileName string) *Config {
47 return NewConfig(
48 fileName,
49 "testrelease", "testchannel", "testtargetrelease", "testtargetchannel",
50 true, true, true)
51}
52func testConfigContents(fileName string) string {
53 return `{` +
54 fmt.Sprintf(`"FileName":"%s",`, fileName) +
55 `"Release":"testrelease",` +
56 `"Channel":"testchannel",` +
57 `"TargetRelease":"testtargetrelease",` +
58 `"TargetChannel":"testtargetchannel",` +
59 `"RemoteTestbed":true,` +
60 `"Update":true,` +
61 `"Rollback":true` +
62 `}`
63}
64
65func (s *ConfigSuite) TestWriteConfig(c *check.C) {
66 // Do not print to stdout.
67 devnull, err := os.Open(os.DevNull)
68 c.Assert(err, check.IsNil)
69 oldStdout := os.Stdout
70 os.Stdout = devnull
71 defer func() {
72 os.Stdout = oldStdout
73 }()
74 configFileName := testConfigFileName(c)
75
76 cfg := testConfigStruct(configFileName)
77 cfg.Write()
78
79 writtenConfig, err := ioutil.ReadFile(configFileName)
80 c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
81 c.Assert(string(writtenConfig), check.Equals, testConfigContents(configFileName))
82}
83
84func (s *ConfigSuite) TestReadConfig(c *check.C) {
85 configFileName := testConfigFileName(c)
86
87 configContents := testConfigContents(configFileName)
88 ioutil.WriteFile(configFileName, []byte(configContents), 0644)
89
90 cfg, err := ReadConfig(configFileName)
91
92 c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
93 c.Assert(cfg, check.DeepEquals, testConfigStruct(configFileName))
94}
95
96func (s *ConfigSuite) TestReadConfigLocalTestBed(c *check.C) {
97 configFileName := testConfigFileName(c)
98
99 configContents := `{` +
100 fmt.Sprintf(`"FileName":"%s",`, configFileName) +
101 `"Release":"testrelease",` +
102 `"Channel":"testchannel",` +
103 `"TargetRelease":"testtargetrelease",` +
104 `"TargetChannel":"testtargetchannel",` +
105 `"RemoteTestbed":false,` +
106 `"Update":true,` +
107 `"Rollback":true` +
108 `}`
109
110 ioutil.WriteFile(configFileName, []byte(configContents), 0644)
111
112 cfg, err := ReadConfig(configFileName)
113
114 testConfigStruct := NewConfig(
115 configFileName,
116 "testrelease", "testchannel", "testtargetrelease", "testtargetchannel",
117 false, true, true)
118
119 c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
120 c.Assert(cfg, check.DeepEquals, testConfigStruct)
121}
0122
=== added directory '_integration-tests/testutils/image'
=== added file '_integration-tests/testutils/image/image.go'
--- _integration-tests/testutils/image/image.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/image/image.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,86 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package image
21
22import (
23 "fmt"
24 "path/filepath"
25 "strings"
26
27 "launchpad.net/snappy/_integration-tests/testutils"
28)
29
30// Image type encapsulates image actions
31type Image struct {
32 release string
33 channel string
34 revision string
35 baseDir string
36}
37
38// NewImage is the Image constructor
39func NewImage(release, channel, revision, baseDir string) *Image {
40 return &Image{release: release, channel: channel, revision: revision, baseDir: baseDir}
41}
42
43// UdfCreate forms and executes the UDF command for creating the image
44func (img Image) UdfCreate() (string, error) {
45 fmt.Println("Creating image...")
46
47 imageDir := filepath.Join(img.baseDir, "image")
48
49 testutils.PrepareTargetDir(imageDir)
50
51 udfCommand := []string{"sudo", "ubuntu-device-flash", "--verbose"}
52
53 if img.revision != "" {
54 udfCommand = append(udfCommand, "--revision", img.revision)
55 }
56
57 imagePath := img.imagePath(imageDir)
58
59 coreOptions := []string{
60 "core", img.release,
61 "--output", imagePath,
62 "--channel", img.channel,
63 "--developer-mode",
64 }
65
66 err := testutils.ExecCommand(append(udfCommand, coreOptions...)...)
67
68 return imagePath, err
69}
70
71func (img Image) imagePath(imageDir string) string {
72 revisionTag := img.revision
73 if revisionTag == "" {
74 revisionTag = "latest"
75 }
76
77 imageName := strings.Join(
78 []string{"snappy", img.release, img.channel, revisionTag}, "-") + ".img"
79
80 return filepath.Join(imageDir, imageName)
81}
82
83// SetRevision is the setter method for revision
84func (img Image) SetRevision(rev string) {
85 img.revision = rev
86}
087
=== added file '_integration-tests/testutils/testutils.go'
--- _integration-tests/testutils/testutils.go 1970-01-01 00:00:00 +0000
+++ _integration-tests/testutils/testutils.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,61 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2015 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
20package testutils
21
22import (
23 "fmt"
24 "log"
25 "os"
26 "os/exec"
27 "strings"
28)
29
30// PrepareTargetDir creates the given target directory, removing it previously if it didn't exist
31func PrepareTargetDir(targetDir string) {
32 if _, err := os.Stat(targetDir); err == nil {
33 // dir exists, remove it
34 os.RemoveAll(targetDir)
35 }
36 os.MkdirAll(targetDir, 0777)
37}
38
39// RootPath return the test current working directory.
40func RootPath() string {
41 dir, err := os.Getwd()
42 if err != nil {
43 log.Panic(err)
44 }
45 return dir
46}
47
48// ExecCommand executes the given command and pipes the results to os.Stdout and os.Stderr, returning the resulting error
49func ExecCommand(cmds ...string) error {
50 fmt.Println(strings.Join(cmds, " "))
51
52 cmd := exec.Command(cmds[0], cmds[1:]...)
53 cmd.Stdout = os.Stdout
54 cmd.Stderr = os.Stderr
55
56 err := cmd.Run()
57 if err != nil {
58 log.Panicf("Error while running %s: %s\n", cmd.Args, err)
59 }
60 return err
61}
062
=== modified file 'clickdeb/deb.go'
=== modified file 'clickdeb/deb_test.go'
=== modified file 'cmd/snappy/cmd_internal_unpack.go'
--- cmd/snappy/cmd_internal_unpack.go 2015-07-02 16:01:11 +0000
+++ cmd/snappy/cmd_internal_unpack.go 2015-09-16 17:51:11 +0000
@@ -129,6 +129,7 @@
129129
130 // first find out what user to use130 // first find out what user to use
131 passFile := passwdFile(rootDir, "passwd")131 passFile := passwdFile(rootDir, "passwd")
132<<<<<<< TREE
132 for _, dropPrivsUser = range dropPrivsUsers {133 for _, dropPrivsUser = range dropPrivsUsers {
133 _, err := readUID(dropPrivsUser, passFile)134 _, err := readUID(dropPrivsUser, passFile)
134 if err == nil {135 if err == nil {
@@ -138,6 +139,9 @@
138139
139 // then get uid/gid140 // then get uid/gid
140 uid, err := readUID(dropPrivsUser, passFile)141 uid, err := readUID(dropPrivsUser, passFile)
142=======
143 uid, err := readUID(dropPrivsUser, passFile)
144>>>>>>> MERGE-SOURCE
141 if err != nil {145 if err != nil {
142 return err146 return err
143 }147 }
144148
=== modified file 'cmd/snappy/cmd_internal_unpack_test.go'
--- cmd/snappy/cmd_internal_unpack_test.go 2015-07-02 16:01:11 +0000
+++ cmd/snappy/cmd_internal_unpack_test.go 2015-09-16 17:51:11 +0000
@@ -42,7 +42,11 @@
42snappypkg:x:101:104::/nonexistent:/bin/false42snappypkg:x:101:104::/nonexistent:/bin/false
43`)43`)
4444
45<<<<<<< TREE
45 uid, err := readUID("snappypkg", f.Name())46 uid, err := readUID("snappypkg", f.Name())
47=======
48 uid, err := readUID("clickpkg", f.Name())
49>>>>>>> MERGE-SOURCE
46 c.Assert(err, IsNil)50 c.Assert(err, IsNil)
47 c.Assert(uid, Equals, 101)51 c.Assert(uid, Equals, 101)
48}52}
@@ -53,7 +57,11 @@
53snappypkg:x:104:57snappypkg:x:104:
54`)58`)
5559
60<<<<<<< TREE
56 gid, err := readUID("snappypkg", f.Name())61 gid, err := readUID("snappypkg", f.Name())
62=======
63 gid, err := readUID("clickpkg", f.Name())
64>>>>>>> MERGE-SOURCE
57 c.Assert(err, IsNil)65 c.Assert(err, IsNil)
58 c.Assert(gid, Equals, 104)66 c.Assert(gid, Equals, 104)
59}67}
@@ -66,7 +74,11 @@
66`)74`)
67 defer os.Remove(f.Name())75 defer os.Remove(f.Name())
6876
77<<<<<<< TREE
69 uid, err := readUID("snappypkg", f.Name())78 uid, err := readUID("snappypkg", f.Name())
79=======
80 uid, err := readUID("clickpkg", f.Name())
81>>>>>>> MERGE-SOURCE
70 c.Assert(err, IsNil)82 c.Assert(err, IsNil)
71 c.Assert(uid, Equals, 102)83 c.Assert(uid, Equals, 102)
72}84}
@@ -77,7 +89,11 @@
77snappypkg:x:89snappypkg:x:
78`)90`)
7991
92<<<<<<< TREE
80 _, err := readUID("snappypkg", f.Name())93 _, err := readUID("snappypkg", f.Name())
94=======
95 _, err := readUID("clickpkg", f.Name())
96>>>>>>> MERGE-SOURCE
81 c.Assert(err, NotNil)97 c.Assert(err, NotNil)
82}98}
8399
@@ -86,6 +102,10 @@
86daemon:102daemon:
87`)103`)
88104
105<<<<<<< TREE
89 _, err := readUID("snappypkg", f.Name())106 _, err := readUID("snappypkg", f.Name())
107=======
108 _, err := readUID("clickpkg", f.Name())
109>>>>>>> MERGE-SOURCE
90 c.Assert(err, NotNil)110 c.Assert(err, NotNil)
91}111}
92112
=== modified file 'cmd/snappy/cmd_rollback.go'
--- cmd/snappy/cmd_rollback.go 2015-07-09 06:05:53 +0000
+++ cmd/snappy/cmd_rollback.go 2015-09-16 17:51:11 +0000
@@ -79,5 +79,14 @@
79 parts := snappy.FindSnapsByNameAndVersion(pkg, nowVersion, installed)79 parts := snappy.FindSnapsByNameAndVersion(pkg, nowVersion, installed)
80 showVerboseList(parts, os.Stdout)80 showVerboseList(parts, os.Stdout)
8181
82 m := snappy.NewMetaRepository()
83 installed, err := m.Installed()
84 if err != nil {
85 return err
86 }
87
88 parts := snappy.FindSnapsByNameAndVersion(pkg, nowVersion, installed)
89 showVerboseList(parts, os.Stdout)
90
82 return nil91 return nil
83}92}
8493
=== modified file 'cmd/snappy/cmd_set.go'
--- cmd/snappy/cmd_set.go 2015-06-30 12:52:52 +0000
+++ cmd/snappy/cmd_set.go 2015-09-16 17:51:11 +0000
@@ -23,8 +23,12 @@
23 "fmt"23 "fmt"
24 "strings"24 "strings"
2525
26<<<<<<< TREE
26 "launchpad.net/snappy/i18n"27 "launchpad.net/snappy/i18n"
27 "launchpad.net/snappy/logger"28 "launchpad.net/snappy/logger"
29=======
30 "launchpad.net/snappy/priv"
31>>>>>>> MERGE-SOURCE
28 "launchpad.net/snappy/progress"32 "launchpad.net/snappy/progress"
29 "launchpad.net/snappy/snappy"33 "launchpad.net/snappy/snappy"
30)34)
@@ -53,8 +57,18 @@
53}57}
5458
55func (x *cmdSet) Execute(args []string) (err error) {59func (x *cmdSet) Execute(args []string) (err error) {
60<<<<<<< TREE
56 x.args = args61 x.args = args
57 return withMutex(x.doSet)62 return withMutex(x.doSet)
63=======
64 privMutex := priv.New()
65 if err := privMutex.TryLock(); err != nil {
66 return err
67 }
68 defer privMutex.Unlock()
69
70 return set(args)
71>>>>>>> MERGE-SOURCE
58}72}
5973
60func (x *cmdSet) doSet() (err error) {74func (x *cmdSet) doSet() (err error) {
6175
=== modified file 'cmd/snappy/cmd_set_test.go'
--- cmd/snappy/cmd_set_test.go 2015-07-08 07:58:40 +0000
+++ cmd/snappy/cmd_set_test.go 2015-09-16 17:51:11 +0000
@@ -20,9 +20,26 @@
20package main20package main
2121
22import (22import (
23 . "gopkg.in/check.v1"23<<<<<<< TREE
24 . "gopkg.in/check.v1"
25=======
26 "testing"
27
28 . "gopkg.in/check.v1"
29>>>>>>> MERGE-SOURCE
24)30)
2531
32<<<<<<< TREE
33=======
34// Hook up check.v1 into the "go test" runner
35func Test(t *testing.T) { TestingT(t) }
36
37type CmdTestSuite struct {
38}
39
40var _ = Suite(&CmdTestSuite{})
41
42>>>>>>> MERGE-SOURCE
26func (s *CmdTestSuite) TestParseSetPropertyCmdline(c *C) {43func (s *CmdTestSuite) TestParseSetPropertyCmdline(c *C) {
2744
28 // simple case45 // simple case
2946
=== modified file 'cmd/snappy/main.go'
--- cmd/snappy/main.go 2015-06-11 20:30:46 +0000
+++ cmd/snappy/main.go 2015-09-16 17:51:11 +0000
@@ -52,10 +52,14 @@
52 // the CLI user.52 // the CLI user.
53 err = snappy.ErrNeedRoot53 err = snappy.ErrNeedRoot
54 }54 }
55<<<<<<< TREE
55 fmt.Fprintln(os.Stderr, err)56 fmt.Fprintln(os.Stderr, err)
56 if _, ok := err.(*flags.Error); !ok {57 if _, ok := err.(*flags.Error); !ok {
57 logger.Debugf("%v failed: %v", os.Args, err)58 logger.Debugf("%v failed: %v", os.Args, err)
58 }59 }
60=======
61 fmt.Fprintln(os.Stderr, err)
62>>>>>>> MERGE-SOURCE
59 os.Exit(1)63 os.Exit(1)
60 }64 }
61}65}
6266
=== modified file 'coreconfig/config.go'
=== modified file 'coreconfig/config_test.go'
--- coreconfig/config_test.go 2015-09-15 21:36:22 +0000
+++ coreconfig/config_test.go 2015-09-16 17:51:11 +0000
@@ -26,9 +26,14 @@
26 "path/filepath"26 "path/filepath"
27 "testing"27 "testing"
2828
29<<<<<<< TREE
29 "launchpad.net/snappy/helpers"30 "launchpad.net/snappy/helpers"
3031
31 . "gopkg.in/check.v1"32 . "gopkg.in/check.v1"
33=======
34 . "gopkg.in/check.v1"
35 "launchpad.net/snappy/helpers"
36>>>>>>> MERGE-SOURCE
32)37)
3338
34// Hook up check.v1 into the "go test" runner.39// Hook up check.v1 into the "go test" runner.
@@ -50,12 +55,20 @@
50 originalCmdAutopilotEnabled = cmdAutopilotEnabled55 originalCmdAutopilotEnabled = cmdAutopilotEnabled
51 originalCmdSystemctl = cmdSystemctl56 originalCmdSystemctl = cmdSystemctl
52 originalHostnamePath = hostnamePath57 originalHostnamePath = hostnamePath
58<<<<<<< TREE
53 originalModprobePath = modprobePath59 originalModprobePath = modprobePath
54 originalInterfacesRoot = interfacesRoot60 originalInterfacesRoot = interfacesRoot
55 originalPppRoot = pppRoot61 originalPppRoot = pppRoot
56 originalWatchdogStartupPath = watchdogStartupPath62 originalWatchdogStartupPath = watchdogStartupPath
57 originalWatchdogConfigPath = watchdogConfigPath63 originalWatchdogConfigPath = watchdogConfigPath
58 originalTzZoneInfoTarget = tzZoneInfoTarget64 originalTzZoneInfoTarget = tzZoneInfoTarget
65=======
66 originalModprobePath = modprobePath
67 originalInterfacesRoot = interfacesRoot
68 originalPppRoot = pppRoot
69 originalWatchdogStartupPath = watchdogStartupPath
70 originalWatchdogConfigPath = watchdogConfigPath
71>>>>>>> MERGE-SOURCE
59)72)
6073
61type ConfigTestSuite struct {74type ConfigTestSuite struct {
@@ -82,12 +95,20 @@
82 hostname = host95 hostname = host
83 return nil96 return nil
84 }97 }
98<<<<<<< TREE
85 tzZoneInfoTarget = filepath.Join(c.MkDir(), "localtime")99 tzZoneInfoTarget = filepath.Join(c.MkDir(), "localtime")
86100
87 interfacesRoot = c.MkDir() + "/"101 interfacesRoot = c.MkDir() + "/"
88 pppRoot = c.MkDir() + "/"102 pppRoot = c.MkDir() + "/"
89 watchdogConfigPath = filepath.Join(c.MkDir(), "watchdog-config")103 watchdogConfigPath = filepath.Join(c.MkDir(), "watchdog-config")
90 watchdogStartupPath = filepath.Join(c.MkDir(), "watchdog-startup")104 watchdogStartupPath = filepath.Join(c.MkDir(), "watchdog-startup")
105=======
106
107 interfacesRoot = c.MkDir() + "/"
108 pppRoot = c.MkDir() + "/"
109 watchdogConfigPath = filepath.Join(c.MkDir(), "watchdog-config")
110 watchdogStartupPath = filepath.Join(c.MkDir(), "watchdog-startup")
111>>>>>>> MERGE-SOURCE
91}112}
92113
93func (cts *ConfigTestSuite) TearDownTest(c *C) {114func (cts *ConfigTestSuite) TearDownTest(c *C) {
@@ -106,12 +127,20 @@
106 cmdStopAutopilot = originalCmdStopAutopilot127 cmdStopAutopilot = originalCmdStopAutopilot
107 cmdAutopilotEnabled = originalCmdAutopilotEnabled128 cmdAutopilotEnabled = originalCmdAutopilotEnabled
108 cmdSystemctl = originalCmdSystemctl129 cmdSystemctl = originalCmdSystemctl
130<<<<<<< TREE
109 modprobePath = originalModprobePath131 modprobePath = originalModprobePath
110 interfacesRoot = originalInterfacesRoot132 interfacesRoot = originalInterfacesRoot
111 pppRoot = originalPppRoot133 pppRoot = originalPppRoot
112 watchdogStartupPath = originalWatchdogStartupPath134 watchdogStartupPath = originalWatchdogStartupPath
113 watchdogConfigPath = originalWatchdogConfigPath135 watchdogConfigPath = originalWatchdogConfigPath
114 tzZoneInfoTarget = originalTzZoneInfoTarget136 tzZoneInfoTarget = originalTzZoneInfoTarget
137=======
138 modprobePath = originalModprobePath
139 interfacesRoot = originalInterfacesRoot
140 pppRoot = originalPppRoot
141 watchdogStartupPath = originalWatchdogStartupPath
142 watchdogConfigPath = originalWatchdogConfigPath
143>>>>>>> MERGE-SOURCE
115}144}
116145
117// TestGet is a broad test, close enough to be an integration test for146// TestGet is a broad test, close enough to be an integration test for
@@ -156,6 +185,7 @@
156 autopilot: false185 autopilot: false
157 timezone: America/Argentina/Mendoza186 timezone: America/Argentina/Mendoza
158 hostname: testhost187 hostname: testhost
188<<<<<<< TREE
159 modprobe: ""189 modprobe: ""
160`190`
161191
@@ -184,6 +214,14 @@
184 content, err := ioutil.ReadFile(tzZoneInfoTarget)214 content, err := ioutil.ReadFile(tzZoneInfoTarget)
185 c.Assert(err, IsNil)215 c.Assert(err, IsNil)
186 c.Assert(content, Not(DeepEquals), []byte(canary))216 c.Assert(content, Not(DeepEquals), []byte(canary))
217=======
218 modprobe: ""
219`
220
221 rawConfig, err := Set(expected)
222 c.Assert(err, IsNil)
223 c.Assert(rawConfig, Equals, expected)
224>>>>>>> MERGE-SOURCE
187}225}
188226
189// TestSetAutopilot is a broad test, close enough to be an integration test.227// TestSetAutopilot is a broad test, close enough to be an integration test.
190228
=== modified file 'debian/control'
--- debian/control 2015-09-14 19:04:47 +0000
+++ debian/control 2015-09-16 17:51:11 +0000
@@ -9,13 +9,18 @@
9 fakeroot,9 fakeroot,
10 gettext,10 gettext,
11 golang-ar-dev,11 golang-ar-dev,
12<<<<<<< TREE
12 golang-check.v1-dev,13 golang-check.v1-dev,
13 golang-gettext-dev,14 golang-gettext-dev,
15=======
16 golang-check.v1-dev,
17>>>>>>> MERGE-SOURCE
14 golang-go,18 golang-go,
15 golang-go-flags-dev,19 golang-go-flags-dev,
16 golang-go.crypto-dev,20 golang-go.crypto-dev,
17 golang-goconfigparser-dev,21 golang-goconfigparser-dev,
18 golang-pb-dev,22 golang-pb-dev,
23<<<<<<< TREE
19 golang-uboot-go-dev,24 golang-uboot-go-dev,
20 golang-yaml.v2-dev,25 golang-yaml.v2-dev,
21 golang-mux-dev,26 golang-mux-dev,
@@ -24,6 +29,10 @@
24 lsb-release,29 lsb-release,
25 python3,30 python3,
26 python3-markdown31 python3-markdown
32=======
33 golang-uboot-go-dev,
34 golang-yaml.v2-dev
35>>>>>>> MERGE-SOURCE
27Standards-Version: 3.9.636Standards-Version: 3.9.6
28Homepage: https://launchpad.net/snappy37Homepage: https://launchpad.net/snappy
29Vcs-Browser: http://bazaar.launchpad.net/~snappy-dev/snappy/trunk/files38Vcs-Browser: http://bazaar.launchpad.net/~snappy-dev/snappy/trunk/files
3039
=== modified file 'debian/rules'
--- debian/rules 2015-09-16 11:32:44 +0000
+++ debian/rules 2015-09-16 17:51:11 +0000
@@ -4,9 +4,13 @@
4#export DH_VERBOSE=14#export DH_VERBOSE=1
5export DH_OPTIONS5export DH_OPTIONS
6export DH_GOPKG := launchpad.net/snappy6export DH_GOPKG := launchpad.net/snappy
7<<<<<<< TREE
7#export DEB_BUILD_OPTIONS=nocheck8#export DEB_BUILD_OPTIONS=nocheck
89
9RELEASE = $(shell lsb_release -c -s)10RELEASE = $(shell lsb_release -c -s)
11=======
12#export DEB_BUILD_OPTIONS=nocheck
13>>>>>>> MERGE-SOURCE
1014
11%:15%:
12 dh $@ --buildsystem=golang --with=golang --fail-missing --with systemd16 dh $@ --buildsystem=golang --with=golang --fail-missing --with systemd
@@ -37,6 +41,7 @@
37 --no-enable \41 --no-enable \
38 -pubuntu-snappy \42 -pubuntu-snappy \
39 snappy-autopilot.service43 snappy-autopilot.service
44<<<<<<< TREE
40 # enable wait4network45 # enable wait4network
41 dh_systemd_enable \46 dh_systemd_enable \
42 -pubuntu-snappy \47 -pubuntu-snappy \
@@ -45,6 +50,12 @@
45 dh_systemd_enable \50 dh_systemd_enable \
46 -pubuntu-snappy \51 -pubuntu-snappy \
47 ubuntu-snappy.snapd.socket52 ubuntu-snappy.snapd.socket
53=======
54 # enable wait4network
55 dh_systemd_enable \
56 -pubuntu-snappy \
57 snappy-wait4network.service
58>>>>>>> MERGE-SOURCE
4859
49override_dh_systemd_start:60override_dh_systemd_start:
50 # start boot-ok61 # start boot-ok
@@ -68,6 +79,7 @@
68 --no-start \79 --no-start \
69 -pubuntu-snappy \80 -pubuntu-snappy \
70 snappy-autopilot.service81 snappy-autopilot.service
82<<<<<<< TREE
71 # start wait4network83 # start wait4network
72 dh_systemd_start \84 dh_systemd_start \
73 -pubuntu-snappy \85 -pubuntu-snappy \
@@ -90,6 +102,14 @@
90 fi;102 fi;
91103
92override_dh_auto_install: snappy.8104override_dh_auto_install: snappy.8
105=======
106 # start wait4network
107 dh_systemd_start \
108 -pubuntu-snappy \
109 snappy-wait4network.service
110
111override_dh_auto_install:
112>>>>>>> MERGE-SOURCE
93 dh_auto_install -O--buildsystem=golang113 dh_auto_install -O--buildsystem=golang
94 # we do not need this in the package, its just needed during build114 # we do not need this in the package, its just needed during build
95 rm -rf ${CURDIR}/debian/tmp/usr/bin/xgettext-go115 rm -rf ${CURDIR}/debian/tmp/usr/bin/xgettext-go
96116
=== added file 'debian/snappy-wait4network.service'
--- debian/snappy-wait4network.service 1970-01-01 00:00:00 +0000
+++ debian/snappy-wait4network.service 2015-09-16 17:51:11 +0000
@@ -0,0 +1,10 @@
1[Unit]
2Description=Wait for network
3After=network-online.target
4
5[Service]
6Type=oneshot
7RemainAfterExit=yes
8TimeoutStartSec=0
9ExecStart=/bin/sh -ec 'while [ -z "$( /sbin/ip route show 0/0 )" ]; do sleep 5; done'
10
011
=== renamed file 'debian/snappy-wait4network.service' => 'debian/snappy-wait4network.service.moved'
=== modified file 'dependencies.tsv'
--- dependencies.tsv 2015-09-16 12:04:05 +0000
+++ dependencies.tsv 2015-09-16 17:51:11 +0000
@@ -6,9 +6,17 @@
6github.com/gosexy/gettext git 98b7b91596d20b96909e6b60d57411547dd9959c 2013-02-21T11:21:43Z6github.com/gosexy/gettext git 98b7b91596d20b96909e6b60d57411547dd9959c 2013-02-21T11:21:43Z
7github.com/jessevdk/go-flags git 1acbbaff2f347c412a0c7884873bd72cc9c1f5b4 2015-08-16T10:05:21Z7github.com/jessevdk/go-flags git 1acbbaff2f347c412a0c7884873bd72cc9c1f5b4 2015-08-16T10:05:21Z
8github.com/mvo5/goconfigparser git 26426272dda20cc76aa1fa44286dc743d2972fe8 2015-02-12T09:37:50Z8github.com/mvo5/goconfigparser git 26426272dda20cc76aa1fa44286dc743d2972fe8 2015-02-12T09:37:50Z
9<<<<<<< TREE
9github.com/mvo5/uboot-go git 361f6ebcbb54f389d15dc9faefa000e996ba3e37 2015-07-22T06:53:46Z10github.com/mvo5/uboot-go git 361f6ebcbb54f389d15dc9faefa000e996ba3e37 2015-07-22T06:53:46Z
10golang.org/x/crypto git 60052bd85f2d91293457e8811b0cf26b773de469 2015-06-22T23:34:07Z11golang.org/x/crypto git 60052bd85f2d91293457e8811b0cf26b773de469 2015-06-22T23:34:07Z
11gopkg.in/check.v1 git 64131543e7896d5bcc6bd5a76287eb75ea96c673 2014-10-24T13:38:53Z12gopkg.in/check.v1 git 64131543e7896d5bcc6bd5a76287eb75ea96c673 2014-10-24T13:38:53Z
12gopkg.in/tomb.v2 git 14b3d72120e8d10ea6e6b7f87f7175734b1faab8 2014-06-26T14:46:23Z13gopkg.in/tomb.v2 git 14b3d72120e8d10ea6e6b7f87f7175734b1faab8 2014-06-26T14:46:23Z
14=======
15github.com/mvo5/uboot-go git 361f6ebcbb54f389d15dc9faefa000e996ba3e37 2015-07-22T06:53:46Z
16gopkg.in/check.v1 git 64131543e7896d5bcc6bd5a76287eb75ea96c673 2014-10-24T13:38:53Z
17>>>>>>> MERGE-SOURCE
13gopkg.in/yaml.v2 git 49c95bdc21843256fb6c4e0d370a05f24a0bf213 2015-02-24T22:57:58Z18gopkg.in/yaml.v2 git 49c95bdc21843256fb6c4e0d370a05f24a0bf213 2015-02-24T22:57:58Z
19<<<<<<< TREE
14code.google.com/p/go.crypto hg 69e2a90ed92d03812364aeb947b7068dc42e561e 23520code.google.com/p/go.crypto hg 69e2a90ed92d03812364aeb947b7068dc42e561e 235
21=======
22>>>>>>> MERGE-SOURCE
1523
=== added directory 'etc'
=== renamed directory 'etc' => 'etc.moved'
=== added directory 'etc/grub.d'
=== added file 'etc/grub.d/09_snappy'
--- etc/grub.d/09_snappy 1970-01-01 00:00:00 +0000
+++ etc/grub.d/09_snappy 2015-09-16 17:51:11 +0000
@@ -0,0 +1,441 @@
1#!/bin/sh
2#---------------------------------------------------------------------
3# Summary: Grub bootloader logic for Ubuntu Snappy systems.
4# Description: This is a heavily modified "10_linux" grub snippet that
5# deals with Snappy dual-rootfs systems.
6#
7# XXX: Note that this script is called from within a chroot environment
8# on snappy systems!
9#
10#---------------------------------------------------------------------
11
12set -e
13
14prefix="/usr"
15exec_prefix="/usr"
16datarootdir="/usr/share"
17
18# Utility functions
19. "${datarootdir}/grub/grub-mkconfig_lib"
20
21# Globals
22machine=`uname -m`
23
24SNAPPY_OS="Ubuntu Core Snappy"
25SNAPPY_TYPE=simple
26
27#---------------------------------------------------------------------
28
29# Display message and exit
30die()
31{
32 msg="$*"
33 echo "ERROR: $msg" >&2
34 exit 1
35}
36
37# Create a grub menu entry by writing a menuentry to stdout.
38linux_entry_ext()
39{
40 local name="$1"
41 local os="$2"
42 local version="$3"
43 local type="$4"
44 local args="$5"
45 local device="$6"
46 local kernel="$7"
47 local initrd="$8"
48
49 local boot_device_id=
50 local prepare_root_cache=
51 local prepare_boot_cache=
52
53 if [ -z "$boot_device_id" ]; then
54 boot_device_id="$(grub_get_device_id "${device}")"
55 fi
56
57 echo "menuentry '$name' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
58
59 if [ x$type != xrecovery ] ; then
60 save_default_entry | grub_add_tab
61 fi
62
63 # Use ELILO's generic "efifb" when it's known to be available.
64 # FIXME: We need an interface to select vesafb in case efifb can't be used.
65 if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
66 echo " load_video" | sed "s/^/$submenu_indentation/"
67 else
68 if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
69 echo " load_video" | sed "s/^/$submenu_indentation/"
70 fi
71 fi
72 if ([ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]) && \
73 ([ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 1 ]); then
74 echo " gfxmode \$linux_gfx_mode" | sed "s/^/$submenu_indentation/"
75 fi
76
77 echo " insmod gzio" | sed "s/^/$submenu_indentation/"
78 echo " if [ x\$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi" | sed "s/^/$submenu_indentation/"
79
80 # device may be a label (LABEL=name), so convert back to full path
81 label_name=$(echo "$device"|sed 's/^LABEL=//g')
82 if [ "$device" = "$label_name" ]
83 then
84 device_path="$device"
85 else
86 # found a label
87 device_path=$(get_partition_from_label "$label_name")
88 fi
89
90 if [ x$dirname = x/ ]; then
91 if [ -z "${prepare_root_cache}" ]; then
92
93 prepare_root_cache="$(prepare_grub_to_access_device ${device_path} | grub_add_tab)"
94 fi
95 printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
96 else
97 if [ -z "${prepare_boot_cache}" ]; then
98 prepare_boot_cache="$(prepare_grub_to_access_device ${device_path} | grub_add_tab)"
99 fi
100 printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
101 fi
102
103 if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then
104 message="$(gettext_printf "Loading Linux %s ..." ${version})"
105 sed "s/^/$submenu_indentation/" << EOF
106 echo '$(echo "$message" | grub_quote)'
107EOF
108 fi
109
110 sed "s/^/$submenu_indentation/" << EOF
111 linux ${kernel} root=${device} ro ${args}
112EOF
113
114 if test -n "${initrd}"; then
115 # TRANSLATORS: ramdisk isn't identifier. Should be translated.
116 if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then
117 message="$(gettext_printf "Loading initial ramdisk ...")"
118 sed "s/^/$submenu_indentation/" << EOF
119 echo '$(echo "$message" | grub_quote)'
120EOF
121 fi
122 sed "s/^/$submenu_indentation/" << EOF
123 initrd ${initrd}
124EOF
125 fi
126
127 sed "s/^/$submenu_indentation/" << EOF
128}
129EOF
130}
131
132# Returns a list of the currently available kernels.
133# $1: If set, look for kernel below "$1/boot/".
134get_kernels()
135{
136 local prefix_dir="$1"
137 local list
138
139 case "x$machine" in
140 xi?86 | xx86_64)
141 list=`for i in $prefix_dir/boot/vmlinuz-* \
142 $prefix_dir/vmlinuz-* \
143 $prefix_dir/boot/kernel-* ; do
144 if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
145 done` ;;
146 *)
147 list=`for i in $prefix_dir/boot/vmlinuz-* \
148 $prefix_dir/boot/vmlinux-* \
149 $prefix_dir/vmlinuz-* \
150 $prefix_dir/vmlinux-* \
151 $prefix_dir/boot/kernel-* ; do
152 if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
153 done` ;;
154 esac
155 echo "$list"
156}
157
158# Composes and returns a kernel cmd line
159get_cmdline() {
160 channel_ini="/etc/system-image/channel.ini"
161 grep -q 'device: azure_amd64' "$channel_ini" && azure_cmdline="rootdelay=300"
162
163 echo "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} $azure_cmdline"
164}
165
166# Returns the path to the initrd for the kernel specified by $1.
167# $1: kernel version.
168# $2: directory to look in.
169get_initrd()
170{
171 local version="$1"
172 local dir="$2"
173
174 local alt_version=`echo $version | sed -e "s,\.old$,,g"`
175 local initrd=
176 local i=
177
178 for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \
179 "initrd-${version}" "initramfs-${version}.img" \
180 "initrd.img-${alt_version}" "initrd-${alt_version}.img" \
181 "initrd-${alt_version}" "initramfs-${alt_version}.img" \
182 "initramfs-genkernel-${version}" \
183 "initramfs-genkernel-${alt_version}" \
184 "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \
185 "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do
186 if test -e "${dir}/${i}" ; then
187 initrd="${dir}/${i}"
188 break
189 fi
190 done
191 echo "$initrd"
192}
193
194# Determine full path to disk partition given a filesystem label.
195get_partition_from_label()
196{
197 local label="$1"
198 local part=
199 local path=
200
201 [ -n "$label" ] || grub_warn "need FS label"
202
203 part=$(find /dev -name "$label"|tail -1)
204 [ -z "$part" ] && return
205 path=$(readlink -f "$part")
206 [ -n "$path" ] && echo "$path"
207}
208
209# Return the partition label for the given partition device.
210# $1: full path to partition device.
211get_label_from_device()
212{
213 local root="$1"
214
215 local label=
216 local std_label=
217 local label_rootfs=
218
219 for std_label in system-a system-b; do
220 label_rootfs=$(findfs "PARTLABEL=$std_label" 2>/dev/null || :)
221 if [ "$label_rootfs" = "$root" ]; then
222 label="$std_label"
223 break
224 fi
225 done
226
227 echo "$label"
228}
229
230# Return the full path to the device corresponding to the given
231# partition label.
232#
233# $1: partition label.
234get_device_from_label()
235{
236 local label="$1"
237 local device=
238
239 device=$(findfs "PARTLABEL=$label" 2>/dev/null || :)
240 echo "$device"
241}
242
243# Given a rootfs label, return the rootfs label corresponding to the
244# "other" rootfs partition.
245get_other_rootfs_label()
246{
247 local label="$1"
248
249 if [ "$label" = "system-a" ]; then
250 echo "system-b"
251 else
252 echo "system-a"
253 fi
254}
255
256# Given a mountpoint, return the corresponding device path
257# $1: mountpoint.
258get_device_from_mountpoint()
259{
260 local mountpoint="$1"
261 local device=
262
263 # XXX: Parse mount output rather than looking in /proc/mounts to
264 # avoid seeing the mounts outside the chroot.
265 device=$(/bin/mount | grep "^/dev/.* on ${mountpoint}[[:space:]]" 2>/dev/null |\
266 awk '{print $1}' || :)
267
268 echo "$device"
269}
270
271# Convert a partition label name to a menuentry name
272make_name()
273{
274 local label="$1"
275
276 echo "$SNAPPY_OS $label rootfs" | grub_quote
277}
278
279# Arrange for a grub menuentry to be created for the given partition.
280#
281# $1: full path to rootfs partition device
282# $2: partition label associated with $1
283# $3: mountpoint of $1.
284handle_menu_entry()
285{
286 local rootfs_device="$1"
287 local label="$2"
288 local mountpoint="$3"
289
290 local name=
291 local device=
292 local mount_prefix=
293 local list=
294 local linux=
295 local basename=
296 local dirname=
297 local rel_dirname=
298 local version=
299 local initrd=
300 local cmdline=
301
302 # boot by label
303 device="LABEL=$label"
304
305 name=$(make_name "$label")
306
307 # avoid double-leading slashes and the subsequent need to call
308 # 'readlink -f'.
309 if [ "$mountpoint" = "/" ]; then
310 mount_prefix=""
311 else
312 mount_prefix="$mountpoint"
313 fi
314 list=$(get_kernels "$mount_prefix")
315
316 linux=$(version_find_latest $list)
317 basename=$(basename "$linux")
318 dirname=$(dirname "$linux")
319 rel_dirname=$(make_system_path_relative_to_its_root "$dirname")
320 version=$(echo "$basename" | sed -e "s,^[^0-9]*-,,g")
321
322 initrd=$(get_initrd "$version" "$dirname")
323
324 cmdline=$(get_cmdline)
325
326 # convert the path to the mounted "other" rootfs back to a
327 # a standard one by removing the mountpoint prefix.
328 if [ "$mountpoint" != "/" ]; then
329 linux=$(echo "$linux" | sed "s!^${mountpoint}!!g")
330 initrd=$(echo "$initrd" | sed "s!^${mountpoint}!!g")
331 fi
332
333 # Create menu entries for the 2 snappy rootfs's.
334 linux_entry_ext "$name" "$SNAPPY_OS" "$version" \
335 "$SNAPPY_TYPE" "$cmdline" "$device" \
336 "$linux" "$initrd"
337}
338
339#---------------------------------------------------------------------
340# main
341
342case "$machine" in
343 i?86) GENKERNEL_ARCH="x86" ;;
344 mips|mips64) GENKERNEL_ARCH="mips" ;;
345 mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
346 arm*) GENKERNEL_ARCH="arm" ;;
347 *) GENKERNEL_ARCH="$machine" ;;
348esac
349
350# Determine which partition label is being used for the current root
351# directory. This is slightly convoluted but required since this code
352# runs within a chroot environment (where lsblk does not work).
353#
354# XXX: Note that since this code is run from within a chroot (where the
355# "other" rootfs is mounted), it might appear that the logic is
356# inverted. However, the code below simply
357this_mountpoint="/"
358this_root=$(get_device_from_mountpoint "$this_mountpoint")
359[ -z "$this_root" ] && {
360 die "cannot determine rootfs for $this_mountpoint"
361}
362
363this_label=$(get_label_from_device "$this_root")
364[ -z "$this_label" ] && {
365 die "cannot determine partition label for rootfs $this_root"
366}
367
368handle_menu_entry "$this_root" "$this_label" "$this_mountpoint"
369
370other_mountpoint="/writable/cache/system"
371
372# When this script is run on a real snappy system, even if there is only
373# a single rootfs provisioned, the other rootfs partition is expected to
374# be formatted and mounted.
375#
376# However this script is also run at provisioning time where
377# $other_mountpoint will not be a mountpoint. Therefore in the provisioning
378# scenario, only a single menuentry will be generated if only a single
379# rootfs is provisioned.
380if $(mountpoint -q "$other_mountpoint"); then
381 other_label=$(get_other_rootfs_label "$this_label")
382
383 other_root=$(get_device_from_label "$other_label")
384 [ -z "$other_root" ] && {
385 die "cannot determine rootfs"
386 }
387
388 handle_menu_entry "$other_root" "$other_label" "$other_mountpoint"
389fi
390
391# Toggle rootfs if previous boot failed.
392#
393# Since grub sets snappy_trial_boot, if it is _already_ set when grub starts
394# and we're in try mode, the previous boot must have failed to unset it,
395# so toggle the rootfs.
396sed "s/^/$submenu_indentation/" << EOF
397 # set defaults
398 if [ -z "\$snappy_mode" ]; then
399 set snappy_mode=regular
400 save_env snappy_mode
401 fi
402 if [ -z "\$snappy_ab" ]; then
403 set snappy_ab=a
404 save_env snappy_ab
405 fi
406
407 if [ "\$snappy_mode" = "try" ]; then
408 if [ "\$snappy_trial_boot" = "1" ]; then
409 # Previous boot failed to unset snappy_trial_boot, so toggle
410 # rootfs.
411 if [ "\$snappy_ab" = "a" ]; then
412 set default="$(make_name system-b)"
413 set snappy_ab=b
414 else
415 set snappy_ab=a
416 set default="$(make_name system-a)"
417 fi
418 save_env snappy_ab
419 else
420 # Trial mode so set the snappy_trial_boot (which snappy is
421 # expected to unset).
422 #
423 # Note: don't use the standard recordfail variable since that forces
424 # the menu to be displayed and sets an infinite timeout if set.
425 set snappy_trial_boot=1
426 save_env snappy_trial_boot
427
428 if [ "\$snappy_ab" = "a" ]; then
429 set default="$(make_name system-a)"
430 else
431 set default="$(make_name system-b)"
432 fi
433 fi
434 else
435 if [ "\$snappy_ab" = "a" ]; then
436 set default="$(make_name system-a)"
437 else
438 set default="$(make_name system-b)"
439 fi
440 fi
441EOF
0442
=== modified file 'helpers/cmp_test.go'
=== modified file 'helpers/helpers.go'
--- helpers/helpers.go 2015-09-01 10:00:49 +0000
+++ helpers/helpers.go 2015-09-16 17:51:11 +0000
@@ -26,6 +26,7 @@
26 "encoding/hex"26 "encoding/hex"
27 "fmt"27 "fmt"
28 "io"28 "io"
29 "io/ioutil"
29 "math/rand"30 "math/rand"
30 "os"31 "os"
31 "os/exec"32 "os/exec"
@@ -198,14 +199,37 @@
198 }199 }
199}200}
200201
201// IsSupportedArchitecture returns true if the system architecture is in the202<<<<<<< TREE
202// list of architectures.203// IsSupportedArchitecture returns true if the system architecture is in the
203func IsSupportedArchitecture(architectures []string) bool {204// list of architectures.
204 systemArch := UbuntuArchitecture()205func IsSupportedArchitecture(architectures []string) bool {
205206 systemArch := UbuntuArchitecture()
206 for _, arch := range architectures {207
207 if arch == "all" || arch == systemArch {208 for _, arch := range architectures {
208 return true209 if arch == "all" || arch == systemArch {
210 return true
211=======
212// IsSupportedArchitecture returns true if the system architecture is in the
213// list of architectures.
214func IsSupportedArchitecture(architectures []string) bool {
215 systemArch := UbuntuArchitecture()
216
217 for _, arch := range architectures {
218 if arch == "all" || arch == systemArch {
219 return true
220 }
221 }
222
223 return false
224}
225
226// EnsureDir ensures that the given directory exists and if
227// not creates it with the given permissions.
228func EnsureDir(dir string, perm os.FileMode) (err error) {
229 if _, err := os.Stat(dir); os.IsNotExist(err) {
230 if err := os.MkdirAll(dir, perm); err != nil {
231 return err
232>>>>>>> MERGE-SOURCE
209 }233 }
210 }234 }
211235
@@ -360,6 +384,7 @@
360 return syscall.Getuid() == 0 || syscall.Getgid() == 0384 return syscall.Getuid() == 0 || syscall.Getgid() == 0
361385
362}386}
387<<<<<<< TREE
363388
364// MajorMinor returns the major/minor number of the given os.FileInfo389// MajorMinor returns the major/minor number of the given os.FileInfo
365func MajorMinor(info os.FileInfo) (uint32, uint32, error) {390func MajorMinor(info os.FileInfo) (uint32, uint32, error) {
@@ -530,3 +555,140 @@
530555
531 return nil556 return nil
532}557}
558=======
559
560func makeDirMap(dirName string) (map[string]struct{}, error) {
561 dir, err := ioutil.ReadDir(dirName)
562 if err != nil {
563 return nil, err
564 }
565
566 dirMap := make(map[string]struct{})
567 for _, dent := range dir {
568 if dent.IsDir() {
569 return nil, fmt.Errorf("subdirs are not supported")
570 }
571 dirMap[dent.Name()] = struct{}{}
572 }
573
574 return dirMap, nil
575}
576
577// RSyncWithDelete syncs srcDir to destDir
578func RSyncWithDelete(srcDirName, destDirName string) error {
579
580 // first remove everything thats not in srcdir
581 err := filepath.Walk(destDirName, func(path string, info os.FileInfo, err error) error {
582 if err != nil {
583 return err
584 }
585
586 // relative to the root "destDirName"
587 relPath := path[len(destDirName):]
588 if !FileExists(filepath.Join(srcDirName, relPath)) {
589 if err := os.RemoveAll(path); err != nil {
590 return err
591 }
592 if info.IsDir() {
593 return filepath.SkipDir
594 }
595 }
596 return nil
597 })
598 if err != nil {
599 return err
600 }
601
602 // then copy or update the data from srcdir to destdir
603 err = filepath.Walk(srcDirName, func(path string, info os.FileInfo, err error) error {
604 if err != nil {
605 return err
606 }
607
608 // relative to the root "srcDirName"
609 relPath := path[len(srcDirName):]
610 if info.IsDir() {
611 return os.MkdirAll(filepath.Join(destDirName, relPath), info.Mode())
612 }
613 src := path
614 dst := filepath.Join(destDirName, relPath)
615 if !FilesAreEqual(src, dst) {
616 // XXX: on snappy-trunk we can use CopyFile here
617 output, err := exec.Command("cp", "-va", src, dst).CombinedOutput()
618 if err != nil {
619 return fmt.Errorf("Failed to copy %s to %s (%s)", src, dst, output)
620 }
621 }
622 return nil
623 })
624
625 return err
626}
627
628func fillSnapEnvVars(desc interface{}, vars []string) []string {
629 for i, v := range vars {
630 var templateOut bytes.Buffer
631 t := template.Must(template.New("wrapper").Parse(v))
632 if err := t.Execute(&templateOut, desc); err != nil {
633 // this can never happen, except we forget a variable
634 logger.LogAndPanic(err)
635 }
636 vars[i] = templateOut.String()
637 }
638 return vars
639}
640
641// GetBasicSnapEnvVars returns the app-level environment variables for a snap.
642// Despite this being a bit snap-specific, this is in helpers.go because it's
643// used by so many other modules, we run into circular dependencies if it's
644// somewhere more reasonable like the snappy module.
645func GetBasicSnapEnvVars(desc interface{}) []string {
646 return fillSnapEnvVars(desc, []string{
647 "TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
648 "TEMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
649 "SNAP_APP_PATH={{.AppPath}}",
650 "SNAP_APP_DATA_PATH=/var/lib{{.AppPath}}",
651 "SNAP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
652 "SNAP_NAME={{.AppName}}",
653 "SNAP_VERSION={{.Version}}",
654 "SNAP_ORIGIN={{.Namespace}}",
655 "SNAP_FULLNAME={{.UdevAppName}}",
656 "SNAP_ARCH={{.AppArch}}",
657 })
658}
659
660// GetUserSnapEnvVars returns the user-level environment variables for a snap.
661// Despite this being a bit snap-specific, this is in helpers.go because it's
662// used by so many other modules, we run into circular dependencies if it's
663// somewhere more reasonable like the snappy module.
664func GetUserSnapEnvVars(desc interface{}) []string {
665 return fillSnapEnvVars(desc, []string{
666 "SNAP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
667 })
668}
669
670// GetDeprecatedBasicSnapEnvVars returns the app-level deprecated environment
671// variables for a snap.
672// Despite this being a bit snap-specific, this is in helpers.go because it's
673// used by so many other modules, we run into circular dependencies if it's
674// somewhere more reasonable like the snappy module.
675func GetDeprecatedBasicSnapEnvVars(desc interface{}) []string {
676 return fillSnapEnvVars(desc, []string{
677 "SNAPP_APP_PATH={{.AppPath}}",
678 "SNAPP_APP_DATA_PATH=/var/lib{{.AppPath}}",
679 "SNAPP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
680 "SNAPPY_APP_ARCH={{.AppArch}}",
681 })
682}
683
684// GetDeprecatedUserSnapEnvVars returns the user-level deprecated environment
685// variables for a snap.
686// Despite this being a bit snap-specific, this is in helpers.go because it's
687// used by so many other modules, we run into circular dependencies if it's
688// somewhere more reasonable like the snappy module.
689func GetDeprecatedUserSnapEnvVars(desc interface{}) []string {
690 return fillSnapEnvVars(desc, []string{
691 "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
692 })
693}
694>>>>>>> MERGE-SOURCE
533695
=== modified file 'helpers/helpers_test.go'
--- helpers/helpers_test.go 2015-08-21 12:14:16 +0000
+++ helpers/helpers_test.go 2015-09-16 17:51:11 +0000
@@ -271,6 +271,7 @@
271 c.Assert(err, IsNil)271 c.Assert(err, IsNil)
272 c.Assert(home, Equals, oldHome)272 c.Assert(home, Equals, oldHome)
273}273}
274<<<<<<< TREE
274275
275func skipOnMissingDevKmsg(c *C) {276func skipOnMissingDevKmsg(c *C) {
276 _, err := os.Stat("/dev/kmsg")277 _, err := os.Stat("/dev/kmsg")
@@ -483,3 +484,106 @@
483 err := CopyIfDifferent(src, dst)484 err := CopyIfDifferent(src, dst)
484 c.Assert(err, NotNil)485 c.Assert(err, NotNil)
485}486}
487=======
488
489func makeTestFiles(c *C, srcDir, destDir string) {
490 // a new file
491 err := ioutil.WriteFile(filepath.Join(srcDir, "new"), []byte(nil), 0644)
492 c.Assert(err, IsNil)
493
494 // a existing file that needs update
495 err = ioutil.WriteFile(filepath.Join(destDir, "existing-update"), []byte("old-content"), 0644)
496 c.Assert(err, IsNil)
497 err = ioutil.WriteFile(filepath.Join(srcDir, "existing-update"), []byte("some-new-content"), 0644)
498 c.Assert(err, IsNil)
499
500 // existing file that needs no update
501 err = ioutil.WriteFile(filepath.Join(srcDir, "existing-unchanged"), []byte(nil), 0644)
502 c.Assert(err, IsNil)
503 err = exec.Command("cp", "-a", filepath.Join(srcDir, "existing-unchanged"), filepath.Join(destDir, "existing-unchanged")).Run()
504 c.Assert(err, IsNil)
505
506 // a file that needs removal
507 err = ioutil.WriteFile(filepath.Join(destDir, "to-be-deleted"), []byte(nil), 0644)
508 c.Assert(err, IsNil)
509}
510
511func compareDirs(c *C, srcDir, destDir string) {
512 d1, err := exec.Command("ls", "-al", srcDir).CombinedOutput()
513 c.Assert(err, IsNil)
514 d2, err := exec.Command("ls", "-al", destDir).CombinedOutput()
515 c.Assert(err, IsNil)
516 c.Assert(string(d1), Equals, string(d2))
517 // ensure content got updated
518 c1, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", srcDir)).CombinedOutput()
519 c.Assert(err, IsNil)
520 c2, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", destDir)).CombinedOutput()
521 c.Assert(err, IsNil)
522 c.Assert(string(c1), Equals, string(c2))
523}
524
525func (ts *HTestSuite) TestSyncDirs(c *C) {
526
527 for _, l := range [][2]string{
528 [2]string{"src-short", "dst-loooooooooooong"},
529 [2]string{"src-loooooooooooong", "dst-short"},
530 [2]string{"src-eq", "dst-eq"},
531 } {
532
533 // ensure we have src, dest dirs with different length
534 srcDir := filepath.Join(c.MkDir(), l[0])
535 err := os.MkdirAll(srcDir, 0755)
536 c.Assert(err, IsNil)
537 destDir := filepath.Join(c.MkDir(), l[1])
538 err = os.MkdirAll(destDir, 0755)
539 c.Assert(err, IsNil)
540
541 // add a src subdir
542 subdir := filepath.Join(srcDir, "subdir")
543 err = os.Mkdir(subdir, 0755)
544 c.Assert(err, IsNil)
545 makeTestFiles(c, subdir, destDir)
546
547 // add a dst subdir that needs to get deleted
548 subdir2 := filepath.Join(destDir, "to-be-deleted-subdir")
549 err = os.Mkdir(subdir2, 0755)
550 subdir3 := filepath.Join(subdir2, "to-be-deleted-sub-subdir")
551 err = os.Mkdir(subdir3, 0755)
552
553 // and a toplevel
554 makeTestFiles(c, srcDir, destDir)
555
556 // do it
557 err = RSyncWithDelete(srcDir, destDir)
558 c.Assert(err, IsNil)
559
560 // ensure meta-data is identical
561 compareDirs(c, srcDir, destDir)
562 compareDirs(c, filepath.Join(srcDir, "subdir"), filepath.Join(destDir, "subdir"))
563 }
564}
565
566func (ts *HTestSuite) TestSyncDirFails(c *C) {
567 srcDir := c.MkDir()
568 err := os.MkdirAll(srcDir, 0755)
569 c.Assert(err, IsNil)
570
571 destDir := c.MkDir()
572 err = os.MkdirAll(destDir, 0755)
573 c.Assert(err, IsNil)
574
575 err = ioutil.WriteFile(filepath.Join(destDir, "meep"), []byte(nil), 0644)
576 c.Assert(err, IsNil)
577
578 // ensure remove fails
579 err = os.Chmod(destDir, 0100)
580 c.Assert(err, IsNil)
581 // make tempdir cleanup work again
582 defer os.Chmod(destDir, 0755)
583
584 // do it
585 err = RSyncWithDelete(srcDir, destDir)
586 c.Check(err, NotNil)
587 c.Check(err, ErrorMatches, ".*permission denied.*")
588}
589>>>>>>> MERGE-SOURCE
486590
=== modified file 'helpers/touch.go'
=== modified file 'helpers/touch_test.go'
=== added directory 'logger'
=== renamed directory 'logger' => 'logger.moved'
=== added file 'logger/logger_test.go'
--- logger/logger_test.go 1970-01-01 00:00:00 +0000
+++ logger/logger_test.go 2015-09-16 17:51:11 +0000
@@ -0,0 +1,331 @@
1/*
2 * Copyright (C) 2014-2015 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18package logger
19
20import (
21 "bytes"
22 "errors"
23 "fmt"
24 "log/syslog"
25 "regexp"
26 "strings"
27 "testing"
28 "time"
29
30 "github.com/juju/loggo"
31 . "gopkg.in/check.v1"
32)
33
34func Test(t *testing.T) { TestingT(t) }
35
36type LoggerTestSuite struct {
37}
38
39var _ = Suite(&LoggerTestSuite{})
40
41type MockLogWriter struct {
42 buf bytes.Buffer
43}
44
45var mockWriter *MockLogWriter
46
47var loggoLevels = []string{"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
48
49func mockGetSyslog(priority syslog.Priority, tag string) (w logWriterInterface, err error) {
50 mockWriter = &MockLogWriter{}
51 return mockWriter, nil
52}
53
54func readLines() (lines []string) {
55 lines = strings.Split(string(mockWriter.buf.Bytes()), "\n")
56
57 // remove the last line if empty due to split.
58 length := len(lines)
59 last := lines[length-1]
60 if last == "" {
61 lines = lines[:length-1]
62 }
63 // clear the buffer to avoid contents accumulating indefinitely
64 mockWriter.buf.Reset()
65 return lines
66}
67
68func (ts *LoggerTestSuite) SetUpTest(c *C) {
69 getSyslog = mockGetSyslog
70}
71
72func (w *MockLogWriter) Debug(m string) error {
73 _, err := w.buf.Write([]byte(fmt.Sprintf("DEBUG: %s\n", m)))
74 return err
75}
76
77func (w *MockLogWriter) Info(m string) error {
78 _, err := w.buf.Write([]byte(fmt.Sprintf("INFO: %s\n", m)))
79 return err
80}
81
82func (w *MockLogWriter) Warning(m string) error {
83 _, err := w.buf.Write([]byte(fmt.Sprintf("WARNING: %s\n", m)))
84 return err
85}
86
87func (w *MockLogWriter) Err(m string) error {
88 _, err := w.buf.Write([]byte(fmt.Sprintf("ERROR: %s\n", m)))
89 return err
90}
91
92func (w *MockLogWriter) Crit(m string) error {
93 _, err := w.buf.Write([]byte(fmt.Sprintf("CRITICAL: %s\n", m)))
94 return err
95}
96
97// Search for value in array and return true if found
98func sliceContainsString(array []string, value string) bool {
99 str := string(strings.Join(array, ""))
100
101 return strings.Contains(str, value)
102}
103
104// Return true if array contains the pattern regex.
105func sliceContainsRegex(array []string, regex string) bool {
106 str := string(strings.Join(array, ""))
107
108 pattern := regexp.MustCompile(regex)
109
110 matches := pattern.FindAllStringSubmatch(str, -1)
111
112 return matches != nil
113}
114
115func (ts *LoggerTestSuite) TestNewLogWriter(c *C) {
116 var w, w2 *LogWriter
117 var err error
118
119 w, err = newLogWriter()
120 c.Assert(err, IsNil)
121 c.Assert(w, Not(IsNil))
122 c.Assert(w.systemLog, Not(IsNil))
123
124 w2, err = newLogWriter()
125 c.Assert(err, IsNil)
126 c.Assert(w2, Not(IsNil))
127 c.Assert(w2.systemLog, Not(IsNil))
128
129 // There should be a single shared syslog connection, hence the
130 // systemLog objects should be identical.
131 c.Assert(w.systemLog, Equals, w2.systemLog)
132 c.Assert(w.systemLog, DeepEquals, w2.systemLog)
133}
134
135func (ts *LoggerTestSuite) TestWrite(c *C) {
136 w, err := newLogWriter()
137 c.Assert(err, IsNil)
138 c.Assert(w, Not(IsNil))
139 c.Assert(w.systemLog, Not(IsNil))
140
141 t := time.Now()
142 strTime := fmt.Sprintf("%s", t)
143
144 for _, l := range loggoLevels {
145 level := stringToLogLevel(l)
146
147 w.Write(level, "module", "filename", 1234, t, "a message")
148 lines := readLines()
149
150 if level < loggo.ERROR {
151 c.Assert(len(lines), Equals, 1)
152 } else {
153 c.Assert(len(lines) > 1, Equals, true)
154
155 c.Assert(sliceContainsString(lines, "filename"), Equals, true)
156 c.Assert(sliceContainsString(lines, "1234"), Equals, true)
157 }
158
159 c.Assert(sliceContainsString(lines, "module"), Equals, true)
160
161 // We discard the timestamp as syslog adds that itself
162 c.Assert(sliceContainsString(lines, strTime), Equals, false)
163
164 c.Assert(sliceContainsString(lines, "a message"), Equals, true)
165 }
166
167}
168
169// Convert a loggo log level string representation into a real log
170// level.
171func stringToLogLevel(name string) loggo.Level {
172 level, ok := loggo.ParseLevel(name)
173
174 if !ok {
175 panic(fmt.Sprintf("unknown loggo level string: %q", name))
176 }
177
178 return level
179}
180
181func (ts *LoggerTestSuite) TestFormat(c *C) {
182 w, err := newLogWriter()
183 c.Assert(err, IsNil)
184 c.Assert(w, Not(IsNil))
185 c.Assert(w.systemLog, Not(IsNil))
186
187 for _, l := range loggoLevels {
188 level := stringToLogLevel(l)
189
190 if level < loggo.ERROR {
191 out := w.Format(level, "module", "filename", 1234, time.Now(), "a message")
192 c.Assert(out, Equals, fmt.Sprintf("%s:%s:%s", l, "module", "a message"))
193 } else {
194 out := w.Format(level, "module", "filename", 1234, time.Now(), "a message")
195 c.Assert(out, Equals, fmt.Sprintf("%s:%s:%s:%d:%s", l, "module", "filename", 1234, "a message"))
196 }
197 }
198}
199
200func (ts *LoggerTestSuite) TestLogStackTrace(c *C) {
201 var output []string
202
203 w, err := newLogWriter()
204 c.Assert(err, IsNil)
205 c.Assert(w, Not(IsNil))
206
207 f := func(s string) error {
208 output = append(output, s)
209 return nil
210 }
211
212 t := time.Now()
213 strTime := fmt.Sprintf("%s", t)
214
215 w.logStacktrace(loggo.DEBUG, "name", "filename", 9876, t, f)
216
217 c.Assert(sliceContainsString(output, "Stack trace"), Equals, true)
218 c.Assert(sliceContainsString(output, "name"), Equals, true)
219 c.Assert(sliceContainsString(output, "filename"), Equals, true)
220 c.Assert(sliceContainsString(output, "9876"), Equals, true)
221
222 // We discard the timestamp as syslog adds that itself
223 c.Assert(sliceContainsString(output, strTime), Equals, false)
224}
225
226func (ts *LoggerTestSuite) checkLogLevel(c *C, level, msg string) {
227 err := ActivateLogger()
228 c.Assert(err, IsNil)
229
230 expectBacktrace := (level == "ERROR" || level == "CRITICAL")
231
232 logger := loggo.GetLogger("snappy")
233 c.Assert(logger, Not(IsNil))
234
235 switch level {
236 case "DEBUG":
237 c.Assert(logger.IsDebugEnabled(), Equals, true)
238 logger.Debugf(msg)
239
240 case "INFO":
241 c.Assert(logger.IsInfoEnabled(), Equals, true)
242 logger.Infof(msg)
243
244 case "WARNING":
245 c.Assert(logger.IsWarningEnabled(), Equals, true)
246 logger.Warningf(msg)
247
248 case "ERROR":
249 c.Assert(logger.IsErrorEnabled(), Equals, true)
250 logger.Errorf(msg)
251
252 case "CRITICAL":
253 // loggo doesn't provide a IsCriticalEnabled()
254 c.Assert(logger.IsErrorEnabled(), Equals, true)
255 logger.Criticalf(msg)
256 }
257
258 lines := readLines()
259
260 if expectBacktrace {
261 c.Assert(len(lines) > 1, Equals, true)
262 } else {
263 c.Assert(len(lines), Equals, 1)
264 }
265
266 needle := fmt.Sprintf("%s.*%s", level, msg)
267 c.Assert(sliceContainsRegex(lines, needle), Equals, true)
268
269 c.Assert(sliceContainsString(lines, "Stack trace"), Equals, expectBacktrace)
270}
271
272func (ts *LoggerTestSuite) TestLogLevels(c *C) {
273 msg := "an error message"
274
275 for _, level := range loggoLevels {
276 ts.checkLogLevel(c, level, msg)
277 }
278}
279
280func (ts *LoggerTestSuite) TestLogError(c *C) {
281 level := "ERROR"
282 msg := "I am an error"
283
284 err := ActivateLogger()
285 c.Assert(err, IsNil)
286
287 result := LogError(nil)
288 c.Assert(result, IsNil)
289
290 err = errors.New(msg)
291 c.Assert(err, Not(IsNil))
292
293 // We expect to get back exactly what was passsed...
294 result = LogError(err)
295 c.Assert(result, DeepEquals, err)
296
297 // ... but also to have the error logged
298 ts.checkLogLevel(c, level, msg)
299}
300
301func (ts *LoggerTestSuite) TestLogAndPanic(c *C) {
302 level := "CRITICAL"
303 msg := "I am a fatal error"
304
305 panicked := false
306
307 err := ActivateLogger()
308 c.Assert(err, IsNil)
309
310 // If the specified error is nil, no panic is expected and no
311 // log entry should be added.
312 func() {
313 defer func() {
314 if r := recover(); r != nil {
315 panicked = true
316 }
317 }()
318 LogAndPanic(nil)
319 }()
320
321 c.Assert(panicked, Equals, false)
322 c.Assert(len(readLines()), Equals, 0)
323
324 err = errors.New(msg)
325
326 // expect a panic...
327 c.Assert(func() { LogAndPanic(err) }, Panics, err)
328
329 // ... and a log entry
330 ts.checkLogLevel(c, level, msg)
331}
0332
=== modified file 'partition/bootloader.go'
=== modified file 'partition/bootloader_grub.go'
--- partition/bootloader_grub.go 2015-07-23 11:54:14 +0000
+++ partition/bootloader_grub.go 2015-09-16 17:51:11 +0000
@@ -32,7 +32,12 @@
32 bootloaderGrubConfigFileReal = "/boot/grub/grub.cfg"32 bootloaderGrubConfigFileReal = "/boot/grub/grub.cfg"
33 bootloaderGrubEnvFileReal = "/boot/grub/grubenv"33 bootloaderGrubEnvFileReal = "/boot/grub/grubenv"
3434
35<<<<<<< TREE
35 bootloaderGrubEnvCmdReal = "/usr/bin/grub-editenv"36 bootloaderGrubEnvCmdReal = "/usr/bin/grub-editenv"
37=======
38 bootloaderGrubEnvCmdReal = "/usr/bin/grub-editenv"
39 bootloaderGrubUpdateCmdReal = "/usr/sbin/update-grub"
40>>>>>>> MERGE-SOURCE
36)41)
3742
38// var to make it testable43// var to make it testable
@@ -115,9 +120,24 @@
115 return g.GetBootVar(bootloaderRootfsVar)120 return g.GetBootVar(bootloaderRootfsVar)
116}121}
117122
123<<<<<<< TREE
118func (g *grub) MarkCurrentBootSuccessful(currentRootfs string) (err error) {124func (g *grub) MarkCurrentBootSuccessful(currentRootfs string) (err error) {
119 // Clear the variable set on boot to denote a good boot.125 // Clear the variable set on boot to denote a good boot.
120 if err := g.setBootVar(bootloaderTrialBootVar, "0"); err != nil {126 if err := g.setBootVar(bootloaderTrialBootVar, "0"); err != nil {
127=======
128func (g *grub) GetRootFSName() string {
129 return g.currentRootfs
130}
131
132func (g *grub) GetOtherRootFSName() string {
133 return g.otherRootfs
134}
135
136func (g *grub) MarkCurrentBootSuccessful() (err error) {
137 // Clear the variable set by grub on boot to denote a good
138 // boot.
139 if err := g.unsetBootVar(bootloaderTrialBootVar); err != nil {
140>>>>>>> MERGE-SOURCE
121 return err141 return err
122 }142 }
123143
124144
=== modified file 'partition/bootloader_grub_test.go'
--- partition/bootloader_grub_test.go 2015-07-23 11:54:14 +0000
+++ partition/bootloader_grub_test.go 2015-09-16 17:51:11 +0000
@@ -23,11 +23,16 @@
23 "fmt"23 "fmt"
24 "io/ioutil"24 "io/ioutil"
25 "os"25 "os"
26<<<<<<< TREE
26 "path/filepath"27 "path/filepath"
2728
28 "launchpad.net/snappy/helpers"29 "launchpad.net/snappy/helpers"
2930
30 . "gopkg.in/check.v1"31 . "gopkg.in/check.v1"
32=======
33
34 . "gopkg.in/check.v1"
35>>>>>>> MERGE-SOURCE
31)36)
3237
33func mockGrubFile(c *C, newPath string, mode os.FileMode) {38func mockGrubFile(c *C, newPath string, mode os.FileMode) {
3439
=== modified file 'partition/bootloader_uboot.go'
--- partition/bootloader_uboot.go 2015-07-24 12:00:01 +0000
+++ partition/bootloader_uboot.go 2015-09-16 17:51:11 +0000
@@ -55,9 +55,14 @@
55 bootloaderUbootConfigFile = bootloaderUbootConfigFileReal55 bootloaderUbootConfigFile = bootloaderUbootConfigFileReal
56 bootloaderUbootStampFile = bootloaderUbootStampFileReal56 bootloaderUbootStampFile = bootloaderUbootStampFileReal
57 bootloaderUbootEnvFile = bootloaderUbootEnvFileReal57 bootloaderUbootEnvFile = bootloaderUbootEnvFileReal
58<<<<<<< TREE
58 bootloaderUbootFwEnvFile = bootloaderUbootFwEnvFileReal59 bootloaderUbootFwEnvFile = bootloaderUbootFwEnvFileReal
5960
60 atomicWriteFile = helpers.AtomicWriteFile61 atomicWriteFile = helpers.AtomicWriteFile
62=======
63 bootloaderUbootFwEnvFile = bootloaderUbootFwEnvFileReal
64 atomicFileUpdate = atomicFileUpdateImpl
65>>>>>>> MERGE-SOURCE
61)66)
6267
63const bootloaderNameUboot bootloaderName = "u-boot"68const bootloaderNameUboot bootloaderName = "u-boot"
@@ -103,15 +108,64 @@
103 return bootloaderNameUboot108 return bootloaderNameUboot
104}109}
105110
111<<<<<<< TREE
106func (u *uboot) ToggleRootFS(otherRootfs string) (err error) {112func (u *uboot) ToggleRootFS(otherRootfs string) (err error) {
107 if err := setBootVar(bootloaderRootfsVar, string(otherRootfs)); err != nil {113 if err := setBootVar(bootloaderRootfsVar, string(otherRootfs)); err != nil {
108 return err114 return err
115=======
116// ToggleRootFS make the U-Boot bootloader switch rootfs's.
117//
118// Approach:
119//
120// - Assume the device's installed version of u-boot supports
121// CONFIG_SUPPORT_RAW_INITRD (that allows u-boot to boot a
122// standard initrd+kernel on the fat32 disk partition).
123// - Copy the "other" rootfs's kernel+initrd to the boot partition,
124// renaming them in the process to ensure the next boot uses the
125// correct versions.
126func (u *uboot) ToggleRootFS() (err error) {
127 // modern system
128 if helpers.FileExists(bootloaderUbootFwEnvFile) {
129 return u.toggleRootFSFwEnv()
130 }
131
132 // legacy
133 return u.toggleRootFSLegacy()
134}
135
136func (u *uboot) toggleRootFSFwEnv() (err error) {
137 if err := u.setBootVar(bootloaderRootfsVar, string(u.otherRootfs)); err != nil {
138 return err
139 }
140
141 return u.setBootVar(bootloaderBootmodeVar, bootloaderBootmodeTry)
142}
143
144func (u *uboot) toggleRootFSLegacy() (err error) {
145 // If the file exists, update it. Otherwise create it.
146 //
147 // The file _should_ always exist, but since it's on a writable
148 // partition, it's possible the admin removed it by mistake. So
149 // recreate to allow the system to boot!
150 changes := []configFileChange{
151 configFileChange{Name: bootloaderRootfsVar,
152 Value: string(u.otherRootfs),
153 },
154 configFileChange{Name: bootloaderBootmodeVar,
155 Value: bootloaderBootmodeTry,
156 },
157>>>>>>> MERGE-SOURCE
109 }158 }
110159
111 return setBootVar(bootloaderBootmodeVar, bootloaderBootmodeTry)160 return setBootVar(bootloaderBootmodeVar, bootloaderBootmodeTry)
112}161}
113162
163<<<<<<< TREE
114func getBootVarLegacy(name string) (value string, err error) {164func getBootVarLegacy(name string) (value string, err error) {
165=======
166func (u *uboot) getBootVarLegacy(name string) (value string, err error) {
167
168>>>>>>> MERGE-SOURCE
115 cfg := goconfigparser.New()169 cfg := goconfigparser.New()
116 cfg.AllowNoSectionHeader = true170 cfg.AllowNoSectionHeader = true
117 if err := cfg.ReadFile(bootloaderUbootEnvFile); err != nil {171 if err := cfg.ReadFile(bootloaderUbootEnvFile); err != nil {
@@ -121,6 +175,7 @@
121 return cfg.Get("", name)175 return cfg.Get("", name)
122}176}
123177
178<<<<<<< TREE
124func setBootVarLegacy(name, value string) error {179func setBootVarLegacy(name, value string) error {
125 curVal, err := getBootVarLegacy(name)180 curVal, err := getBootVarLegacy(name)
126 if err == nil && curVal == value {181 if err == nil && curVal == value {
@@ -165,6 +220,16 @@
165 return getBootVar(name)220 return getBootVar(name)
166}221}
167222
223=======
224func (u *uboot) GetBootVar(name string) (value string, err error) {
225 if helpers.FileExists(bootloaderUbootFwEnvFile) {
226 return u.getBootVar(name)
227 }
228
229 return u.getBootVarLegacy(name)
230}
231
232>>>>>>> MERGE-SOURCE
168func (u *uboot) GetNextBootRootFSName() (label string, err error) {233func (u *uboot) GetNextBootRootFSName() (label string, err error) {
169 value, err := u.GetBootVar(bootloaderRootfsVar)234 value, err := u.GetBootVar(bootloaderRootfsVar)
170 if err != nil {235 if err != nil {
@@ -175,6 +240,7 @@
175 return value, nil240 return value, nil
176}241}
177242
243<<<<<<< TREE
178// FIXME: this is super similar to grub now, refactor to extract the244// FIXME: this is super similar to grub now, refactor to extract the
179// common code245// common code
180func (u *uboot) MarkCurrentBootSuccessful(currentRootfs string) error {246func (u *uboot) MarkCurrentBootSuccessful(currentRootfs string) error {
@@ -197,6 +263,260 @@
197263
198func (u *uboot) BootDir() string {264func (u *uboot) BootDir() string {
199 return bootloaderUbootDir265 return bootloaderUbootDir
266=======
267func (u *uboot) GetRootFSName() string {
268 return u.currentRootfs
269}
270
271func (u *uboot) GetOtherRootFSName() string {
272 return u.otherRootfs
273}
274
275// FIXME: put into utils package
276func readLines(path string) (lines []string, err error) {
277
278 file, err := os.Open(path)
279
280 if err != nil {
281 return nil, err
282 }
283
284 defer file.Close()
285
286 scanner := bufio.NewScanner(file)
287 for scanner.Scan() {
288 lines = append(lines, scanner.Text())
289 }
290
291 return lines, scanner.Err()
292}
293
294// FIXME: put into utils package
295func writeLines(lines []string, path string) (err error) {
296
297 file, err := os.Create(path)
298
299 if err != nil {
300 return err
301 }
302
303 defer func() {
304 e := file.Close()
305 if err == nil {
306 err = e
307 }
308 }()
309
310 writer := bufio.NewWriter(file)
311
312 for _, line := range lines {
313 if _, err := fmt.Fprintln(writer, line); err != nil {
314 return err
315 }
316 }
317
318 if err := writer.Flush(); err != nil {
319 return err
320 }
321
322 return file.Sync()
323}
324
325func (u *uboot) SyncBootFiles() (err error) {
326 srcDir := u.currentBootPath
327 destDir := u.otherBootPath
328
329 return helpers.RSyncWithDelete(srcDir, destDir)
330}
331
332func (u *uboot) HandleAssets() (err error) {
333 // check if we have anything, if there is no hardware yaml, there is nothing
334 // to process.
335 hardware, err := u.partition.hardwareSpec()
336 if err == ErrNoHardwareYaml {
337 return nil
338 } else if err != nil {
339 return err
340 }
341 // ensure to remove the file once we are done
342 defer os.Remove(u.partition.hardwareSpecFile)
343
344 // validate bootloader
345 if hardware.Bootloader != u.Name() {
346 return fmt.Errorf(
347 "bootloader is of type %s but hardware spec requires %s",
348 u.Name(),
349 hardware.Bootloader)
350 }
351
352 // validate partition layout
353 if u.partition.dualRootPartitions() && hardware.PartitionLayout != bootloaderSystemAB {
354 return fmt.Errorf("hardware spec requires dual root partitions")
355 }
356
357 // ensure we have the destdir
358 destDir := u.otherBootPath
359 if err := os.MkdirAll(destDir, dirMode); err != nil {
360 return err
361 }
362
363 // install kernel+initrd
364 for _, file := range []string{hardware.Kernel, hardware.Initrd} {
365
366 if file == "" {
367 continue
368 }
369
370 // expand path
371 path := path.Join(u.partition.cacheDir(), file)
372
373 if !helpers.FileExists(path) {
374 return fmt.Errorf("can not find file %s", path)
375 }
376
377 // ensure we remove the dir later
378 defer os.RemoveAll(filepath.Dir(path))
379
380 if err := runCommand("/bin/cp", path, destDir); err != nil {
381 return err
382 }
383 }
384
385 // TODO: look at the OEM package for dtb changes too once that is
386 // fully speced
387
388 // install .dtb files
389 dtbSrcDir := filepath.Join(u.partition.cacheDir(), hardware.DtbDir)
390 if helpers.FileExists(dtbSrcDir) {
391 // ensure we cleanup the source dir
392 defer os.RemoveAll(dtbSrcDir)
393
394 dtbDestDir := path.Join(destDir, "dtbs")
395 if err := os.MkdirAll(dtbDestDir, dirMode); err != nil {
396 return err
397 }
398
399 files, err := filepath.Glob(path.Join(dtbSrcDir, "*"))
400 if err != nil {
401 return err
402 }
403
404 for _, file := range files {
405 if err := runCommand("/bin/cp", file, dtbDestDir); err != nil {
406 return err
407 }
408 }
409 }
410
411 flashAssetsDir := u.partition.flashAssetsDir()
412
413 if helpers.FileExists(flashAssetsDir) {
414 // FIXME: we don't currently do anything with the
415 // MLO + uImage files since they are not specified in
416 // the hardware spec. So for now, just remove them.
417
418 if err := os.RemoveAll(flashAssetsDir); err != nil {
419 return err
420 }
421 }
422
423 return err
424}
425
426func (u *uboot) setBootVar(name, value string) error {
427 env, err := uenv.Open(bootloaderUbootFwEnvFile)
428 if err != nil {
429 return err
430 }
431
432 // already set, nothing to do
433 if env.Get(name) == value {
434 return nil
435 }
436
437 env.Set(name, value)
438 return env.Save()
439}
440
441func (u *uboot) hasBootVar(name string) (bool, error) {
442 v, err := u.getBootVar(name)
443 return v != "", err
444}
445
446func (u *uboot) getBootVar(name string) (string, error) {
447 env, err := uenv.Open(bootloaderUbootFwEnvFile)
448 if err != nil {
449 return "", err
450 }
451
452 return env.Get(name), nil
453}
454
455// FIXME: this is super similar to grub now, refactor to extract the
456// common code
457func (u *uboot) markCurrentBootSuccessfulFwEnv(currentRootfs string) error {
458 // Clear the variable set on boot to denote a good boot.
459 if err := u.setBootVar(bootloaderTrialBootVar, "0"); err != nil {
460 return err
461 }
462
463 if err := u.setBootVar(bootloaderRootfsVar, currentRootfs); err != nil {
464 return err
465 }
466
467 return u.setBootVar(bootloaderBootmodeVar, bootloaderBootmodeSuccess)
468}
469
470func (u *uboot) markCurrentBootSuccessfulLegacy(currentRootfs string) error {
471 changes := []configFileChange{
472 configFileChange{Name: bootloaderBootmodeVar,
473 Value: bootloaderBootmodeSuccess,
474 },
475 configFileChange{Name: bootloaderRootfsVar,
476 Value: string(u.currentRootfs),
477 },
478 }
479
480 if err := modifyNameValueFile(bootloaderUbootEnvFile, changes); err != nil {
481 return err
482 }
483
484 return os.RemoveAll(bootloaderUbootStampFile)
485}
486
487func (u *uboot) MarkCurrentBootSuccessful() error {
488 // modern system
489 if helpers.FileExists(bootloaderUbootFwEnvFile) {
490 return u.markCurrentBootSuccessfulFwEnv(u.currentRootfs)
491 }
492
493 // legacy
494 return u.markCurrentBootSuccessfulLegacy(u.currentRootfs)
495}
496
497// Write lines to file atomically. File does not have to preexist.
498// FIXME: put into utils package
499func atomicFileUpdateImpl(file string, lines []string) (err error) {
500 tmpFile := fmt.Sprintf("%s.NEW", file)
501
502 // XXX: if go switches to use aio_fsync, we need to open the dir for writing
503 dir, err := os.Open(filepath.Dir(file))
504 if err != nil {
505 return err
506 }
507 defer dir.Close()
508
509 if err := writeLines(lines, tmpFile); err != nil {
510 return err
511 }
512
513 // atomic update
514 if err := os.Rename(tmpFile, file); err != nil {
515 return err
516 }
517
518 return dir.Sync()
519>>>>>>> MERGE-SOURCE
200}520}
201521
202// Rewrite the specified file, applying the specified set of changes.522// Rewrite the specified file, applying the specified set of changes.
@@ -206,8 +526,13 @@
206// appended to the file.526// appended to the file.
207//527//
208// FIXME: put into utils package528// FIXME: put into utils package
529<<<<<<< TREE
209// FIXME: improve logic530// FIXME: improve logic
210func modifyNameValueFile(path string, changes []configFileChange) error {531func modifyNameValueFile(path string, changes []configFileChange) error {
532=======
533// FIXME: improve logic
534func modifyNameValueFile(file string, changes []configFileChange) (err error) {
535>>>>>>> MERGE-SOURCE
211 var updated []configFileChange536 var updated []configFileChange
212537
213 // we won't write to a file if we don't need to.538 // we won't write to a file if we don't need to.
@@ -217,12 +542,21 @@
217 if err != nil {542 if err != nil {
218 return err543 return err
219 }544 }
545<<<<<<< TREE
220 defer file.Close()546 defer file.Close()
221547
222 buf := bytes.NewBuffer(nil)548 buf := bytes.NewBuffer(nil)
223 scanner := bufio.NewScanner(file)549 scanner := bufio.NewScanner(file)
224 for scanner.Scan() {550 for scanner.Scan() {
225 line := scanner.Text()551 line := scanner.Text()
552=======
553
554 var new []string
555 // we won't write to a file if we don't need to.
556 updateNeeded := false
557
558 for _, line := range lines {
559>>>>>>> MERGE-SOURCE
226 for _, change := range changes {560 for _, change := range changes {
227 if strings.HasPrefix(line, fmt.Sprintf("%s=", change.Name)) {561 if strings.HasPrefix(line, fmt.Sprintf("%s=", change.Name)) {
228 value := strings.SplitN(line, "=", 2)[1]562 value := strings.SplitN(line, "=", 2)[1]
@@ -260,9 +594,18 @@
260 }594 }
261 }595 }
262596
597<<<<<<< TREE
263 if updateNeeded {598 if updateNeeded {
264 return atomicWriteFile(path, buf.Bytes(), 0644)599 return atomicWriteFile(path, buf.Bytes(), 0644)
265 }600 }
601=======
602 if updateNeeded {
603 return atomicFileUpdate(file, lines)
604 }
605
606 return nil
607}
608>>>>>>> MERGE-SOURCE
266609
267 return nil610 return nil
268}611}
269612
=== modified file 'partition/bootloader_uboot_test.go'
--- partition/bootloader_uboot_test.go 2015-07-24 11:58:04 +0000
+++ partition/bootloader_uboot_test.go 2015-09-16 17:51:11 +0000
@@ -382,3 +382,93 @@
382 c.Assert(err, IsNil)382 c.Assert(err, IsNil)
383 c.Assert(st.ModTime(), Equals, st2.ModTime())383 c.Assert(st.ModTime(), Equals, st2.ModTime())
384}384}
385
386func (s *PartitionTestSuite) TestNoWriteNotNeeded(c *C) {
387 s.makeFakeUbootEnv(c)
388
389 atomiCall := false
390 atomicFileUpdate = func(a string, b []string) error { atomiCall = true; return atomicFileUpdateImpl(a, b) }
391
392 partition := New()
393 u := newUboot(partition)
394 c.Assert(u, NotNil)
395
396 c.Check(u.MarkCurrentBootSuccessful(), IsNil)
397 c.Assert(atomiCall, Equals, false)
398}
399
400func (s *PartitionTestSuite) TestWriteDueToMissingValues(c *C) {
401 s.makeFakeUbootEnv(c)
402
403 // this file needs specific data
404 c.Assert(ioutil.WriteFile(bootloaderUbootEnvFile, []byte(""), 0644), IsNil)
405
406 atomiCall := false
407 atomicFileUpdate = func(a string, b []string) error { atomiCall = true; return atomicFileUpdateImpl(a, b) }
408
409 partition := New()
410 u := newUboot(partition)
411 c.Assert(u, NotNil)
412
413 c.Check(u.MarkCurrentBootSuccessful(), IsNil)
414 c.Assert(atomiCall, Equals, true)
415
416 bytes, err := ioutil.ReadFile(bootloaderUbootEnvFile)
417 c.Assert(err, IsNil)
418 c.Check(strings.Contains(string(bytes), "snappy_mode=try"), Equals, false)
419 c.Check(strings.Contains(string(bytes), "snappy_mode=regular"), Equals, true)
420 c.Check(strings.Contains(string(bytes), "snappy_ab=a"), Equals, true)
421}
422
423func (s *PartitionTestSuite) TestUbootMarkCurrentBootSuccessfulFwEnv(c *C) {
424 s.makeFakeUbootEnv(c)
425
426 env, err := uenv.Create(bootloaderUbootFwEnvFile, 4096)
427 c.Assert(err, IsNil)
428 env.Set("snappy_ab", "a")
429 env.Set("snappy_mode", "try")
430 env.Set("snappy_trial_boot", "1")
431 err = env.Save()
432 c.Assert(err, IsNil)
433
434 partition := New()
435 u := newUboot(partition)
436 c.Assert(u, NotNil)
437
438 err = u.MarkCurrentBootSuccessful()
439 c.Assert(err, IsNil)
440
441 env, err = uenv.Open(bootloaderUbootFwEnvFile)
442 c.Assert(err, IsNil)
443 c.Assert(env.String(), Equals, "snappy_ab=a\nsnappy_mode=regular\nsnappy_trial_boot=0\n")
444}
445
446func (s *PartitionTestSuite) TestUbootSetEnvNoUselessWrites(c *C) {
447 s.makeFakeUbootEnv(c)
448
449 env, err := uenv.Create(bootloaderUbootFwEnvFile, 4096)
450 c.Assert(err, IsNil)
451 env.Set("snappy_ab", "a")
452 env.Set("snappy_mode", "regular")
453 err = env.Save()
454 c.Assert(err, IsNil)
455
456 st, err := os.Stat(bootloaderUbootFwEnvFile)
457 c.Assert(err, IsNil)
458 time.Sleep(100 * time.Millisecond)
459
460 partition := New()
461 u := newUboot(partition)
462 c.Assert(u, NotNil)
463
464 err = u.(*uboot).setBootVar(bootloaderRootfsVar, "a")
465 c.Assert(err, IsNil)
466
467 env, err = uenv.Open(bootloaderUbootFwEnvFile)
468 c.Assert(err, IsNil)
469 c.Assert(env.String(), Equals, "snappy_ab=a\nsnappy_mode=regular\n")
470
471 st2, err := os.Stat(bootloaderUbootFwEnvFile)
472 c.Assert(err, IsNil)
473 c.Assert(st.ModTime(), Equals, st2.ModTime())
474}
385475
=== modified file 'partition/partition.go'
--- partition/partition.go 2015-07-15 07:53:43 +0000
+++ partition/partition.go 2015-09-16 17:51:11 +0000
@@ -596,6 +596,7 @@
596 return errors.New("System is not dual root")596 return errors.New("System is not dual root")
597 }597 }
598598
599<<<<<<< TREE
599 bootloader, err := bootloader(p)600 bootloader, err := bootloader(p)
600 if err != nil {601 if err != nil {
601 return err602 return err
@@ -619,4 +620,23 @@
619 }620 }
620621
621 return bootloader.BootDir()622 return bootloader.BootDir()
623=======
624 bootloader, err := getBootloader(p)
625 if err != nil {
626 return err
627 }
628
629 // XXX: first toggle roofs and then handle assets? that seems
630 // wrong given that handleAssets may fails and we will
631 // knowingly boot into a broken system
632 err = p.RunWithOther(RW, func(otherRoot string) (err error) {
633 return bootloader.ToggleRootFS()
634 })
635
636 if err != nil {
637 return err
638 }
639
640 return bootloader.HandleAssets()
641>>>>>>> MERGE-SOURCE
622}642}
623643
=== modified file 'partition/partition_test.go'
=== modified file 'partition/utils_test.go'
=== modified file 'policy/policy_test.go'
=== modified file 'priv/priv_test.go'
=== modified file 'progress/progress.go'
=== modified file 'progress/progress_test.go'
=== modified file 'release/release_test.go'
=== modified file 'run-checks'
--- run-checks 2015-09-02 18:11:49 +0000
+++ run-checks 2015-09-16 17:51:11 +0000
@@ -53,6 +53,7 @@
53lint=$(golint ./... && golint ./_integration-tests/testutils/... && golint ./_integration-tests/tests/...)53lint=$(golint ./... && golint ./_integration-tests/testutils/... && golint ./_integration-tests/tests/...)
54if [ -n "$lint" ]; then54if [ -n "$lint" ]; then
55 echo "Lint complains:"55 echo "Lint complains:"
56<<<<<<< TREE
56 echo "$lint"57 echo "$lint"
57 exit 158 exit 1
58fi59fi
@@ -83,6 +84,24 @@
83 if which subunit2pyunit >/dev/null 2>&1; then84 if which subunit2pyunit >/dev/null 2>&1; then
84 subunit-1to2 /tmp/snappy-test/output/artifacts/results.subunit | subunit2pyunit85 subunit-1to2 /tmp/snappy-test/output/artifacts/results.subunit | subunit2pyunit
85 fi86 fi
87=======
88 echo "$lint"
89 exit 1
90>>>>>>> MERGE-SOURCE
91fi
92
93# integration tests
94echo Building the integration tests
95go build _integration-tests/main.go
96
97# the rabbit hole
98echo Running the tests for the integration testutils
99$goctest -v -cover ./_integration-tests/testutils/...
100
101# integration suite in kvm
102if which adt-run >/dev/null 2>&1; then
103 echo "Running integration tests on 15.04 edge"
104 go run _integration-tests/main.go --snappy-from-branch --release=15.04
86fi105fi
87106
88echo "All good, what could possibly go wrong"107echo "All good, what could possibly go wrong"
89108
=== modified file 'snappy/auth.go'
=== modified file 'snappy/auth_test.go'
--- snappy/auth_test.go 2015-06-09 12:56:34 +0000
+++ snappy/auth_test.go 2015-09-16 17:51:11 +0000
@@ -36,8 +36,8 @@
36const mockStoreInvalidLoginCode = 40136const mockStoreInvalidLoginCode = 401
37const mockStoreInvalidLogin = `37const mockStoreInvalidLogin = `
38{38{
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches