1#!/usr/bin/env python3

2# Copyright 2015-2020 Canonical Ltd.

3# All rights reserved.

4#

5# Written by:

6# Authors: Jonathan Cave <jonathan.cave@canonical.com>

7

8 import argparse

9 import os

10 import sys

11

12 from checkbox_support.snap_utils.snapd import Snapd

13

14# Requirements for the test snap:

15# - the snap must be strictly confined (no classic or devmode flags)

16# - there must be different revisions on the stable & edge channels

17 try:

18 TEST_SNAP = os.environ["TEST_SNAP"]

19 except KeyError:

20 runtime = os.getenv("CHECKBOX_RUNTIME", "/snap/checkbox/current")

21 if "checkbox18" in runtime:

22 TEST_SNAP = "test-snapd-tools-core18"

23 elif "checkbox20" in runtime:

24 TEST_SNAP = "test-snapd-tools-core20"

25 elif "checkbox22" in runtime:

26 TEST_SNAP = "test-snapd-tools-core22"

27 else:

28 TEST_SNAP = "test-snapd-tools"

29 SNAPD_TASK_TIMEOUT = int(os.getenv("SNAPD_TASK_TIMEOUT", 30))

30 SNAPD_POLL_INTERVAL = int(os.getenv("SNAPD_POLL_INTERVAL", 1))

31

32

33 class SnapList:

34 """snap list sub-command."""

35

36 def invoked(self):

37 """snap list should show the core package is installed."""

38 data = Snapd().list()

39 for snap in data:

40 if snap["name"] in (

41 "core",

42 "core16",

43 "core18",

44 "core20",

45 "core22",

46 "core24",

47 ):

48 print("Found a core snap")

49 print(snap["name"], snap["version"], snap["revision"])

50 return 0

51 return 1

52

53

54 class SnapSearch:

55 """snap search sub-command."""

56

57 def invoked(self):

58 """snap search for TEST_SNAP."""

59 data = Snapd().find(

60 TEST_SNAP,

61 )

62 for snap in data:

63 print("ID:", snap["id"])

64 print("Name:", snap["name"])

65 print("Developer:", snap["developer"])

66 return 0

67 return 1

68

69

70 class SnapInstall:

71 """snap install sub-command."""

72

73 def invoked(self):

74 """Test install of test-snapd-tools snap."""

75 parser = argparse.ArgumentParser()

76 parser.add_argument("channel", help="channel to install from")

77 args = parser.parse_args(sys.argv[2:])

78 print("Install {}...".format(TEST_SNAP))

79 s = Snapd(SNAPD_TASK_TIMEOUT, SNAPD_POLL_INTERVAL, verbose=True)

80 if s.list(TEST_SNAP):

81 print("{} already installed. Removing".format(TEST_SNAP))

82 s.remove(TEST_SNAP)

83 s.install(TEST_SNAP, args.channel)

84 print("Confirm in snap list...")

85 data = s.list()

86 for snap in data:

87 if snap["name"] == TEST_SNAP:

88 return 0

89 print(" not in snap list")

90 return 1

91

92

93 class SnapRefresh:

94 """snap refresh sub-command."""

95

96 def invoked(self):

97 """Test refresh of test-snapd-tools snap."""

98 s = Snapd(SNAPD_TASK_TIMEOUT, SNAPD_POLL_INTERVAL)

99 if s.list(TEST_SNAP):

100 print("Remove previously installed revision")

101 s.remove(TEST_SNAP)

102 print("Install starting revision...")

103 s.install(TEST_SNAP, "stable")

104 start_rev = s.list(TEST_SNAP)["revision"]

105 print(" revision:", start_rev)

106 print("Refresh to edge...")

107 s.refresh(TEST_SNAP, "edge")

108 print("Get new revision...")

109 new_rev = s.list(TEST_SNAP)["revision"]

110 print(" revision:", new_rev)

111 if new_rev == start_rev:

112 return 1

113 return 0

114

115

116 class SnapRevert:

117 """snap revert sub-command."""

118

119 def invoked(self):

120 """Test revert of test-snapd-tools snap."""

121 s = Snapd(SNAPD_TASK_TIMEOUT, SNAPD_POLL_INTERVAL)

122 if s.list(TEST_SNAP):

123 s.remove(TEST_SNAP)

124 print("Install stable revision")

125 s.install(TEST_SNAP)

126 print("Refresh to edge")

127 s.refresh(TEST_SNAP, "edge")

128 print("Get stable channel revision from store...")

129 r = s.info(TEST_SNAP)

130 stable_rev = r["channels"]["latest/stable"]["revision"]

131 r = s.list(TEST_SNAP)

132 installed_rev = r["revision"] # should be edge revision

133 print("Reverting snap {}...".format(TEST_SNAP))

134 s.revert(TEST_SNAP)

135 print("Get new installed revision...")

136 r = s.list(TEST_SNAP)

137 rev = r["revision"]

138 if rev != stable_rev:

139 print("Not stable revision number")

140 return 1

141 if rev == installed_rev:

142 print("Identical revision number")

143 return 1

144 return 0

145

146

147 class SnapReupdate:

148 """snap reupdate sub-command."""

149

150 def invoked(self):

151 """Test re-update of test-snapd-tools snap."""

152 s = Snapd(SNAPD_TASK_TIMEOUT, SNAPD_POLL_INTERVAL)

153 print("Get edge channel revision from store...")

154 if s.list(TEST_SNAP):

155 s.remove(TEST_SNAP)

156 s.install(TEST_SNAP)

157 s.refresh(TEST_SNAP, "edge")

158 s.revert(TEST_SNAP)

159 r = s.info(TEST_SNAP)

160 edge_rev = r["channels"]["latest/edge"]["revision"]

161 print("Remove edge revision...")

162 s.remove(TEST_SNAP, edge_rev)

163 print("Refresh to edge channel...")

164 s.refresh(TEST_SNAP, "edge")

165 print("Get new installed revision...")

166 r = s.list(TEST_SNAP)

167 rev = r["revision"]

168 if rev != edge_rev:

169 print("Not edge revision number")

170 return 1

171

172

173 class SnapRemove:

174 """snap remove sub-command."""

175

176 def invoked(self):

177 """Test remove of test-snapd-tools snap."""

178 print("Remove {}...".format(TEST_SNAP))

179 s = Snapd(SNAPD_TASK_TIMEOUT, SNAPD_POLL_INTERVAL)

180 if not s.list(TEST_SNAP):

181 print("{} not found. Installing".format(TEST_SNAP))

182 s.install(TEST_SNAP)

183 s.remove(TEST_SNAP)

184 print("Check not in snap list")

185 data = s.list()

186 for snap in data:

187 if snap["name"] == TEST_SNAP:

188 print(" found in snap list")

189 return 1

190 return 0

191

192

193 class Snap:

194 """Fake snap like command."""

195

196 def main(self):

197 sub_commands = {

198 "list": SnapList,

199 "search": SnapSearch,

200 "install": SnapInstall,

201 "refresh": SnapRefresh,

202 "revert": SnapRevert,

203 "reupdate": SnapReupdate,

204 "remove": SnapRemove,

205 }

206 parser = argparse.ArgumentParser()

207 parser.add_argument("subcommand", type=str, choices=sub_commands)

208 args = parser.parse_args(sys.argv[1:2])

209 return sub_commands[args.subcommand]().invoked()

210

211

212 if __name__ == "__main__":

213 sys.exit(Snap().main())