Minor refactoring of EventBridge utils, fix location of EVENTS_TMP_DIR
diff --git a/localstack/services/awslambda/lambda_api.py b/localstack/services/awslambda/lambda_api.py
index e54b9a703ac44..cffedb7ad748a 100644
--- a/localstack/services/awslambda/lambda_api.py
+++ b/localstack/services/awslambda/lambda_api.py
@@ -1083,9 +1083,7 @@ def generic_handler(*_):
     if not is_local_mount:
         # Lambda code must be uploaded in Zip format
         if not is_zip_file(zip_file_content):
-            raise ClientError(
-                "Uploaded Lambda code for runtime ({}) is not in Zip format".format(runtime)
-            )
+            raise ClientError(f"Uploaded Lambda code for runtime ({runtime}) is not in Zip format")
         # Unzip the Lambda archive contents
         unzip(tmp_file, lambda_cwd)
 
diff --git a/localstack/services/events/events_listener.py b/localstack/services/events/events_listener.py
index 8cb27dfcc41cb..6221de79d048d 100644
--- a/localstack/services/events/events_listener.py
+++ b/localstack/services/events/events_listener.py
@@ -3,6 +3,7 @@
 import os
 import re
 import time
+from typing import Dict, Set
 
 from localstack import config
 from localstack.constants import ENV_INTERNAL_TEST_RUN, MOTO_ACCOUNT_ID, TEST_AWS_ACCOUNT_ID
@@ -30,10 +31,13 @@
 
 
 class EventsBackend(RegionBackend):
+    # maps event bus name to set of event rules - TODO: check if still required, or available upstream?
+    event_rules: Dict[str, Set]
+    # maps rule name to job_id
+    rule_scheduled_jobs: Dict[str, str]
+
     def __init__(self):
-        # maps event bus name to set of event rules - TODO: check if still required, or available upstream?
         self.event_rules = {DEFAULT_EVENT_BUS_NAME: set()}
-        # maps rule to job_id
         self.rule_scheduled_jobs = {}
 
 
@@ -60,10 +64,8 @@ def _create_and_register_temp_dir():
 def _dump_events_to_files(events_with_added_uuid):
     current_time_millis = int(round(time.time() * 1000))
     for event in events_with_added_uuid:
-        save_file(
-            os.path.join(EVENTS_TMP_DIR, "%s_%s" % (current_time_millis, event["uuid"])),
-            json.dumps(event["event"]),
-        )
+        target = os.path.join(_get_events_tmp_dir(), "%s_%s" % (current_time_millis, event["uuid"]))
+        save_file(target, json.dumps(event["event"]))
 
 
 def _get_events_tmp_dir():
@@ -77,8 +79,9 @@ def func(*args, **kwargs):
         targets = client.list_targets_by_rule(Rule=rule_name)["Targets"]
         if targets:
             LOG.debug(
-                "Notifying %s targets in response to triggered Events rule %s"
-                % (len(targets), rule_name)
+                "Notifying %s targets in response to triggered Events rule %s",
+                len(targets),
+                rule_name,
             )
         for target in targets:
             arn = target.get("Arn")
@@ -115,7 +118,7 @@ def convert_schedule_to_cron(schedule):
     return schedule
 
 
-def handle_put_rule(data):
+def handle_put_rule(data: Dict):
     schedule = data.get("ScheduleExpression")
     enabled = data.get("State") != "DISABLED"
 
@@ -131,7 +134,7 @@ def handle_put_rule(data):
     return True
 
 
-def handle_delete_rule(rule_name):
+def handle_delete_rule(rule_name: str):
     rule_scheduled_jobs = EventsBackend.get().rule_scheduled_jobs
     job_id = rule_scheduled_jobs.get(rule_name)
     if job_id:
@@ -139,7 +142,7 @@ def handle_delete_rule(rule_name):
         JobScheduler.instance().cancel_job(job_id=job_id)
 
 
-def handle_disable_rule(rule_name):
+def handle_disable_rule(rule_name: str):
     rule_scheduled_jobs = EventsBackend.get().rule_scheduled_jobs
     job_id = rule_scheduled_jobs.get(rule_name)
     if job_id:
