Merge lp:~snappy-dev/snappy/snappy-moved-to-github into lp:snappy/15.04

Proposed by Michael Vogt
Status: Merged
Approved by: Michael Vogt
Approved revision: 793
Merged at revision: 716
Proposed branch: lp:~snappy-dev/snappy/snappy-moved-to-github
Merge into: lp:snappy/15.04
Diff against target: 3284 lines (+1579/-247)
64 files modified
_integration-tests/data/snaps/basic-binaries/bin/fail (+3/-0)
_integration-tests/data/snaps/basic-binaries/bin/success (+3/-0)
_integration-tests/data/snaps/basic-binaries/meta/package.yaml (+2/-0)
_integration-tests/data/snaps/basic-config/meta/hooks/config (+37/-0)
_integration-tests/data/snaps/basic-config/meta/package.yaml (+4/-0)
_integration-tests/data/snaps/basic-config/meta/readme.md (+3/-0)
_integration-tests/data/snaps/basic-framework/meta/package.yaml (+5/-0)
_integration-tests/data/snaps/basic-framework/meta/readme.md (+3/-0)
_integration-tests/data/snaps/basic-service/bin/start (+3/-0)
_integration-tests/data/snaps/basic-service/meta/package.yaml (+8/-0)
_integration-tests/data/snaps/basic-service/meta/readme.md (+3/-0)
_integration-tests/data/tpl/control (+1/-1)
_integration-tests/scripts/install-test-initramfs (+25/-0)
_integration-tests/scripts/resize-writable-test (+123/-0)
_integration-tests/tests/activate_test.go (+15/-8)
_integration-tests/tests/apt_test.go (+1/-1)
_integration-tests/tests/build_test.go (+8/-7)
_integration-tests/tests/config_test.go (+1/-1)
_integration-tests/tests/console_test.go (+141/-0)
_integration-tests/tests/examples_test.go (+114/-12)
_integration-tests/tests/failover_test.go (+2/-1)
_integration-tests/tests/hwAssign_test.go (+36/-11)
_integration-tests/tests/info_test.go (+5/-4)
_integration-tests/tests/initramfs_test.go (+63/-4)
_integration-tests/tests/installApp_test.go (+34/-36)
_integration-tests/tests/installFramework_test.go (+13/-4)
_integration-tests/tests/rollback_test.go (+5/-8)
_integration-tests/tests/service_test.go (+21/-14)
_integration-tests/tests/snapd_1_0_packages_test.go (+14/-3)
_integration-tests/tests/snapd_test.go (+6/-5)
_integration-tests/tests/ubuntuFan_test.go (+10/-4)
_integration-tests/testutils/build/snap.go (+5/-15)
_integration-tests/testutils/common/common.go (+10/-2)
_integration-tests/testutils/data/data.go (+39/-0)
_integration-tests/testutils/wait/wait.go (+3/-2)
_integration-tests/testutils/wait/wait_test.go (+2/-2)
cmd/snappy/cmd_info.go (+14/-4)
cmd/snappy/common_test.go (+6/-1)
coreconfig/config.go (+107/-6)
coreconfig/config_test.go (+189/-4)
daemon/api.go (+78/-3)
daemon/api_test.go (+224/-7)
daemon/daemon.go (+22/-0)
daemon/response.go (+11/-5)
daemon/task.go (+3/-3)
daemon/task_test.go (+3/-3)
docs/meta.md (+17/-4)
helpers/helpers.go (+7/-4)
helpers/helpers_test.go (+21/-0)
i18n/i18n.go (+3/-0)
pkg/remote/remote.go (+1/-0)
po/de.po (+6/-3)
po/es.po (+6/-3)
po/gl.po (+7/-4)
po/snappy.pot (+4/-1)
snappy/click.go (+1/-1)
snappy/click_test.go (+28/-0)
snappy/common_test.go (+1/-0)
snappy/install_test.go (+2/-5)
snappy/parts.go (+6/-4)
snappy/snapp.go (+12/-5)
snappy/snapp_test.go (+11/-8)
snappy/systemimage.go (+6/-9)
snappy/systemimage_test.go (+12/-15)
To merge this branch: bzr merge lp:~snappy-dev/snappy/snappy-moved-to-github
Reviewer Review Type Date Requested Status
Michael Vogt Approve
Review via email: mp+275272@code.launchpad.net

Description of the change

