Repository: mitmproxy/mitmproxy

Issue:
Addons: `running` is invoked twice.
##### Steps to reproduce the problem:

1. Write an addon that implements `running()`
2. Running is invoked twice on startup.

Addons: `running` is invoked twice.
##### Steps to reproduce the problem:

1. Write an addon that implements `running()`
2. Running is invoked twice on startup.



Discussion:
+1
👍 
+1
+1
👍 
+1

Resolving patch:
diff --git a/mitmproxy/addons/script.py b/mitmproxy/addons/script.py
--- a/mitmproxy/addons/script.py
+++ b/mitmproxy/addons/script.py
@@ -75,6 +75,7 @@ def __init__(self, path: str, reload: bool) -> None:
             path.strip("'\" ")
         )
         self.ns = None
+        self.is_running = False
 
         if not os.path.isfile(self.fullpath):
             raise exceptions.OptionsError('No such script')
@@ -85,6 +86,9 @@ def __init__(self, path: str, reload: bool) -> None:
         else:
             self.loadscript()
 
+    def running(self):
+        self.is_running = True
+
     def done(self):
         if self.reloadtask:
             self.reloadtask.cancel()
@@ -105,7 +109,8 @@ def loadscript(self):
         if self.ns:
             # We're already running, so we have to explicitly register and
             # configure the addon
-            ctx.master.addons.invoke_addon(self.ns, hooks.RunningHook())
+            if self.is_running:
+                ctx.master.addons.invoke_addon(self.ns, hooks.RunningHook())
             try:
                 ctx.master.addons.invoke_addon(
                     self.ns,


Test patch:
diff --git a/test/mitmproxy/addons/test_script.py b/test/mitmproxy/addons/test_script.py
--- a/test/mitmproxy/addons/test_script.py
+++ b/test/mitmproxy/addons/test_script.py
@@ -1,5 +1,6 @@
 import asyncio
 import os
+import re
 import sys
 import traceback
 
@@ -11,6 +12,7 @@
 from mitmproxy.proxy.layers.http import HttpRequestHook
 from mitmproxy.test import taddons
 from mitmproxy.test import tflow
+from mitmproxy.tools import main
 
 
 # We want this to be speedy for testing
@@ -90,7 +92,7 @@ async def test_simple(self, tdata):
         )
         with taddons.context(sc) as tctx:
             tctx.configure(sc)
-            await tctx.master.await_log("recorder running")
+            await tctx.master.await_log("recorder configure")
             rec = tctx.master.addons.get("recorder")
 
             assert rec.call_log[0][0:2] == ("recorder", "load")
@@ -128,7 +130,7 @@ async def test_exception(self, tdata):
                 True,
             )
             tctx.master.addons.add(sc)
-            await tctx.master.await_log("error running")
+            await tctx.master.await_log("error load")
             tctx.configure(sc)
 
             f = tflow.tflow(resp=True)
@@ -331,3 +333,21 @@ async def test_order(self, tdata):
                 'e running',
                 'e configure',
             ]
+
+
+def test_order(event_loop, tdata, capsys):
+    """Integration test: Make sure that the runtime hooks are triggered on startup in the correct order."""
+    asyncio.set_event_loop(event_loop)
+    main.mitmdump([
+        "-n",
+        "-s", tdata.path("mitmproxy/data/addonscripts/recorder/recorder.py"),
+        "-s", tdata.path("mitmproxy/data/addonscripts/shutdown.py"),
+    ])
+    assert re.match(
+        r"Loading script.+recorder.py\n"
+        r"\('recorder', 'load', .+\n"
+        r"\('recorder', 'configure', .+\n"
+        r"Loading script.+shutdown.py\n"
+        r"\('recorder', 'running', .+\n$",
+        capsys.readouterr().out,
+    )
diff --git a/test/mitmproxy/data/addonscripts/error.py b/test/mitmproxy/data/addonscripts/error.py
--- a/test/mitmproxy/data/addonscripts/error.py
+++ b/test/mitmproxy/data/addonscripts/error.py
@@ -1,8 +1,8 @@
 from mitmproxy import ctx
 
 
-def running():
-    ctx.log.info("error running")
+def load(loader):
+    ctx.log.info("error load")
 
 
 def request(flow):