Merge lp:~snappy-dev/snappy/snappy-moved-to-github into lp:snappy/15.04
- snappy-moved-to-github
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Vogt (community) | Approve | ||
Review via email: mp+275272@code.launchpad.net |
Commit message
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' |
90 | Binary 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' |
112 | Binary 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' |
146 | Binary 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) |