Merge trunk to 15.04 for the new stable release.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '_integration-tests/data/snaps/basic-binaries/bin/fail'
2--- _integration-tests/data/snaps/basic-binaries/bin/fail 1970-01-01 00:00:00 +0000
3+++ _integration-tests/data/snaps/basic-binaries/bin/fail 2015-10-22 07:06:04 +0000
4@@ -0,0 +1,3 @@
5+#!/bin/sh
6+
7+exit 1
8
9=== added file '_integration-tests/data/snaps/basic-binaries/bin/success'
10--- _integration-tests/data/snaps/basic-binaries/bin/success 1970-01-01 00:00:00 +0000
11+++ _integration-tests/data/snaps/basic-binaries/bin/success 2015-10-22 07:06:04 +0000
12@@ -0,0 +1,3 @@
13+#!/bin/sh
14+
15+exit 0
16
17=== modified file '_integration-tests/data/snaps/basic-binaries/meta/package.yaml'
18--- _integration-tests/data/snaps/basic-binaries/meta/package.yaml 2015-10-09 07:42:40 +0000
19+++ _integration-tests/data/snaps/basic-binaries/meta/package.yaml 2015-10-22 07:06:04 +0000
20@@ -4,3 +4,5 @@
21 icon: meta/snappy64.png
22 binaries:
23 - name: bin/echo
24+ - name: bin/success
25+ - name: bin/fail
26
27=== added directory '_integration-tests/data/snaps/basic-config'
28=== added directory '_integration-tests/data/snaps/basic-config/meta'
29=== added directory '_integration-tests/data/snaps/basic-config/meta/hooks'
30=== added file '_integration-tests/data/snaps/basic-config/meta/hooks/config'
31--- _integration-tests/data/snaps/basic-config/meta/hooks/config 1970-01-01 00:00:00 +0000
32+++ _integration-tests/data/snaps/basic-config/meta/hooks/config 2015-10-22 07:06:04 +0000
33@@ -0,0 +1,37 @@
34+#!/usr/bin/python3
35+
36+import os.path
37+import sys
38+import yaml
39+
40+PKGNAME="basic-config"
41+CFG_FILE = os.path.join(os.environ["SNAP_APP_DATA_PATH"], "cfg")
42+
43+def get_config():
44+ config = {"config": {
45+ PKGNAME: {},
46+ }
47+ }
48+ if not os.path.exists(CFG_FILE):
49+ return config
50+ with open(CFG_FILE) as fp:
51+ val = fp.read()
52+ config["config"]["basic-config"]["key"] = val
53+ return config
54+
55+
56+def set_config():
57+ config = yaml.load(sys.stdin)
58+ if not config:
59+ return
60+
61+ val = config.get("key", "")
62+ if val:
63+ with open(CFG_FILE, "w") as fp:
64+ fp.write(val)
65+
66+
67+if __name__ == "__main__":
68+ set_config()
69+ config = get_config()
70+ yaml.dump(config, stream=sys.stdout, default_flow_style=False)
71
72=== added file '_integration-tests/data/snaps/basic-config/meta/package.yaml'
73--- _integration-tests/data/snaps/basic-config/meta/package.yaml 1970-01-01 00:00:00 +0000
74+++ _integration-tests/data/snaps/basic-config/meta/package.yaml 2015-10-22 07:06:04 +0000
75@@ -0,0 +1,4 @@
76+name: basic-config
77+version: 1.0
78+vendor: Snappy Developers <snappy-devel@lists.ubuntu.com>
79+icon: meta/snappy64.png
80
81=== added file '_integration-tests/data/snaps/basic-config/meta/readme.md'
82--- _integration-tests/data/snaps/basic-config/meta/readme.md 1970-01-01 00:00:00 +0000
83+++ _integration-tests/data/snaps/basic-config/meta/readme.md 2015-10-22 07:06:04 +0000
84@@ -0,0 +1,3 @@
85+Basic Config snap
86+
87+A basic snap with config hook
88
89=== added file '_integration-tests/data/snaps/basic-config/meta/snappy64.png'
90Binary files _integration-tests/data/snaps/basic-config/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/basic-config/meta/snappy64.png 2015-10-22 07:06:04 +0000 differ
91=== added directory '_integration-tests/data/snaps/basic-framework'
92=== added directory '_integration-tests/data/snaps/basic-framework/meta'
93=== added file '_integration-tests/data/snaps/basic-framework/meta/package.yaml'
94--- _integration-tests/data/snaps/basic-framework/meta/package.yaml 1970-01-01 00:00:00 +0000
95+++ _integration-tests/data/snaps/basic-framework/meta/package.yaml 2015-10-22 07:06:04 +0000
96@@ -0,0 +1,5 @@
97+name: basic-framework
98+version: 1.0
99+vendor: Snappy Developers <snappy-devel@lists.ubuntu.com>
100+icon: meta/snappy64.png
101+type: framework
102
103=== added file '_integration-tests/data/snaps/basic-framework/meta/readme.md'
104--- _integration-tests/data/snaps/basic-framework/meta/readme.md 1970-01-01 00:00:00 +0000
105+++ _integration-tests/data/snaps/basic-framework/meta/readme.md 2015-10-22 07:06:04 +0000
106@@ -0,0 +1,3 @@
107+Basic framework snap
108+
109+A basic buildable framework snap
110
111=== added file '_integration-tests/data/snaps/basic-framework/meta/snappy64.png'
112Binary files _integration-tests/data/snaps/basic-framework/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/basic-framework/meta/snappy64.png 2015-10-22 07:06:04 +0000 differ
113=== added directory '_integration-tests/data/snaps/basic-service'
114=== added directory '_integration-tests/data/snaps/basic-service/bin'
115=== added file '_integration-tests/data/snaps/basic-service/bin/start'
116--- _integration-tests/data/snaps/basic-service/bin/start 1970-01-01 00:00:00 +0000
117+++ _integration-tests/data/snaps/basic-service/bin/start 2015-10-22 07:06:04 +0000
118@@ -0,0 +1,3 @@
119+#!/bin/sh
120+
121+while :; do echo 'Service running'; sleep 10; done
122
123=== added directory '_integration-tests/data/snaps/basic-service/meta'
124=== added file '_integration-tests/data/snaps/basic-service/meta/package.yaml'
125--- _integration-tests/data/snaps/basic-service/meta/package.yaml 1970-01-01 00:00:00 +0000
126+++ _integration-tests/data/snaps/basic-service/meta/package.yaml 2015-10-22 07:06:04 +0000
127@@ -0,0 +1,8 @@
128+name: basic-service
129+version: 1.0
130+vendor: Snappy Developers <snappy-devel@lists.ubuntu.com>
131+icon: meta/snappy64.png
132+services:
133+ - name: service
134+ start: ./bin/start
135+ description: Test service
136
137=== added file '_integration-tests/data/snaps/basic-service/meta/readme.md'
138--- _integration-tests/data/snaps/basic-service/meta/readme.md 1970-01-01 00:00:00 +0000
139+++ _integration-tests/data/snaps/basic-service/meta/readme.md 2015-10-22 07:06:04 +0000
140@@ -0,0 +1,3 @@
141+Basic-service snap
142+
143+A basic buildable snap with a service.
144
145=== added file '_integration-tests/data/snaps/basic-service/meta/snappy64.png'
146Binary files _integration-tests/data/snaps/basic-service/meta/snappy64.png 1970-01-01 00:00:00 +0000 and _integration-tests/data/snaps/basic-service/meta/snappy64.png 2015-10-22 07:06:04 +0000 differ
147=== modified file '_integration-tests/data/tpl/control'
148--- _integration-tests/data/tpl/control 2015-07-22 16:36:14 +0000
149+++ _integration-tests/data/tpl/control 2015-10-22 07:06:04 +0000
150@@ -1,4 +1,4 @@
151 {{ $filter := .Filter }}
152 {{ $test := .Test }}
153-Test-Command: ./_integration-tests/reboot-wrapper {{ $test }} {{ if $filter }}-gocheck.f {{ $filter }}{{ end }}
154+Test-Command: ./_integration-tests/scripts/reboot-wrapper {{ $test }} {{ if $filter }}-gocheck.f {{ $filter }}{{ end }}
155 Restrictions: allow-stderr
156
157=== added directory '_integration-tests/scripts'
158=== renamed file '_integration-tests/tests/get_unpartitioned_space' => '_integration-tests/scripts/get_unpartitioned_space'
159=== added file '_integration-tests/scripts/install-test-initramfs'
160--- _integration-tests/scripts/install-test-initramfs 1970-01-01 00:00:00 +0000
161+++ _integration-tests/scripts/install-test-initramfs 2015-10-22 07:06:04 +0000
162@@ -0,0 +1,25 @@
163+#! /bin/sh -e
164+# Prepare the initramfs image for the tests.
165+
166+current_boot_dir=$1
167+writable_percent=$2
168+tree_dir=$(pwd)
169+initrd_unpack_dir=$ADT_ARTIFACTS/initrd
170+
171+cp ${current_boot_dir}/initrd.img /tmp/initrd.xz
172+cd /tmp/
173+unxz /tmp/initrd.xz
174+mkdir $initrd_unpack_dir || true
175+cd $initrd_unpack_dir
176+cpio -id < /tmp/initrd
177+# We need sfdisk to shrink the partition in mbr.
178+cp /sbin/sfdisk sbin
179+# Libs required by sfdisk.
180+cp /lib/*/libfdisk.so.1 lib
181+cp /lib/*/libsmartcols.so.1 lib
182+cp $tree_dir/_integration-tests/scripts/resize-writable-test scripts/local-premount/
183+sed -i "s/writable_percent=.*/writable_percent=${writable_percent}/" scripts/local-premount/resize-writable-test
184+sed -i '1i /scripts/local-premount/resize-writable-test "$@"\n[ -e /conf/param.conf ] && . /conf/param.conf' scripts/local-premount/ORDER
185+find .|cpio -o -H newc|xz -c -7 --check=crc32 > initrd.img
186+sudo rm $current_boot_dir/initrd.img
187+sudo mv initrd.img $current_boot_dir
188
189=== renamed file '_integration-tests/reboot-wrapper' => '_integration-tests/scripts/reboot-wrapper'
190=== added file '_integration-tests/scripts/resize-writable-test'
191--- _integration-tests/scripts/resize-writable-test 1970-01-01 00:00:00 +0000
192+++ _integration-tests/scripts/resize-writable-test 2015-10-22 07:06:04 +0000
193@@ -0,0 +1,123 @@
194+#! /bin/sh -ex
195+# initramfs local-premount script to resize writable for testing
196+
197+PREREQ=""
198+
199+# Output pre-requisites
200+prereqs()
201+{
202+ echo "$PREREQ"
203+}
204+
205+case "$1" in
206+ prereqs)
207+ prereqs
208+ exit 0
209+ ;;
210+esac
211+
212+TMPFILE="/run/initramfs/old-table-test.txt"
213+LOGFILE="/run/initramfs/resize-writable-test.log"
214+
215+writable_percent=100
216+
217+wait-for-root "LABEL=writable" "${ROOTDELAY:-180}" >/dev/null || true
218+
219+writable_part="$(findfs LABEL=writable)"
220+
221+syspath="$(dirname $(realpath /sys/class/block/$(basename $writable_part)))"
222+device="$(realpath /dev/block/$(cat $syspath/dev))"
223+partition=$(cat $syspath/$(basename $writable_part)/partition)
224+
225+device_size="$(($(cat $syspath/size)/2))"
226+
227+get_end()
228+{
229+ NUM=$1
230+ lastpart="$(grep -cE ^'[0-9]{1,}': $TMPFILE)"
231+ if [ "$lastpart" = "$NUM" ]; then
232+ endsize="$(parted -ms $DEV unit B print| grep ^/ | cut -d: -f2|sed 's/B$//')"
233+ else
234+ # we are not at the end ! get the start of the next partition
235+ # (minus 1 byte) instead of using the absolute end of the disk
236+ endsize=$(($(parted -ms $DEV unit B print|grep ^$(($num+1)):|\
237+ cut -d: -f2|sed 's/B$//')-1))
238+ fi
239+ echo "endsize: ${endsize}" >/dev/kmsg || true
240+ endsize_percent=$(($endsize*$writable_percent/100))
241+ echo "endsize percent: ${endsize_percent}" >/dev/kmsg || true
242+ echo "$endsize_percent"
243+}
244+
245+do_gpt()
246+{
247+ DEV=$1
248+ # create new empty GPT
249+ parted -s $DEV mklabel gpt
250+ oIFS=$IFS
251+ IFS=:
252+ # re-create all partitions from backup table
253+ grep -E ^'[0-9]{1,}': $TMPFILE|while read -r num start end size type name flags; do
254+ if [ "$name" = "writable" ]; then
255+ endsize=$(get_end $num)B
256+ parted -s $DEV mkpart \"$name\" \"$type\" $start $endsize
257+ else
258+ flags="$(echo $flags|sed -e 's/[,;]//g' -e 's/ /:/')"
259+ parted -s $DEV mkpart \"$name\" \"$type\" $start $end
260+ if [ -n "$flags" ]; then
261+ for flag in ${flags}; do
262+ parted -s $DEV set $num $flag on
263+ done
264+ fi
265+ fi
266+ done
267+ IFS=$oIFS
268+ parted -ms $DEV unit B print >/run/initramfs/new-gpt-table.txt 2>/dev/null
269+}
270+
271+do_mbr()
272+{
273+ DEV=$1
274+ PART=$2
275+ endsize=$(get_end $PART)
276+ # We can't just resize with parted because it prints a warning when you try to shrink the
277+ # partition.
278+ part_start="$(parted -ms $DEV unit B print | grep ^$PART: | cut -d: -f2 | sed 's/B$//')"
279+ part_end=$(($endsize-$part_start))
280+ part_end_sectors=$(($part_end/512))
281+ echo ", ${part_end_sectors}" | sfdisk -f -N$PART $DEV
282+}
283+
284+
285+echo "initrd: resize ${writable_part} to ${writable_percent}% of the disk" >/dev/kmsg || true
286+echo "initrd: see ${LOGFILE} for details" >/dev/kmsg || true
287+
288+# check the filesystem before attempting re-size
289+e2fsck -fy $writable_part >>$LOGFILE 2>&1
290+# shrink the filesystem to the minimum
291+resize2fs -M $writable_part >>$LOGFILE 2>&1
292+
293+# back up the original partition table for later use or debugging
294+parted -ms $device unit B print >$TMPFILE 2>/dev/null
295+table="$(parted -ms $device print| grep ^/| cut -d: -f6)"
296+case $table in
297+ gpt)
298+ # do_gpt needs the device name
299+ do_gpt $device >>$LOGFILE 2>&1
300+ ;;
301+ mbr|msdos)
302+ # do_mbr needs the device node and partition number
303+ do_mbr $device $partition >>$LOGFILE 2>&1
304+ resizeopts="-f"
305+ ;;
306+ *)
307+ echo "unknown partition table type, not resizing" >>$LOGFILE
308+ exit 0
309+ ;;
310+esac
311+# make sure we re read the partition table in any case
312+blockdev --rereadpt $device >>$LOGFILE 2>&1
313+# check the filesystem before attempting re-size
314+e2fsck -fy $writable_part >>$LOGFILE 2>&1
315+# resize the filesystem to full size of the partition
316+resize2fs $resizeopts $writable_part >>$LOGFILE 2>&1
317
318=== modified file '_integration-tests/tests/activate_test.go'
319--- _integration-tests/tests/activate_test.go 2015-10-09 07:49:19 +0000
320+++ _integration-tests/tests/activate_test.go 2015-10-22 07:06:04 +0000
321@@ -27,10 +27,11 @@
322 "launchpad.net/snappy/_integration-tests/testutils/build"
323 "launchpad.net/snappy/_integration-tests/testutils/cli"
324 "launchpad.net/snappy/_integration-tests/testutils/common"
325+ "launchpad.net/snappy/_integration-tests/testutils/data"
326 )
327
328 const (
329- activateSnapName = "basic-binaries"
330+ activateSnapName = data.BasicBinariesSnapName
331 activateBinName = activateSnapName + ".echo"
332 activateEchoOutput = "From basic-binaries snap\n"
333 baseActivatePattern = "(?msU).*" + activateSnapName + `\s*.*\s*.*sideload`
334@@ -45,17 +46,21 @@
335 snapPath string
336 }
337
338-func (s *activateSuite) SetUpSuite(c *check.C) {
339- s.SnappySuite.SetUpSuite(c)
340+func (s *activateSuite) SetUpTest(c *check.C) {
341+ s.SnappySuite.SetUpTest(c)
342+ if common.Release(c) == "15.04" {
343+ c.Skip("activate CLI command not available on 15.04, reenable the test when present")
344+ }
345 var err error
346 s.snapPath, err = build.LocalSnap(c, activateSnapName)
347- c.Assert(err, check.IsNil)
348+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
349 common.InstallSnap(c, s.snapPath)
350 }
351
352-func (s *activateSuite) TearDownSuite(c *check.C) {
353+func (s *activateSuite) TearDownTest(c *check.C) {
354 os.Remove(s.snapPath)
355 common.RemoveSnap(c, activateSnapName)
356+ s.SnappySuite.TearDownTest(c)
357 }
358
359 func (s *activateSuite) TestDeactivateRemovesBinary(c *check.C) {
360@@ -63,8 +68,9 @@
361 defer cli.ExecCommand(c, "sudo", "snappy", "activate", activateSnapName)
362 output, err := cli.ExecCommandErr(activateBinName)
363
364- c.Assert(err, check.NotNil)
365- c.Assert(output, check.Not(check.Equals), activateEchoOutput)
366+ c.Assert(err, check.NotNil, check.Commentf("Deactivated snap binary did not exit with an error"))
367+ c.Assert(output, check.Not(check.Equals), activateEchoOutput,
368+ check.Commentf("Deactivated snap binary was not removed"))
369
370 list := cli.ExecCommand(c, "snappy", "list", "-v")
371
372@@ -76,7 +82,8 @@
373 cli.ExecCommand(c, "sudo", "snappy", "activate", activateSnapName)
374 output := cli.ExecCommand(c, activateBinName)
375
376- c.Assert(output, check.Equals, activateEchoOutput)
377+ c.Assert(output, check.Equals, activateEchoOutput,
378+ check.Commentf("Wrong output from active snap binary"))
379
380 list := cli.ExecCommand(c, "snappy", "list", "-v")
381
382
383=== modified file '_integration-tests/tests/apt_test.go'
384--- _integration-tests/tests/apt_test.go 2015-09-30 11:27:49 +0000
385+++ _integration-tests/tests/apt_test.go 2015-10-22 07:06:04 +0000
386@@ -36,5 +36,5 @@
387 aptOutput := cli.ExecCommand(c, "apt-get", "update")
388
389 expected := "Ubuntu Core does not use apt-get, see 'snappy --help'!\n"
390- c.Assert(aptOutput, check.Equals, expected)
391+ c.Assert(aptOutput, check.Equals, expected, check.Commentf("Wrong apt-get output"))
392 }
393
394=== modified file '_integration-tests/tests/build_test.go'
395--- _integration-tests/tests/build_test.go 2015-09-28 10:35:06 +0000
396+++ _integration-tests/tests/build_test.go 2015-10-22 07:06:04 +0000
397@@ -26,6 +26,7 @@
398
399 "launchpad.net/snappy/_integration-tests/testutils/build"
400 "launchpad.net/snappy/_integration-tests/testutils/common"
401+ "launchpad.net/snappy/_integration-tests/testutils/data"
402
403 "gopkg.in/check.v1"
404 )
405@@ -38,37 +39,37 @@
406
407 func (s *buildSuite) TestBuildBasicSnapOnSnappy(c *check.C) {
408 // build basic snap and check output
409- snapPath, err := build.LocalSnap(c, build.BasicSnapName)
410+ snapPath, err := build.LocalSnap(c, data.BasicSnapName)
411 defer os.Remove(snapPath)
412- c.Assert(err, check.IsNil)
413+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
414
415 // install built snap and check output
416 installOutput := common.InstallSnap(c, snapPath)
417- defer common.RemoveSnap(c, build.BasicSnapName)
418+ defer common.RemoveSnap(c, data.BasicSnapName)
419 expected := "(?ms)" +
420 "Installing " + snapPath + "\n" +
421 ".*Signature check failed, but installing anyway as requested\n" +
422 "Name +Date +Version +Developer \n" +
423 ".*\n" +
424- build.BasicSnapName + " +.* +.* +sideload \n" +
425+ data.BasicSnapName + " +.* +.* +sideload \n" +
426 ".*\n"
427
428 c.Check(installOutput, check.Matches, expected)
429 }
430
431 func (s *buildSuite) TestBuildWrongYamlSnapOnSnappy(c *check.C) {
432- commonWrongTest(c, build.WrongYamlSnapName,
433+ commonWrongTest(c, data.WrongYamlSnapName,
434 "(?msi).*Can not parse.*yaml: line 2: mapping values are not allowed in this context.*")
435 }
436
437 func (s *buildSuite) TestBuildMissingReadmeSnapOnSnappy(c *check.C) {
438- commonWrongTest(c, build.MissingReadmeSnapName,
439+ commonWrongTest(c, data.MissingReadmeSnapName,
440 ".*readme.md: no such file or directory\n")
441 }
442
443 func commonWrongTest(c *check.C, testName, expected string) {
444 // build wrong snap and check error
445- cmd := exec.Command("snappy", "build", fmt.Sprintf("%s/%s", build.BaseSnapPath, testName))
446+ cmd := exec.Command("snappy", "build", fmt.Sprintf("%s/%s", data.BaseSnapPath, testName))
447 echoOutput, err := cmd.CombinedOutput()
448 c.Assert(err, check.NotNil, check.Commentf("%s should not be built", testName))
449
450
451=== modified file '_integration-tests/tests/config_test.go'
452--- _integration-tests/tests/config_test.go 2015-10-02 10:23:47 +0000
453+++ _integration-tests/tests/config_test.go 2015-10-22 07:06:04 +0000
454@@ -77,7 +77,7 @@
455 config := configString(targetCfg)
456
457 err := s.setConfig(c, config)
458- c.Assert(err, check.IsNil)
459+ c.Assert(err, check.IsNil, check.Commentf("Error setting config: %s", err))
460
461 actualConfig := currentConfig(c)
462
463
464=== added file '_integration-tests/tests/console_test.go'
465--- _integration-tests/tests/console_test.go 1970-01-01 00:00:00 +0000
466+++ _integration-tests/tests/console_test.go 2015-10-22 07:06:04 +0000
467@@ -0,0 +1,141 @@
468+// -*- Mode: Go; indent-tabs-mode: t -*-
469+
470+/*
471+ * Copyright (C) 2015 Canonical Ltd
472+ *
473+ * This program is free software: you can redistribute it and/or modify
474+ * it under the terms of the GNU General Public License version 3 as
475+ * published by the Free Software Foundation.
476+ *
477+ * This program is distributed in the hope that it will be useful,
478+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
479+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
480+ * GNU General Public License for more details.
481+ *
482+ * You should have received a copy of the GNU General Public License
483+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
484+ *
485+ */
486+
487+package tests
488+
489+import (
490+ "bufio"
491+ "io"
492+ "os/exec"
493+
494+ "launchpad.net/snappy/_integration-tests/testutils/common"
495+
496+ "gopkg.in/check.v1"
497+)
498+
499+var _ = check.Suite(&consoleSuite{})
500+
501+type consoleSuite struct {
502+ common.SnappySuite
503+ cmd *exec.Cmd
504+ stdin io.WriteCloser
505+ stdout io.ReadCloser
506+ outbr *bufio.Reader
507+}
508+
509+type consoleMsg struct {
510+ txt string
511+ err error
512+}
513+
514+func (s *consoleSuite) SetUpTest(c *check.C) {
515+ s.SnappySuite.SetUpTest(c)
516+
517+ var err error
518+ s.cmd = exec.Command("snappy", "console")
519+ s.stdin, err = s.cmd.StdinPipe()
520+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
521+ s.stdout, err = s.cmd.StdoutPipe()
522+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
523+
524+ s.outbr = bufio.NewReader(s.stdout)
525+
526+ err = s.cmd.Start()
527+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
528+
529+ s.checkPrompt(c)
530+}
531+
532+func (s *consoleSuite) TearDownTest(c *check.C) {
533+ s.SnappySuite.TearDownTest(c)
534+
535+ s.stdin.Close()
536+ s.stdout.Close()
537+
538+ proc := s.cmd.Process
539+ if proc != nil {
540+ proc.Kill()
541+ }
542+}
543+
544+func (s *consoleSuite) checkPrompt(c *check.C) {
545+ expected := []string{"Welcome to the snappy console\n",
546+ "Type 'help' for help\n",
547+ "Type 'shell' for entering a shell\n"}
548+
549+ match, err := s.matchLinesFromConsole(expected)
550+
551+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
552+ c.Assert(match, check.Equals, true,
553+ check.Commentf("Console output didn't match expected value"))
554+}
555+
556+func (s *consoleSuite) TestHelp(c *check.C) {
557+ s.writeToConsole("help\n")
558+
559+ expected := []string{"> Usage:\n",
560+ " snappy [OPTIONS] <command>\n", "\n",
561+ "Help Options:\n",
562+ " -h, --help Show this help message\n", "\n",
563+ "Available commands:\n"}
564+
565+ match, err := s.matchLinesFromConsole(expected)
566+
567+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
568+ c.Assert(match, check.Equals, true,
569+ check.Commentf("Console output didn't match expected value"))
570+}
571+
572+func (s *consoleSuite) writeToConsole(msg string) (err error) {
573+ _, err = s.stdin.Write([]byte(msg))
574+ return
575+}
576+
577+func (s *consoleSuite) getConsoleChannel(len int) chan *consoleMsg {
578+ c := make(chan *consoleMsg)
579+ go func() {
580+ for i := 0; i < len; i++ {
581+ txt, err := s.outbr.ReadString(byte('\n'))
582+ if err == io.EOF {
583+ close(c)
584+ return
585+ }
586+ if err != nil {
587+ c <- &consoleMsg{"", err}
588+ }
589+ c <- &consoleMsg{txt, nil}
590+ }
591+ }()
592+ return c
593+}
594+
595+func (s *consoleSuite) matchLinesFromConsole(lines []string) (match bool, err error) {
596+ c := s.getConsoleChannel(len(lines))
597+
598+ for _, expected := range lines {
599+ msg := <-c
600+ if msg.err != nil {
601+ return false, msg.err
602+ }
603+ if msg.txt != expected {
604+ return false, nil
605+ }
606+ }
607+ return true, nil
608+}
609
610=== modified file '_integration-tests/tests/examples_test.go'
611--- _integration-tests/tests/examples_test.go 2015-10-09 16:18:01 +0000
612+++ _integration-tests/tests/examples_test.go 2015-10-22 07:06:04 +0000
613@@ -20,7 +20,10 @@
614 package tests
615
616 import (
617+ "fmt"
618+ "io/ioutil"
619 "net/http"
620+ "os"
621
622 "launchpad.net/snappy/_integration-tests/testutils/cli"
623 "launchpad.net/snappy/_integration-tests/testutils/common"
624@@ -29,25 +32,86 @@
625 "gopkg.in/check.v1"
626 )
627
628-var _ = check.Suite(&webserverExampleSuite{})
629-
630-type webserverExampleSuite struct {
631- common.SnappySuite
632-}
633-
634-func (s *webserverExampleSuite) TestNetworkingServiceMustBeStarted(c *check.C) {
635+var _ = check.Suite(&helloWorldExampleSuite{})
636+
637+type helloWorldExampleSuite struct {
638+ common.SnappySuite
639+}
640+
641+func (s *helloWorldExampleSuite) TestCallHelloWorldBinary(c *check.C) {
642+ common.InstallSnap(c, "hello-world")
643+ s.AddCleanup(func() {
644+ common.RemoveSnap(c, "hello-world")
645+ })
646+
647+ echoOutput := cli.ExecCommand(c, "hello-world.echo")
648+
649+ c.Assert(echoOutput, check.Equals, "Hello World!\n",
650+ check.Commentf("Wrong output from hello-world binary"))
651+}
652+
653+func (s *helloWorldExampleSuite) TestCallHelloWorldEvilMustPrintPermissionDeniedError(c *check.C) {
654+ common.InstallSnap(c, "hello-world")
655+ s.AddCleanup(func() {
656+ common.RemoveSnap(c, "hello-world")
657+ })
658+
659+ echoOutput, err := cli.ExecCommandErr("hello-world.evil")
660+ c.Assert(err, check.NotNil, check.Commentf("hello-world.evil did not fail"))
661+
662+ expected := "" +
663+ "Hello Evil World!\n" +
664+ "This example demonstrates the app confinement\n" +
665+ "You should see a permission denied error next\n" +
666+ "/apps/hello-world.canonical/.*/bin/evil: \\d+: " +
667+ "/apps/hello-world.canonical/.*/bin/evil: " +
668+ "cannot create /var/tmp/myevil.txt: Permission denied\n"
669+
670+ c.Assert(string(echoOutput), check.Matches, expected)
671+}
672+
673+var _ = check.Suite(&pythonWebserverExampleSuite{})
674+
675+type pythonWebserverExampleSuite struct {
676+ common.SnappySuite
677+}
678+
679+func (s *pythonWebserverExampleSuite) TestNetworkingServiceMustBeStarted(c *check.C) {
680 baseAppName := "xkcd-webserver"
681 appName := baseAppName + ".canonical"
682 common.InstallSnap(c, appName)
683 defer common.RemoveSnap(c, appName)
684
685- err := wait.ForServerOnPort(c, 80)
686- c.Assert(err, check.IsNil)
687+ err := wait.ForServerOnPort(c, "tcp", 80)
688+ c.Assert(err, check.IsNil, check.Commentf("Error waiting for server: %s", err))
689
690 resp, err := http.Get("http://localhost")
691- c.Assert(err, check.IsNil)
692- c.Check(resp.Status, check.Equals, "200 OK")
693- c.Assert(resp.Proto, check.Equals, "HTTP/1.0")
694+ c.Assert(err, check.IsNil, check.Commentf("Error getting the http resource: %s", err))
695+ c.Check(resp.Status, check.Equals, "200 OK", check.Commentf("Wrong reply status"))
696+ c.Assert(resp.Proto, check.Equals, "HTTP/1.0", check.Commentf("Wrong reply protocol"))
697+}
698+
699+var _ = check.Suite(&goWebserverExampleSuite{})
700+
701+type goWebserverExampleSuite struct {
702+ common.SnappySuite
703+}
704+
705+func (s *goWebserverExampleSuite) TestGetRootPathMustPrintMessage(c *check.C) {
706+ appName := "go-example-webserver"
707+ common.InstallSnap(c, appName)
708+ defer common.RemoveSnap(c, appName)
709+
710+ err := wait.ForServerOnPort(c, "tcp6", 8081)
711+ c.Assert(err, check.IsNil, check.Commentf("Error waiting for server: %s", err))
712+
713+ resp, err := http.Get("http://localhost:8081/")
714+ defer resp.Body.Close()
715+ c.Assert(err, check.IsNil, check.Commentf("Error getting the http resource: %s", err))
716+ c.Check(resp.Status, check.Equals, "200 OK", check.Commentf("Wrong reply status"))
717+ body, err := ioutil.ReadAll(resp.Body)
718+ c.Assert(err, check.IsNil, check.Commentf("Error reading the reply body: %s", err))
719+ c.Assert(string(body), check.Equals, "Hello World\n", check.Commentf("Wrong reply body"))
720 }
721
722 var _ = check.Suite(&frameworkExampleSuite{})
723@@ -70,3 +134,41 @@
724 c.Assert(output, check.Equals, expected,
725 check.Commentf("Expected output %s not found, %s", expected, output))
726 }
727+
728+var _ = check.Suite(&configExampleSuite{})
729+
730+type configExampleSuite struct {
731+ common.SnappySuite
732+}
733+
734+var configTests = []struct {
735+ snap string
736+ origin string
737+ message string
738+}{
739+ {"config-example", "", "test config example message"},
740+ {"config-example-bash", ".canonical", "test config example bash message"},
741+}
742+
743+func (s *configExampleSuite) TestPrintMessageFromConfig(c *check.C) {
744+ for _, t := range configTests {
745+ common.InstallSnap(c, t.snap+t.origin)
746+ defer common.RemoveSnap(c, t.snap)
747+
748+ config := fmt.Sprintf(`config:
749+ %s:
750+ msg: |
751+ %s`, t.snap, t.message)
752+
753+ configFile, err := ioutil.TempFile("", "snappy-cfg")
754+ defer func() { configFile.Close(); os.Remove(configFile.Name()) }()
755+ c.Assert(err, check.IsNil, check.Commentf("Error creating temp file: %s", err))
756+ _, err = configFile.Write([]byte(config))
757+ c.Assert(err, check.IsNil, check.Commentf("Error writing the conf to the temp file: %s", err))
758+
759+ cli.ExecCommand(c, "sudo", "snappy", "config", t.snap, configFile.Name())
760+
761+ output := cli.ExecCommand(c, t.snap+".hello")
762+ c.Assert(output, check.Equals, t.message, check.Commentf("Wrong message"))
763+ }
764+}
765
766=== modified file '_integration-tests/tests/failover_test.go'
767--- _integration-tests/tests/failover_test.go 2015-09-30 11:27:49 +0000
768+++ _integration-tests/tests/failover_test.go 2015-10-22 07:06:04 +0000
769@@ -48,7 +48,8 @@
770 if common.AfterReboot(c) {
771 common.RemoveRebootMark(c)
772 f.unset(c)
773- c.Assert(common.GetSavedVersion(c), check.Equals, currentVersion)
774+ c.Assert(common.GetSavedVersion(c), check.Equals, currentVersion,
775+ check.Commentf("Rebooted to the wrong version"))
776 } else {
777 common.SetSavedVersion(c, currentVersion-1)
778 common.CallFakeUpdate(c)
779
780=== modified file '_integration-tests/tests/hwAssign_test.go'
781--- _integration-tests/tests/hwAssign_test.go 2015-10-07 07:39:25 +0000
782+++ _integration-tests/tests/hwAssign_test.go 2015-10-22 07:06:04 +0000
783@@ -49,7 +49,7 @@
784 s.SnappySuite.SetUpTest(c)
785 var err error
786 s.snapPath, err = build.LocalSnap(c, snapName)
787- c.Assert(err, check.IsNil)
788+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
789 common.InstallSnap(c, s.snapPath)
790 }
791
792@@ -63,8 +63,10 @@
793 cmd := exec.Command(binName)
794 output, err := cmd.CombinedOutput()
795
796- c.Assert(err, check.NotNil)
797- c.Assert(string(output), check.Equals, hwAssignError)
798+ c.Assert(err, check.NotNil,
799+ check.Commentf("The snap binary without hardware assigned did not exit with an error"))
800+ c.Assert(string(output), check.Equals, hwAssignError,
801+ check.Commentf("Wrong error message"))
802 }
803
804 func (s *hwAssignSuite) TestSuccessAfterHwAssign(c *check.C) {
805@@ -74,7 +76,8 @@
806 cmd := exec.Command(binName)
807 output, _ := cmd.CombinedOutput()
808
809- c.Assert(string(output), check.Not(check.Equals), hwAssignError)
810+ c.Assert(string(output), check.Not(check.Equals), hwAssignError,
811+ check.Commentf("The snap binary with hardware assigned printed a permission denied error"))
812 }
813
814 func (s *hwAssignSuite) TestErrorAfterHwUnAssign(c *check.C) {
815@@ -84,23 +87,45 @@
816 cmd := exec.Command(binName)
817 output, err := cmd.CombinedOutput()
818
819- c.Assert(err, check.NotNil)
820- c.Assert(string(output), check.Equals, hwAssignError)
821+ c.Assert(err, check.NotNil,
822+ check.Commentf("The snap binary without hardware assigned did not exit with an error"))
823+ c.Assert(string(output), check.Equals, hwAssignError,
824+ check.Commentf("Wrong error message"))
825+}
826+
827+func (s *hwAssignSuite) TestHwInfo(c *check.C) {
828+ cmd := exec.Command("sudo", "snappy", "hw-info", installedSnapName)
829+ boutput, _ := cmd.CombinedOutput()
830+ output := string(boutput)
831+ expected := fmt.Sprintf("'%s:' is not allowed to access additional hardware\n", installedSnapName)
832+ c.Assert(output, check.Equals, expected,
833+ check.Commentf(`Expected "%s", obtained "%s"`, expected, output))
834+
835+ assign(c, snapName, hwName)
836+ defer unassign(c, snapName, hwName)
837+
838+ cmd = exec.Command("sudo", "snappy", "hw-info", installedSnapName)
839+ boutput, _ = cmd.CombinedOutput()
840+ output = string(boutput)
841+ expected = fmt.Sprintf("%s: %s\n", installedSnapName, hwName)
842+ c.Assert(output, check.Equals, expected,
843+ check.Commentf(`Expected "%s", obtained "%s"`, expected, output))
844 }
845
846 func assign(c *check.C, snap, hw string) {
847 cmd := exec.Command("sudo", "snappy", "hw-assign", installedSnapName, hwName)
848 output, err := cmd.CombinedOutput()
849- c.Assert(err, check.IsNil)
850+ c.Assert(err, check.IsNil, check.Commentf("Error assigning hardware: %s", err))
851 c.Assert(string(output), check.Equals,
852- fmt.Sprintf("'%s' is now allowed to access '%s'\n", installedSnapName, hwName))
853+ fmt.Sprintf("'%s' is now allowed to access '%s'\n", installedSnapName, hwName),
854+ check.Commentf("Wrong message after assigning hardware"))
855 }
856
857 func unassign(c *check.C, snap, hw string) {
858 cmd := exec.Command("sudo", "snappy", "hw-unassign", installedSnapName, hwName)
859 output, err := cmd.CombinedOutput()
860- c.Assert(err, check.IsNil)
861+ c.Assert(err, check.IsNil, check.Commentf("Error unassigning hardware: %s", err))
862 c.Assert(string(output), check.Equals,
863- fmt.Sprintf("'%s' is no longer allowed to access '%s'\n", installedSnapName, hwName))
864-
865+ fmt.Sprintf("'%s' is no longer allowed to access '%s'\n", installedSnapName, hwName),
866+ check.Commentf("Wrong message after unassigning hardware"))
867 }
868
869=== modified file '_integration-tests/tests/info_test.go'
870--- _integration-tests/tests/info_test.go 2015-10-08 06:40:06 +0000
871+++ _integration-tests/tests/info_test.go 2015-10-22 07:06:04 +0000
872@@ -26,6 +26,7 @@
873 "launchpad.net/snappy/_integration-tests/testutils/build"
874 "launchpad.net/snappy/_integration-tests/testutils/cli"
875 "launchpad.net/snappy/_integration-tests/testutils/common"
876+ "launchpad.net/snappy/_integration-tests/testutils/data"
877
878 "gopkg.in/check.v1"
879 )
880@@ -55,17 +56,17 @@
881 }
882
883 func (s *infoSuite) TestInfoMustPrintInstalledApps(c *check.C) {
884- snapPath, err := build.LocalSnap(c, build.BasicSnapName)
885+ snapPath, err := build.LocalSnap(c, data.BasicSnapName)
886 defer os.Remove(snapPath)
887- c.Assert(err, check.IsNil)
888+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
889 common.InstallSnap(c, snapPath)
890- defer common.RemoveSnap(c, build.BasicSnapName)
891+ defer common.RemoveSnap(c, data.BasicSnapName)
892
893 infoOutput := cli.ExecCommand(c, "snappy", "info")
894
895 expected := "(?ms)" +
896 ".*" +
897- "^apps: .*" + build.BasicSnapName + "\\.sideload.*\n"
898+ "^apps: .*" + data.BasicSnapName + "\\.sideload.*\n"
899 c.Assert(infoOutput, check.Matches, expected)
900 }
901
902
903=== modified file '_integration-tests/tests/initramfs_test.go'
904--- _integration-tests/tests/initramfs_test.go 2015-09-08 18:25:45 +0000
905+++ _integration-tests/tests/initramfs_test.go 2015-10-22 07:06:04 +0000
906@@ -20,11 +20,15 @@
907 package tests
908
909 import (
910+ "os"
911 "os/exec"
912+ "path"
913 "strconv"
914 "strings"
915
916+ "launchpad.net/snappy/_integration-tests/testutils/cli"
917 "launchpad.net/snappy/_integration-tests/testutils/common"
918+ "launchpad.net/snappy/_integration-tests/testutils/partition"
919
920 "gopkg.in/check.v1"
921 )
922@@ -35,14 +39,69 @@
923 common.SnappySuite
924 }
925
926-func (s *initRAMFSSuite) TestFreeSpace(c *check.C) {
927- cmd := exec.Command("sh", "_integration-tests/tests/get_unpartitioned_space")
928+func getFreeSpacePercent(c *check.C) float64 {
929+ cmd := exec.Command("sh", "_integration-tests/scripts/get_unpartitioned_space")
930 free, err := cmd.Output()
931 c.Assert(err, check.IsNil, check.Commentf("Error running the script to get the free space: %s", err))
932 freePercent := strings.TrimRight(strings.TrimSpace(string(free)), "%")
933 freePercentFloat, err := strconv.ParseFloat(freePercent, 32)
934 c.Assert(err, check.IsNil,
935 check.Commentf("Error converting the free space percentage to float: %s", err))
936- c.Assert(freePercentFloat < 10, check.Equals, true,
937- check.Commentf("The free space at the end of the disk is greater than 10%"))
938+ return freePercentFloat
939+}
940+
941+func getCurrentBootDir(c *check.C) string {
942+ system, err := partition.BootSystem()
943+ c.Assert(err, check.IsNil, check.Commentf("Error getting the boot system: %s", err))
944+ bootDir := partition.BootDir(system)
945+ current, err := partition.CurrentPartition()
946+ c.Assert(err, check.IsNil, check.Commentf("Error getting the current partition: %s", err))
947+ return path.Join(bootDir, current)
948+}
949+
950+func (s *initRAMFSSuite) SetUpTest(c *check.C) {
951+ s.SnappySuite.SetUpTest(c)
952+ if common.BeforeReboot() {
953+ bootDir := getCurrentBootDir(c)
954+ cli.ExecCommand(c, "cp", path.Join(bootDir, "initrd.img"), os.Getenv("ADT_ARTIFACTS"))
955+ }
956+}
957+
958+func (s *initRAMFSSuite) TearDownTest(c *check.C) {
959+ s.SnappySuite.TearDownTest(c)
960+ if !common.IsInRebootProcess() {
961+ bootDir := getCurrentBootDir(c)
962+ cli.ExecCommand(
963+ c, "sudo", "mv", path.Join(os.Getenv("ADT_ARTIFACTS"), "initrd.img"), bootDir)
964+ }
965+}
966+
967+func (s *initRAMFSSuite) TestFreeSpaceWithoutResize(c *check.C) {
968+ writablePercent := "95"
969+ if common.BeforeReboot() {
970+ bootDir := getCurrentBootDir(c)
971+ cli.ExecCommand(
972+ c, "sh", "-x", "_integration-tests/scripts/install-test-initramfs", bootDir, writablePercent)
973+ common.Reboot(c)
974+ } else if common.AfterReboot(c) {
975+ common.RemoveRebootMark(c)
976+ freeSpace := getFreeSpacePercent(c)
977+ c.Assert(freeSpace, check.Equals, float64(5),
978+ check.Commentf("The writable partition was resized"))
979+ }
980+}
981+
982+func (s *initRAMFSSuite) TestFreeSpaceWithResize(c *check.C) {
983+ if common.BeforeReboot() {
984+ bootDir := getCurrentBootDir(c)
985+ writablePercent := "85"
986+ cli.ExecCommand(
987+ c, "sh", "-x", "_integration-tests/scripts/install-test-initramfs", bootDir, writablePercent)
988+ common.Reboot(c)
989+ } else if common.AfterReboot(c) {
990+ common.RemoveRebootMark(c)
991+ freeSpace := getFreeSpacePercent(c)
992+ c.Assert(freeSpace < 10, check.Equals, true,
993+ check.Commentf("The writable partition was not resized"))
994+ }
995 }
996
997=== modified file '_integration-tests/tests/installApp_test.go'
998--- _integration-tests/tests/installApp_test.go 2015-10-08 06:45:29 +0000
999+++ _integration-tests/tests/installApp_test.go 2015-10-22 07:06:04 +0000
1000@@ -20,10 +20,14 @@
1001 package tests
1002
1003 import (
1004+ "fmt"
1005+ "os"
1006 "os/exec"
1007
1008+ "launchpad.net/snappy/_integration-tests/testutils/build"
1009 "launchpad.net/snappy/_integration-tests/testutils/cli"
1010 "launchpad.net/snappy/_integration-tests/testutils/common"
1011+ "launchpad.net/snappy/_integration-tests/testutils/data"
1012
1013 "gopkg.in/check.v1"
1014 )
1015@@ -35,59 +39,53 @@
1016 }
1017
1018 func (s *installAppSuite) TestInstallAppMustPrintPackageInformation(c *check.C) {
1019- installOutput := common.InstallSnap(c, "hello-world")
1020- s.AddCleanup(func() {
1021- common.RemoveSnap(c, "hello-world")
1022- })
1023+ snapPath, err := build.LocalSnap(c, data.BasicSnapName)
1024+ defer os.Remove(snapPath)
1025+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
1026+ installOutput := common.InstallSnap(c, snapPath)
1027+ defer common.RemoveSnap(c, data.BasicSnapName)
1028
1029 expected := "(?ms)" +
1030- "Installing hello-world\n" +
1031+ fmt.Sprintf("Installing %s\n", snapPath) +
1032+ ".*Signature check failed, but installing anyway as requested\n" +
1033 "Name +Date +Version +Developer \n" +
1034 ".*" +
1035- "^hello-world +.* +.* +canonical \n" +
1036+ "^basic +.* +.* +sideload *\n" +
1037 ".*"
1038
1039 c.Assert(installOutput, check.Matches, expected)
1040 }
1041
1042-func (s *installAppSuite) TestCallBinaryFromInstalledSnap(c *check.C) {
1043- common.InstallSnap(c, "hello-world")
1044- s.AddCleanup(func() {
1045- common.RemoveSnap(c, "hello-world")
1046- })
1047-
1048- echoOutput := cli.ExecCommand(c, "hello-world.echo")
1049-
1050- c.Assert(echoOutput, check.Equals, "Hello World!\n")
1051+func (s *installAppSuite) TestCallSuccessfulBinaryFromInstalledSnap(c *check.C) {
1052+ snapPath, err := build.LocalSnap(c, data.BasicBinariesSnapName)
1053+ defer os.Remove(snapPath)
1054+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
1055+ common.InstallSnap(c, snapPath)
1056+ defer common.RemoveSnap(c, data.BasicBinariesSnapName)
1057+
1058+ // Exec command does not fail.
1059+ cli.ExecCommand(c, "basic-binaries.success")
1060 }
1061
1062-func (s *installAppSuite) TestCallBinaryWithPermissionDeniedMustPrintError(c *check.C) {
1063- common.InstallSnap(c, "hello-world")
1064- s.AddCleanup(func() {
1065- common.RemoveSnap(c, "hello-world")
1066- })
1067-
1068- cmd := exec.Command("hello-world.evil")
1069- echoOutput, err := cmd.CombinedOutput()
1070- c.Assert(err, check.NotNil, check.Commentf("hello-world.evil did not fail"))
1071-
1072- expected := "" +
1073- "Hello Evil World!\n" +
1074- "This example demonstrates the app confinement\n" +
1075- "You should see a permission denied error next\n" +
1076- "/apps/hello-world.canonical/.*/bin/evil: \\d+: " +
1077- "/apps/hello-world.canonical/.*/bin/evil: " +
1078- "cannot create /var/tmp/myevil.txt: Permission denied\n"
1079-
1080- c.Assert(string(echoOutput), check.Matches, expected)
1081+func (s *installAppSuite) TestCallFailBinaryFromInstalledSnap(c *check.C) {
1082+ snapPath, err := build.LocalSnap(c, data.BasicBinariesSnapName)
1083+ defer os.Remove(snapPath)
1084+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
1085+ common.InstallSnap(c, snapPath)
1086+ defer common.RemoveSnap(c, data.BasicBinariesSnapName)
1087+
1088+ _, err = cli.ExecCommandErr("basic-binaries.fail")
1089+ c.Assert(err, check.NotNil, check.Commentf("The binary did not fail"))
1090 }
1091
1092 func (s *installAppSuite) TestInstallUnexistingAppMustPrintError(c *check.C) {
1093 cmd := exec.Command("sudo", "snappy", "install", "unexisting.canonical")
1094 output, err := cmd.CombinedOutput()
1095
1096- c.Assert(err, check.NotNil)
1097+ c.Check(err, check.NotNil,
1098+ check.Commentf("Trying to install an unexisting snap did not exit with an error"))
1099 c.Assert(string(output), check.Equals,
1100 "Installing unexisting.canonical\n"+
1101- "unexisting failed to install: snappy package not found\n")
1102+ "unexisting failed to install: snappy package not found\n",
1103+ check.Commentf("Wrong error message"))
1104 }
1105
1106=== modified file '_integration-tests/tests/installFramework_test.go'
1107--- _integration-tests/tests/installFramework_test.go 2015-10-08 06:53:50 +0000
1108+++ _integration-tests/tests/installFramework_test.go 2015-10-22 07:06:04 +0000
1109@@ -20,7 +20,12 @@
1110 package tests
1111
1112 import (
1113+ "fmt"
1114+ "os"
1115+
1116+ "launchpad.net/snappy/_integration-tests/testutils/build"
1117 "launchpad.net/snappy/_integration-tests/testutils/common"
1118+ "launchpad.net/snappy/_integration-tests/testutils/data"
1119
1120 "gopkg.in/check.v1"
1121 )
1122@@ -32,14 +37,18 @@
1123 }
1124
1125 func (s *installFrameworkSuite) TestInstallFrameworkMustPrintPackageInformation(c *check.C) {
1126- installOutput := common.InstallSnap(c, "hello-dbus-fwk.canonical")
1127- defer common.RemoveSnap(c, "hello-dbus-fwk.canonical")
1128+ snapPath, err := build.LocalSnap(c, data.BasicFrameworkSnapName)
1129+ defer os.Remove(snapPath)
1130+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
1131+ installOutput := common.InstallSnap(c, snapPath)
1132+ defer common.RemoveSnap(c, data.BasicFrameworkSnapName)
1133
1134 expected := "(?ms)" +
1135- "Installing hello-dbus-fwk.canonical\n" +
1136+ fmt.Sprintf("Installing %s\n", snapPath) +
1137+ ".*Signature check failed, but installing anyway as requested\n" +
1138 "Name +Date +Version +Developer \n" +
1139 ".*" +
1140- "^hello-dbus-fwk +.* +.* +canonical \n" +
1141+ "^basic-framework +.* +.* +sideload *\n" +
1142 ".*"
1143
1144 c.Assert(installOutput, check.Matches, expected)
1145
1146=== modified file '_integration-tests/tests/rollback_test.go'
1147--- _integration-tests/tests/rollback_test.go 2015-10-02 10:29:29 +0000
1148+++ _integration-tests/tests/rollback_test.go 2015-10-22 07:06:04 +0000
1149@@ -24,8 +24,6 @@
1150
1151 "launchpad.net/snappy/_integration-tests/testutils/cli"
1152 "launchpad.net/snappy/_integration-tests/testutils/common"
1153- "launchpad.net/snappy/_integration-tests/testutils/partition"
1154- "launchpad.net/snappy/_integration-tests/testutils/wait"
1155
1156 "gopkg.in/check.v1"
1157 )
1158@@ -42,18 +40,17 @@
1159 common.Reboot(c)
1160 } else if common.CheckRebootMark(c.TestName()) {
1161 common.RemoveRebootMark(c)
1162- // Workaround for bug https://bugs.launchpad.net/snappy/+bug/1498293
1163- // TODO remove once the bug is fixed. --elopio - 2015-09-30
1164- wait.ForFunction(c, "regular", partition.Mode)
1165 currentVersion := common.GetCurrentUbuntuCoreVersion(c)
1166- c.Assert(currentVersion > common.GetSavedVersion(c), check.Equals, true)
1167+ c.Assert(currentVersion > common.GetSavedVersion(c), check.Equals, true,
1168+ check.Commentf("Rebooted to the wrong version: %d", currentVersion))
1169 cli.ExecCommand(c, "sudo", "snappy", "rollback", "ubuntu-core",
1170 strconv.Itoa(common.GetSavedVersion(c)))
1171 common.SetSavedVersion(c, currentVersion)
1172 common.RebootWithMark(c, c.TestName()+"-rollback")
1173 } else if common.CheckRebootMark(c.TestName() + "-rollback") {
1174 common.RemoveRebootMark(c)
1175- c.Assert(
1176- common.GetCurrentUbuntuCoreVersion(c) < common.GetSavedVersion(c), check.Equals, true)
1177+ currentVersion := common.GetCurrentUbuntuCoreVersion(c)
1178+ c.Assert(currentVersion < common.GetSavedVersion(c), check.Equals, true,
1179+ check.Commentf("Rebooted to the wrong version: %d", currentVersion))
1180 }
1181 }
1182
1183=== modified file '_integration-tests/tests/service_test.go'
1184--- _integration-tests/tests/service_test.go 2015-10-08 05:57:00 +0000
1185+++ _integration-tests/tests/service_test.go 2015-10-22 07:06:04 +0000
1186@@ -21,10 +21,13 @@
1187
1188 import (
1189 "fmt"
1190+ "os"
1191 "regexp"
1192
1193+ "launchpad.net/snappy/_integration-tests/testutils/build"
1194 "launchpad.net/snappy/_integration-tests/testutils/cli"
1195 "launchpad.net/snappy/_integration-tests/testutils/common"
1196+ "launchpad.net/snappy/_integration-tests/testutils/data"
1197 "launchpad.net/snappy/_integration-tests/testutils/wait"
1198
1199 "gopkg.in/check.v1"
1200@@ -38,25 +41,23 @@
1201
1202 func (s *serviceSuite) TearDownTest(c *check.C) {
1203 if !common.NeedsReboot() && common.CheckRebootMark("") {
1204- common.RemoveSnap(c, "hello-dbus-fwk.canonical")
1205+ common.RemoveSnap(c, data.BasicServiceSnapName)
1206 }
1207 // run cleanup last
1208 s.SnappySuite.TearDownTest(c)
1209 }
1210
1211 func isServiceRunning(c *check.C) bool {
1212- packageVersion := common.GetCurrentVersion(c, "hello-dbus-fwk")
1213- service := fmt.Sprintf("hello-dbus-fwk_srv_%s.service", packageVersion)
1214+ packageVersion := common.GetCurrentVersion(c, data.BasicServiceSnapName)
1215+ service := fmt.Sprintf("%s_service_%s.service", data.BasicServiceSnapName, packageVersion)
1216
1217 err := wait.ForActiveService(c, service)
1218 c.Assert(err, check.IsNil)
1219
1220- statusOutput := cli.ExecCommand(
1221- c, "systemctl", "status",
1222- service)
1223+ statusOutput := cli.ExecCommand(c, "systemctl", "status", service)
1224
1225 expected := "(?ms)" +
1226- ".* hello-dbus-fwk_srv_.*\\.service .*\n" +
1227+ fmt.Sprintf(".* %s_service_.*\\.service .*\n", data.BasicServiceSnapName) +
1228 ".*Loaded: loaded .*\n" +
1229 ".*Active: active \\(running\\) .*\n" +
1230 ".*"
1231@@ -66,29 +67,35 @@
1232 return matched
1233 }
1234
1235+func installSnapWithService(c *check.C) {
1236+ snapPath, err := build.LocalSnap(c, data.BasicServiceSnapName)
1237+ defer os.Remove(snapPath)
1238+ c.Assert(err, check.IsNil, check.Commentf("Error building local snap: %s", err))
1239+ common.InstallSnap(c, snapPath)
1240+}
1241+
1242 func (s *serviceSuite) TestInstalledServiceMustBeStarted(c *check.C) {
1243- common.InstallSnap(c, "hello-dbus-fwk.canonical")
1244-
1245- c.Assert(isServiceRunning(c), check.Equals, true)
1246+ installSnapWithService(c)
1247+ c.Assert(isServiceRunning(c), check.Equals, true, check.Commentf("Service is not running"))
1248 }
1249
1250 func (s *serviceSuite) TestServiceMustBeStartedAfterReboot(c *check.C) {
1251 if common.BeforeReboot() {
1252- common.InstallSnap(c, "hello-dbus-fwk.canonical")
1253+ installSnapWithService(c)
1254 common.Reboot(c)
1255 } else if common.AfterReboot(c) {
1256 common.RemoveRebootMark(c)
1257- c.Assert(isServiceRunning(c), check.Equals, true)
1258+ c.Assert(isServiceRunning(c), check.Equals, true, check.Commentf("Service is not running"))
1259 }
1260 }
1261
1262 func (s *serviceSuite) TestServiceMustBeStartedAfterUpdate(c *check.C) {
1263 if common.BeforeReboot() {
1264- common.InstallSnap(c, "hello-dbus-fwk.canonical")
1265+ installSnapWithService(c)
1266 common.CallFakeUpdate(c)
1267 common.Reboot(c)
1268 } else if common.AfterReboot(c) {
1269 common.RemoveRebootMark(c)
1270- c.Assert(isServiceRunning(c), check.Equals, true)
1271+ c.Assert(isServiceRunning(c), check.Equals, true, check.Commentf("Service is not running"))
1272 }
1273 }
1274
1275=== modified file '_integration-tests/tests/snapd_1_0_packages_test.go'
1276--- _integration-tests/tests/snapd_1_0_packages_test.go 2015-10-08 08:55:17 +0000
1277+++ _integration-tests/tests/snapd_1_0_packages_test.go 2015-10-22 07:06:04 +0000
1278@@ -24,6 +24,7 @@
1279
1280 "launchpad.net/snappy/_integration-tests/testutils/build"
1281 "launchpad.net/snappy/_integration-tests/testutils/common"
1282+ "launchpad.net/snappy/_integration-tests/testutils/data"
1283
1284 "gopkg.in/check.v1"
1285 )
1286@@ -64,14 +65,14 @@
1287 func (s *snapd10PackagesTestSuite) SetUpTest(c *check.C) {
1288 s.snapdTestSuite.SetUpTest(c)
1289 var err error
1290- s.snapPath, err = build.LocalSnap(c, build.BasicSnapName)
1291+ s.snapPath, err = build.LocalSnap(c, data.BasicConfigSnapName)
1292 c.Assert(err, check.IsNil)
1293 }
1294
1295 func (s *snapd10PackagesTestSuite) TearDownTest(c *check.C) {
1296 s.snapdTestSuite.TearDownTest(c)
1297 os.Remove(s.snapPath)
1298- common.RemoveSnap(c, build.BasicSnapName)
1299+ common.RemoveSnap(c, data.BasicConfigSnapName)
1300 }
1301
1302 func (s *snapd10PackagesTestSuite) resource() string {
1303@@ -92,7 +93,17 @@
1304 payload: s.snapPath,
1305 waitPattern: `(?U){.*,"status":"active".*"status":"OK","status_code":200,"type":"sync"}`,
1306 waitFunction: func() (string, error) {
1307- output, err := genericRequest(s.resource()+"/"+build.BasicSnapName+".sideload", "GET", nil)
1308+ output, err := genericRequest(s.resource()+"/"+data.BasicConfigSnapName+".sideload", "GET", nil)
1309+ return string(output), err
1310+ }}}
1311+}
1312+
1313+func (s *snapd10PackagesTestSuite) putInteractions() apiInteractions {
1314+ return []apiInteraction{{
1315+ payload: `{"` + data.BasicConfigSnapName + ".sideload" + `": "key: value"}`,
1316+ waitPattern: `(?Us){"result":.*` + data.BasicConfigSnapName + `.*key: value.*","status":"OK","status_code":200,"type":"sync"}`,
1317+ waitFunction: func() (string, error) {
1318+ output, err := genericRequest(s.resource()+"/"+data.BasicConfigSnapName+".sideload/config", "GET", nil)
1319 return string(output), err
1320 }}}
1321 }
1322
1323=== modified file '_integration-tests/tests/snapd_test.go'
1324--- _integration-tests/tests/snapd_test.go 2015-09-28 11:15:51 +0000
1325+++ _integration-tests/tests/snapd_test.go 2015-10-22 07:06:04 +0000
1326@@ -51,13 +51,14 @@
1327
1328 func (s *snapdTestSuite) SetUpTest(c *check.C) {
1329 s.SnappySuite.SetUpTest(c)
1330- s.cmd = exec.Command("sudo", "/lib/systemd/systemd-activate",
1331+ s.cmd = exec.Command("sudo", "env", "PATH="+os.Getenv("PATH"),
1332+ "/lib/systemd/systemd-activate",
1333 "-l", "0.0.0.0:"+port, "snapd")
1334
1335 s.cmd.Start()
1336
1337 intPort, _ := strconv.Atoi(port)
1338- err := wait.ForServerOnPort(c, intPort)
1339+ err := wait.ForServerOnPort(c, "tcp", intPort)
1340 c.Assert(err, check.IsNil)
1341 }
1342
1343@@ -191,20 +192,20 @@
1344 }
1345
1346 body, err := genericRequest(resource, verb, payload)
1347- c.Check(err, check.IsNil)
1348+ c.Check(err, check.IsNil, check.Commentf("Error making the request: %s", err))
1349
1350 if interaction.responseObject == nil {
1351 interaction.responseObject = &response{}
1352 }
1353 err = json.Unmarshal(body, interaction.responseObject)
1354- c.Check(err, check.IsNil)
1355+ c.Check(err, check.IsNil, check.Commentf("Error unmarshalling the response: %s", err))
1356
1357 if interaction.responsePattern != "" {
1358 c.Check(string(body), check.Matches, interaction.responsePattern)
1359 }
1360 if interaction.waitPattern != "" {
1361 err = wait.ForFunction(c, interaction.waitPattern, interaction.waitFunction)
1362- c.Check(err, check.IsNil)
1363+ c.Check(err, check.IsNil, check.Commentf("Error waiting for function: %s", err))
1364 }
1365 }
1366
1367
1368=== modified file '_integration-tests/tests/ubuntuFan_test.go'
1369--- _integration-tests/tests/ubuntuFan_test.go 2015-09-30 11:27:49 +0000
1370+++ _integration-tests/tests/ubuntuFan_test.go 2015-10-22 07:06:04 +0000
1371@@ -53,7 +53,7 @@
1372 s.SnappySuite.SetUpTest(c)
1373 var err error
1374 s.subjectIP, err = getIPAddr(c)
1375- c.Assert(err, check.IsNil)
1376+ c.Assert(err, check.IsNil, check.Commentf("Error getting IP address: %s", err))
1377
1378 s.fanCtl(c, "up")
1379 s.bridgeIP = s.fanBridgeIP(c)
1380@@ -179,8 +179,11 @@
1381 cli.ExecCommand(c, "sudo", "systemctl", "restart", dockerService)
1382
1383 // we need to wait until the socket is ready, an active systemctl status is not enough
1384- err := wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
1385- c.Assert(err, check.IsNil)
1386+ err := wait.ForActiveService(c, dockerService)
1387+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
1388+
1389+ err = wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
1390+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
1391 }
1392
1393 func (s *fanTestSuite) fanName() string {
1394@@ -198,7 +201,10 @@
1395 dockerService := fmt.Sprintf("docker_docker-daemon_%s.service", dockerVersion)
1396
1397 err := wait.ForActiveService(c, dockerService)
1398- c.Assert(err, check.IsNil)
1399+ c.Assert(err, check.IsNil, check.Commentf("Error waiting for service: %s", err))
1400+
1401+ err = wait.ForCommand(c, `(?ms).*docker\.sock\s.*`, "ls", "/run")
1402+ c.Assert(err, check.IsNil, check.Commentf("Expected nil error, got %s", err))
1403
1404 cli.ExecCommand(c, "docker", "pull", baseContainer)
1405 }
1406
1407=== modified file '_integration-tests/testutils/build/snap.go'
1408--- _integration-tests/testutils/build/snap.go 2015-09-30 11:06:40 +0000
1409+++ _integration-tests/testutils/build/snap.go 2015-10-22 07:06:04 +0000
1410@@ -25,20 +25,10 @@
1411
1412 "gopkg.in/check.v1"
1413 "launchpad.net/snappy/_integration-tests/testutils/cli"
1414-)
1415-
1416-const (
1417- // BaseSnapPath is the path for the snap sources used in testing
1418- BaseSnapPath = "_integration-tests/data/snaps"
1419- // BasicSnapName is the name of the basic snap
1420- BasicSnapName = "basic"
1421- // WrongYamlSnapName is the name of a snap with an invalid meta yaml
1422- WrongYamlSnapName = "wrong-yaml"
1423- // MissingReadmeSnapName is the name of a snap without readme
1424- MissingReadmeSnapName = "missing-readme"
1425-
1426- snapFilenameSufix = "_1.0_all.snap"
1427-)
1428+ "launchpad.net/snappy/_integration-tests/testutils/data"
1429+)
1430+
1431+const snapFilenameSufix = "_1.0_all.snap"
1432
1433 var (
1434 // dependency aliasing
1435@@ -67,5 +57,5 @@
1436 }
1437
1438 func buildPath(snap string) string {
1439- return filepath.Join(BaseSnapPath, snap)
1440+ return filepath.Join(data.BaseSnapPath, snap)
1441 }
1442
1443=== modified file '_integration-tests/testutils/common/common.go'
1444--- _integration-tests/testutils/common/common.go 2015-10-01 09:37:04 +0000
1445+++ _integration-tests/testutils/common/common.go 2015-10-22 07:06:04 +0000
1446@@ -33,6 +33,7 @@
1447 "launchpad.net/snappy/_integration-tests/testutils/cli"
1448 "launchpad.net/snappy/_integration-tests/testutils/config"
1449 "launchpad.net/snappy/_integration-tests/testutils/partition"
1450+ "launchpad.net/snappy/_integration-tests/testutils/wait"
1451 )
1452
1453 const (
1454@@ -55,6 +56,12 @@
1455 // SetUpSuite disables the snappy autopilot. It will run before all the
1456 // integration suites.
1457 func (s *SnappySuite) SetUpSuite(c *check.C) {
1458+ // Workaround for bug https://bugs.launchpad.net/snappy/+bug/1498293
1459+ // TODO remove once the bug is fixed
1460+ // originally added by elopio - 2015-09-30 to the rollback test, moved
1461+ // here by --fgimenez - 2015-10-15
1462+ wait.ForFunction(c, "regular", partition.Mode)
1463+
1464 cli.ExecCommand(c, "sudo", "systemctl", "stop", "snappy-autopilot.timer")
1465 cli.ExecCommand(c, "sudo", "systemctl", "disable", "snappy-autopilot.timer")
1466 var err error
1467@@ -62,7 +69,7 @@
1468 "_integration-tests/data/output/testconfig.json")
1469 c.Assert(err, check.IsNil, check.Commentf("Error reading config: %v", err))
1470
1471- if !isInRebootProcess() {
1472+ if !IsInRebootProcess() {
1473 if Cfg.Update || Cfg.Rollback {
1474 switchSystemImageConf(c, Cfg.TargetRelease, Cfg.TargetChannel, "0")
1475 // Always use the installed snappy because we are updating from an old
1476@@ -275,7 +282,8 @@
1477 return os.Getenv("ADT_REBOOT_MARK") == mark
1478 }
1479
1480-func isInRebootProcess() bool {
1481+// IsInRebootProcess returns True if the suite needs to execute a reboot or has just rebooted.
1482+func IsInRebootProcess() bool {
1483 return !CheckRebootMark("") || NeedsReboot()
1484 }
1485
1486
1487=== added directory '_integration-tests/testutils/data'
1488=== added file '_integration-tests/testutils/data/data.go'
1489--- _integration-tests/testutils/data/data.go 1970-01-01 00:00:00 +0000
1490+++ _integration-tests/testutils/data/data.go 2015-10-22 07:06:04 +0000
1491@@ -0,0 +1,39 @@
1492+// -*- Mode: Go; indent-tabs-mode: t -*-
1493+
1494+/*
1495+ * Copyright (C) 2015 Canonical Ltd
1496+ *
1497+ * This program is free software: you can redistribute it and/or modify
1498+ * it under the terms of the GNU General Public License version 3 as
1499+ * published by the Free Software Foundation.
1500+ *
1501+ * This program is distributed in the hope that it will be useful,
1502+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1503+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1504+ * GNU General Public License for more details.
1505+ *
1506+ * You should have received a copy of the GNU General Public License
1507+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1508+ *
1509+ */
1510+
1511+package data
1512+
1513+const (
1514+ // BaseSnapPath is the path for the snap sources used in testing
1515+ BaseSnapPath = "_integration-tests/data/snaps"
1516+ // BasicSnapName is the name of the basic snap
1517+ BasicSnapName = "basic"
1518+ // BasicBinariesSnapName is the name of the basic snap with binaries
1519+ BasicBinariesSnapName = "basic-binaries"
1520+ // BasicConfigSnapName is the name of the basic snap with config hook
1521+ BasicConfigSnapName = "basic-config"
1522+ // BasicFrameworkSnapName is the name of the basic framework snap
1523+ BasicFrameworkSnapName = "basic-framework"
1524+ // BasicServiceSnapName is the name of the basic snap with a service
1525+ BasicServiceSnapName = "basic-service"
1526+ // WrongYamlSnapName is the name of a snap with an invalid meta yaml
1527+ WrongYamlSnapName = "wrong-yaml"
1528+ // MissingReadmeSnapName is the name of a snap without readme
1529+ MissingReadmeSnapName = "missing-readme"
1530+)
1531
1532=== modified file '_integration-tests/testutils/wait/wait.go'
1533--- _integration-tests/testutils/wait/wait.go 2015-09-30 11:06:40 +0000
1534+++ _integration-tests/testutils/wait/wait.go 2015-10-22 07:06:04 +0000
1535@@ -46,8 +46,9 @@
1536 }
1537
1538 // ForServerOnPort uses ForCommand to check for process listening on the given port
1539-func ForServerOnPort(c *check.C, port int) (err error) {
1540- return ForCommand(c, fmt.Sprintf(`(?msU)^.*tcp.*0\.0\.0\.0:%d .*`, port), "netstat", "-tapn")
1541+func ForServerOnPort(c *check.C, protocol string, port int) (err error) {
1542+ return ForCommand(c, fmt.Sprintf(`(?msU)^.*%s .*:%d .* LISTEN.*`, protocol, port),
1543+ "netstat", "-tapn")
1544 }
1545
1546 // forCommand uses ForFunction to check for the execCommand output
1547
1548=== modified file '_integration-tests/testutils/wait/wait_test.go'
1549--- _integration-tests/testutils/wait/wait_test.go 2015-09-28 10:54:40 +0000
1550+++ _integration-tests/testutils/wait/wait_test.go 2015-10-22 07:06:04 +0000
1551@@ -177,9 +177,9 @@
1552 return
1553 }
1554
1555- ForServerOnPort(c, 1234)
1556+ ForServerOnPort(c, "tcp", 1234)
1557
1558- expectedCalled := `ForCommand called with pattern '(?msU)^.*tcp.*0\.0\.0\.0:1234 .*' and cmds 'netstat -tapn'`
1559+ expectedCalled := `ForCommand called with pattern '(?msU)^.*tcp .*:1234 .* LISTEN.*' and cmds 'netstat -tapn'`
1560 c.Assert(called, check.Equals, expectedCalled, check.Commentf("Expected call to ForCommand didn't happen"))
1561 }
1562
1563
1564=== modified file 'cmd/snappy/cmd_info.go'
1565--- cmd/snappy/cmd_info.go 2015-10-01 19:28:27 +0000
1566+++ cmd/snappy/cmd_info.go 2015-10-22 07:06:04 +0000
1567@@ -30,8 +30,9 @@
1568 )
1569
1570 type cmdInfo struct {
1571- Verbose bool `short:"v" long:"verbose"`
1572- Positional struct {
1573+ Verbose bool `short:"v" long:"verbose"`
1574+ IncludeRemote bool `long:"include-remote"`
1575+ Positional struct {
1576 PackageName string `positional-arg-name:"package name"`
1577 } `positional-args:"yes"`
1578 }
1579@@ -56,19 +57,28 @@
1580 logger.Panicf("Unable to info: %v", err)
1581 }
1582 addOptionDescription(arg, "verbose", i18n.G("Provides more detailed information"))
1583+ addOptionDescription(arg, "include-remote", i18n.G("Include information about packages from the snappy store"))
1584 addOptionDescription(arg, "package name", i18n.G("Provide information about a specific installed package"))
1585 }
1586
1587 func (x *cmdInfo) Execute(args []string) (err error) {
1588 if x.Positional.PackageName != "" {
1589- return snapInfo(x.Positional.PackageName, x.Verbose)
1590+ return snapInfo(x.Positional.PackageName, x.IncludeRemote, x.Verbose)
1591 }
1592
1593 return info()
1594 }
1595
1596-func snapInfo(pkgname string, verbose bool) error {
1597+func snapInfo(pkgname string, includeStore, verbose bool) error {
1598 snap := snappy.ActiveSnapByName(pkgname)
1599+ if snap == nil && includeStore {
1600+ m := snappy.NewUbuntuStoreSnapRepository()
1601+ snaps, err := m.Details(snappy.SplitOrigin(pkgname))
1602+ if err == nil && len(snaps) == 1 {
1603+ snap = snaps[0]
1604+ }
1605+ }
1606+
1607 if snap == nil {
1608 return fmt.Errorf("No snap '%s' found", pkgname)
1609 }
1610
1611=== modified file 'cmd/snappy/common_test.go'
1612--- cmd/snappy/common_test.go 2015-07-09 06:05:53 +0000
1613+++ cmd/snappy/common_test.go 2015-10-22 07:06:04 +0000
1614@@ -23,8 +23,9 @@
1615 "testing"
1616
1617 "github.com/jessevdk/go-flags"
1618-
1619 . "gopkg.in/check.v1"
1620+
1621+ "launchpad.net/snappy/logger"
1622 )
1623
1624 // Hook up check.v1 into the "go test" runner
1625@@ -66,6 +67,10 @@
1626 }
1627
1628 func (s *CmdTestSuite) TestAddOptionDescriptionOrPanicWillPanic(c *C) {
1629+ // disable logging so log doesn't scare people
1630+ logger.SetLogger(logger.NullLogger)
1631+ defer func() { c.Check(logger.SimpleSetup(), IsNil) }()
1632+
1633 parser := flags.NewParser(&struct{}{}, 0)
1634 arg, err := parser.AddCommand("mock", "shortHelp", "longHelp", &struct{}{})
1635 c.Assert(err, IsNil)
1636
1637=== modified file 'coreconfig/config.go'
1638--- coreconfig/config.go 2015-09-18 15:16:17 +0000
1639+++ coreconfig/config.go 2015-10-22 07:06:04 +0000
1640@@ -20,12 +20,15 @@
1641 package coreconfig
1642
1643 import (
1644+ "bufio"
1645+ "bytes"
1646 "errors"
1647 "io/ioutil"
1648 "os"
1649 "os/exec"
1650 "path/filepath"
1651 "reflect"
1652+ "sort"
1653 "strings"
1654 "syscall"
1655
1656@@ -52,6 +55,7 @@
1657
1658 var (
1659 modprobePath = "/etc/modprobe.d/ubuntu-core.conf"
1660+ modulesPath = "/etc/modules-load.d/ubuntu-core.conf"
1661 interfacesRoot = "/etc/network/interfaces.d/"
1662 pppRoot = "/etc/ppp/"
1663 watchdogConfigPath = "/etc/watchdog.conf"
1664@@ -73,6 +77,7 @@
1665 Timezone *string `yaml:"timezone,omitempty"`
1666 Hostname *string `yaml:"hostname,omitempty"`
1667 Modprobe *string `yaml:"modprobe,omitempty"`
1668+ Modules []string `yaml:"load-kernel-modules,omitempty"`
1669 Network *networkConfig `yaml:"network,omitempty"`
1670 Watchdog *watchdogConfig `yaml:"watchdog,omitempty"`
1671 }
1672@@ -119,6 +124,10 @@
1673 if err != nil {
1674 return nil, err
1675 }
1676+ modules, err := getModules()
1677+ if err != nil {
1678+ return nil, err
1679+ }
1680 interfaces, err := getInterfaces()
1681 if err != nil {
1682 return nil, err
1683@@ -145,6 +154,7 @@
1684 Timezone: &tz,
1685 Hostname: &hostname,
1686 Modprobe: &modprobe,
1687+ Modules: modules,
1688 Network: network,
1689 Watchdog: watchdog,
1690 }
1691@@ -244,6 +254,10 @@
1692 if err := setModprobe(*newConfig.Modprobe); err != nil {
1693 return "", err
1694 }
1695+ case "Modules":
1696+ if err := setModules(newConfig.Modules); err != nil {
1697+ return "", err
1698+ }
1699 case "Network":
1700 if oldConfig.Network == nil || !passthroughEqual(oldConfig.Network.Interfaces, newConfig.Network.Interfaces) {
1701 if err := setInterfaces(newConfig.Network.Interfaces); err != nil {
1702@@ -297,7 +311,7 @@
1703 return err
1704 }
1705
1706- return ioutil.WriteFile(tzFile(), []byte(timezone), 0644)
1707+ return helpers.AtomicWriteFile(tzFile(), []byte(timezone), 0644)
1708 }
1709
1710 func getPassthrough(rootDir string) (pc []passthroughConfig, err error) {
1711@@ -326,7 +340,7 @@
1712 os.Remove(path)
1713 continue
1714 }
1715- if err := ioutil.WriteFile(path, []byte(c.Content), 0644); err != nil {
1716+ if err := helpers.AtomicWriteFile(path, []byte(c.Content), 0644); err != nil {
1717 return err
1718 }
1719 }
1720@@ -362,7 +376,94 @@
1721
1722 // setModprobe sets the specified modprobe config
1723 var setModprobe = func(modprobe string) error {
1724- return ioutil.WriteFile(modprobePath, []byte(modprobe), 0644)
1725+ return helpers.AtomicWriteFile(modprobePath, []byte(modprobe), 0644)
1726+}
1727+
1728+func getModules() ([]string, error) {
1729+ f, err := os.Open(modulesPath)
1730+ if err != nil {
1731+ if os.IsNotExist(err) {
1732+ return nil, nil
1733+ }
1734+
1735+ return nil, err
1736+ }
1737+
1738+ // there's a warning at the top of the file
1739+ // but you know they're just going to edit it anyway
1740+ // so be kind
1741+
1742+ var modules []string
1743+ scanner := bufio.NewScanner(f)
1744+ for scanner.Scan() {
1745+ line := strings.TrimSpace(scanner.Text())
1746+ if len(line) == 0 {
1747+ continue
1748+ }
1749+ if line[0] == '#' || line[0] == ';' {
1750+ continue
1751+ }
1752+
1753+ modules = append(modules, line)
1754+ }
1755+ if err := scanner.Err(); err != nil {
1756+ return nil, err
1757+ }
1758+
1759+ // doing the sort on get makes testing easier
1760+ sort.Strings(modules)
1761+
1762+ return modules, nil
1763+}
1764+
1765+const modulesHeader = `#
1766+# DO NOT EDIT THIS FILE
1767+# it is auto-generated, and will be overwritten.
1768+`
1769+
1770+func setModules(modules []string) error {
1771+ oldModules, err := getModules()
1772+ if err != nil {
1773+ return err
1774+ }
1775+
1776+ for i := range modules {
1777+ m := strings.TrimSpace(modules[i])
1778+ if len(m) == 0 {
1779+ continue
1780+ }
1781+
1782+ if m[0] == '-' {
1783+ m = m[1:]
1784+ idx := sort.SearchStrings(oldModules, m)
1785+ if idx == len(oldModules) || oldModules[idx] != m {
1786+ // not found
1787+ continue
1788+ }
1789+ oldModules = append(oldModules[:idx], oldModules[idx+1:]...)
1790+ } else {
1791+ idx := sort.SearchStrings(oldModules, m)
1792+ if idx < len(oldModules) && oldModules[idx] == m {
1793+ // already got it
1794+ continue
1795+ }
1796+ oldModules = append(oldModules, "")
1797+ copy(oldModules[idx+1:], oldModules[idx:])
1798+ oldModules[idx] = m
1799+ }
1800+ }
1801+
1802+ var buf bytes.Buffer
1803+
1804+ // bytes' Write* methods always return nil error
1805+ buf.WriteString(modulesHeader)
1806+
1807+ for i := range oldModules {
1808+ buf.WriteString(oldModules[i])
1809+ buf.WriteByte('\n')
1810+ }
1811+
1812+ return helpers.AtomicWriteFile(modulesPath, buf.Bytes(), 0644)
1813 }
1814
1815 // getWatchdog returns the current watchdog config
1816@@ -388,11 +489,11 @@
1817
1818 // setWatchdog sets the specified watchdog config
1819 var setWatchdog = func(wf *watchdogConfig) error {
1820- if err := ioutil.WriteFile(watchdogStartupPath, []byte(wf.Startup), 0644); err != nil {
1821+ if err := helpers.AtomicWriteFile(watchdogStartupPath, []byte(wf.Startup), 0644); err != nil {
1822 return err
1823 }
1824
1825- return ioutil.WriteFile(watchdogConfigPath, []byte(wf.Config), 0644)
1826+ return helpers.AtomicWriteFile(watchdogConfigPath, []byte(wf.Config), 0644)
1827 }
1828
1829 // for testing purposes
1830@@ -467,5 +568,5 @@
1831 return err
1832 }
1833
1834- return ioutil.WriteFile(hostnamePath, hostnameB, 0644)
1835+ return helpers.AtomicWriteFile(hostnamePath, hostnameB, 0644)
1836 }
1837
1838=== modified file 'coreconfig/config_test.go'
1839--- coreconfig/config_test.go 2015-09-21 15:14:41 +0000
1840+++ coreconfig/config_test.go 2015-10-22 07:06:04 +0000
1841@@ -51,6 +51,7 @@
1842 originalCmdSystemctl = cmdSystemctl
1843 originalHostnamePath = hostnamePath
1844 originalModprobePath = modprobePath
1845+ originalModulesPath = modulesPath
1846 originalInterfacesRoot = interfacesRoot
1847 originalPppRoot = pppRoot
1848 originalWatchdogStartupPath = watchdogStartupPath
1849@@ -107,6 +108,7 @@
1850 cmdAutopilotEnabled = originalCmdAutopilotEnabled
1851 cmdSystemctl = originalCmdSystemctl
1852 modprobePath = originalModprobePath
1853+ modulesPath = originalModulesPath
1854 interfacesRoot = originalInterfacesRoot
1855 pppRoot = originalPppRoot
1856 watchdogStartupPath = originalWatchdogStartupPath
1857@@ -489,12 +491,195 @@
1858 _, err := Set(input)
1859 c.Assert(err, IsNil)
1860
1861- // ensure its really there
1862+ // ensure it's really there
1863 content, err := ioutil.ReadFile(modprobePath)
1864 c.Assert(err, IsNil)
1865 c.Assert(string(content), Equals, "blacklist floppy\nsoftdep mlx4_core post: mlx4_en\n")
1866 }
1867
1868+func (cts *ConfigTestSuite) TestModules(c *C) {
1869+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1870+
1871+ modules, err := getModules()
1872+ c.Assert(err, IsNil)
1873+ c.Check(modules, HasLen, 0)
1874+
1875+ c.Assert(setModules([]string{"foo"}), IsNil)
1876+
1877+ modules, err = getModules()
1878+ c.Assert(err, IsNil)
1879+ c.Check(modules, DeepEquals, []string{"foo"})
1880+
1881+ c.Assert(setModules([]string{"bar"}), IsNil)
1882+
1883+ modules, err = getModules()
1884+ c.Assert(err, IsNil)
1885+ c.Check(modules, DeepEquals, []string{"bar", "foo"})
1886+
1887+ c.Assert(setModules([]string{"-foo"}), IsNil)
1888+
1889+ modules, err = getModules()
1890+ c.Assert(err, IsNil)
1891+ c.Check(modules, DeepEquals, []string{"bar"})
1892+}
1893+
1894+func (cts *ConfigTestSuite) TestModulesRemoveAbsent(c *C) {
1895+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1896+
1897+ c.Assert(setModules([]string{"foo"}), IsNil)
1898+ c.Assert(setModules([]string{"-bar"}), IsNil)
1899+
1900+ modules, err := getModules()
1901+ c.Assert(err, IsNil)
1902+ c.Check(modules, DeepEquals, []string{"foo"})
1903+}
1904+
1905+func (cts *ConfigTestSuite) TestModulesRemoveEmpty(c *C) {
1906+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1907+
1908+ c.Assert(setModules([]string{"foo"}), IsNil)
1909+ c.Assert(setModules([]string{"-"}), IsNil)
1910+
1911+ modules, err := getModules()
1912+ c.Assert(err, IsNil)
1913+ c.Check(modules, DeepEquals, []string{"foo"})
1914+}
1915+
1916+func (cts *ConfigTestSuite) TestModulesRemoveBlank(c *C) {
1917+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1918+
1919+ c.Assert(setModules([]string{"foo"}), IsNil)
1920+ c.Assert(setModules([]string{"- "}), IsNil)
1921+
1922+ modules, err := getModules()
1923+ c.Assert(err, IsNil)
1924+ c.Check(modules, DeepEquals, []string{"foo"})
1925+}
1926+
1927+func (cts *ConfigTestSuite) TestModulesAddDupe(c *C) {
1928+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1929+
1930+ c.Assert(setModules([]string{"foo"}), IsNil)
1931+ c.Assert(setModules([]string{"foo"}), IsNil)
1932+
1933+ modules, err := getModules()
1934+ c.Assert(err, IsNil)
1935+ c.Check(modules, DeepEquals, []string{"foo"})
1936+}
1937+
1938+func (cts *ConfigTestSuite) TestModulesAddEmpty(c *C) {
1939+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1940+
1941+ c.Assert(setModules([]string{"foo"}), IsNil)
1942+ c.Assert(setModules([]string{""}), IsNil)
1943+
1944+ modules, err := getModules()
1945+ c.Assert(err, IsNil)
1946+ c.Check(modules, DeepEquals, []string{"foo"})
1947+}
1948+
1949+func (cts *ConfigTestSuite) TestModulesAddBlank(c *C) {
1950+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1951+
1952+ c.Assert(setModules([]string{"foo"}), IsNil)
1953+ c.Assert(setModules([]string{" "}), IsNil)
1954+
1955+ modules, err := getModules()
1956+ c.Assert(err, IsNil)
1957+ c.Check(modules, DeepEquals, []string{"foo"})
1958+}
1959+
1960+func (cts *ConfigTestSuite) TestModulesHasWarning(c *C) {
1961+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1962+
1963+ c.Assert(setModules([]string{"foo"}), IsNil)
1964+
1965+ bs, err := ioutil.ReadFile(modulesPath)
1966+ c.Assert(err, IsNil)
1967+ c.Check(string(bs), Matches, `(?s).*DO NOT EDIT.*`)
1968+}
1969+
1970+func (cts *ConfigTestSuite) TestModulesIsKind(c *C) {
1971+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1972+ c.Assert(ioutil.WriteFile(modulesPath, []byte(`# hello
1973+# this is what happens when soembody comes and edits the file
1974+# just to be sure
1975+; modules-load.d(5) says comments can also start with a ;
1976+ ; actually not even start
1977+ # it's the first non-whitespace that counts
1978+# also here's an empty line:
1979+
1980+# and here's a module with spurious whitespace:
1981+ oops
1982+# that is all. Have a good day.
1983+`), 0644), IsNil)
1984+
1985+ modules, err := getModules()
1986+ c.Check(err, IsNil)
1987+ c.Check(modules, DeepEquals, []string{"oops"})
1988+}
1989+
1990+func (cts *ConfigTestSuite) TestModulesYaml(c *C) {
1991+ modulesPath = filepath.Join(c.MkDir(), "test.conf")
1992+
1993+ c.Assert(setModules([]string{"foo"}), IsNil)
1994+
1995+ cfg, err := newSystemConfig()
1996+ c.Assert(err, IsNil)
1997+ c.Check(cfg.Modules, DeepEquals, []string{"foo"})
1998+
1999+ input := `config:
2000+ ubuntu-core:
2001+ load-kernel-modules: [-foo, bar]
2002+`
2003+ _, err = Set(input)
2004+ c.Assert(err, IsNil)
2005+
2006+ // ensure it's really there
2007+ content, err := ioutil.ReadFile(modulesPath)
2008+ c.Assert(err, IsNil)
2009+ c.Assert(string(content), Matches, `(?sm).*^bar$.*`)
2010+
2011+ modules, err := getModules()
2012+ c.Assert(err, IsNil)
2013+ c.Check(modules, DeepEquals, []string{"bar"})
2014+}
2015+
2016+func (cts *ConfigTestSuite) TestModulesErrorWrite(c *C) {
2017+ // modulesPath is not writable, but only notexist read error
2018+ modulesPath = filepath.Join(c.MkDir(), "not-there", "test.conf")
2019+
2020+ c.Check(setModules([]string{"bar"}), NotNil)
2021+
2022+ input := `config:
2023+ ubuntu-core:
2024+ load-kernel-modules: [foo]
2025+`
2026+ _, err := Set(input)
2027+ c.Check(err, NotNil)
2028+
2029+ _, err = getModules()
2030+ c.Check(err, IsNil)
2031+
2032+ _, err = newSystemConfig()
2033+ c.Check(err, IsNil)
2034+}
2035+
2036+func (cts *ConfigTestSuite) TestModulesErrorRW(c *C) {
2037+ modulesPath = c.MkDir()
2038+
2039+ modules, err := getModules()
2040+ c.Check(err, NotNil)
2041+ c.Check(modules, HasLen, 0)
2042+ c.Check(setModules([]string{"bar"}), NotNil)
2043+
2044+ _, err = newSystemConfig()
2045+ c.Check(err, NotNil)
2046+
2047+ _, err = Set("config: {ubuntu-core: {modules: [foo]}}")
2048+ c.Check(err, NotNil)
2049+}
2050+
2051 func (cts *ConfigTestSuite) TestNetworkGet(c *C) {
2052 path := filepath.Join(interfacesRoot, "eth0")
2053 content := "auto eth0"
2054@@ -573,7 +758,7 @@
2055 _, err := Set(input)
2056 c.Assert(err, IsNil)
2057
2058- // ensure its really there
2059+ // ensure it's really there
2060 content, err := ioutil.ReadFile(filepath.Join(interfacesRoot, "eth0"))
2061 c.Assert(err, IsNil)
2062 c.Assert(string(content), Equals, "auto dhcp")
2063@@ -593,7 +778,7 @@
2064 _, err := Set(input)
2065 c.Assert(err, IsNil)
2066
2067- // ensure its really there
2068+ // ensure it's really there
2069 content, err := ioutil.ReadFile(filepath.Join(pppRoot, "chap-secret"))
2070 c.Assert(err, IsNil)
2071 c.Assert(string(content), Equals, "password")
2072@@ -670,7 +855,7 @@
2073 _, err := Set(input)
2074 c.Assert(err, IsNil)
2075
2076- // ensure its really there
2077+ // ensure it's really there
2078 content, err := ioutil.ReadFile(watchdogStartupPath)
2079 c.Assert(err, IsNil)
2080 c.Assert(string(content), Equals, "some startup")
2081
2082=== modified file 'daemon/api.go'
2083--- daemon/api.go 2015-10-11 15:32:36 +0000
2084+++ daemon/api.go 2015-10-22 07:06:04 +0000
2085@@ -80,6 +80,7 @@
2086 Path: "/1.0/packages",
2087 GET: getPackagesInfo,
2088 POST: sideloadPackage,
2089+ PUT: configMulti,
2090 }
2091
2092 packageCmd = &Command{
2093@@ -112,8 +113,9 @@
2094 }
2095
2096 operationCmd = &Command{
2097- Path: "/1.0/operations/{uuid}",
2098- GET: getOpInfo,
2099+ Path: "/1.0/operations/{uuid}",
2100+ GET: getOpInfo,
2101+ DELETE: deleteOp,
2102 }
2103 )
2104
2105@@ -424,9 +426,13 @@
2106 pkgName := name + "." + origin
2107
2108 bag := lightweight.PartBagByName(name, origin)
2109+ if bag == nil {
2110+ return NotFound
2111+ }
2112+
2113 idx := bag.ActiveIndex()
2114 if idx < 0 {
2115- return NotFound
2116+ return BadRequest
2117 }
2118
2119 part, err := bag.Load(idx)
2120@@ -447,6 +453,59 @@
2121 return SyncResponse(config)
2122 }
2123
2124+type configSubtask struct {
2125+ Status string `json:"status"`
2126+ Output interface{} `json:"output"`
2127+}
2128+
2129+func configMulti(c *Command, r *http.Request) Response {
2130+ route := c.d.router.Get(operationCmd.Path)
2131+ if route == nil {
2132+ return InternalError(nil, "router can't find route for operation")
2133+ }
2134+
2135+ decoder := json.NewDecoder(r.Body)
2136+ var pkgmap map[string]string
2137+ if err := decoder.Decode(&pkgmap); err != nil {
2138+ return BadRequest(err, "can't decode request body into map[string]string: %v", err)
2139+ }
2140+
2141+ return AsyncResponse(c.d.AddTask(func() interface{} {
2142+ rspmap := make(map[string]*configSubtask, len(pkgmap))
2143+ bags := lightweight.AllPartBags()
2144+ for pkg, cfg := range pkgmap {
2145+ out := errorResult{}
2146+ sub := configSubtask{Status: TaskFailed, Output: &out}
2147+ rspmap[pkg] = &sub
2148+ bag, ok := bags[pkg]
2149+ if !ok {
2150+ out.Str = snappy.ErrPackageNotFound.Error()
2151+ out.Obj = snappy.ErrPackageNotFound
2152+ continue
2153+ }
2154+
2155+ part, _ := bag.Load(bag.ActiveIndex())
2156+ if part == nil {
2157+ out.Str = snappy.ErrSnapNotActive.Error()
2158+ out.Obj = snappy.ErrSnapNotActive
2159+ continue
2160+ }
2161+
2162+ config, err := part.Config([]byte(cfg))
2163+ if err != nil {
2164+ out.Msg = "Config failed"
2165+ out.Str = err.Error()
2166+ out.Obj = err
2167+ continue
2168+ }
2169+ sub.Status = TaskSucceeded
2170+ sub.Output = config
2171+ }
2172+
2173+ return rspmap
2174+ }).Map(route))
2175+}
2176+
2177 func getOpInfo(c *Command, r *http.Request) Response {
2178 route := c.d.router.Get(c.Path)
2179 if route == nil {
2180@@ -462,6 +521,22 @@
2181 return SyncResponse(task.Map(route))
2182 }
2183
2184+func deleteOp(c *Command, r *http.Request) Response {
2185+ id := muxVars(r)["uuid"]
2186+ err := c.d.DeleteTask(id)
2187+
2188+ switch err {
2189+ case nil:
2190+ return SyncResponse("done")
2191+ case errTaskNotFound:
2192+ return NotFound
2193+ case errTaskStillRunning:
2194+ return BadRequest
2195+ default:
2196+ return InternalError(err, "")
2197+ }
2198+}
2199+
2200 type packageInstruction struct {
2201 Action string `json:"action"`
2202 LeaveOld bool `json:"leave_old"`
2203
2204=== modified file 'daemon/api_test.go'
2205--- daemon/api_test.go 2015-10-11 15:32:36 +0000
2206+++ daemon/api_test.go 2015-10-22 07:06:04 +0000
2207@@ -27,6 +27,7 @@
2208 "go/ast"
2209 "go/parser"
2210 "go/token"
2211+ "io"
2212 "io/ioutil"
2213 "net/http"
2214 "net/http/httptest"
2215@@ -243,7 +244,7 @@
2216
2217 c.Check(rsp.Type, check.Equals, ResponseTypeError)
2218 c.Check(rsp.Status, check.Equals, http.StatusInternalServerError)
2219- c.Check(rsp.Result.(map[string]interface{})["msg"], check.Matches, `route can't build URL .*`)
2220+ c.Check(rsp.Result.(*errorResult).Msg, check.Matches, `route can't build URL .*`)
2221 }
2222
2223 func (s *apiSuite) TestListIncludesAll(c *check.C) {
2224@@ -414,6 +415,40 @@
2225 }
2226 }
2227
2228+func (s *apiSuite) TestDeleteOpNotFound(c *check.C) {
2229+ d := New()
2230+ d.addRoutes()
2231+
2232+ s.vars = map[string]string{"uuid": "42"}
2233+ rsp := deleteOp(operationCmd, nil).Self(nil, nil).(*resp)
2234+ c.Check(rsp.Type, check.Equals, ResponseTypeError)
2235+ c.Check(rsp.Status, check.Equals, http.StatusNotFound)
2236+}
2237+
2238+func (s *apiSuite) TestDeleteOpStillRunning(c *check.C) {
2239+ d := New()
2240+ d.addRoutes()
2241+
2242+ d.tasks["42"] = &Task{}
2243+ s.vars = map[string]string{"uuid": "42"}
2244+ rsp := deleteOp(operationCmd, nil).Self(nil, nil).(*resp)
2245+ c.Check(rsp.Type, check.Equals, ResponseTypeError)
2246+ c.Check(rsp.Status, check.Equals, http.StatusBadRequest)
2247+}
2248+
2249+func (s *apiSuite) TestDeleteOp(c *check.C) {
2250+ d := New()
2251+ d.addRoutes()
2252+
2253+ task := &Task{}
2254+ d.tasks["42"] = task
2255+ task.tomb.Kill(nil)
2256+ s.vars = map[string]string{"uuid": "42"}
2257+ rsp := deleteOp(operationCmd, nil).Self(nil, nil).(*resp)
2258+ c.Check(rsp.Type, check.Equals, ResponseTypeSync)
2259+ c.Check(rsp.Status, check.Equals, http.StatusOK)
2260+}
2261+
2262 func (s *apiSuite) TestGetOpInfoIntegration(c *check.C) {
2263 d := New()
2264 d.addRoutes()
2265@@ -575,12 +610,16 @@
2266 }
2267 }
2268
2269-type cfgc struct{ cfg string }
2270+type cfgc struct {
2271+ cfg string
2272+ err error
2273+ idx int
2274+}
2275
2276 func (cfgc) IsInstalled(string) bool { return true }
2277-func (cfgc) ActiveIndex() int { return 0 }
2278+func (c cfgc) ActiveIndex() int { return c.idx }
2279 func (c cfgc) Load(string) (snappy.Part, error) {
2280- return &tP{name: "foo", version: "v1", origin: "bar", isActive: true, config: c.cfg}, nil
2281+ return &tP{name: "foo", version: "v1", origin: "bar", isActive: true, config: c.cfg, configErr: c.err}, nil
2282 }
2283
2284 func (s *apiSuite) TestPackageGetConfig(c *check.C) {
2285@@ -596,7 +635,7 @@
2286 lightweight.NewConcrete = oldConcrete
2287 }()
2288 lightweight.NewConcrete = func(*lightweight.PartBag, string) lightweight.Concreter {
2289- return &cfgc{configStr}
2290+ return &cfgc{cfg: configStr}
2291 }
2292
2293 s.vars = map[string]string{"name": "foo", "origin": "bar"}
2294@@ -611,6 +650,43 @@
2295 })
2296 }
2297
2298+func (s *apiSuite) TestPackageGetConfigMissing(c *check.C) {
2299+ s.vars = map[string]string{"name": "foo", "origin": "bar"}
2300+
2301+ req, err := http.NewRequest("GET", "/1.0/packages/foo.bar/config", bytes.NewBuffer(nil))
2302+ c.Assert(err, check.IsNil)
2303+
2304+ rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2305+
2306+ c.Check(rsp.Status, check.Equals, http.StatusNotFound)
2307+}
2308+
2309+func (s *apiSuite) TestPackageGetConfigInactive(c *check.C) {
2310+ s.vars = map[string]string{"name": "foo", "origin": "bar"}
2311+
2312+ s.mkInstalled(c, "foo", "bar", "v1", false, "")
2313+
2314+ req, err := http.NewRequest("GET", "/1.0/packages/foo.bar/config", bytes.NewBuffer(nil))
2315+ c.Assert(err, check.IsNil)
2316+
2317+ rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2318+
2319+ c.Check(rsp.Status, check.Equals, http.StatusBadRequest)
2320+}
2321+
2322+func (s *apiSuite) TestPackageGetConfigNoConfig(c *check.C) {
2323+ s.vars = map[string]string{"name": "foo", "origin": "bar"}
2324+
2325+ s.mkInstalled(c, "foo", "bar", "v1", true, "")
2326+
2327+ req, err := http.NewRequest("GET", "/1.0/packages/foo.bar/config", bytes.NewBuffer(nil))
2328+ c.Assert(err, check.IsNil)
2329+
2330+ rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2331+
2332+ c.Check(rsp.Status, check.Equals, http.StatusInternalServerError)
2333+}
2334+
2335 func (s *apiSuite) TestPackagePutConfig(c *check.C) {
2336 d := New()
2337 d.addRoutes()
2338@@ -625,13 +701,13 @@
2339 lightweight.NewConcrete = oldConcrete
2340 }()
2341 lightweight.NewConcrete = func(*lightweight.PartBag, string) lightweight.Concreter {
2342- return &cfgc{configStr}
2343+ return &cfgc{cfg: configStr}
2344 }
2345
2346 s.vars = map[string]string{"name": "foo", "origin": "bar"}
2347 s.mkInstalled(c, "foo", "bar", "v1", true, "")
2348
2349- rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2350+ rsp := packageConfig(packageConfigCmd, req).Self(nil, nil).(*resp)
2351
2352 c.Check(rsp, check.DeepEquals, &resp{
2353 Type: ResponseTypeSync,
2354@@ -640,6 +716,147 @@
2355 })
2356 }
2357
2358+func (s *apiSuite) TestPackagePutConfigMissing(c *check.C) {
2359+ s.vars = map[string]string{"name": "foo", "origin": "bar"}
2360+
2361+ req, err := http.NewRequest("PUT", "/1.0/packages/foo.bar/config", bytes.NewBuffer(nil))
2362+ c.Assert(err, check.IsNil)
2363+
2364+ rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2365+
2366+ c.Check(rsp.Status, check.Equals, http.StatusNotFound)
2367+}
2368+
2369+func (s *apiSuite) TestPackagePutConfigInactive(c *check.C) {
2370+ s.vars = map[string]string{"name": "foo", "origin": "bar"}
2371+
2372+ s.mkInstalled(c, "foo", "bar", "v1", false, "")
2373+
2374+ req, err := http.NewRequest("PUT", "/1.0/packages/foo.bar/config", bytes.NewBuffer(nil))
2375+ c.Assert(err, check.IsNil)
2376+
2377+ rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2378+
2379+ c.Check(rsp.Status, check.Equals, http.StatusBadRequest)
2380+}
2381+
2382+func (s *apiSuite) TestPackagePutConfigNoConfig(c *check.C) {
2383+ s.vars = map[string]string{"name": "foo", "origin": "bar"}
2384+
2385+ s.mkInstalled(c, "foo", "bar", "v1", true, "")
2386+
2387+ req, err := http.NewRequest("PUT", "/1.0/packages/foo.bar/config", bytes.NewBuffer(nil))
2388+ c.Assert(err, check.IsNil)
2389+
2390+ rsp := packageConfig(packagesCmd, req).Self(nil, nil).(*resp)
2391+
2392+ c.Check(rsp.Status, check.Equals, http.StatusInternalServerError)
2393+}
2394+
2395+func (s *apiSuite) TestConfigMultiBadBody(c *check.C) {
2396+ d := New()
2397+ d.addRoutes()
2398+
2399+ req, err := http.NewRequest("PUT", "/1.0/packages", bytes.NewBuffer(nil))
2400+ c.Assert(err, check.IsNil)
2401+ rsp := configMulti(packagesCmd, req).Self(nil, nil).(*resp)
2402+ c.Check(rsp.Status, check.Equals, http.StatusBadRequest)
2403+}
2404+
2405+func (s *apiSuite) TestPackagesPutStr(c *check.C) {
2406+ newConfigs := map[string]string{"foo.bar": "some other config", "baz.qux": "stuff", "missing.pkg": "blah blah"}
2407+ bs, err := json.Marshal(newConfigs)
2408+ c.Assert(err, check.IsNil)
2409+ s.genericTestPackagePut(c, bytes.NewBuffer(bs), 2, map[string]*configSubtask{
2410+ "foo.bar": &configSubtask{Status: TaskSucceeded, Output: "some other config"},
2411+ "baz.qux": &configSubtask{Status: TaskFailed, Output: &errorResult{Str: snappy.ErrConfigNotFound.Error(), Obj: snappy.ErrConfigNotFound, Msg: "Config failed"}},
2412+ "missing.pkg": &configSubtask{Status: TaskFailed, Output: &errorResult{Str: snappy.ErrPackageNotFound.Error(), Obj: snappy.ErrPackageNotFound}},
2413+ })
2414+}
2415+
2416+func (s *apiSuite) TestPackagesPutNil(c *check.C) {
2417+ newConfigs := map[string][]byte{"foo.bar": nil, "mip.brp": nil}
2418+ bs, err := json.Marshal(newConfigs)
2419+ c.Assert(err, check.IsNil)
2420+ s.genericTestPackagePut(c, bytes.NewBuffer(bs), 2, map[string]*configSubtask{
2421+ "foo.bar": &configSubtask{Status: TaskSucceeded, Output: "some: config"},
2422+ "mip.brp": &configSubtask{Status: TaskFailed, Output: &errorResult{Str: snappy.ErrSnapNotActive.Error(), Obj: snappy.ErrSnapNotActive}},
2423+ })
2424+}
2425+
2426+func (s *apiSuite) genericTestPackagePut(c *check.C, body io.Reader, concreteNo int, expected map[string]*configSubtask) {
2427+ d := New()
2428+ d.addRoutes()
2429+
2430+ req, err := http.NewRequest("PUT", "/1.0/packages", body)
2431+ c.Assert(err, check.IsNil)
2432+
2433+ configStr := "some: config"
2434+ oldConcrete := lightweight.NewConcrete
2435+ defer func() {
2436+ lightweight.NewConcrete = oldConcrete
2437+ }()
2438+ lightweight.NewConcrete = func(bag *lightweight.PartBag, _ string) lightweight.Concreter {
2439+ switch bag.Name {
2440+ case "foo":
2441+ return &cfgc{cfg: configStr}
2442+ case "mip":
2443+ return &cfgc{idx: -1}
2444+ default:
2445+ return &cfgc{err: snappy.ErrConfigNotFound}
2446+ }
2447+ }
2448+
2449+ s.mkInstalled(c, "foo", "bar", "v1", true, "")
2450+ s.mkInstalled(c, "baz", "qux", "v1", true, "")
2451+ s.mkInstalled(c, "mip", "brp", "v1", false, "")
2452+
2453+ rsp := configMulti(packagesCmd, req).Self(nil, nil).(*resp)
2454+
2455+ c.Check(rsp.Type, check.Equals, ResponseTypeAsync)
2456+ c.Check(rsp.Status, check.Equals, http.StatusAccepted)
2457+ m := rsp.Result.(map[string]interface{})
2458+ c.Check(m["resource"], check.Matches, "/1.0/operations/.*")
2459+
2460+ uuid := m["resource"].(string)[16:]
2461+
2462+ task := d.GetTask(uuid)
2463+ c.Assert(task, check.NotNil)
2464+ c.Check(task.State(), check.Equals, TaskRunning)
2465+
2466+ // wait up to another ten seconds (!) for the task to finish properly
2467+ for i := 0; i < 1000; i++ {
2468+ if d.GetTask(uuid).State() != TaskRunning {
2469+ break
2470+ }
2471+ time.Sleep(10 * time.Millisecond)
2472+ }
2473+
2474+ c.Assert(task.State(), check.Equals, TaskSucceeded)
2475+ out := task.Output().(map[string]*configSubtask)
2476+ c.Check(out, check.HasLen, len(expected))
2477+
2478+ var missing []string
2479+ for k, v := range out {
2480+ exp, ok := expected[k]
2481+ if !ok {
2482+ missing = append(missing, k)
2483+ continue
2484+ }
2485+
2486+ c.Check(v.Status, check.Equals, exp.Status, check.Commentf(k))
2487+ c.Check(v.Output, check.DeepEquals, exp.Output, check.Commentf(k))
2488+ }
2489+ c.Check(missing, check.HasLen, 0, check.Commentf("missing from expected"))
2490+ missing = nil
2491+ for k := range expected {
2492+ if _, ok := out[k]; !ok {
2493+ missing = append(missing, k)
2494+ }
2495+ }
2496+ c.Check(missing, check.HasLen, 0, check.Commentf("missing from obtained"))
2497+}
2498+
2499 func (s *apiSuite) TestPackageServiceGet(c *check.C) {
2500 d := New()
2501 d.addRoutes()
2502
2503=== modified file 'daemon/daemon.go'
2504--- daemon/daemon.go 2015-10-05 23:10:59 +0000
2505+++ daemon/daemon.go 2015-10-22 07:06:04 +0000
2506@@ -20,6 +20,7 @@
2507 package daemon
2508
2509 import (
2510+ "errors"
2511 "fmt"
2512 "net"
2513 "net/http"
2514@@ -177,6 +178,27 @@
2515 return d.tasks[uuid]
2516 }
2517
2518+var (
2519+ errTaskNotFound = errors.New("task not found")
2520+ errTaskStillRunning = errors.New("task still running")
2521+)
2522+
2523+// DeleteTask removes a task from the tasks map, by uuid.
2524+func (d *Daemon) DeleteTask(uuid string) error {
2525+ d.Lock()
2526+ defer d.Unlock()
2527+ task, ok := d.tasks[uuid]
2528+ if !ok || task == nil {
2529+ return errTaskNotFound
2530+ }
2531+ if task.State() != TaskRunning {
2532+ delete(d.tasks, uuid)
2533+ return nil
2534+ }
2535+
2536+ return errTaskStillRunning
2537+}
2538+
2539 // New Daemon
2540 func New() *Daemon {
2541 return &Daemon{
2542
2543=== modified file 'daemon/response.go'
2544--- daemon/response.go 2015-10-08 12:52:40 +0000
2545+++ daemon/response.go 2015-10-22 07:06:04 +0000
2546@@ -89,22 +89,28 @@
2547 return r
2548 }
2549
2550+type errorResult struct {
2551+ Str string `json:"str,omitempty"`
2552+ Msg string `json:"msg,omitempty"`
2553+ Obj error `json:"obj,omitempty"`
2554+}
2555+
2556 func (r *resp) SetError(err error, format string, v ...interface{}) Response {
2557- m := make(map[string]interface{})
2558+ m := errorResult{}
2559 newr := &resp{
2560 Type: ResponseTypeError,
2561- Result: m,
2562+ Result: &m,
2563 Status: r.Status,
2564 }
2565
2566 if format != "" {
2567 logger.Noticef(format, v...)
2568- m["msg"] = fmt.Sprintf(format, v...)
2569+ m.Msg = fmt.Sprintf(format, v...)
2570 }
2571
2572 if err != nil {
2573- m["obj"] = err
2574- m["str"] = err.Error()
2575+ m.Obj = err
2576+ m.Str = err.Error()
2577 }
2578
2579 return newr
2580
2581=== modified file 'daemon/task.go'
2582--- daemon/task.go 2015-09-15 12:55:09 +0000
2583+++ daemon/task.go 2015-10-22 07:06:04 +0000
2584@@ -132,9 +132,9 @@
2585
2586 if err, ok := out.(error); ok {
2587 // // TODO: make errors properly json-serializable, and avoid this hack (loses info!)
2588- t.output = map[string]interface{}{
2589- "obj": err,
2590- "str": err.Error(),
2591+ t.output = errorResult{
2592+ Obj: err,
2593+ Str: err.Error(),
2594 }
2595 return err
2596 }
2597
2598=== modified file 'daemon/task_test.go'
2599--- daemon/task_test.go 2015-09-15 12:55:09 +0000
2600+++ daemon/task_test.go 2015-10-22 07:06:04 +0000
2601@@ -79,8 +79,8 @@
2602 time.Sleep(time.Millisecond)
2603
2604 c.Check(t.State(), check.Equals, TaskFailed)
2605- c.Check(t.Output(), check.DeepEquals, map[string]interface{}{
2606- "obj": err,
2607- "str": err.Error(),
2608+ c.Check(t.Output(), check.DeepEquals, errorResult{
2609+ Obj: err,
2610+ Str: err.Error(),
2611 })
2612 }
2613
2614=== modified file 'docs/meta.md'
2615--- docs/meta.md 2015-09-15 14:53:38 +0000
2616+++ docs/meta.md 2015-10-22 07:06:04 +0000
2617@@ -72,10 +72,23 @@
2618 * `bus-name`: (optional) message bus connection name for the service.
2619 May only be specified for snaps of 'type: framework' (see above). See
2620 frameworks.md for details.
2621- * `socket`: (optional) Set to "true" is the service is socket activated
2622- * `listen-stream`: (optional) The full path of the stream socket
2623- * `socket-user`: (optional) The user that owns the stream socket
2624- * `socket-group`: (optional) The group that own the stream socket
2625+ * `socket`: (optional) Set to "true" if the service is socket activated.
2626+ Must be specified with `listen-stream`.
2627+ * `listen-stream`: (optional) The full path of the stream socket or an
2628+ abstract socket. When specifying an absolute path, it should
2629+ normally be in one of the app-specific writable directories.
2630+ When specifying an abstract socket, it must start with '@' and
2631+ typically be followed by either the snap package name or the
2632+ snap package name followed by '\_' and any other characters
2633+ (eg, '@name' or '@name\_something').
2634+ * `socket-user`: (optional) The user that owns the stream socket. The user
2635+ should normally match the snap package name. Must be
2636+ specified with `listen-stream`. This option is reserved
2637+ for future use.
2638+ * `socket-group`: (optional) The group that own the stream socket. The
2639+ group should normally match the snap package name. Must
2640+ be specified with `listen-stream`. This option is
2641+ reserved for future use.
2642
2643 * `binaries`: the binaries (executables) that the snap provides
2644 * `name`: (required) the name of the binary, the user will be able to
2645
2646=== modified file 'helpers/helpers.go'
2647--- helpers/helpers.go 2015-10-08 06:25:35 +0000
2648+++ helpers/helpers.go 2015-10-22 07:06:04 +0000
2649@@ -269,7 +269,7 @@
2650 const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy"
2651
2652 // MakeRandomString returns a random string of length length
2653-func MakeRandomString(length int) string {
2654+var MakeRandomString = func(length int) string {
2655
2656 out := ""
2657 for i := 0; i < length; i++ {
2658@@ -293,9 +293,12 @@
2659 }
2660
2661 // AtomicWriteFile updates the filename atomically and works otherwise
2662-// exactly like io/ioutil.WriteFile()
2663+// like io/ioutil.WriteFile()
2664+//
2665+// Note that it won't follow symlinks and will replace existing symlinks
2666+// with the real file
2667 func AtomicWriteFile(filename string, data []byte, perm os.FileMode) (err error) {
2668- tmp := filename + ".new"
2669+ tmp := filename + "." + MakeRandomString(12)
2670
2671 // XXX: if go switches to use aio_fsync, we need to open the dir for writing
2672 dir, err := os.Open(filepath.Dir(filename))
2673@@ -304,7 +307,7 @@
2674 }
2675 defer dir.Close()
2676
2677- fd, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
2678+ fd, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, perm)
2679 if err != nil {
2680 return err
2681 }
2682
2683=== modified file 'helpers/helpers_test.go'
2684--- helpers/helpers_test.go 2015-10-08 06:33:39 +0000
2685+++ helpers/helpers_test.go 2015-10-22 07:06:04 +0000
2686@@ -266,6 +266,24 @@
2687 c.Assert(st.Mode()&os.ModePerm, Equals, os.FileMode(0600))
2688 }
2689
2690+func (ts *HTestSuite) TestAtomicWriteFileNoOverwriteTmpExisting(c *C) {
2691+ tmpdir := c.MkDir()
2692+ realMakeRandomString := MakeRandomString
2693+ defer func() { MakeRandomString = realMakeRandomString }()
2694+ MakeRandomString = func(n int) string {
2695+ // chosen by fair dice roll.
2696+ // guranteed to be random.
2697+ return "4"
2698+ }
2699+
2700+ p := filepath.Join(tmpdir, "foo")
2701+ err := ioutil.WriteFile(p+".4", []byte(""), 0644)
2702+ c.Assert(err, IsNil)
2703+
2704+ err = AtomicWriteFile(p, []byte(""), 0600)
2705+ c.Assert(err, ErrorMatches, "open .*: file exists")
2706+}
2707+
2708 func (ts *HTestSuite) TestCurrentHomeDirHOMEenv(c *C) {
2709 tmpdir := c.MkDir()
2710
2711@@ -280,6 +298,9 @@
2712
2713 func (ts *HTestSuite) TestCurrentHomeDirNoHomeEnv(c *C) {
2714 oldHome := os.Getenv("HOME")
2715+ if oldHome == "/sbuild-nonexistent" {
2716+ c.Skip("running in schroot this test won't work")
2717+ }
2718 defer os.Setenv("HOME", oldHome)
2719
2720 os.Setenv("HOME", "")
2721
2722=== modified file 'i18n/i18n.go'
2723--- i18n/i18n.go 2015-06-30 10:38:55 +0000
2724+++ i18n/i18n.go 2015-10-22 07:06:04 +0000
2725@@ -25,6 +25,9 @@
2726 "github.com/gosexy/gettext"
2727 )
2728
2729+// TEXTDOMAIN is the message domain used by snappy; see dgettext(3)
2730+// for more information.
2731+//
2732 // Note that we have to use dgettext() here because we are a library
2733 // and we can not use getext.Textdomain() as this would override the
2734 // applications default
2735
2736=== modified file 'pkg/remote/remote.go'
2737--- pkg/remote/remote.go 2015-10-05 22:15:59 +0000
2738+++ pkg/remote/remote.go 2015-10-22 07:06:04 +0000
2739@@ -27,6 +27,7 @@
2740 type Snap struct {
2741 Alias string `json:"alias,omitempty"`
2742 AnonDownloadURL string `json:"anon_download_url,omitempty"`
2743+ Channel string `json:"channel,omitempty"`
2744 DownloadSha512 string `json:"download_sha512,omitempty"`
2745 Description string `json:"description,omitempty"`
2746 DownloadSize int64 `json:"binary_filesize,omitempty"`
2747
2748=== modified file 'po/de.po'
2749--- po/de.po 2015-10-06 06:22:45 +0000
2750+++ po/de.po 2015-10-22 07:06:04 +0000
2751@@ -7,15 +7,15 @@
2752 msgstr ""
2753 "Project-Id-Version: snappy\n"
2754 "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
2755-"POT-Creation-Date: 2015-09-29 10:18+0100\n"
2756+"POT-Creation-Date: 2015-10-15 15:53+0200\n"
2757 "PO-Revision-Date: 2015-09-02 22:57+0000\n"
2758 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
2759 "Language-Team: German <de@li.org>\n"
2760 "MIME-Version: 1.0\n"
2761 "Content-Type: text/plain; charset=UTF-8\n"
2762 "Content-Transfer-Encoding: 8bit\n"
2763-"X-Launchpad-Export-Date: 2015-10-06 06:22+0000\n"
2764-"X-Generator: Launchpad (build 17796)\n"
2765+"X-Launchpad-Export-Date: 2015-10-21 06:21+0000\n"
2766+"X-Generator: Launchpad (build 17812)\n"
2767
2768 #. TRANSLATORS: the %s is a pkgname, the second a comma separated list of paths
2769 #, c-format
2770@@ -132,6 +132,9 @@
2771 msgid "Generated '%s' snap\n"
2772 msgstr ""
2773
2774+msgid "Include information about packages from the snappy store"
2775+msgstr ""
2776+
2777 msgid "Install a snap package"
2778 msgstr ""
2779
2780
2781=== modified file 'po/es.po'
2782--- po/es.po 2015-10-06 06:22:45 +0000
2783+++ po/es.po 2015-10-22 07:06:04 +0000
2784@@ -7,15 +7,15 @@
2785 msgstr ""
2786 "Project-Id-Version: snappy\n"
2787 "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
2788-"POT-Creation-Date: 2015-09-29 10:18+0100\n"
2789+"POT-Creation-Date: 2015-10-15 15:53+0200\n"
2790 "PO-Revision-Date: 2015-09-13 12:42+0000\n"
2791 "Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n"
2792 "Language-Team: Spanish <es@li.org>\n"
2793 "MIME-Version: 1.0\n"
2794 "Content-Type: text/plain; charset=UTF-8\n"
2795 "Content-Transfer-Encoding: 8bit\n"
2796-"X-Launchpad-Export-Date: 2015-10-06 06:22+0000\n"
2797-"X-Generator: Launchpad (build 17796)\n"
2798+"X-Launchpad-Export-Date: 2015-10-21 06:21+0000\n"
2799+"X-Generator: Launchpad (build 17812)\n"
2800
2801 #. TRANSLATORS: the %s is a pkgname, the second a comma separated list of paths
2802 #, c-format
2803@@ -142,6 +142,9 @@
2804 msgid "Generated '%s' snap\n"
2805 msgstr "Snap «%s» generado\n"
2806
2807+msgid "Include information about packages from the snappy store"
2808+msgstr ""
2809+
2810 msgid "Install a snap package"
2811 msgstr "Instalar un paquete snap"
2812
2813
2814=== modified file 'po/gl.po'
2815--- po/gl.po 2015-10-11 05:37:57 +0000
2816+++ po/gl.po 2015-10-22 07:06:04 +0000
2817@@ -7,15 +7,15 @@
2818 msgstr ""
2819 "Project-Id-Version: snappy\n"
2820 "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
2821-"POT-Creation-Date: 2015-09-29 10:18+0100\n"
2822-"PO-Revision-Date: 2015-10-10 05:33+0000\n"
2823+"POT-Creation-Date: 2015-10-15 15:53+0200\n"
2824+"PO-Revision-Date: 2015-10-21 16:12+0000\n"
2825 "Last-Translator: Marcos Lans <Unknown>\n"
2826 "Language-Team: Galician <gl@li.org>\n"
2827 "MIME-Version: 1.0\n"
2828 "Content-Type: text/plain; charset=UTF-8\n"
2829 "Content-Transfer-Encoding: 8bit\n"
2830-"X-Launchpad-Export-Date: 2015-10-11 05:37+0000\n"
2831-"X-Generator: Launchpad (build 17802)\n"
2832+"X-Launchpad-Export-Date: 2015-10-22 05:57+0000\n"
2833+"X-Generator: Launchpad (build 17812)\n"
2834
2835 #. TRANSLATORS: the %s is a pkgname, the second a comma separated list of paths
2836 #, c-format
2837@@ -159,6 +159,9 @@
2838 msgid "Generated '%s' snap\n"
2839 msgstr "Xerado o paquete snap de «%s»\n"
2840
2841+msgid "Include information about packages from the snappy store"
2842+msgstr "Incluír información sobre paquetes da tenda de snappy"
2843+
2844 msgid "Install a snap package"
2845 msgstr "Instalar un paquete snap"
2846
2847
2848=== modified file 'po/snappy.pot'
2849--- po/snappy.pot 2015-09-29 09:45:15 +0000
2850+++ po/snappy.pot 2015-10-22 07:06:04 +0000
2851@@ -7,7 +7,7 @@
2852 msgid ""
2853 msgstr "Project-Id-Version: snappy\n"
2854 "Report-Msgid-Bugs-To: snappy-devel@lists.ubuntu.com\n"
2855- "POT-Creation-Date: 2015-09-29 10:18+0100\n"
2856+ "POT-Creation-Date: 2015-10-15 15:53+0200\n"
2857 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
2858 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
2859 "Language-Team: LANGUAGE <LL@li.org>\n"
2860@@ -113,6 +113,9 @@
2861 msgid "Generated '%s' snap\n"
2862 msgstr ""
2863
2864+msgid "Include information about packages from the snappy store"
2865+msgstr ""
2866+
2867 msgid "Install a snap package"
2868 msgstr ""
2869
2870
2871=== modified file 'snappy/click.go'
2872--- snappy/click.go 2015-10-07 15:47:01 +0000
2873+++ snappy/click.go 2015-10-22 07:06:04 +0000
2874@@ -758,7 +758,7 @@
2875 if err != nil {
2876 return err
2877 }
2878- if err := ioutil.WriteFile(filepath.Join(clickMetaDir, cm.Name+".manifest"), []byte(outStr), 0644); err != nil {
2879+ if err := helpers.AtomicWriteFile(filepath.Join(clickMetaDir, cm.Name+".manifest"), []byte(outStr), 0644); err != nil {
2880 return err
2881 }
2882
2883
2884=== modified file 'snappy/click_test.go'
2885--- snappy/click_test.go 2015-10-10 13:27:50 +0000
2886+++ snappy/click_test.go 2015-10-22 07:06:04 +0000
2887@@ -1645,3 +1645,31 @@
2888 c.Assert(err, IsNil)
2889 c.Assert(generatedWrapper, Equals, expectedSocketUsingWrapper)
2890 }
2891+
2892+func (s *SnapTestSuite) TestWriteCompatManifestJSON(c *C) {
2893+ manifest := []byte(`{
2894+ "name": "hello-world"
2895+}
2896+`)
2897+ manifestJSON := filepath.Join(s.tempdir, "hello-world.some-origin.manifest")
2898+
2899+ err := writeCompatManifestJSON(s.tempdir, manifest, "some-origin")
2900+ c.Assert(err, IsNil)
2901+ c.Assert(helpers.FileExists(manifestJSON), Equals, true)
2902+}
2903+
2904+func (s *SnapTestSuite) TestWriteCompatManifestJSONNoFollow(c *C) {
2905+ manifest := []byte(`{
2906+ "name": "hello-world"
2907+}
2908+`)
2909+ manifestJSON := filepath.Join(s.tempdir, "hello-world.some-origin.manifest")
2910+ symlinkTarget := filepath.Join(s.tempdir, "symlink-target")
2911+ os.Symlink(symlinkTarget, manifestJSON)
2912+ c.Assert(helpers.FileExists(symlinkTarget), Equals, false)
2913+
2914+ err := writeCompatManifestJSON(s.tempdir, manifest, "some-origin")
2915+ c.Assert(err, IsNil)
2916+ c.Check(helpers.FileExists(manifestJSON), Equals, true)
2917+ c.Check(helpers.FileExists(symlinkTarget), Equals, false)
2918+}
2919
2920=== modified file 'snappy/common_test.go'
2921--- snappy/common_test.go 2015-10-10 13:27:50 +0000
2922+++ snappy/common_test.go 2015-10-22 07:06:04 +0000
2923@@ -108,6 +108,7 @@
2924 Origin: origin,
2925 Version: version,
2926 Description: desc,
2927+ Channel: "remote-channel",
2928 })
2929 if err != nil {
2930 return err
2931
2932=== modified file 'snappy/install_test.go'
2933--- snappy/install_test.go 2015-09-29 07:07:13 +0000
2934+++ snappy/install_test.go 2015-10-22 07:06:04 +0000
2935@@ -249,12 +249,9 @@
2936 }
2937 defer func() { newPartition = newPartitionImpl }()
2938
2939- tempdir := c.MkDir()
2940- systemImageRoot = tempdir
2941-
2942- makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, systemImageChannelConfig), "1")
2943+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, systemImageChannelConfig), "1")
2944 // setup fake /other partition
2945- makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, "other", systemImageChannelConfig), "2")
2946+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "2")
2947
2948 siServer := runMockSystemImageWebServer()
2949 defer siServer.Close()
2950
2951=== modified file 'snappy/parts.go'
2952--- snappy/parts.go 2015-10-07 16:07:35 +0000
2953+++ snappy/parts.go 2015-10-22 07:06:04 +0000
2954@@ -257,7 +257,8 @@
2955 return res, nil
2956 }
2957
2958-// ActiveSnapNamesByType returns all installed snap names with the given type
2959+// ActiveSnapIterByType returns the result of applying the given
2960+// function to all active snaps with the given type.
2961 var ActiveSnapIterByType = activeSnapIterByTypeImpl
2962
2963 func activeSnapIterByTypeImpl(f func(Part) string, snapTs ...pkg.Type) ([]string, error) {
2964@@ -293,7 +294,7 @@
2965 // FindSnapsByName returns all snaps with the given name in the "haystack"
2966 // slice of parts (useful for filtering)
2967 func FindSnapsByName(needle string, haystack []Part) (res []Part) {
2968- name, origin := splitOrigin(needle)
2969+ name, origin := SplitOrigin(needle)
2970 ignorens := origin == ""
2971
2972 for _, part := range haystack {
2973@@ -305,7 +306,8 @@
2974 return res
2975 }
2976
2977-func splitOrigin(name string) (string, string) {
2978+// SplitOrigin splits a snappy name name into a (name, origin) pair
2979+func SplitOrigin(name string) (string, string) {
2980 idx := strings.LastIndexAny(name, ".")
2981 if idx > -1 {
2982 return name[:idx], name[idx+1:]
2983@@ -317,7 +319,7 @@
2984 // FindSnapsByNameAndVersion returns the parts with the name/version in the
2985 // given slice of parts
2986 func FindSnapsByNameAndVersion(needle, version string, haystack []Part) []Part {
2987- name, origin := splitOrigin(needle)
2988+ name, origin := SplitOrigin(needle)
2989 ignorens := origin == ""
2990 var found []Part
2991
2992
2993=== modified file 'snappy/snapp.go'
2994--- snappy/snapp.go 2015-10-10 13:35:00 +0000
2995+++ snappy/snapp.go 2015-10-22 07:06:04 +0000
2996@@ -706,8 +706,12 @@
2997
2998 // Channel returns the channel used
2999 func (s *SnapPart) Channel() string {
3000- // FIXME: real channel support
3001- return "edge"
3002+ if r := s.remoteM; r != nil {
3003+ return r.Channel
3004+ }
3005+
3006+ // default for compat with older installs
3007+ return "stable"
3008 }
3009
3010 // Icon returns the path to the icon
3011@@ -1468,8 +1472,7 @@
3012
3013 // Channel returns the channel used
3014 func (s *RemoteSnapPart) Channel() string {
3015- // FIXME: real channel support, this requires server work
3016- return "edge"
3017+ return s.pkg.Channel
3018 }
3019
3020 // Icon returns the icon
3021@@ -1754,6 +1757,7 @@
3022 req.Header.Set("X-Ubuntu-Frameworks", strings.Join(addCoreFmk(frameworks), ","))
3023 req.Header.Set("X-Ubuntu-Architecture", string(Architecture()))
3024 req.Header.Set("X-Ubuntu-Release", release.String())
3025+ req.Header.Set("X-Ubuntu-Device-Channel", release.Get().Channel)
3026
3027 if storeID := os.Getenv("UBUNTU_STORE_ID"); storeID != "" {
3028 req.Header.Set("X-Ubuntu-Store", storeID)
3029@@ -1904,7 +1908,10 @@
3030 // sense in sending it our ubuntu-core snap
3031 //
3032 // NOTE this *will* send .sideload apps to the store.
3033- installed, err := ActiveSnapIterByType(FullName, pkg.TypeApp, pkg.TypeFramework, pkg.TypeOem)
3034+ fullNameWithChannel := func(p Part) string {
3035+ return fmt.Sprintf("%s/%s", FullName(p), p.Channel())
3036+ }
3037+ installed, err := ActiveSnapIterByType(fullNameWithChannel, pkg.TypeApp, pkg.TypeFramework, pkg.TypeOem)
3038 if err != nil || len(installed) == 0 {
3039 return nil, err
3040 }
3041
3042=== modified file 'snappy/snapp_test.go'
3043--- snappy/snapp_test.go 2015-10-10 13:27:50 +0000
3044+++ snappy/snapp_test.go 2015-10-22 07:06:04 +0000
3045@@ -98,9 +98,6 @@
3046 c.Assert(err, IsNil)
3047
3048 runScFilterGen = mockRunScFilterGen
3049-
3050- // ensure we do not look at the system
3051- systemImageRoot = s.tempdir
3052 }
3053
3054 func (s *SnapTestSuite) TearDownTest(c *C) {
3055@@ -276,7 +273,7 @@
3056 `
3057
3058 /* acquired via:
3059-curl -s --data-binary '{"name":["8nzc1x4iim2xj1g2ul64.chipaca"]}' -H 'content-type: application/json' https://search.apps.ubuntu.com/api/v1/click-metadata/
3060+curl -s --data-binary '{"name":["8nzc1x4iim2xj1g2ul64.chipaca"]}' -H 'content-type: application/json' https://search.apps.ubuntu.com/api/v1/click-metadata
3061 */
3062 const MockUpdatesJSON = `[
3063 {
3064@@ -322,6 +319,7 @@
3065 "blacklist_country_codes": [
3066 "AX"
3067 ],
3068+ "channel": "edge",
3069 "changelog": "",
3070 "click_framework": [],
3071 "click_version": "0.1",
3072@@ -476,8 +474,6 @@
3073 c.Check(parts[0].Vendor(), Equals, funkyAppVendor)
3074 c.Check(parts[0].Version(), Equals, "42")
3075 c.Check(parts[0].Description(), Equals, "Returns for store credit only.")
3076-
3077- c.Check(parts[0].Channel(), Equals, "edge")
3078 }
3079
3080 func (s *SnapTestSuite) TestUbuntuStoreRepositoryAliasSearch(c *C) {
3081@@ -513,8 +509,6 @@
3082
3083 alias := results["hello-world"].Alias
3084 c.Assert(alias, DeepEquals, parts[0])
3085-
3086- c.Check(parts[0].Channel(), Equals, "edge")
3087 }
3088 func mockActiveSnapIterByType(mockSnaps []string) {
3089 ActiveSnapIterByType = func(f func(Part) string, snapTs ...pkg.Type) (res []string, err error) {
3090@@ -609,6 +603,7 @@
3091 c.Check(results[0].Hash(), Equals, "5364253e4a988f4f5c04380086d542f410455b97d48cc6c69ca2a5877d8aef2a6b2b2f83ec4f688cae61ebc8a6bf2cdbd4dbd8f743f0522fc76540429b79df42")
3092 c.Check(results[0].Date().String(), Equals, "2015-04-15 18:30:16 +0000 UTC")
3093 c.Check(results[0].DownloadSize(), Equals, int64(65375))
3094+ c.Check(results[0].Channel(), Equals, "edge")
3095 }
3096
3097 func (s *SnapTestSuite) TestUbuntuStoreRepositoryNoDetails(c *C) {
3098@@ -1655,3 +1650,11 @@
3099
3100 c.Check(before, Not(Equals), after)
3101 }
3102+
3103+func (s *SnapTestSuite) TestChannelFromLocalManifest(c *C) {
3104+ snapYaml, err := s.makeInstalledMockSnap()
3105+ c.Assert(err, IsNil)
3106+
3107+ snap, err := NewInstalledSnapPart(snapYaml, testOrigin)
3108+ c.Assert(snap.Channel(), Equals, "remote-channel")
3109+}
3110
3111=== modified file 'snappy/systemimage.go'
3112--- snappy/systemimage.go 2015-10-07 15:54:33 +0000
3113+++ snappy/systemimage.go 2015-10-22 07:06:04 +0000
3114@@ -31,6 +31,7 @@
3115 "github.com/mvo5/goconfigparser"
3116
3117 "launchpad.net/snappy/coreconfig"
3118+ "launchpad.net/snappy/dirs"
3119 "launchpad.net/snappy/helpers"
3120 "launchpad.net/snappy/logger"
3121 "launchpad.net/snappy/partition"
3122@@ -68,10 +69,6 @@
3123 systemImageCli = "system-image-cli"
3124 )
3125
3126-// This is the root directory of the filesystem. Its only useful to
3127-// change when writing tests
3128-var systemImageRoot = "/"
3129-
3130 // will replace newPartition() to return a mockPartition
3131 var newPartition = newPartitionImpl
3132
3133@@ -225,7 +222,7 @@
3134 // XXX: Note that systemImageDownloadUpdate() requires
3135 // the s-i _client_ config file whereas otherIsEmpty()
3136 // checks the s-i _channel_ config file.
3137- otherConfigFile := filepath.Join(systemImageRoot, otherRoot, systemImageClientConfig)
3138+ otherConfigFile := filepath.Join(dirs.GlobalRootDir, otherRoot, systemImageClientConfig)
3139 if !otherIsEmpty(otherRoot) && helpers.FileExists(otherConfigFile) {
3140 configFile = otherConfigFile
3141 }
3142@@ -378,7 +375,7 @@
3143
3144 // Returns the part associated with the current rootfs
3145 func makeCurrentPart(p partition.Interface) Part {
3146- configFile := filepath.Join(systemImageRoot, systemImageChannelConfig)
3147+ configFile := filepath.Join(dirs.GlobalRootDir, systemImageChannelConfig)
3148 part, err := makePartFromSystemImageConfigFile(p, configFile, true)
3149 if err != nil {
3150 return nil
3151@@ -395,7 +392,7 @@
3152 // This function encapsulates the heuristics to determine if the rootfs
3153 // is complete.
3154 func otherIsEmpty(root string) bool {
3155- configFile := filepath.Join(systemImageRoot, root, systemImageChannelConfig)
3156+ configFile := filepath.Join(dirs.GlobalRootDir, root, systemImageChannelConfig)
3157
3158 st, err := os.Stat(configFile)
3159
3160@@ -425,7 +422,7 @@
3161 return nil
3162 }
3163
3164- configFile := filepath.Join(systemImageRoot, otherRoot, systemImageChannelConfig)
3165+ configFile := filepath.Join(dirs.GlobalRootDir, otherRoot, systemImageChannelConfig)
3166 part, err = makePartFromSystemImageConfigFile(p, configFile, false)
3167 if err != nil {
3168 logger.Noticef("Can not make system-image part for %q: %v", configFile, err)
3169@@ -463,7 +460,7 @@
3170
3171 // Updates returns the available updates
3172 func (s *SystemImageRepository) Updates() ([]Part, error) {
3173- configFile := filepath.Join(systemImageRoot, systemImageChannelConfig)
3174+ configFile := filepath.Join(dirs.GlobalRootDir, systemImageChannelConfig)
3175 updateStatus, err := systemImageClientCheckForUpdates(configFile)
3176 if err != nil {
3177 return nil, err
3178
3179=== modified file 'snappy/systemimage_test.go'
3180--- snappy/systemimage_test.go 2015-10-05 22:01:44 +0000
3181+++ snappy/systemimage_test.go 2015-10-22 07:06:04 +0000
3182@@ -28,6 +28,7 @@
3183 "strings"
3184 "testing"
3185
3186+ "launchpad.net/snappy/dirs"
3187 "launchpad.net/snappy/partition"
3188 "launchpad.net/snappy/provisioning"
3189
3190@@ -51,13 +52,10 @@
3191
3192 s.systemImage = NewSystemImageRepository()
3193 c.Assert(s, NotNil)
3194- // setup alternative root for system image
3195- tempdir := c.MkDir()
3196- systemImageRoot = tempdir
3197
3198- makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, systemImageChannelConfig), "1")
3199+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, systemImageChannelConfig), "1")
3200 // setup fake /other partition
3201- makeFakeSystemImageChannelConfig(c, filepath.Join(tempdir, "other", systemImageChannelConfig), "0")
3202+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "0")
3203
3204 // run test webserver instead of talking to the real one
3205 //
3206@@ -66,12 +64,11 @@
3207 c.Assert(s.mockSystemImageWebServer, NotNil)
3208
3209 // create mock system-image-cli
3210- systemImageCli = makeMockSystemImageCli(c, tempdir)
3211+ systemImageCli = makeMockSystemImageCli(c, dirs.GlobalRootDir)
3212 }
3213
3214 func (s *SITestSuite) TearDownTest(c *C) {
3215 s.mockSystemImageWebServer.Close()
3216- systemImageRoot = "/"
3217 bootloaderDir = bootloaderDirImpl
3218 }
3219
3220@@ -184,7 +181,7 @@
3221 // FIXME: ideally we would change the version to "2" as a side-effect
3222 // of calling sp.Install() we need to update it because the
3223 // sp.Install() will verify that it got applied
3224- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, "other", systemImageChannelConfig), "2")
3225+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "2")
3226
3227 // add a update
3228 mockSystemImageIndexJSON = fmt.Sprintf(mockSystemImageIndexJSONTemplate, "2")
3229@@ -257,7 +254,7 @@
3230 // FIXME: ideally we would change the version to "2" as a side-effect
3231 // of calling sp.Install() we need to update it because the
3232 // sp.Install() will verify that it got applied
3233- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, "other", systemImageChannelConfig), "2")
3234+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "2")
3235
3236 // add a update
3237 mockSystemImageIndexJSON = fmt.Sprintf(mockSystemImageIndexJSONTemplate, "2")
3238@@ -386,7 +383,7 @@
3239 // - "1" on current
3240 // - "2" on other
3241 // the webserver will tell us that "2" is latest
3242- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, "other", systemImageChannelConfig), "2")
3243+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "2")
3244 parts, err := s.systemImage.Updates()
3245
3246 part := parts[0].(*SystemImagePart)
3247@@ -399,7 +396,7 @@
3248 //
3249 // but this time the other part is *not* updated, i.e. we set it to
3250 // something else
3251- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, "other", systemImageChannelConfig), "1")
3252+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "1")
3253
3254 // the update will have "2" and we only installed "1" on other
3255 parts, err := s.systemImage.Updates()
3256@@ -413,7 +410,7 @@
3257
3258 func (s *SITestSuite) TestOtherIsEmpty(c *C) {
3259 otherRoot := "/other"
3260- otherRootFull := filepath.Join(systemImageRoot, otherRoot)
3261+ otherRootFull := filepath.Join(dirs.GlobalRootDir, otherRoot)
3262
3263 siConfig := filepath.Join(otherRootFull, systemImageChannelConfig)
3264
3265@@ -530,8 +527,8 @@
3266
3267 // we are on 1 and "upgrade" to 2 which is already installed
3268 // (e.g. because we rolled back earlier)
3269- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, systemImageChannelConfig), "1")
3270- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, "other", systemImageChannelConfig), "2")
3271+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, systemImageChannelConfig), "1")
3272+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "2")
3273
3274 // now we get the other part (v2)
3275 parts, err := s.systemImage.Installed()
3276@@ -559,7 +556,7 @@
3277 }
3278
3279 func (s *SITestSuite) TestNeedsBootAssetSyncNoNeed(c *C) {
3280- makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, "other", systemImageChannelConfig), "2")
3281+ makeFakeSystemImageChannelConfig(c, filepath.Join(dirs.GlobalRootDir, "other", systemImageChannelConfig), "2")
3282
3283 parts, err := s.systemImage.Installed()
3284 c.Assert(err, IsNil)

Subscribers

People subscribed via source and target branches