diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2020-10-01 16:39:47 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2020-10-01 16:39:47 +0200 |
| commit | 8a351c6d267c55445de7b7b40b1de3b16305bd02 (patch) | |
| tree | 17e59ab15e809868acdcd14353521a3f11fffce5 /src | |
| parent | 1f18e740539aed751865ecff9d0f3cba44230e54 (diff) | |
| download | philosophers_test-8a351c6d267c55445de7b7b40b1de3b16305bd02.tar.gz philosophers_test-8a351c6d267c55445de7b7b40b1de3b16305bd02.tar.bz2 philosophers_test-8a351c6d267c55445de7b7b40b1de3b16305bd02.zip | |
Readded some check
Diffstat (limited to 'src')
| -rw-r--r-- | src/philo/log.py | 4 | ||||
| -rw-r--r-- | src/philo/philo.py | 114 | ||||
| -rw-r--r-- | src/philo/table.py | 8 | ||||
| -rw-r--r-- | src/suite.py | 18 | ||||
| -rw-r--r-- | src/test.py | 27 |
5 files changed, 99 insertions, 72 deletions
diff --git a/src/philo/log.py b/src/philo/log.py index f5817d0..14bdd75 100644 --- a/src/philo/log.py +++ b/src/philo/log.py @@ -6,7 +6,7 @@ # By: cacharle <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/10/01 10:51:39 by cacharle #+# #+# # -# Updated: 2020/10/01 11:30:53 by cacharle ### ########.fr # +# Updated: 2020/10/01 14:19:29 by cacharle ### ########.fr # # # # ############################################################################ # @@ -44,4 +44,4 @@ class Log: return value def __repr__(self): - return "{}ms #{} {}".format(self.timestamp, self.id, self.event) + return "{} {} {}".format(self.timestamp, self.id, Event.to_string(self.event)) diff --git a/src/philo/philo.py b/src/philo/philo.py index afb6362..0f75589 100644 --- a/src/philo/philo.py +++ b/src/philo/philo.py @@ -6,7 +6,7 @@ # By: cacharle <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/10/01 10:52:56 by cacharle #+# #+# # -# Updated: 2020/10/01 11:19:23 by cacharle ### ########.fr # +# Updated: 2020/10/01 16:39:30 by cacharle ### ########.fr # # # # ############################################################################ # @@ -54,54 +54,80 @@ class Philo: - State switch should be thinking -> take fork -> take fork -> eat * meal_num -> sleep -> repeat - Should die when starving: last log timestamp - timeout_death > last_time_eat + - Should eat n times, Should take fork 2 times, The other event should happend 1 time """ if len(self.logs) == 0: return - # def _check_fork_taking(self): - # for l1, l2, l3 in zip(self.logs, self.logs[1:], self.logs[2:]): - # if l1.event is Event.FORK and (l2.event is not Event.FORK or l2.event is not Event.EAT): - # self._raise("should take 2 forks then eat") - # - # def _check_meal(self): - # grouped = [(e, list(g)) for e, g in itertools.groupby(self.logs, (lambda x: x.event))] - # for e, g in grouped: - # if e is Event.EATING: - # if len(g) != self._meal_num: - # raise error.Log(self.logs, "should eat {} times".format(self._meal_num)) - # else: - # if len(g) != 1: - # raise error.Log(self.logs, "event {} should occur 1 time".format(Event.to_string(e))) - # - # def _check_order(self): - # for l1, l2 in zip(self.logs, self.logs[1:]): - # if l2.event is Event.DIED: - # break - # if l1.event is Event.EATING and l2.event is Event.EATING: - # if l2.timestamp - l1.timestamp > self._timeout_eat: - # raise ValueError - # second, timeout = { - # Event.THINKING: (Event.EATING, None), - # Event.EATING: (Event.SLEEPING, self._timeout_eat), - # Event.SLEEPING: (Event.THINKING, self._timeout_sleep) - # }[l1.event] - # if l2.event is not second: - # raise error.Log(self.logs, "invalid switch {} -> {}".format(l1.event, l2.event)) - # if timeout is not None and l2.timestamp - l1.timestamp > timeout: - # raise ValueError - # - # def _check_death_timeout(self): - # last_eat = None - # for log in reversed(self.logs): - # if log.event is Event.EATING: - # last_eat = log - # break - # last = self.logs[-1] - # if last_eat is not None and last_eat is not last: - # if last.timestamp - last_eat.timestamp > self._timeout_die + 10: - # raise error.Log(self.logs, "{} should be dead {} - {} > {}".format( - # self.id, last.timestamp, last_eat.timestamp, self._timeout_die + 10)) + # check 2 forks before eating + for l1, l2, l3 in zip(self.logs, self.logs[1:], self.logs[2:]): + if (l3.event is Event.EAT + and (l1.event is not Event.FORK + or l2.event is not Event.FORK)): + self._raise("should take 2 forks then eat") + + # check log event number + grouped = [(e, list(g)) for e, g in itertools.groupby(self.logs, (lambda x: x.event))] + for e, g in grouped[:-1]: + if e is Event.EAT: + if len(g) != self._meal_num: + self._raise("Should eat {} times".format(self._meal_num)) + elif e is Event.FORK: + if len(g) != 2: + self._raise("Should take fork 2 times") + elif len(g) != 1: + self._raise("Event `{}` should occur 1 time".format(Event.to_string(e))) + + # check state switch order + events = [e for e, _ in grouped] + for e1, e2 in zip(events, events[1:]): + second = { + Event.THINK: Event.FORK, + Event.FORK: Event.EAT, + Event.EAT: Event.SLEEP, + Event.SLEEP: Event.THINK + }[e1] + if e2 is not second: + self._raise("invalid state switch `{}` -> `{}`".format( + Event.to_string(e1), Event.to_string(e2))) + + # check timeouts + for l1, l2 in zip(self.logs, self.logs[1:]): + e1, e2 = l1.event, l2.event + t1, t2 = l1.timestamp, l2.timestamp + if e1 is Event.FORK and e2 is Event.EAT: + if t2 - t1 > 10: + self._raise("Delay between taking second fork and eat > 10") + if e1 is Event.SLEEP: + self._check_time_range(t1, t2, self._timeout_sleep, "Slept") + if e1 is Event.EAT: + self._check_time_range(t1, t2, self._timeout_eat, "Ate") + + + # if l1.event is Event.EATING and l2.event is Event.EATING: + # if l2.timestamp - l1.timestamp > self._timeout_eat: + # raise ValueError + # if timeout is not None and l2.timestamp - l1.timestamp > timeout: + # raise ValueError + + # check if should be dead + # last_eat = None + # for log in reversed(self.logs): + # if log.event is Event.EATING: + # last_eat = log + # break + # last = self.logs[-1] + # if last_eat is not None and last_eat is not last: + # if last.timestamp - last_eat.timestamp > self._timeout_die + 10: + # self._raise("{} should be dead {} - {} > {}".format(self.id, last.timestamp, last_eat.timestamp, self._timeout_die + 10)) + + def _check_time_range(self, t1, t2, timeout, verb): + lo = timeout - 10 + hi = timeout + 10 + if not (lo <= t2 - t1 <= hi): + self._raise("{} {}ms expected {}-{}ms".format(verb, t2 - t1, lo, hi)) + def _raise(self, msg): """ Helper to raise Log errrors""" diff --git a/src/philo/table.py b/src/philo/table.py index ea93391..56ed331 100644 --- a/src/philo/table.py +++ b/src/philo/table.py @@ -6,7 +6,7 @@ # By: cacharle <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/10/01 10:53:29 by cacharle #+# #+# # -# Updated: 2020/10/01 11:31:44 by cacharle ### ########.fr # +# Updated: 2020/10/01 14:15:09 by cacharle ### ########.fr # # # # ############################################################################ # @@ -41,7 +41,7 @@ class Table: philo.logs.append(log) # move if self.dead: - raise error.Log(self._logs, "should not output after death") + raise error.Log(self._logs, "Output after death") if log.event is Event.DIE: self.dead = True @@ -61,7 +61,7 @@ class Table: fork_used = sum([p.used_forks for p in self._philos]) if fork_used > self._philo_num: - raise error.Log(self._logs, "using nonexistant forks") + raise error.Log(self._logs, "Using nonexistant forks") for l1, l2 in zip(self._logs, self._logs[1:]): if l1.timestamp > l2.timestamp: - raise error.Log(self._logs, "timestamps not in ordered") + raise error.Log(self._logs, "Timestamps not in ordered") diff --git a/src/suite.py b/src/suite.py index d4734a9..07b2432 100644 --- a/src/suite.py +++ b/src/suite.py @@ -6,7 +6,7 @@ # By: cacharle <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/10/01 10:41:43 by cacharle #+# #+# # -# Updated: 2020/10/01 11:37:50 by cacharle ### ########.fr # +# Updated: 2020/10/01 12:08:18 by cacharle ### ########.fr # # # # ############################################################################ # @@ -41,14 +41,14 @@ def suite(): Test(0, 100, 10, 10) Test(1, 100, 10, 10) - # - # Test(2, 100, 50, 50) - # Test(3, 100, 50, 50) - # Test(4, 100, 50, 50) - # Test(5, 100, 50, 50) - # Test(6, 100, 50, 50) - # Test(7, 100, 50, 50) - # + + Test(2, 100, 50, 50) + Test(3, 100, 50, 50) + Test(4, 100, 50, 50) + Test(5, 100, 50, 50) + Test(6, 100, 50, 50) + Test(7, 100, 50, 50) + # Test(100, 100, 50, 50) # # Test(10, 100, 100, 10) diff --git a/src/test.py b/src/test.py index 49059f6..8aafc57 100644 --- a/src/test.py +++ b/src/test.py @@ -6,7 +6,7 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/27 11:36:32 by charles #+# #+# # -# Updated: 2020/10/01 11:41:21 by cacharle ### ########.fr # +# Updated: 2020/10/01 16:27:21 by cacharle ### ########.fr # # # # ############################################################################ # @@ -80,22 +80,23 @@ class Test: process = subprocess.Popen( self._argv(), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT + stderr=subprocess.PIPE, + bufsize=0 + ) if self._error_cmd is not None: self._check_error(process) return - out = "" try: - out, _ = process.communicate(timeout=1) - except subprocess.TimeoutExpired as e: - out = e.stdout + out, err = process.communicate(timeout=config.TIMEOUT) + # process.terminate() + except subprocess.TimeoutExpired: + process.kill() + out, err = process.communicate() end_time = current_ms() - try: - out = out.decode() - except UnicodeDecodeError: - pass # TODO + out = out.decode() + err = err.decode() table = philo.Table( self._philo_num, @@ -110,13 +111,13 @@ class Test: def _check_error(self, process): try: - out, _ = process.communicate(timeout=config.TIMEOUT_ERROR) + _, err = process.communicate(timeout=config.TIMEOUT_ERROR) except subprocess.TimeoutExpired: raise error.ShouldFail("no error message") if process.returncode == 0: raise error.ShouldFail("non zero status code: {}".format(process.returncode)) - if out.decode().count('\n') != 1: - raise error.ShouldFail("no error message") + if err.decode().count('\n') != 1: + raise error.ShouldFail("no error message on stderr") def _argv(self, basename=False): exec_path = os.path.basename(Test._exec_path) if basename else Test._exec_path |
