diff --git a/composer.json b/composer.json
index 6424ead7122481cf61bc15cf284e0f0e27802bad..d1eaa936ecf6e450a33ebfdcba0a1ce5322147c2 100644
--- a/composer.json
+++ b/composer.json
@@ -44,7 +44,6 @@
         "jaimeperez/twig-configurable-i18n": "^1.2"
     },
     "require-dev": {
-        "ext-pdo_sqlite": "*",
         "phpunit/phpunit": "~4.8.35",
         "mikey179/vfsStream": "~1.6",
         "friendsofphp/php-cs-fixer": "^2.2"
diff --git a/tests/modules/core/lib/Storage/SQLPermanentStorageTest.php b/tests/modules/core/lib/Storage/SQLPermanentStorageTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8e1071050440000315d29522754401565964ed76
--- /dev/null
+++ b/tests/modules/core/lib/Storage/SQLPermanentStorageTest.php
@@ -0,0 +1,84 @@
+<?php
+
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Test for the SQLPermanentStorage class.
+ */
+class Test_Core_Storage_SQLPermanentStorage extends TestCase
+{
+    private static $sql;
+
+    public static function setUpBeforeClass()
+    {
+        // Create instance
+        $config = \SimpleSAML_Configuration::loadFromArray([
+            'datadir' => sys_get_temp_dir(),
+        ]);
+        self::$sql = new sspmod_core_Storage_SQLPermanentStorage('test', $config);
+    }
+
+    public static function tearDownAfterClass()
+    {
+        self::$sql = null;
+        unlink(sys_get_temp_dir().'/sqllite/test.sqlite');
+    }
+
+    public function testSet()
+    {
+        // Set a new value
+        self::$sql->set('testtype', 'testkey1', 'testkey2', 'testvalue', 0);
+
+        // Test getCondition
+        $result = self::$sql->get();
+        $this->assertEquals('testvalue', $result['value']);
+    }
+
+    public function testSetOverwrite()
+    {
+        // Overwrite existing value
+        self::$sql->set('testtype', 'testkey1', 'testkey2', 'testvaluemodified', 0);
+
+        // Test that the value was actually overwriten
+        $result = self::$sql->getValue('testtype', 'testkey1', 'testkey2');
+        $this->assertEquals('testvaluemodified', $result);
+
+        $result = self::$sql->getList('testtype', 'testkey1', 'testkey2');
+        $this->assertEquals('testvaluemodified', $result[0]['value']);
+    }
+
+    public function testNonexistentKey()
+    {
+        // Test that getting some non-existing key will return null
+        $result = self::$sql->getValue('testtype_nonexistent', 'testkey1_nonexistent', 'testkey2_nonexistent');
+        $this->assertNull($result);
+        $result = self::$sql->getList('testtype_nonexistent', 'testkey1_nonexistent', 'testkey2_nonexistent');
+        $this->assertNull($result);
+        $result = self::$sql->get('testtype_nonexistent', 'testkey1_nonexistent', 'testkey2_nonexistent');
+        $this->assertNull($result);
+    }
+
+    public function testExpiration()
+    {
+        // Make sure the earlier created entry has expired now
+        sleep(1);
+
+        // Now add a second entry that never expires
+        self::$sql->set('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring', 'testvalue_nonexpiring', null);
+
+        // Expire entries and verify that only the second one is left
+        self::$sql->removeExpired();
+        $result = self::$sql->getValue('testtype', 'testkey1', 'testkey2');
+        $this->assertNull($result);
+        $result = self::$sql->getValue('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring');
+        $this->assertEquals('testvalue_nonexpiring', $result);
+    }
+
+    public function testRemove()
+    {
+        // Now remove the nonexpiring entry and make sure it's gone
+        self::$sql->remove('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring');
+        $result = self::$sql->getValue('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring');
+        $this->assertNull($result);
+    }
+}