From 36644243f61aeb80b13d3dae4a1bff91400db880 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Mon, 6 Jan 2020 13:01:55 -0500
Subject: [PATCH] Clean up at stop service time

---
 src/_zkapauthorizer/lease_maintenance.py      |  7 ++++-
 .../tests/test_lease_maintenance.py           | 30 +++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/src/_zkapauthorizer/lease_maintenance.py b/src/_zkapauthorizer/lease_maintenance.py
index 2f40458..e7e0bb3 100644
--- a/src/_zkapauthorizer/lease_maintenance.py
+++ b/src/_zkapauthorizer/lease_maintenance.py
@@ -260,11 +260,16 @@ class _FuzzyTimerService(Service):
 
     def startService(self):
         Service.startService(self)
-        self.reactor.callLater(
+        self._call = self.reactor.callLater(
             self.initial_interval.total_seconds(),
             self._iterate,
         )
 
+    def stopService(self):
+        self._call.cancel()
+        self._call = None
+        return Service.stopService(self)
+
     def _iterate(self):
         """
         Run the operation once and then schedule it to run again.
diff --git a/src/_zkapauthorizer/tests/test_lease_maintenance.py b/src/_zkapauthorizer/tests/test_lease_maintenance.py
index 5edf640..add7d18 100644
--- a/src/_zkapauthorizer/tests/test_lease_maintenance.py
+++ b/src/_zkapauthorizer/tests/test_lease_maintenance.py
@@ -32,6 +32,7 @@ from testtools import (
     TestCase,
 )
 from testtools.matchers import (
+    Is,
     Equals,
     Always,
     HasLength,
@@ -69,6 +70,7 @@ from twisted.internet.task import (
 )
 from twisted.internet.defer import (
     succeed,
+    maybeDeferred,
 )
 from twisted.application.service import (
     IService,
@@ -307,6 +309,34 @@ class LeaseMaintenanceServiceTests(TestCase):
             between(low, high),
         )
 
+    @given(
+        randoms(),
+        clocks(),
+    )
+    def test_clean_up_when_stopped(self, random, clock):
+        """
+        When the service is stopped, the delayed call in the reactor is removed.
+        """
+        service = lease_maintenance_service(
+            lambda: None,
+            clock,
+            FilePath(self.useFixture(TempDir()).join(u"last-run")),
+            random,
+        )
+        service.startService()
+        self.assertThat(
+            maybeDeferred(service.stopService),
+            succeeded(Is(None)),
+        )
+        self.assertThat(
+            clock.getDelayedCalls(),
+            Equals([]),
+        )
+        self.assertThat(
+            service.running,
+            Equals(False),
+        )
+
     @given(
         randoms(),
         clocks(),
-- 
GitLab