blob: e83d91bb9c57609ce246549e9423fc07d5d6dfe7 [file] [log] [blame]
Holger Hans Peter Freyther574e62f2018-06-20 09:15:15 +01001# osmo_ms_driver: Locationg Update Test
2# 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 Freyther99a6a412018-08-29 04:24:38 +010019from copy import copy
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000020from osmo_gsm_tester import log
21from .starter import OsmoVirtPhy, OsmoMobile
Holger Hans Peter Freyther574e62f2018-06-20 09:15:15 +010022from .test_support import imsi_ki_gen, Results
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000023
24from datetime import timedelta
25
26import time
27
Holger Hans Peter Freyther574e62f2018-06-20 09:15:15 +010028class LUResult(Results):
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000029
30 def __init__(self, name):
Holger Hans Peter Freyther574e62f2018-06-20 09:15:15 +010031 super().__init__(name)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000032 self._time_of_lu = None
33
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000034 def set_lu_time(self, time):
35 assert self._time_of_lu is None
36 self._time_of_lu = time
37
Holger Hans Peter Freyther0f6e4102018-06-23 15:52:25 +010038 def has_lu_time(self):
39 return self._time_of_lu is not None
40
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000041 def lu_time(self):
42 return self._time_of_lu or 0
43
44 def lu_delay(self):
45 return self.lu_time() - self.start_time()
46
47class MassUpdateLocationTest(log.Origin):
48 """
49 A test to launch a configurable amount of MS and make them
50 execute a Location Updating Procedure.
51
52 Configure the number of MS to be tested and a function that
53 decides how quickly to start them and a timeout.
54 """
55
56 TEMPLATE_LUA = "osmo-mobile-lu.lua"
57 TEMPLATE_CFG = "osmo-mobile.cfg"
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000058
59 def __init__(self, name, number_of_ms, cdf_function, event_server, tmp_dir):
60 super().__init__(log.C_RUN, name)
61 self._number_of_ms = number_of_ms
62 self._cdf = cdf_function
63 self._cdf.set_target(number_of_ms)
64 self._unstarted = []
Holger Hans Peter Freyther99a6a412018-08-29 04:24:38 +010065 self._mobiles = []
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000066 self._phys = []
67 self._results = {}
68 imsi_gen = imsi_ki_gen()
69
Holger Hans Peter Freyther0f6e4102018-06-23 15:52:25 +010070 self._outstanding = number_of_ms
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000071 for i in range(0, number_of_ms):
72 ms_name = "%.5d" % i
73
74 phy = OsmoVirtPhy(ms_name, tmp_dir)
75 self._phys.append(phy)
76
77 launcher = OsmoMobile(ms_name, tmp_dir, self.TEMPLATE_LUA,
78 self.TEMPLATE_CFG, imsi_gen,
79 phy.phy_filename(),
80 event_server.server_path())
Holger Hans Peter Freyther574e62f2018-06-20 09:15:15 +010081 self._results[ms_name] = LUResult(ms_name)
Holger Hans Peter Freyther99a6a412018-08-29 04:24:38 +010082 self._mobiles.append(launcher)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000083 self._event_server = event_server
84 self._event_server.register(self.handle_msg)
Holger Hans Peter Freyther99a6a412018-08-29 04:24:38 +010085 self._unstarted = copy(self._mobiles)
86
87 def mobiles(self):
88 return self._mobiles
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +000089
90 def pre_launch(self, loop):
91 """
92 We need the virtphy's be ready when the lua script in the
93 mobile comes and kicks-off the test. In lua we don't seem to
94 be able to just stat/check if a file/socket exists so we need
95 to do this from here.
96 """
97 self.log("Pre-launching all virtphy's")
98 for phy in self._phys:
99 phy.start(loop)
100
101 self.log("Checking if sockets are in the filesystem")
102 for phy in self._phys:
103 phy.verify_ready()
104
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100105 def prepare(self, loop):
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000106 self.log("Starting testcase")
107
108 self.pre_launch(loop)
109
110 self._start_time = time.clock_gettime(time.CLOCK_MONOTONIC)
111 self._end_time = self._start_time + \
112 self._cdf.duration().total_seconds() + \
113 timedelta(seconds=120).total_seconds()
114
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000115 self._started = []
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100116 self._too_slow = 0
117
118 def step_once(self, loop, current_time):
119 if len(self._unstarted) <= 0:
120 return current_time, None
121
122 step_size = self._cdf.step_size().total_seconds()
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000123
124 # Start
125 self._cdf.step_once()
126
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100127 # Check for timeout
128 # start pending MS
129 while len(self._started) < self._cdf.current_scaled_value() and len(self._unstarted) > 0:
130 ms = self._unstarted.pop(0)
131 ms.start(loop)
132 launch_time = time.clock_gettime(time.CLOCK_MONOTONIC)
133 self._results[ms.name_number()].set_launch_time(launch_time)
134 self._started.append(ms)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000135
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100136 now_time = time.clock_gettime(time.CLOCK_MONOTONIC)
137 sleep_time = (current_time + step_size) - now_time
138 if sleep_time <= 0:
139 self.log("Starting too slowly. Moving on",
140 target=(current_time + step_size), now=now_time, sleep=sleep_time)
141 self._too_slow += 1
142 sleep_time = 0
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000143
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100144 if len(self._unstarted) == 0:
145 end_time = time.clock_gettime(time.CLOCK_MONOTONIC)
146 self.log("All started...", too_slow=self._too_slow, duration=end_time - self._start_time)
147 return current_time, None
148
149 return current_time + step_size, sleep_time
150
Holger Hans Peter Freyther1dc9a042018-06-23 22:27:23 +0100151 def run_test(self, loop, test_duration):
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100152 self.prepare(loop)
153
Holger Hans Peter Freyther1dc9a042018-06-23 22:27:23 +0100154 to_complete_time = self._start_time + test_duration.total_seconds()
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100155 tick_time = self._start_time
156
157 while not self.all_completed():
158 tick_time, sleep_time = self.step_once(loop, tick_time)
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000159 now_time = time.clock_gettime(time.CLOCK_MONOTONIC)
Holger Hans Peter Freyther6926c572018-06-23 19:58:38 +0100160 if sleep_time is None:
161 sleep_time = to_complete_time - now_time
162 if sleep_time < 0:
163 break
164 loop.schedule_timeout(sleep_time)
165 loop.select()
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000166
167 def stop_all(self):
168 for launcher in self._started:
169 launcher.kill()
170
Holger Hans Peter Freyther05895a92018-06-17 19:31:46 +0100171 def handle_msg(self, _data, addr, time):
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000172 import json
173 data = json.loads(_data.decode())
174
175 if data['type'] == 'register':
176 ms = self._results[data['ms']]
177 ms.set_start_time(time)
178 launch_delay = ms.start_time() - ms.launch_time()
179 self.log("MS start registered ", ms=ms, at=time, delay=launch_delay)
180 elif data['type'] == 'event':
181 if data['data']['lu_done'] == 1:
182 ms = self._results[data['ms']]
Holger Hans Peter Freyther0f6e4102018-06-23 15:52:25 +0100183 if not ms.has_lu_time():
184 self._outstanding = self._outstanding - 1
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000185 ms.set_lu_time(time)
186 self.log("MS performed LU ", ms=ms, at=time, lu_delay=ms.lu_delay())
187 else:
188 print(time, data)
189 raise Exception("Unknown event type..:" + _data.decode())
190
191
Holger Hans Peter Freyther0f6e4102018-06-23 15:52:25 +0100192 def all_completed(self):
193 return self._outstanding == 0
194
Holger Hans Peter Freytheraf522fd2018-06-23 21:35:30 +0100195 def results_min_max(self, results):
196 min_value = max_value = None
197 for result in results:
198 if min_value is None or result.lu_delay() < min_value:
199 min_value = result.lu_delay()
200 if max_value is None or result.lu_delay() > max_value:
201 max_value = result.lu_delay()
202 return min_value, max_value
203
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000204 def print_stats(self):
Holger Hans Peter Freyther0f6e4102018-06-23 15:52:25 +0100205 all_completed = self.all_completed()
Holger Hans Peter Freytheraf522fd2018-06-23 21:35:30 +0100206 min_value, max_value = self.results_min_max(filter(lambda x: x.has_lu_time(), self._results.values()))
Holger Hans Peter Freyther30cc0212018-02-25 21:34:35 +0000207
208 self.log("Tests done", all_completed=all_completed,
Holger Hans Peter Freytheraf522fd2018-06-23 21:35:30 +0100209 min=min_value, max=max_value)