blob: 1a33f092a79d64d2f017a3acd64e87d4671fdaec [file] [log] [blame]
Holger Hans Peter Freyther799fe622018-11-07 03:48:58 +00001# osmo_ms_driver: Location Update Test
Holger Hans Peter Freyther574e62f2018-06-20 09:15:15 +01002# Create MS's and wait for the Location Update to succeed.
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +00003#
4# Copyright (C) 2018 by Holger Hans Peter Freyther
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as
8# published by the Free Software Foundation, either version 3 of the
9# License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000019from datetime import timedelta
20
Holger Hans Peter Freyther75c9cc72019-04-30 15:38:51 +010021from .test_support import TestBase
22
Holger Hans Peter Freyther337141f2019-02-23 09:58:59 +000023import collections
Holger Hans Peter Freyther92cc0c92019-04-28 16:55:30 +010024import json
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000025import time
26
Holger Hans Peter Freyther61f28772019-04-27 14:25:22 +010027# Key used for the result dictionary
28LU_RESULT_NAME = 'lu_time'
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000029
Holger Hans Peter Freyther61f28772019-04-27 14:25:22 +010030def has_lu_time(result):
31 """
32 Returns true if a LU occurred.
33 """
34 return result.has_result(LU_RESULT_NAME)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000035
Holger Hans Peter Freyther61f28772019-04-27 14:25:22 +010036def lu_time(result):
37 """
38 Returns the time of the LU occurrence.
39 """
40 return result.get_result(LU_RESULT_NAME, default=0)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000041
Holger Hans Peter Freyther61f28772019-04-27 14:25:22 +010042def lu_delay(result):
43 """
44 Returns the delay from LU success to MS start time.
45 """
46 return lu_time(result) - result.start_time()
Holger Hans Peter Freyther0f6e4102018-06-23 15:52:25 +010047
Holger Hans Peter Freyther61f28772019-04-27 14:25:22 +010048def set_lu_time(result, time):
49 """
50 Sets/Overrides the time of the LU success for this MS.
51 """
52 result.set_result(LU_RESULT_NAME, time)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000053
Holger Hans Peter Freyther337141f2019-02-23 09:58:59 +000054
55LUStats = collections.namedtuple("LUStats", ["num_attempted", "num_completed",
56 "min_latency", "max_latency"])
57
Holger Hans Peter Freyther75c9cc72019-04-30 15:38:51 +010058class MassUpdateLocationTest(TestBase):
Holger Hans Peter Freyther92cc0c92019-04-28 16:55:30 +010059 def __init__(self, name, event_server, results):
Holger Hans Peter Freyther75c9cc72019-04-30 15:38:51 +010060 super().__init__(name, event_server, results)
Holger Hans Peter Freyther92cc0c92019-04-28 16:55:30 +010061 self._event_server.register(self.handle_msg)
Holger Hans Peter Freyther92cc0c92019-04-28 16:55:30 +010062
63 def configure(self, num_subscribers):
64 self._num_subscribers = num_subscribers
65 self._outstanding = num_subscribers
66
67 def handle_msg(self, _data, addr, time):
68 data = json.loads(_data.decode())
69
70 if data['type'] == 'event':
71 if data['data']['lu_done'] == 1:
72 ms = self._results[data['ms']]
73 if not has_lu_time(ms):
74 self._outstanding = self._outstanding - 1
75 set_lu_time(ms, time)
76 self.log("MS performed LU ", ms=ms, at=time, lu_delay=lu_delay(ms))
77
Holger Hans Peter Freyther75c9cc72019-04-30 15:38:51 +010078 def has_completed(self):
Holger Hans Peter Freyther92cc0c92019-04-28 16:55:30 +010079 return self._outstanding == 0
80
81 def wait_for_test(self, loop, deadline):
82 """Waits up to the absolute deadline for the test to complete."""
Holger Hans Peter Freyther75c9cc72019-04-30 15:38:51 +010083 while not self.has_completed():
Holger Hans Peter Freyther92cc0c92019-04-28 16:55:30 +010084 now_time = time.clock_gettime(time.CLOCK_MONOTONIC)
85 sleep_time = deadline - now_time
86 if sleep_time < 0:
87 break
88 loop.schedule_timeout(sleep_time)
89 loop.select()
90
91 def find_min_max(self, results):
92 min_value = max_value = None
93 for result in results:
94 if min_value is None or lu_delay(result) < min_value:
95 min_value = lu_delay(result)
96 if max_value is None or lu_delay(result) > max_value:
97 max_value = lu_delay(result)
98 return min_value, max_value
99
100 def get_result_values(self):
101 """
102 Returns the raw result values of the test run in any order.
103 """
104 return self._results.values()
105
106 def get_stats(self):
107 """
108 Returns a statistical summary of the test.
109 """
110 attempted = self._num_subscribers
111 completed = attempted - self._outstanding
112 min_latency, max_latency = self.find_min_max(filter(lambda x: has_lu_time(x), self._results.values()))
113 return LUStats(attempted, completed, min_latency, max_latency)
114
115 def print_stats(self):
116 stats = self.get_stats()
117 all_completed = stats.num_attempted == stats.num_completed
118
119 self.log("Tests done", all_completed=all_completed,
120 min=stats.min_latency, max=stats.max_latency)
121
122 def lus_less_than(self, acceptable_delay):
123 """
124 Returns LUs that completed within the acceptable delay.
125 """
126 res = []
127 for result in self._results.values():
128 if not has_lu_time(result):
129 continue
130 if timedelta(seconds=lu_delay(result)) >= acceptable_delay:
131 continue
132 res.append(result)
133 return res
134