Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(730)

Side by Side Diff: testing/legion/lib/event_server.py

Issue 1585373003: Adding a cross-task eventing server. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing a return code for one of the server use cases. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """A server to allow events to be passed from one task to another.
6
7 This server supports getting, setting, and deleting of arbitrary event names.
8 This is a "pull" style of server, so its on the producer and consumer to
9 proactively get, set, and delete the events.
10
11
12 Operation | Url | Action
13 -------------------------------------------------------------------------------
14 GET | /events/<NAME> | Returns 200 for an event that is set.
15 | | Returns 404 for an event that is not set
16 -------------------------------------------------------------------------------
17 PUT | /events/<NAME> | Sets the event and returns 200.
M-A Ruel 2016/01/15 14:07:13 You test for POST, not PUT.
Mike Meade 2016/01/18 20:25:51 Done.
18 -------------------------------------------------------------------------------
19 DELETE | /events/<NAME> | Deletes the event and returns 200.
20 -------------------------------------------------------------------------------
21
22 Errors
23 Error | Action | Reason
24 -------------------------------------------------------------------------------
25 403 | GET | Category is not specified
26 -------------------------------------------------------------------------------
27 404 | GET | Event doesn't exist or isn't set
28 -------------------------------------------------------------------------------
29 501 | All | Incorrect URL format (must be events/<NAME>)
30 -------------------------------------------------------------------------------
31 """
32
33 import BaseHTTPServer
34 import httplib
35 import re
36 import SimpleHTTPServer
37 import SocketServer
38 import threading
39
40 from legion.lib import common_lib
41
42
43 class ThreadedServer(SocketServer.ThreadingMixIn,
44 BaseHTTPServer.HTTPServer):
45 """An extension of the HTTPServer class which handles requests in threads."""
46
47 def __init__(self, address=''):
48 self._port = common_lib.GetUnusedPort()
49 self._address = address
50 BaseHTTPServer.HTTPServer.__init__(self,
51 (self._address, self._port),
52 HttpRequestHandler)
53
54 @property
55 def port(self):
56 return self._port
57
58 @property
59 def address(self):
60 return self._address
61
62 def start(self):
63 """Starts the server in another thread.
64
65 The thread will stay active until shutdown() is called. There is no reason
66 to hold a reference to the thread object.
67 """
68 threading.Thread(target=self.serve_forever).start()
69
70
71 class EventHandler(object):
72 """Handles event set/get/delete operations."""
73
74 _REGEX = re.compile('^/events/(?P<name>[a-zA-Z0-9]*)')
75 _events = {}
76 _event_lock = threading.Lock()
77
78 def _GetName(self, request):
79 """Gets the event name from the URL."""
80 match = self._REGEX.match(request.path)
81 if not match:
82 return None
83 return match.group('name')
84
85
86 def do_GET(self, request):
87 """Handles GET requests."""
88 name = self._GetName(request)
89 if not name:
90 return request.send_error(501, 'Event name required')
91 with self._event_lock:
92 if name not in self._events:
93 return request.send_error(404, 'Event: %s not found' % name)
94 else:
95 return request.send_response(200)
96
97 def do_POST(self, request):
98 """Handles POST requests."""
99 name = self._GetName(request)
100 if not name:
101 return request.send_error(501, 'Event name required')
102 with self._event_lock:
103 self._events[name] = 1
104 return request.send_response(200)
105
106 def do_DELETE(self, request):
107 """Handles DELETE requests."""
108 name = self._GetName(request)
109 if not name:
110 return request.send_error(501, 'Event name required')
111 with self._event_lock:
112 if name in self._events:
113 del self._events[name]
114 return request.send_response(200)
115 else:
116 return request.send_error(404, 'Event not found')
117
118
119 class HttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
120 """Request handler which dispatches requests to the correct subhandler.
121
122 To extend this functionality implement a class that handles do_GET, do_POST,
123 and do_DELETE methods, then add the name/class to the _HANDLERS dict.
124 """
125
126 _REGEX = re.compile('/(?P<category>[a-zA-Z0-9]*)')
127
128 _HANDLERS = {
129 'events': EventHandler,
130 }
131
132 def log_message(self, *args, **kwargs):
133 """Silence those pesky server-side print statements."""
134 pass
135
136 def _GetCategoryName(self):
137 """Extracts and returns the category name."""
138 match = self._REGEX.match(self.path)
139 if not match:
140 return
141 return match.group('category')
142
143 def _GetHandler(self):
144 """Returns the category handler object if it exists."""
145 category = self._GetCategoryName()
146 if not category:
147 return self.send_error(403, 'Category must be supplied')
148 handler = self._HANDLERS.get(category)
149 if not handler:
150 return self.send_error(501, '/%s is not supported' % category)
151 return handler()
152
153 def do_GET(self):
154 """Handles GET requests."""
155 handler = self._GetHandler()
156 if handler:
157 handler.do_GET(self)
158
159 def do_POST(self):
160 """Handles POST requests."""
161 handler = self._GetHandler()
162 if handler:
163 handler.do_POST(self)
164
165 def do_DELETE(self):
166 """Handles DELETE requests."""
167 handler = self._GetHandler()
168 if handler:
169 handler.do_DELETE(self)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698