From c8fee5f6c8a0d9e6fe7454d695c79c70f72cd6b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl>
Date: Mon, 14 Dec 2020 20:00:16 +0100
Subject: [PATCH] add unit tests for varlen series

---
 README.md              |  3 +++
 tempsdb/database.pxd   |  2 ++
 tempsdb/database.pyx   | 53 +++++++++++++++++++++++++++++++++++++++---
 tests/test_database.py | 17 ++++++++++++++
 4 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 26ff1b1..c53e60e 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,9 @@ Then copy your resulting wheel and install it via pip on the target system.
   emit a warning if the user forgot to
 * if page_size is default, it won't be written as part of the metadata
 * added support for per-series metadata
+* following additions to `Database`:
+    * `delete_series`
+    * `delete_varlen_series`
 * following additions to `TimeSeries`:
     * added `append_padded`
     * added metadata support, `metadata` property and `set_metadata` call
diff --git a/tempsdb/database.pxd b/tempsdb/database.pxd
index c729f44..c3dda7a 100644
--- a/tempsdb/database.pxd
+++ b/tempsdb/database.pxd
@@ -25,6 +25,8 @@ cdef class Database:
                                             int size_struct,
                                             unsigned long entries_per_chunk,
                                             int gzip_level=*)
+    cpdef int delete_series(self, str name) except -1
+    cpdef int delete_varlen_series(self, str name) except -1
     cpdef list get_open_series(self)
     cpdef list get_all_series(self)
     cpdef int close_all_open_series(self) except -1
diff --git a/tempsdb/database.pyx b/tempsdb/database.pyx
index 2d54421..5ddaaf4 100644
--- a/tempsdb/database.pyx
+++ b/tempsdb/database.pyx
@@ -1,10 +1,11 @@
 import os
+import shutil
 import threading
 import warnings
 
 from satella.coding import DictDeleter
 
-from tempsdb.exceptions import DoesNotExist, AlreadyExists
+from tempsdb.exceptions import DoesNotExist, AlreadyExists, StillOpen
 from .series cimport TimeSeries, create_series
 from .varlen cimport VarlenSeries, create_varlen_series
 
@@ -53,6 +54,47 @@ cdef class Database:
                         output.append(series)
         return output
 
+    cpdef int delete_series(self, str name) except -1:
+        """
+        Deletes a constant-length time series
+        
+        :param name: name of series to delete
+        :raises ValueError: tried to delete "varlen" series
+        :raises StillOpen: series is open
+        """
+        if name == 'varlen':
+            raise ValueError('tried to delete varlen series')
+        if not os.path.exists(os.path.join(self.path, name)):
+            raise DoesNotExist('series does not exist')
+        cdef TimeSeries series
+        with self.lock:
+            if name in self.open_series:
+                series = self.open_series[name]
+                if not series.closed:
+                    raise StillOpen('series is open!')
+            shutil.rmtree(os.path.join(self.path, name))
+            return 0
+
+    cpdef int delete_varlen_series(self, str name) except -1:
+        """
+        Deletes a variable-length time series
+        
+        :param name: name of series to delete
+        :raises DoesNotExist: series does not exist
+        :raises StillOpen: series is open
+        """
+        cdef str path = os.path.join(self.path, 'varlen', name)
+        if not os.path.exists(path):
+            raise DoesNotExist('series does not exist')
+        cdef VarlenSeries series
+        with self.lock:
+            if name in self.open_varlen_series:
+                series = self.open_varlen_series[name]
+                if not series.closed:
+                    raise StillOpen('series is open!')
+            shutil.rmtree(path)
+            return 0
+
     cpdef TimeSeries get_series(self, name: str, bint use_descriptor_based_access = False):
         """
         Load and return an existing series
@@ -207,7 +249,9 @@ cdef class Database:
                                    bint use_descriptor_based_access=False,
                                    int gzip_level=0):
         """
-        Create a new series
+        Create a new series.
+        
+        Note that series cannot be named "varlen"
         
         :param name: name of the series
         :param block_size: size of the data field
@@ -217,11 +261,14 @@ cdef class Database:
             Default is False
         :param gzip_level: gzip compression level. Default is 0 which means "don't use gzip"
         :return: new series
-        :raises ValueError: block size was larger than page_size plus a timestamp
+        :raises ValueError: block size was larger than page_size plus a timestamp or series was named 
+            "varlen"
         :raises AlreadyExists: series with given name already exists
         """
         if block_size > page_size + 8:
             raise ValueError('Invalid block size, pick larger page')
+        if name == 'varlen':
+            raise ValueError('Series cannot be named varlen')
         if os.path.isdir(os.path.join(self.path, name)):
             raise AlreadyExists('Series already exists')
         if gzip_level:
diff --git a/tests/test_database.py b/tests/test_database.py
index 15cb59e..2d1686d 100644
--- a/tests/test_database.py
+++ b/tests/test_database.py
@@ -1,6 +1,7 @@
 import unittest
 
 from tempsdb.database import create_database
+from tempsdb.exceptions import DoesNotExist
 
 
 class TestDatabase(unittest.TestCase):
@@ -18,6 +19,22 @@ class TestDatabase(unittest.TestCase):
         self.assertEqual(ser.last_entry_ts, 20)
         ser.close()
 
+        self.db.delete_series('hello-world')
+        self.assertRaises(DoesNotExist, lambda: self.db.get_series('hello-world'))
+
+    def test_add_varlen_series(self):
+        ser = self.db.create_varlen_series('hello-world', [10, 20], 1, 20)
+        ser.append(10, b'\x00')
+        ser.append(20, b'\x00\x00\x00')
+        ser.close()
+
+        ser = self.db.get_varlen_series('hello-world')
+        self.assertEqual(ser.last_entry_ts, 20)
+        ser.close()
+
+        self.db.delete_varlen_series('hello-world')
+        self.assertRaises(DoesNotExist, lambda: self.db.get_varlen_series('hello-world'))
+
     @classmethod
     def tearDownClass(cls) -> None:
         cls.db.close()
-- 
GitLab