Merge ~teknoraver/snappy-hwe-snaps/+git/wifi-ap:wizard into ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-ap:master

Proposed by Matteo Croce
Status: Merged
Approved by: Matteo Croce
Approved revision: f77adfa785a7725decf7ad373b9cbffbbef7f2b2
Merged at revision: 91a519eda8cc4c17fa76ce34040692332ab0060f
Proposed branch: ~teknoraver/snappy-hwe-snaps/+git/wifi-ap:wizard
Merge into: ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-ap:master
Diff against target: 452 lines (+244/-32)
6 files modified
cmd/client/cmd_wizard.go (+158/-31)
run-tests.sh (+1/-1)
tests/main/conf-wizard-auto-nodefaultip/task.yaml (+25/-0)
tests/main/conf-wizard-auto-noip/task.yaml (+21/-0)
tests/main/conf-wizard-auto-nowifi/task.yaml (+8/-0)
tests/main/conf-wizard-auto/task.yaml (+31/-0)
Reviewer Review Type Date Requested Status
System Enablement Bot continuous-integration Approve
Simon Fels Approve
Matteo Croce (community) Needs Fixing
Jim Hodapp (community) code Needs Fixing
Review via email: mp+311026@code.launchpad.net

Description of the change

automatic configuration for wizard

To post a comment you must log in.
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jim Hodapp (jhodapp) wrote :

Please expand the commit message to say a little bit more about what this MR is about.

Some comments inline below.

review: Needs Fixing (code)
Revision history for this message
Simon Fels (morphis) wrote :

This misses unit-tests and spread tests to verify things are working correct.

review: Needs Fixing
Revision history for this message
Matteo Croce (teknoraver) :
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Matteo Croce (teknoraver) wrote :

spread tests are coming

review: Needs Fixing
Revision history for this message
Simon Fels (morphis) :
review: Needs Fixing
Revision history for this message
Matteo Croce (teknoraver) :
Revision history for this message
Matteo Croce (teknoraver) :
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Simon Fels (morphis) wrote :

Looks really good already but a few comments about the spread tests.

review: Needs Fixing
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Simon Fels (morphis) :
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Simon Fels (morphis) wrote :

A few last comments in line

review: Needs Fixing
Revision history for this message
Simon Fels (morphis) wrote :

Once CI approves we can merge this one.

