1#!/usr/bin/env python3

2

3# Copyright (C) 2012 Canonical, Ltd.

4

5 import re

6 import subprocess

7 import argparse

8 import sys

9

10

11 def get_time_difference(device):

12 """

13 Returns the difference in seconds between the last resume from suspend (S3)

14 and the time it took to reconnect to Wifi. If there is a problem finding

15 the information, None is returned.

16 """

17 resume_time = get_resume_time()

18 if resume_time is None:

19 print(

20 "Unable to obtain wakeup/resume time from dmesg."

21 "Please be sure the system has been suspended",

22 file=sys.stderr,

23 )

24 return None

25 if device == "wifi":

26 reconnect_times = list(get_wifi_reconnect_times())

27 elif device == "wired":

28 reconnect_times = list(get_wired_reconnect_times())

29

30 if not reconnect_times:

31 print(

32 "Unable to obtain %s connection time after a S3. Please be sure"

33 " that the system has been suspended" % device,

34 file=sys.stderr,

35 )

36 return None

37

38 # since some wifi & wired tests can disconnect and reconnect us multiple

39 # times after a suspend, we need to find the reconnect that occurs

40 # immediately after the resume from S3

41 for reconnect_time in reconnect_times:

42 if reconnect_time >= resume_time:

43 return round((reconnect_time - resume_time), 2)

44 return None

45

46

47 def get_wifi_reconnect_times():

48 """

49 Returns a list of all the timestamps for wifi reconnects.

50 """

51 data = subprocess.check_output(["dmesg"], universal_newlines=True)

52 syntax = re.compile(r"\[(.*)\] wlan.* associated")

53 results = re.findall(syntax, data)

54 return map(float, results)

55

56

57 def get_wired_reconnect_times():

58 """

59 Returns a list of all the timestamps for wired reconnects.

60 """

61 data = subprocess.check_output(["dmesg"], universal_newlines=True)

62 syntax = re.compile(r"\[(.*)\].*eth.* Link is [uU]p")

63 results = re.findall(syntax, data)

64 return map(float, results)

65

66

67 def get_resume_time():

68 """

69 Returns the last (most recent) timestamp for an ACPI resume from sleep (S3)

70 If no resume is found, None is returned.

71 """

72 data = subprocess.check_output(["dmesg"], universal_newlines=True)

73 syntax = re.compile(r"\[(.*)\].ACPI: Waking up from system sleep state S3")

74 results = re.findall(syntax, data)

75 if not results:

76 return None

77 else:

78 return float(results[-1])

79

80

81 def main():

82 parser = argparse.ArgumentParser()

83 parser.add_argument(

84 "-t",

85 "--timeout",

86 type=int,

87 help="Specified max time allowed for Wifi/Wired to"

88 " reconnect in seconds",

89 required=True,

90 )

91 parser.add_argument(

92 "-d",

93 "--device",

94 help="Specify the device to test either, eth or wlan",

95 required=True,

96 choices=["wifi", "wired"],

97 )

98 args = parser.parse_args()

99

100 timedif = get_time_difference(args.device)

101

102 if not timedif:

103 return 0

104

105 print(

106 "Your %s resumed in %s seconds after the last suspend"

107 % (args.device, timedif)

108 )

109 if timedif > args.timeout:

110 print("FAIL: the network failed to reconnect within the allotted time")

111 return 1

112 else:

113 print("PASS: the network connected within the allotted time")

114 return 0

115

116

117 if __name__ == "__main__":

118 sys.exit(main())