diff --git a/localstack/services/logs/logs_listener.py b/localstack/services/logs/logs_listener.py
index 3856694a5814d..42288dd7cf54e 100644
--- a/localstack/services/logs/logs_listener.py
+++ b/localstack/services/logs/logs_listener.py
@@ -58,9 +58,8 @@ def _fix_next_token_response(response):
 
 def publish_log_metrics_for_events(data):
     """Filter and publish log metrics for matching events"""
-    from moto.logs.models import (  # TODO: create separate RegionBackend class to store state
-        logs_backends,
-    )
+    # TODO: create separate RegionBackend class to store state
+    from moto.logs.models import logs_backends
 
     data = data if isinstance(data, dict) else json.loads(data)
     log_events = data.get("logEvents") or []
diff --git a/localstack/utils/testutil.py b/localstack/utils/testutil.py
index 8ff69114b2d73..f5ec4f5ad8577 100644
--- a/localstack/utils/testutil.py
+++ b/localstack/utils/testutil.py
@@ -444,7 +444,7 @@ def list_all_s3_objects():
 
 def delete_all_s3_objects(buckets):
     s3_client = aws_stack.connect_to_service("s3")
-    buckets = buckets if isinstance(buckets, list) else [buckets]
+    buckets = ensure_list(buckets)
     for bucket in buckets:
         keys = all_s3_object_keys(bucket)
         deletes = [{"Key": key} for key in keys]
@@ -576,19 +576,22 @@ def check_expected_lambda_log_events_length(expected_length, function_name, rege
     return events
 
 
+def list_all_log_events(log_group_name: str) -> List[Dict]:
+    logs = aws_stack.connect_to_service("logs")
+    return list_all_resources(
+        lambda kwargs: logs.filter_log_events(logGroupName=log_group_name, **kwargs),
+        last_token_attr_name="nextToken",
+        list_attr_name="events",
+    )
+
+
 def get_lambda_log_events(
     function_name, delay_time=DEFAULT_GET_LOG_EVENTS_DELAY, regex_filter: Optional[str] = None
 ):
-    def get_log_events(function_name, delay_time):
-        time.sleep(delay_time)
-
-        logs = aws_stack.connect_to_service("logs")
-        log_group_name = get_lambda_log_group_name(function_name)
-        return list_all_resources(
-            lambda kwargs: logs.filter_log_events(logGroupName=log_group_name, **kwargs),
-            last_token_attr_name="nextToken",
-            list_attr_name="events",
-        )
+    def get_log_events(func_name, delay):
+        time.sleep(delay)
+        log_group_name = get_lambda_log_group_name(func_name)
+        return list_all_log_events(log_group_name)
 
     try:
         events = get_log_events(function_name, delay_time)
diff --git a/tests/integration/test_events.py b/tests/integration/test_events.py
index 0f998ca084efb..1e92625bb7140 100644
--- a/tests/integration/test_events.py
+++ b/tests/integration/test_events.py
@@ -7,7 +7,7 @@
 
 from localstack import config
 from localstack.services.awslambda.lambda_utils import LAMBDA_RUNTIME_PYTHON36
-from localstack.services.events.events_listener import EVENTS_TMP_DIR
+from localstack.services.events.events_listener import _get_events_tmp_dir
 from localstack.services.generic_proxy import ProxyListener
 from localstack.services.infra import start_proxy
 from localstack.utils import testutil
@@ -88,13 +88,14 @@ def test_events_written_to_disk_are_timestamp_prefixed_for_chronological_orderin
                 ]
             )
 
+        events_tmp_dir = _get_events_tmp_dir()
         sorted_events_written_to_disk = map(
-            lambda filename: json.loads(str(load_file(os.path.join(EVENTS_TMP_DIR, filename)))),
-            sorted(os.listdir(EVENTS_TMP_DIR)),
+            lambda filename: json.loads(str(load_file(os.path.join(events_tmp_dir, filename)))),
+            sorted(os.listdir(events_tmp_dir)),
         )
         sorted_events = list(
             filter(
-                lambda event: event["DetailType"] == event_type,
+                lambda event: event.get("DetailType") == event_type,
                 sorted_events_written_to_disk,
             )
         )

* minor refactoring of EventBridge utils
* pull out `list_all_log_events()` util to make it reusable from other places
* fix location of `EVENTS_TMP_DIR` (was previously writing to CWD, instead of /tmp)