review: Approve
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/cmd/client/cmd_wizard.go b/cmd/client/cmd_wizard.go
index 9a9ebd5..a368c24 100644
--- a/cmd/client/cmd_wizard.go
+++ b/cmd/client/cmd_wizard.go
@@ -20,15 +20,24 @@ import (
20 "bytes"20 "bytes"
21 "encoding/json"21 "encoding/json"
22 "fmt"22 "fmt"
23 "io/ioutil"
24 "net"23 "net"
25 "net/http"24 "net/http"
26 "os"25 "os"
26 "path/filepath"
27 "regexp"27 "regexp"
28 "strconv"28 "strconv"
29 "strings"29 "strings"
30)30)
3131
32type wizardStep func(map[string]string, *bufio.Reader, bool) error
33
34// Go stores both IPv4 and IPv6 as [16]byte
35// with IPv4 addresses stored in the end of the buffer
36// in bytes 13..16
37const ipv4Offset = net.IPv6len - net.IPv4len
38
39var defaultIp = net.IPv4(10, 0, 60, 1)
40
32// Utility function to read input and strip the trailing \n41// Utility function to read input and strip the trailing \n
33func readUserInput(reader *bufio.Reader) string {42func readUserInput(reader *bufio.Reader) string {
34 ret, err := reader.ReadString('\n')43 ret, err := reader.ReadString('\n')
@@ -41,15 +50,15 @@ func readUserInput(reader *bufio.Reader) string {
41// Helper function to list network interfaces50// Helper function to list network interfaces
42func findExistingInterfaces(wifi bool) (wifis []string) {51func findExistingInterfaces(wifi bool) (wifis []string) {
43 // Use sysfs to get interfaces list52 // Use sysfs to get interfaces list
44 const sysNetPath = "/sys/class/net/"53 const sysNetPath = "/sys/class/net"
45 ifaces, err := ioutil.ReadDir(sysNetPath)54 ifaces, err := net.Interfaces()
46 wifis = []string{}55 wifis = []string{}
47 if err == nil {56 if err == nil {
48 for _, iface := range ifaces {57 for _, iface := range ifaces {
49 if iface.Name() != "lo" {58 if iface.Flags&net.FlagLoopback == 0 {
50 // The "wireless" subdirectory exists only for wireless interfaces59 // The "wireless" subdirectory exists only for wireless interfaces
51 if _, err := os.Stat(sysNetPath + iface.Name() + "/wireless"); os.IsNotExist(err) != wifi {60 if _, err := os.Stat(filepath.Join(sysNetPath, iface.Name, "wireless")); os.IsNotExist(err) != wifi {
52 wifis = append(wifis, iface.Name())61 wifis = append(wifis, iface.Name)
53 }62 }
54 }63 }
55 }64 }
@@ -58,11 +67,39 @@ func findExistingInterfaces(wifi bool) (wifis []string) {
58 return67 return
59}68}
6069
61type wizardStep func(map[string]string, *bufio.Reader) error70func findFreeSubnet(startIp net.IP) (net.IP, error) {
71 curIp := startIp
72
73 addrs, err := net.InterfaceAddrs()
74 if err != nil {
75 return nil, err
76 }
77
78 // Start from startIp and increment the third octect every time
79 // until we found an IP which isn't assigned to any interface
80 for found := false; !found; {
81 // Cycle through all the assigned addresses
82 for _, addr := range addrs {
83 found = true
84 _, subnet, _ := net.ParseCIDR(addr.String())
85 // If busy, increment the third octect and retry
86 if subnet.Contains(curIp) {
87 found = false
88 if curIp[ipv4Offset+2] == 255 {
89 return nil, fmt.Errorf("No free netmask found")
90 }
91 curIp[ipv4Offset+2]++
92 break
93 }
94 }
95 }
96
97 return curIp, nil
98}
6299
63var allSteps = [...]wizardStep{100var allSteps = [...]wizardStep{
64 // determine the WiFi interface101 // determine the WiFi interface
65 func(configuration map[string]string, reader *bufio.Reader) error {102 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
66 ifaces := findExistingInterfaces(true)103 ifaces := findExistingInterfaces(true)
67 if len(ifaces) == 0 {104 if len(ifaces) == 0 {
68 return fmt.Errorf("There are no valid wireless network interfaces available")105 return fmt.Errorf("There are no valid wireless network interfaces available")
@@ -70,12 +107,19 @@ var allSteps = [...]wizardStep{
70 fmt.Println("Automatically selected only available wireless network interface " + ifaces[0])107 fmt.Println("Automatically selected only available wireless network interface " + ifaces[0])
71 return nil108 return nil
72 }109 }
110
111 if nonInteractive {
112 fmt.Println("Selecting interface", ifaces[0])
113 configuration["wifi.interface"] = ifaces[0]
114 return nil
115 }
116
73 fmt.Print("Which wireless interface you want to use? ")117 fmt.Print("Which wireless interface you want to use? ")
74 ifacesVerb := "are"118 ifacesVerb := "are"
75 if len(ifaces) == 1 {119 if len(ifaces) == 1 {
76 ifacesVerb = "is"120 ifacesVerb = "is"
77 }121 }
78 fmt.Printf("Available %s %s:", ifacesVerb, strings.Join(ifaces, ", "))122 fmt.Printf("Available %s %s: ", ifacesVerb, strings.Join(ifaces, ", "))
79 iface := readUserInput(reader)123 iface := readUserInput(reader)
80 if re := regexp.MustCompile("^[[:alnum:]]+$"); !re.MatchString(iface) {124 if re := regexp.MustCompile("^[[:alnum:]]+$"); !re.MatchString(iface) {
81 return fmt.Errorf("Invalid interface name '%s' given", iface)125 return fmt.Errorf("Invalid interface name '%s' given", iface)
@@ -86,7 +130,12 @@ var allSteps = [...]wizardStep{
86 },130 },
87131
88 // Ask for WiFi ESSID132 // Ask for WiFi ESSID
89 func(configuration map[string]string, reader *bufio.Reader) error {133 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
134 if nonInteractive {
135 configuration["wifi.ssid"] = "Ubuntu"
136 return nil
137 }
138
90 fmt.Print("Which SSID you want to use for the access point: ")139 fmt.Print("Which SSID you want to use for the access point: ")
91 iface := readUserInput(reader)140 iface := readUserInput(reader)
92 if len(iface) == 0 || len(iface) > 31 {141 if len(iface) == 0 || len(iface) > 31 {
@@ -98,7 +147,12 @@ var allSteps = [...]wizardStep{
98 },147 },
99148
100 // Select WiFi encryption type149 // Select WiFi encryption type
101 func(configuration map[string]string, reader *bufio.Reader) error {150 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
151 if nonInteractive {
152 configuration["wifi.security"] = "open"
153 return nil
154 }
155
102 fmt.Print("Do you want to protect your network with a WPA2 password instead of staying open for everyone? (y/n) ")156 fmt.Print("Do you want to protect your network with a WPA2 password instead of staying open for everyone? (y/n) ")
103 switch resp := strings.ToLower(readUserInput(reader)); resp {157 switch resp := strings.ToLower(readUserInput(reader)); resp {
104 case "y":158 case "y":
@@ -113,7 +167,7 @@ var allSteps = [...]wizardStep{
113 },167 },
114168
115 // If WPA2 is set, ask for valid password169 // If WPA2 is set, ask for valid password
116 func(configuration map[string]string, reader *bufio.Reader) error {170 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
117 if configuration["wifi.security"] == "open" {171 if configuration["wifi.security"] == "open" {
118 return nil172 return nil
119 }173 }
@@ -128,7 +182,20 @@ var allSteps = [...]wizardStep{
128 },182 },
129183
130 // Configure WiFi AP IP address184 // Configure WiFi AP IP address
131 func(configuration map[string]string, reader *bufio.Reader) error {185 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
186 if nonInteractive {
187 wifiIp, err := findFreeSubnet(defaultIp)
188 if err != nil {
189 return err
190 }
191
192 fmt.Println("AccessPoint IP set to", wifiIp.String())
193
194 configuration["wifi.address"] = wifiIp.String()
195 configuration["wifi.netmask"] = "255.255.255.0"
196 return nil
197 }
198
132 fmt.Print("Insert the Access Point IP address: ")199 fmt.Print("Insert the Access Point IP address: ")
133 inputIp := readUserInput(reader)200 inputIp := readUserInput(reader)
134 ipv4 := net.ParseIP(inputIp)201 ipv4 := net.ParseIP(inputIp)
@@ -143,21 +210,33 @@ var allSteps = [...]wizardStep{
143 }210 }
144211
145 configuration["wifi.address"] = inputIp212 configuration["wifi.address"] = inputIp
146213 configuration["wifi.netmask"] = ipv4.DefaultMask().String()
147 nmask := ipv4.DefaultMask()
148 configuration["wifi.netmask"] = fmt.Sprintf("%d.%d.%d.%d", nmask[0], nmask[1], nmask[2], nmask[3])
149214
150 return nil215 return nil
151 },216 },
152217
153 // Configure the DHCP pool218 // Configure the DHCP pool
154 func(configuration map[string]string, reader *bufio.Reader) error {219 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
220 if nonInteractive {
221 wifiIp := net.ParseIP(configuration["wifi.address"])
222
223 // Set the DCHP in the range 2..199 with 198 total hosts
224 // leave about 50 hosts outside the pool for static addresses
225 // wifiIp[ipv4Offset + 3] is the last octect of the IP address
226 wifiIp[ipv4Offset+3] = 2
227 configuration["dhcp.range-start"] = wifiIp.String()
228 wifiIp[ipv4Offset+3] = 199
229 configuration["dhcp.range-stop"] = wifiIp.String()
230
231 return nil
232 }
233
155 var maxpoolsize byte234 var maxpoolsize byte
156 ipv4 := net.ParseIP(configuration["wifi.address"])235 ipv4 := net.ParseIP(configuration["wifi.address"])
157 if ipv4[15] <= 128 {236 if ipv4[ipv4Offset+3] <= 128 {
158 maxpoolsize = 254 - ipv4[15]237 maxpoolsize = 254 - ipv4[ipv4Offset+3]
159 } else {238 } else {
160 maxpoolsize = ipv4[15] - 1239 maxpoolsize = ipv4[ipv4Offset+3] - 1
161 }240 }
162241
163 fmt.Printf("How many host do you want your DHCP pool to hold to? (1-%d) ", maxpoolsize)242 fmt.Printf("How many host do you want your DHCP pool to hold to? (1-%d) ", maxpoolsize)
@@ -172,19 +251,28 @@ var allSteps = [...]wizardStep{
172251
173 nhosts := byte(inputhost)252 nhosts := byte(inputhost)
174 // Allocate the pool in the bigger half, trying to avoid overlap with access point IP253 // Allocate the pool in the bigger half, trying to avoid overlap with access point IP
175 if ipv4[15] <= 128 {254 if octect3 := ipv4[ipv4Offset+3]; octect3 <= 128 {
176 configuration["dhcp.range-start"] = fmt.Sprintf("%d.%d.%d.%d", ipv4[12], ipv4[13], ipv4[14], ipv4[15]+1)255 ipv4[ipv4Offset+3] = octect3 + 1
177 configuration["dhcp.range-stop"] = fmt.Sprintf("%d.%d.%d.%d", ipv4[12], ipv4[13], ipv4[14], ipv4[15]+nhosts)256 configuration["dhcp.range-start"] = ipv4.String()
257 ipv4[ipv4Offset+3] = octect3 + nhosts
258 configuration["dhcp.range-stop"] = ipv4.String()
178 } else {259 } else {
179 configuration["dhcp.range-start"] = fmt.Sprintf("%d.%d.%d.%d", ipv4[12], ipv4[13], ipv4[14], ipv4[15]-nhosts)260 ipv4[ipv4Offset+3] = octect3 - nhosts
180 configuration["dhcp.range-stop"] = fmt.Sprintf("%d.%d.%d.%d", ipv4[12], ipv4[13], ipv4[14], ipv4[15]-1)261 configuration["dhcp.range-start"] = ipv4.String()
262 ipv4[ipv4Offset+3] = octect3 - 1
263 configuration["dhcp.range-stop"] = ipv4.String()
181 }264 }
182265
183 return nil266 return nil
184 },267 },
185268
186 // Enable or disable connection sharing269 // Enable or disable connection sharing
187 func(configuration map[string]string, reader *bufio.Reader) error {270 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
271 if nonInteractive {
272 configuration["share.disabled"] = "0"
273 return nil
274 }
275
188 fmt.Print("Do you want to enable connection sharing? (y/n) ")276 fmt.Print("Do you want to enable connection sharing? (y/n) ")
189 switch resp := strings.ToLower(readUserInput(reader)); resp {277 switch resp := strings.ToLower(readUserInput(reader)); resp {
190 case "y":278 case "y":
@@ -199,10 +287,39 @@ var allSteps = [...]wizardStep{
199 },287 },
200288
201 // Select the wired interface to share289 // Select the wired interface to share
202 func(configuration map[string]string, reader *bufio.Reader) error {290 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
291 if nonInteractive {
292 configuration["share.disabled"] = "1"
293
294 procNetRoute, err := os.Open("/proc/net/route")
295 if err != nil {
296 return err
297 }
298 defer procNetRoute.Close()
299
300 scanner := bufio.NewScanner(procNetRoute)
301 // Skip the first line with table header
302 scanner.Text()
303 for scanner.Scan() {
304 route := strings.Fields(scanner.Text())
305 // A /proc/net/route line is in the form: iface destination gateway ...
306 // eg.
307 // eth1 00000000 0155A8C0 ...
308 // look for a 0 destination (0.0.0.0) which is our default route
309 if len(route) > 2 && route[1] == "00000000" {
310 fmt.Println("Selecting", route[0], "for connection sharing")
311 configuration["share.disabled"] = "0"
312 configuration["share.network-interface"] = route[0]
313 }
314 }
315
316 return nil
317 }
318
203 if configuration["share.disabled"] == "1" {319 if configuration["share.disabled"] == "1" {
204 return nil320 return nil
205 }321 }
322
206 ifaces := findExistingInterfaces(false)323 ifaces := findExistingInterfaces(false)
207 if len(ifaces) == 0 {324 if len(ifaces) == 0 {
208 fmt.Println("No network interface available which's connection can be shared. Disabling connection sharing.")325 fmt.Println("No network interface available which's connection can be shared. Disabling connection sharing.")
@@ -224,7 +341,12 @@ var allSteps = [...]wizardStep{
224 return nil341 return nil
225 },342 },
226343
227 func (configuration map[string]string, reader *bufio.Reader) error {344 func(configuration map[string]string, reader *bufio.Reader, nonInteractive bool) error {
345 if nonInteractive {
346 configuration["disabled"] = "0"
347 return nil
348 }
349
228 fmt.Print("Do you want to enable the AP now? (y/n) ")350 fmt.Print("Do you want to enable the AP now? (y/n) ")
229 switch resp := strings.ToLower(readUserInput(reader)); resp {351 switch resp := strings.ToLower(readUserInput(reader)); resp {
230 case "y":352 case "y":
@@ -262,7 +384,9 @@ func applyConfiguration(configuration map[string]string) error {
262 }384 }
263}385}
264386
265type wizardCommand struct{}387type wizardCommand struct {
388 Auto bool `long:"auto" description:"Automatically configure the AP"`
389}
266390
267func (cmd *wizardCommand) Execute(args []string) error {391func (cmd *wizardCommand) Execute(args []string) error {
268 // Setup some sane default values, we don't ask the user for everything392 // Setup some sane default values, we don't ask the user for everything
@@ -272,9 +396,12 @@ func (cmd *wizardCommand) Execute(args []string) error {
272396
273 for _, step := range allSteps {397 for _, step := range allSteps {
274 for {398 for {
275 if err := step(configuration, reader); err != nil {399 if err := step(configuration, reader, cmd.Auto); err != nil {
400 if cmd.Auto {
401 return err
402 }
276 fmt.Println("Error: ", err)403 fmt.Println("Error: ", err)
277 fmt.Print("You want to try again? (y/n) ")404 fmt.Print("Do you want to try again? (y/n) ")
278 answer := readUserInput(reader)405 answer := readUserInput(reader)
279 if strings.ToLower(answer) != "y" {406 if strings.ToLower(answer) != "y" {
280 return err407 return err
diff --git a/run-tests.sh b/run-tests.sh
index eaa2fca..e234fc2 100755
--- a/run-tests.sh
+++ b/run-tests.sh
@@ -73,7 +73,7 @@ if [ ! -e $SPREAD_QEMU_PATH/$image_name ] || [ $force_new_image -eq 1 ] ; then
73 echo "INFO: Creating new qemu test image ..."73 echo "INFO: Creating new qemu test image ..."
74 (cd tests/image ; sudo ./create-image.sh $channel)74 (cd tests/image ; sudo ./create-image.sh $channel)
75 mkdir -p $SPREAD_QEMU_PATH75 mkdir -p $SPREAD_QEMU_PATH
76 mv tests/image/ubuntu-core-16.img $SPREAD_QEMU_PATH/$image_name76 mv -f tests/image/ubuntu-core-16.img $SPREAD_QEMU_PATH/$image_name
77fi77fi
7878
79# We currently only run spread tests but we could do other things79# We currently only run spread tests but we could do other things
diff --git a/tests/main/conf-wizard-auto-nodefaultip/task.yaml b/tests/main/conf-wizard-auto-nodefaultip/task.yaml
80new file mode 10064480new file mode 100644
index 0000000..e6d6e06
--- /dev/null
+++ b/tests/main/conf-wizard-auto-nodefaultip/task.yaml
@@ -0,0 +1,25 @@
1summary: Verify that the wizard is able to find an unused IP
2
3prepare: |
4 # Simulate a radio network interfaces
5 modprobe mac80211_hwsim radios=1
6
7 # Dummy interface to assign an IP to
8 modprobe dummy
9
10 # Use 10.0.60.0/20 to keep 10.0.48.1-10.0.63.254 busy
11 # and force the wizard to use the 10.0.64.0/24
12 ifconfig dummy0 10.0.48.2/20
13
14restore: |
15 rmmod mac80211_hwsim dummy
16
17execute: |
18 # Start the automatic wizard, it must fail
19 /snap/bin/wifi-ap.setup-wizard wizard --auto
20
21 # Check for assigned IP on subnet 10.0.64.0/24
22 test "$(/snap/bin/wifi-ap.config get wifi.address)" = 10.0.64.1
23 test "$(/snap/bin/wifi-ap.config get wifi.netmask)" = 255.255.255.0
24 test "$(/snap/bin/wifi-ap.config get dhcp.range-start)" = 10.0.64.2
25 test "$(/snap/bin/wifi-ap.config get dhcp.range-stop)" = 10.0.64.199
diff --git a/tests/main/conf-wizard-auto-noip/task.yaml b/tests/main/conf-wizard-auto-noip/task.yaml
0new file mode 10064426new file mode 100644
index 0000000..5a0885c
--- /dev/null
+++ b/tests/main/conf-wizard-auto-noip/task.yaml
@@ -0,0 +1,21 @@
1summary: Verify that wizard fails when all private subnets are busy
2
3prepare: |
4 # Simulate a radio network interfaces
5 modprobe mac80211_hwsim radios=1
6
7 # Dummy interface to assign an IP to
8 modprobe dummy
9
10 # Set an IP with a /8 mask which will waste all usable IP
11 ifconfig dummy0 10.0.0.2/8
12
13restore: |
14 rmmod mac80211_hwsim dummy
15
16execute: |
17 # Start the automatic wizard, it must fail
18 ! /snap/bin/wifi-ap.setup-wizard wizard --auto
19
20 # Check for a descriptive error message
21 /snap/bin/wifi-ap.setup-wizard wizard --auto 2>&1 |grep 'No free netmask found'
diff --git a/tests/main/conf-wizard-auto-nowifi/task.yaml b/tests/main/conf-wizard-auto-nowifi/task.yaml
0new file mode 10064422new file mode 100644
index 0000000..18301f1
--- /dev/null
+++ b/tests/main/conf-wizard-auto-nowifi/task.yaml
@@ -0,0 +1,8 @@
1summary: Verify that wizard fails when there are no WiFi devices
2
3execute: |
4 # Start the automatic wizard, it must fail
5 ! /snap/bin/wifi-ap.setup-wizard wizard --auto
6
7 # Check for a descriptive error message
8 /snap/bin/wifi-ap.setup-wizard wizard --auto 2>&1 |grep 'There are no valid wireless network interfaces available'
diff --git a/tests/main/conf-wizard-auto/task.yaml b/tests/main/conf-wizard-auto/task.yaml
0new file mode 1006449new file mode 100644
index 0000000..3d1a2c7
--- /dev/null
+++ b/tests/main/conf-wizard-auto/task.yaml
@@ -0,0 +1,31 @@
1summary: Verify that the automatic wizard works
2
3prepare: |
4 # Simulate two WiFi radio network interfaces
5 modprobe mac80211_hwsim radios=2
6
7restore: |
8 rmmod mac80211_hwsim
9
10execute: |
11 # Start the automatic wizard
12 /snap/bin/wifi-ap.setup-wizard wizard --auto
13
14 # Check that we get good default values
15 test "$(/snap/bin/wifi-ap.config get disabled)" = 0
16
17 test "$(/snap/bin/wifi-ap.config get wifi.interface)" = wlan0
18 test "$(/snap/bin/wifi-ap.config get wifi.security)" = open
19 test "$(/snap/bin/wifi-ap.config get wifi.ssid)" = Ubuntu
20 test "$(/snap/bin/wifi-ap.config get wifi.address)" = 10.0.60.1
21
22 test "$(/snap/bin/wifi-ap.config get dhcp.range-start)" = 10.0.60.2
23 test "$(/snap/bin/wifi-ap.config get dhcp.range-stop)" = 10.0.60.199
24
25 default_route=$(ip route |awk '/default/{print$5}')
26 if [ -n "$default_route" ]; then
27 test "$(/snap/bin/wifi-ap.config get share.disabled)" = 0
28 test "$(/snap/bin/wifi-ap.config get share.network-interface)" = "$default_route"
29 else
30 test "$(/snap/bin/wifi-ap.config get share.disabled)" = 1
31 fi

Subscribers

People subscribed via source and target branches

to all changes: