We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[plugin] Regression: Webhook Test Button
Somehow during transfer to the new plugin architecture, the webhook plugin's Test button has disappeared.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/sentry/api/endpoints/project_plugin_details.py`
Content:
```
1 from __future__ import absolute_import
2 
3 import six
4 
5 from django import forms
6 from django.core.urlresolvers import reverse
7 from rest_framework import serializers
8 from rest_framework.response import Response
9 
10 from sentry.exceptions import PluginError, PluginIdentityRequired
11 from sentry.plugins import plugins
12 from sentry.api.bases.project import ProjectEndpoint
13 from sentry.api.exceptions import ResourceDoesNotExist
14 from sentry.api.serializers import serialize
15 from sentry.api.serializers.models.plugin import (
16     PluginSerializer, PluginWithConfigSerializer, serialize_field
17 )
18 from sentry.signals import plugin_enabled
19 
20 ERR_ALWAYS_ENABLED = 'This plugin is always enabled.'
21 ERR_FIELD_REQUIRED = 'This field is required.'
22 
23 OK_UPDATED = 'Successfully updated configuration.'
24 
25 
26 class ProjectPluginDetailsEndpoint(ProjectEndpoint):
27     def _get_plugin(self, plugin_id):
28         try:
29             return plugins.get(plugin_id)
30         except KeyError:
31             raise ResourceDoesNotExist
32 
33     def get(self, request, project, plugin_id):
34         plugin = self._get_plugin(plugin_id)
35 
36         try:
37             context = serialize(plugin, request.user, PluginWithConfigSerializer(project))
38         except PluginIdentityRequired as e:
39             context = serialize(plugin, request.user, PluginSerializer(project))
40             context['config_error'] = e.message
41             context['auth_url'] = reverse('socialauth_associate', args=[plugin.slug])
42 
43         return Response(context)
44 
45     def post(self, request, project, plugin_id):
46         """
47         Enable plugin
48         """
49         plugin = self._get_plugin(plugin_id)
50 
51         if not plugin.can_disable:
52             return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)
53 
54         plugin.enable(project)
55 
56         return Response(status=201)
57 
58     def delete(self, request, project, plugin_id):
59         """
60         Disable plugin
61         """
62         plugin = self._get_plugin(plugin_id)
63 
64         if not plugin.can_disable:
65             return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)
66 
67         plugin.disable(project)
68 
69         return Response(status=204)
70 
71     def put(self, request, project, plugin_id):
72         plugin = self._get_plugin(plugin_id)
73 
74         config = [
75             serialize_field(project, plugin, c)
76             for c in plugin.get_config(
77                 project=project,
78                 user=request.user,
79             )
80         ]
81 
82         cleaned = {}
83         errors = {}
84         for field in config:
85             key = field['name']
86             value = request.DATA.get(key)
87 
88             if field.get('required') and not value:
89                 errors[key] = ERR_FIELD_REQUIRED
90 
91             try:
92                 value = plugin.validate_config_field(
93                     project=project,
94                     name=key,
95                     value=value,
96                     actor=request.user,
97                 )
98             except (forms.ValidationError, serializers.ValidationError, PluginError) as e:
99                 errors[key] = e.message
100 
101             if not errors.get(key):
102                 cleaned[key] = value
103 
104         if not errors:
105             try:
106                 cleaned = plugin.validate_config(
107                     project=project,
108                     config=cleaned,
109                     actor=request.user,
110                 )
111             except PluginError as e:
112                 errors['__all__'] = e.message
113 
114         if errors:
115             return Response(
116                 {
117                     'errors': errors,
118                 }, status=400
119             )
120 
121         for key, value in six.iteritems(cleaned):
122             if value is None:
123                 plugin.unset_option(
124                     project=project,
125                     key=key,
126                 )
127             else:
128                 plugin.set_option(
129                     project=project,
130                     key=key,
131                     value=value,
132                 )
133 
134         context = serialize(plugin, request.user, PluginWithConfigSerializer(project))
135 
136         plugin_enabled.send(plugin=plugin, project=project, user=request.user, sender=self)
137 
138         return Response(context)
139
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/sentry/api/endpoints/project_plugin_details.py b/src/sentry/api/endpoints/project_plugin_details.py
--- a/src/sentry/api/endpoints/project_plugin_details.py
+++ b/src/sentry/api/endpoints/project_plugin_details.py
@@ -1,11 +1,13 @@
 from __future__ import absolute_import
 
+import logging
 import six
 
 from django import forms
 from django.core.urlresolvers import reverse
 from rest_framework import serializers
 from rest_framework.response import Response
+from requests.exceptions import HTTPError
 
 from sentry.exceptions import PluginError, PluginIdentityRequired
 from sentry.plugins import plugins
@@ -44,10 +46,26 @@
 
     def post(self, request, project, plugin_id):
         """
-        Enable plugin
+        Enable plugin or Test plugin
         """
         plugin = self._get_plugin(plugin_id)
 
+        if request.DATA.get('test') and plugin.is_testable():
+            try:
+                test_results = plugin.test_configuration(project)
+            except Exception as exc:
+                if isinstance(exc, HTTPError):
+                    test_results = '%s\n%s' % (exc, exc.response.text[:256])
+                elif hasattr(exc, 'read') and callable(exc.read):
+                    test_results = '%s\n%s' % (exc, exc.read()[:256])
+                else:
+                    logging.exception('Plugin(%s) raised an error during test',
+                                      plugin_id)
+                    test_results = 'There was an internal error with the Plugin'
+            if not test_results:
+                test_results = 'No errors returned'
+            return Response({'detail': test_results}, status=200)
+
         if not plugin.can_disable:
             return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)

{"golden_diff": "diff --git a/src/sentry/api/endpoints/project_plugin_details.py b/src/sentry/api/endpoints/project_plugin_details.py\n--- a/src/sentry/api/endpoints/project_plugin_details.py\n+++ b/src/sentry/api/endpoints/project_plugin_details.py\n@@ -1,11 +1,13 @@\n from __future__ import absolute_import\n \n+import logging\n import six\n \n from django import forms\n from django.core.urlresolvers import reverse\n from rest_framework import serializers\n from rest_framework.response import Response\n+from requests.exceptions import HTTPError\n \n from sentry.exceptions import PluginError, PluginIdentityRequired\n from sentry.plugins import plugins\n@@ -44,10 +46,26 @@\n \n     def post(self, request, project, plugin_id):\n         \"\"\"\n-        Enable plugin\n+        Enable plugin or Test plugin\n         \"\"\"\n         plugin = self._get_plugin(plugin_id)\n \n+        if request.DATA.get('test') and plugin.is_testable():\n+            try:\n+                test_results = plugin.test_configuration(project)\n+            except Exception as exc:\n+                if isinstance(exc, HTTPError):\n+                    test_results = '%s\\n%s' % (exc, exc.response.text[:256])\n+                elif hasattr(exc, 'read') and callable(exc.read):\n+                    test_results = '%s\\n%s' % (exc, exc.read()[:256])\n+                else:\n+                    logging.exception('Plugin(%s) raised an error during test',\n+                                      plugin_id)\n+                    test_results = 'There was an internal error with the Plugin'\n+            if not test_results:\n+                test_results = 'No errors returned'\n+            return Response({'detail': test_results}, status=200)\n+\n         if not plugin.can_disable:\n             return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)\n", "issue": "[plugin] Regression: Webhook Test Button\nSomehow during transfer to the new plugin architecture, the webhook plugin's Test button has disappeared.\n", "before_files": [{"content": "from __future__ import absolute_import\n\nimport six\n\nfrom django import forms\nfrom django.core.urlresolvers import reverse\nfrom rest_framework import serializers\nfrom rest_framework.response import Response\n\nfrom sentry.exceptions import PluginError, PluginIdentityRequired\nfrom sentry.plugins import plugins\nfrom sentry.api.bases.project import ProjectEndpoint\nfrom sentry.api.exceptions import ResourceDoesNotExist\nfrom sentry.api.serializers import serialize\nfrom sentry.api.serializers.models.plugin import (\n    PluginSerializer, PluginWithConfigSerializer, serialize_field\n)\nfrom sentry.signals import plugin_enabled\n\nERR_ALWAYS_ENABLED = 'This plugin is always enabled.'\nERR_FIELD_REQUIRED = 'This field is required.'\n\nOK_UPDATED = 'Successfully updated configuration.'\n\n\nclass ProjectPluginDetailsEndpoint(ProjectEndpoint):\n    def _get_plugin(self, plugin_id):\n        try:\n            return plugins.get(plugin_id)\n        except KeyError:\n            raise ResourceDoesNotExist\n\n    def get(self, request, project, plugin_id):\n        plugin = self._get_plugin(plugin_id)\n\n        try:\n            context = serialize(plugin, request.user, PluginWithConfigSerializer(project))\n        except PluginIdentityRequired as e:\n            context = serialize(plugin, request.user, PluginSerializer(project))\n            context['config_error'] = e.message\n            context['auth_url'] = reverse('socialauth_associate', args=[plugin.slug])\n\n        return Response(context)\n\n    def post(self, request, project, plugin_id):\n        \"\"\"\n        Enable plugin\n        \"\"\"\n        plugin = self._get_plugin(plugin_id)\n\n        if not plugin.can_disable:\n            return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)\n\n        plugin.enable(project)\n\n        return Response(status=201)\n\n    def delete(self, request, project, plugin_id):\n        \"\"\"\n        Disable plugin\n        \"\"\"\n        plugin = self._get_plugin(plugin_id)\n\n        if not plugin.can_disable:\n            return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)\n\n        plugin.disable(project)\n\n        return Response(status=204)\n\n    def put(self, request, project, plugin_id):\n        plugin = self._get_plugin(plugin_id)\n\n        config = [\n            serialize_field(project, plugin, c)\n            for c in plugin.get_config(\n                project=project,\n                user=request.user,\n            )\n        ]\n\n        cleaned = {}\n        errors = {}\n        for field in config:\n            key = field['name']\n            value = request.DATA.get(key)\n\n            if field.get('required') and not value:\n                errors[key] = ERR_FIELD_REQUIRED\n\n            try:\n                value = plugin.validate_config_field(\n                    project=project,\n                    name=key,\n                    value=value,\n                    actor=request.user,\n                )\n            except (forms.ValidationError, serializers.ValidationError, PluginError) as e:\n                errors[key] = e.message\n\n            if not errors.get(key):\n                cleaned[key] = value\n\n        if not errors:\n            try:\n                cleaned = plugin.validate_config(\n                    project=project,\n                    config=cleaned,\n                    actor=request.user,\n                )\n            except PluginError as e:\n                errors['__all__'] = e.message\n\n        if errors:\n            return Response(\n                {\n                    'errors': errors,\n                }, status=400\n            )\n\n        for key, value in six.iteritems(cleaned):\n            if value is None:\n                plugin.unset_option(\n                    project=project,\n                    key=key,\n                )\n            else:\n                plugin.set_option(\n                    project=project,\n                    key=key,\n                    value=value,\n                )\n\n        context = serialize(plugin, request.user, PluginWithConfigSerializer(project))\n\n        plugin_enabled.send(plugin=plugin, project=project, user=request.user, sender=self)\n\n        return Response(context)\n", "path": "src/sentry/api/endpoints/project_plugin_details.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nimport logging\nimport six\n\nfrom django import forms\nfrom django.core.urlresolvers import reverse\nfrom rest_framework import serializers\nfrom rest_framework.response import Response\nfrom requests.exceptions import HTTPError\n\nfrom sentry.exceptions import PluginError, PluginIdentityRequired\nfrom sentry.plugins import plugins\nfrom sentry.api.bases.project import ProjectEndpoint\nfrom sentry.api.exceptions import ResourceDoesNotExist\nfrom sentry.api.serializers import serialize\nfrom sentry.api.serializers.models.plugin import (\n    PluginSerializer, PluginWithConfigSerializer, serialize_field\n)\nfrom sentry.signals import plugin_enabled\n\nERR_ALWAYS_ENABLED = 'This plugin is always enabled.'\nERR_FIELD_REQUIRED = 'This field is required.'\n\nOK_UPDATED = 'Successfully updated configuration.'\n\n\nclass ProjectPluginDetailsEndpoint(ProjectEndpoint):\n    def _get_plugin(self, plugin_id):\n        try:\n            return plugins.get(plugin_id)\n        except KeyError:\n            raise ResourceDoesNotExist\n\n    def get(self, request, project, plugin_id):\n        plugin = self._get_plugin(plugin_id)\n\n        try:\n            context = serialize(plugin, request.user, PluginWithConfigSerializer(project))\n        except PluginIdentityRequired as e:\n            context = serialize(plugin, request.user, PluginSerializer(project))\n            context['config_error'] = e.message\n            context['auth_url'] = reverse('socialauth_associate', args=[plugin.slug])\n\n        return Response(context)\n\n    def post(self, request, project, plugin_id):\n        \"\"\"\n        Enable plugin or Test plugin\n        \"\"\"\n        plugin = self._get_plugin(plugin_id)\n\n        if request.DATA.get('test') and plugin.is_testable():\n            try:\n                test_results = plugin.test_configuration(project)\n            except Exception as exc:\n                if isinstance(exc, HTTPError):\n                    test_results = '%s\\n%s' % (exc, exc.response.text[:256])\n                elif hasattr(exc, 'read') and callable(exc.read):\n                    test_results = '%s\\n%s' % (exc, exc.read()[:256])\n                else:\n                    logging.exception('Plugin(%s) raised an error during test',\n                                      plugin_id)\n                    test_results = 'There was an internal error with the Plugin'\n            if not test_results:\n                test_results = 'No errors returned'\n            return Response({'detail': test_results}, status=200)\n\n        if not plugin.can_disable:\n            return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)\n\n        plugin.enable(project)\n\n        return Response(status=201)\n\n    def delete(self, request, project, plugin_id):\n        \"\"\"\n        Disable plugin\n        \"\"\"\n        plugin = self._get_plugin(plugin_id)\n\n        if not plugin.can_disable:\n            return Response({'detail': ERR_ALWAYS_ENABLED}, status=400)\n\n        plugin.disable(project)\n\n        return Response(status=204)\n\n    def put(self, request, project, plugin_id):\n        plugin = self._get_plugin(plugin_id)\n\n        config = [\n            serialize_field(project, plugin, c)\n            for c in plugin.get_config(\n                project=project,\n                user=request.user,\n            )\n        ]\n\n        cleaned = {}\n        errors = {}\n        for field in config:\n            key = field['name']\n            value = request.DATA.get(key)\n\n            if field.get('required') and not value:\n                errors[key] = ERR_FIELD_REQUIRED\n\n            try:\n                value = plugin.validate_config_field(\n                    project=project,\n                    name=key,\n                    value=value,\n                    actor=request.user,\n                )\n            except (forms.ValidationError, serializers.ValidationError, PluginError) as e:\n                errors[key] = e.message\n\n            if not errors.get(key):\n                cleaned[key] = value\n\n        if not errors:\n            try:\n                cleaned = plugin.validate_config(\n                    project=project,\n                    config=cleaned,\n                    actor=request.user,\n                )\n            except PluginError as e:\n                errors['__all__'] = e.message\n\n        if errors:\n            return Response(\n                {\n                    'errors': errors,\n                }, status=400\n            )\n\n        for key, value in six.iteritems(cleaned):\n            if value is None:\n                plugin.unset_option(\n                    project=project,\n                    key=key,\n                )\n            else:\n                plugin.set_option(\n                    project=project,\n                    key=key,\n                    value=value,\n                )\n\n        context = serialize(plugin, request.user, PluginWithConfigSerializer(project))\n\n        plugin_enabled.send(plugin=plugin, project=project, user=request.user, sender=self)\n\n        return Response(context)\n", "path": "src/sentry/api/endpoints/project_plugin_details.py"}]}