diff --git a/swh/counters/__init__.py b/swh/counters/__init__.py --- a/swh/counters/__init__.py +++ b/swh/counters/__init__.py @@ -14,6 +14,7 @@ COUNTERS_IMPLEMENTATIONS = { "redis": ".redis.Redis", "remote": ".api.client.RemoteCounters", + "memory": ".in_memory.InMemory", } HISTORY_IMPLEMENTATIONS = { diff --git a/swh/counters/in_memory.py b/swh/counters/in_memory.py new file mode 100644 --- /dev/null +++ b/swh/counters/in_memory.py @@ -0,0 +1,31 @@ +# Copyright (C) 2021 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from collections import defaultdict +from typing import Any, Dict, Iterable, List + + +class InMemory: + """InMemory implementation of the counters. + Naive implementation using a Dict[str, Set]""" + + def __init__(self): + self.counters = defaultdict(set) + + def check(self): + return "OK" + + def add(self, collection: str, keys: Iterable[Any]) -> None: + for value in keys: + self.counters[collection].add(value) + + def get_count(self, collection: str) -> int: + return len(self.counters.get(collection, [])) + + def get_counts(self, collections: List[str]) -> Dict[str, int]: + return {coll: self.get_count(coll) for coll in collections} + + def get_counters(self) -> Iterable[str]: + return list(self.counters.keys()) diff --git a/swh/counters/tests/test_init.py b/swh/counters/tests/test_init.py --- a/swh/counters/tests/test_init.py +++ b/swh/counters/tests/test_init.py @@ -10,12 +10,14 @@ from swh.counters import get_counters, get_history from swh.counters.api.client import RemoteCounters from swh.counters.history import History +from swh.counters.in_memory import InMemory from swh.counters.interface import CountersInterface from swh.counters.redis import Redis COUNTERS_IMPLEMENTATIONS = [ ("remote", RemoteCounters, {"url": "localhost"}), ("redis", Redis, {"host": "localhost"}), + ("memory", InMemory, {}), ] diff --git a/swh/counters/tests/test_inmemory.py b/swh/counters/tests/test_inmemory.py new file mode 100644 --- /dev/null +++ b/swh/counters/tests/test_inmemory.py @@ -0,0 +1,54 @@ +# Copyright (C) 2021 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from swh.counters.in_memory import InMemory + + +def test__inmemory__add(): + im = InMemory() + + im.add("counter1", ["val1"]) + im.add("counter2", ["val1"]) + im.add("counter1", [1]) + + assert im.get_count("counter1") == 2 + assert im.get_count("counter2") == 1 + assert im.get_count("inexisting") == 0 + + +def test__inmemory_getcounters(): + im = InMemory() + + assert len(im.get_counters()) == 0 + + counters = ["c1", "c2", "c3"] + + count = 0 + + for counter in counters: + im.add(counter, [1, 2]) + count += 1 + assert count == len(im.get_counters()) + + results = im.get_counters() + assert results == counters + + +def test__inmemory_getcounts(): + im = InMemory() + + expected = {"c1": 1, "c2": 2, "c3": 0} + + im.add("c1", ["v1"]) + im.add("c2", ["v1", "v2"]) + + result = im.get_counts(["c1", "c2", "c3"]) + assert result == expected + + +def test__inmemory_check(): + im = InMemory() + + assert im.check() == "OK"