diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:09 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:29:09 -0800 |
| commit | 52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98 (patch) | |
| tree | 2eb01432fa3da41550dd622d29fb672509122b51 /tools/axl | |
| parent | d4aee0c0caa00aa02d4c50ed28151591ac0456b5 (diff) | |
| download | android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.tar.gz android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.tar.bz2 android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.zip | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'tools/axl')
| -rw-r--r-- | tools/axl/README.txt | 3 | ||||
| -rwxr-xr-x | tools/axl/axl.py | 253 | ||||
| -rwxr-xr-x | tools/axl/chewie.py | 184 | ||||
| -rwxr-xr-x | tools/axl/chewperf.py | 87 | ||||
| -rw-r--r-- | tools/axl/log.py | 55 | ||||
| -rw-r--r-- | tools/axl/random.dat | bin | 0 -> 1480 bytes | |||
| -rw-r--r-- | tools/axl/singletonmixin.py | 220 | ||||
| -rw-r--r-- | tools/axl/stfu.jpg | bin | 0 -> 943 bytes | |||
| -rwxr-xr-x | tools/axl/udpEater.py | 45 | ||||
| -rwxr-xr-x | tools/axl/udpServer.py | 29 |
10 files changed, 876 insertions, 0 deletions
diff --git a/tools/axl/README.txt b/tools/axl/README.txt new file mode 100644 index 000000000..36f6811a6 --- /dev/null +++ b/tools/axl/README.txt @@ -0,0 +1,3 @@ +TCP and HTTP tests + +axl: hostile web server. diff --git a/tools/axl/axl.py b/tools/axl/axl.py new file mode 100755 index 000000000..f7b541083 --- /dev/null +++ b/tools/axl/axl.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python + +# +# Copyright 2007, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" + axl.py: HTTP Client torture tester + +""" + +import sys, time + +from twisted.internet import protocol, reactor, defer +from twisted.internet.protocol import ServerFactory, Protocol + +import singletonmixin, log + +class BaseProtocol(Protocol): + def __init__(self): + self.log = log.Log.getInstance() + + def write(self, data): + self.log("BaseProtocol.write()", len(data), data) + return self.transport.write(data) + + def dataReceived(self, data): + self.log("BaseProtocol.dataReceived()", len(data), data) + + def connectionMade(self): + self.log("BaseProtocol.connectionMade()") + self.transport.setTcpNoDelay(1) # send immediately + + def connectionLost(self, reason): + self.log("BaseProtocol.connectionLost():", reason) + + def sendResponse(self, response): + self.write("HTTP/1.1 200 OK\r\n") + self.write("Content-Length: %d\r\n\r\n" % len(response)) + if len(response) > 0: + self.write(response) + + +# Tests +# 8000: test driven by resource request + +class Drop(BaseProtocol): + """Drops connection immediately after connect""" + PORT = 8001 + def connectionMade(self): + BaseProtocol.connectionMade(self) + self.transport.loseConnection() + +class ReadAndDrop(BaseProtocol): + """Read 1st line of request, then drop connection""" + PORT = 8002 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.transport.loseConnection() + +class GarbageStatus(BaseProtocol): + """Send garbage statusline""" + PORT = 8003 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("welcome to the jungle baby\r\n") + +class BadHeader(BaseProtocol): + """Drop connection after a header is half-sent""" + PORT = 8004 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 200 OK\r\n") + self.write("Cache-Contr") + time.sleep(1) + self.transport.loseConnection() + +class PauseHeader(BaseProtocol): + """Pause for a second in middle of a header""" + PORT = 8005 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 200 OK\r\n") + self.write("Cache-Contr") + time.sleep(1) + self.write("ol: private\r\n\r\nwe've got fun and games") + time.sleep(1) + self.transport.loseConnection() + +class Redirect(BaseProtocol): + PORT = 8006 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 302 Moved Temporarily\r\n") + self.write("Content-Length: 0\r\n") + self.write("Location: http://shopping.yahoo.com/p:Canon PowerShot SD630 Digital Camera:1993588104;_ylc=X3oDMTFhZXNmcjFjBF9TAzI3MTYxNDkEc2VjA2ZwLXB1bHNlBHNsawNyc3NfcHVsc2U0LmluYw--\r\n\r\n") + self.transport.loseConnection() + +class DataDrop(BaseProtocol): + """Drop connection in body""" + PORT = 8007 + def dataReceived(self, data): + if data.find("favico") >= 0: + self.write("HTTP/1.1 404 Not Found\r\n\r\n") + self.transport.loseConnection() + return + + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 200 OK\r\n") +# self.write("Content-Length: 100\r\n\r\n") + self.write("\r\n") +# self.write("Data cuts off < 100 here!") +# time.sleep(4) + self.transport.loseConnection() + +class DropOnce(BaseProtocol): + """Drop every other connection""" + PORT = 8008 + COUNT = 0 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 200 OK\r\n") + self.write("Content-Length: 5\r\n\r\n") + + if (not(DropOnce.COUNT & 1)): + self.write("HE") + else: + self.write("HELLO") + self.transport.loseConnection() + + DropOnce.COUNT += 1 + +class NoCR(BaseProtocol): + """Send headers without carriage returns""" + PORT = 8009 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 200 OK\n") + self.write("Content-Length: 5\n\n") + + self.write("HELLO") + self.transport.loseConnection() + +class PipeDrop(BaseProtocol): + PORT = 8010 + COUNT = 0 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + if not PipeDrop.COUNT % 3: + self.write("HTTP/1.1 200 OK\n") + self.write("Content-Length: 943\n\n") + + self.write(open("./stfu.jpg").read()) + PipeDrop.COUNT += 1 + + else: + self.transport.loseConnection() + PipeDrop.COUNT += 1 + +class RedirectLoop(BaseProtocol): + """Redirect back to same resource""" + PORT = 8011 + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.write("HTTP/1.1 302 Moved Temporarily\r\n") + self.write("Content-Length: 0\r\n") + self.write("Location: http://localhost:8011/\r\n") + self.write("\r\n") + self.transport.loseConnection() + +class ReadAll(BaseProtocol): + """Read entire request""" + PORT = 8012 + + def connectionMade(self): + self.count = 0 + + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + self.count += len(data) + if self.count == 190890: + self.transport.loseConnection() + +class Timeout(BaseProtocol): + """Timout sending body""" + PORT = 8013 + + def connectionMade(self): + self.count = 0 + + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + if self.count == 0: self.write("HTTP/1.1 200 OK\r\n\r\n") + self.count += 1 + +class SlowResponse(BaseProtocol): + """Ensure client does not time out on slow writes""" + PORT = 8014 + + def connectionMade(self): + self.count = 0 + + def dataReceived(self, data): + BaseProtocol.dataReceived(self, data) + if self.count == 0: self.write("HTTP/1.1 200 OK\r\n\r\n") + self.sendPack(0) + + def sendPack(self, count): + if count > 10: + self.transport.loseConnection() + + self.write("all work and no play makes jack a dull boy %s\n" % count) + d = defer.Deferred() + d.addCallback(self.sendPack) + reactor.callLater(15, d.callback, count + 1) + + +# HTTP/1.1 200 OK +# Cache-Control: private +# Content-Type: text/html +# Set-Cookie: PREF=ID=10644de62c423aa5:TM=1155044293:LM=1155044293:S=0lHtymefQRs2j7nD; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com +# Server: GWS/2.1 +# Transfer-Encoding: chunked +# Date: Tue, 08 Aug 2006 13:38:13 GMT + +def main(): + # Initialize log + log.Log.getInstance(sys.stdout) + + for protocol in Drop, ReadAndDrop, GarbageStatus, BadHeader, PauseHeader, \ + Redirect, DataDrop, DropOnce, NoCR, PipeDrop, RedirectLoop, ReadAll, \ + Timeout, SlowResponse: + factory = ServerFactory() + factory.protocol = protocol + reactor.listenTCP(protocol.PORT, factory) + + + reactor.run() + +if __name__ == '__main__': + main() diff --git a/tools/axl/chewie.py b/tools/axl/chewie.py new file mode 100755 index 000000000..7ed2ba6f3 --- /dev/null +++ b/tools/axl/chewie.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +## +## chewie.py +## chews browser http log. draws graph of connections +## Be sure there is only one pageload in the log. +## +## you'll want to +## sudo apt-get install python-matplotlib +## before running this +## + +import sys, pylab + +# can't just use a dict, because there can be dups +class Queue: + def __init__(self): + self.queue = [] + + def add(self, url, time): + self.queue.append([url, time]) + + def get(self, url): + for x in range(len(self.queue)): + rec = self.queue[x] + if rec[0] == url: + del self.queue[x] + return rec[1] + +## pull out request lag -- queue to start to done +def lag(): + + font = {'color': '#909090', 'fontsize': 6} + extractMe = { + 'RequestQueue.queueRequest': "Q", + 'Connection.openHttpConnection()': "O", + 'Request.sendRequest()': "S", + 'Request.requestSent()': "T", + 'processRequests()': 'R', + 'Request.readResponse():': "D", # done + 'clearPipe()': 'U', # unqueue + 'Request.readResponse()': 'B', # read data block + 'Request.readResponseStatus():': 'HR', # read http response line + 'hdr': 'H', # http header + } + keys = extractMe.keys() + + f = open(sys.argv[1], "r") + + t0 = None + + # thread, queued, opened, send, sent, reading, read, uri, server, y + # 0 1 2 3 4 5 6 7 8 9 + vals = [] + + queued = Queue() + opened = {"http0": None, + "http1": None, + "http2": None, + "http3": None, + "http4": None, + "http5": None} + active = {"http0": [], + "http1": [], + "http2": [], + "http3": [], + "http4": [], + "http5": []} + connectionCount = 0 + byteCount = 0 + killed = [[], []] + + while (True): + line = f.readline() + if len(line) == 0: break + + splitup = line.split() + + # http only + if splitup[0] != "V/http": continue + + x = splitup[3:] + + # filter to named lines + if x[2] not in keys: continue + x[2] = extractMe[x[2]] + + # normalize time + if t0 == None: t0 = int(x[0]) + x[0] = int(x[0]) - t0 + + thread, action = x[1], x[2] + if action == "Q": + time, url = x[0], x[3] + queued.add(url, time) + elif action == "O": + # save opened time and server for this thread, so we can stuff it in l8r + time, thread, host = x[0], x[1], x[4] + opened[thread] = [time, host, connectionCount] + connectionCount += 1 + elif action == "S": + time, thread, url = x[0], x[1], x[3] + opentime, host, connection = opened[thread] + qtime = queued.get(url) + record = [thread, qtime, opentime, time, None, None, None, url, host, connection] + active[thread].append(record) + elif action == "T": + time, thread = x[0], x[1] + record = active[thread][-1] + record[4] = time + elif action == "R": + print x + if x[3] in ["sleep", "no", "wait"]: continue + time, thread, = x[0], x[1] + record = active[thread][0] + record[5] = time + elif action == 'U': + thread = x[1] + record = active[thread][0] + killed[0].append(record[9]) + killed[1].append(x[0]) + queued.add(record[7], record[1]) + del active[thread][0] + elif action == "D": + time, thread = x[0], x[1] + record = active[thread][0] + record[6] = time + vals.append(record) + del active[thread][0] + print record + # print record[3] / 1000, record[6] / 1000, record[7] + elif action == "B": + byteCount += int(x[3]) + elif action == "HR": + byteCount += int(x[2]) + + f.close() + + rng = range(connectionCount) + + opened = [] + drawn = [False for x in rng] + for val in vals: + y= val[9] + if not drawn[y]: + drawn[y] = True + opened.append(val[2]) + pylab.text(0, y - 0.25, "%s %s %s" % (val[9], val[0][4], val[8]), font) + + # define limits + # pylab.plot([vals[-1][6]], rng) + + print opened, rng + pylab.plot(opened, rng, 'ro') + pylab.plot(killed[1], killed[0], 'rx') + + for val in vals: + thread, queued, opened, send, sent, reading, read, uri, server, y = val + # send arrow + arrow = pylab.Arrow(send, y, sent - send, 0) + arrow.set_facecolor("g") + ax = pylab.gca() + ax.add_patch(arrow) + # read arrow + arrow = pylab.Arrow(reading, y, read - reading, 0) + arrow.set_facecolor("r") + ax = pylab.gca() + ax.add_patch(arrow) + + caption = \ + "\nrequests: %s\n" % len(vals) + \ + "byteCount: %s\n" % byteCount + \ + "data rate: %s\n" % (1000 * byteCount / vals[-1][6])+ \ + "connections: %s\n" % connectionCount + + pylab.figtext(0.82, 0.30, caption, bbox=dict(facecolor='lightgrey', alpha=0.5)) + + # print lines, [[x, x] for x in range(len(vals))] + # pylab.plot(lines, [[x, x] for x in range(len(vals))], 'r-') + + pylab.grid() + pylab.show() + +if __name__ == '__main__': lag() diff --git a/tools/axl/chewperf.py b/tools/axl/chewperf.py new file mode 100755 index 000000000..582bdb5ac --- /dev/null +++ b/tools/axl/chewperf.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +""" + chewperf.py: Chew an http perf log + bucketize + +""" + +import sys, time + +def resets(): + f = open(sys.argv[1]).read() + rawLines = f.split('\n') + + times = [] + for x in range(len(rawLines)): + line = rawLines[x].split() + try: + if line[-1] == "SIGNAL_STRENGTH": + ts = int(rawLines[x - 1].split()[-1]) + times.append(ts) + except: + pass + + return times + +def augment(): + f = open(sys.argv[1]).read() + rawLines = f.split('\r\n') + + out = [] + t0 = None + last = 0 + for line in rawLines: + if "Pulled" in line: + chewed = [int(line.split()[5]), int(line.split()[7])] + if not t0: t0 = chewed[1] + tm = chewed[1] - t0 + out.append("%s %d" % (line, (tm - last))) + last = tm + else: + out.append(line) + print "\n".join(out) + +def chew(): + f = open(sys.argv[1]).read() + rawLines = f.split('\n') + lines = [x for x in rawLines if "Pulled" in x] + + sidx = lines[0].split().index("Pulled") + print "sidx", sidx + chewed = [[int(x.split()[sidx + 2]), int(x.split()[sidx + 4])] for x in lines] + + t0 = chewed[0][1] + tLast = chewed[-1][1] + chewed = [[x[1] - t0, x[0]] for x in chewed] + + totalTime = tLast - t0 + bytes = sum(x[1] for x in chewed) + print "total time", totalTime, "bytes", bytes, "rate", bytes * 1000 / totalTime + + buckets = {} + for x in chewed: + bucket = x[0] / 1000 + bytes = x[1] + if bucket in buckets: + buckets[bucket] += bytes + else: + buckets[bucket] = bytes + + top = max(buckets.keys()) + for x in range(top): + if x not in buckets.keys(): + buckets[x] = 0 + + # smooth + window = [0 for x in range(5)] + + for x in range(len(buckets.items())): + window[x % len(window)] = buckets.items()[x][1] + print "%s\t%s" % (buckets.items()[x][0], sum(window) / len(window)) + +def main(): + chew() + +if __name__ == '__main__': + main() diff --git a/tools/axl/log.py b/tools/axl/log.py new file mode 100644 index 000000000..7543270b1 --- /dev/null +++ b/tools/axl/log.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# +# Copyright 2007, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import time, sys +import singletonmixin + +class Log(singletonmixin.Singleton): + + def __init__(self, file): + """_file: filename or open file""" + + if type(file) is str: + self._file = open(file, "a") + else: + self._file = file + + def _getTime(self): + tm = time.time() + return "%s:%.2d" % (time.strftime('%m/%d/%Y %H:%M:%S', + time.localtime(tm)), + int((tm - int(tm)) * 100)) + + def _log(self, *logstrs): + timeStr = self._getTime() + for ln in " ".join(map(str, logstrs)).split("\n"): + self._file.write("%s %s\n" % (timeStr, ln)) + self._file.flush() + + def debug(self, *logstrs): + self._log("D", *logstrs) + def info(self, *logstrs): + self._log("I", *logstrs) + def warn(self, *logstrs): + self._log("W", *logstrs) + def error(self, *logstrs): + self._log("E", *logstrs) + + # default to info + log = info + __call__ = log diff --git a/tools/axl/random.dat b/tools/axl/random.dat Binary files differnew file mode 100644 index 000000000..48c5d48bf --- /dev/null +++ b/tools/axl/random.dat diff --git a/tools/axl/singletonmixin.py b/tools/axl/singletonmixin.py new file mode 100644 index 000000000..7935d6d7c --- /dev/null +++ b/tools/axl/singletonmixin.py @@ -0,0 +1,220 @@ +""" +A Python Singleton mixin class that makes use of some of the ideas +found at http://c2.com/cgi/wiki?PythonSingleton. Just inherit +from it and you have a singleton. No code is required in +subclasses to create singleton behavior -- inheritance from +Singleton is all that is needed. + +Assume S is a class that inherits from Singleton. Useful behaviors +are: + +1) Getting the singleton: + + S.getInstance() + +returns the instance of S. If none exists, it is created. + +2) The usual idiom to construct an instance by calling the class, i.e. + + S() + +is disabled for the sake of clarity. If it were allowed, a programmer +who didn't happen notice the inheritance from Singleton might think he +was creating a new instance. So it is felt that it is better to +make that clearer by requiring the call of a class method that is defined in +Singleton. An attempt to instantiate via S() will restult in an SingletonException +being raised. + +3) If S.__init__(.) requires parameters, include them in the +first call to S.getInstance(.). If subsequent calls have parameters, +a SingletonException is raised. + +4) As an implementation detail, classes that inherit +from Singleton may not have their own __new__ +methods. To make sure this requirement is followed, +an exception is raised if a Singleton subclass includ +es __new__. This happens at subclass instantiation +time (by means of the MetaSingleton metaclass. + +By Gary Robinson, grobinson@transpose.com. No rights reserved -- +placed in the public domain -- which is only reasonable considering +how much it owes to other people's version which are in the +public domain. The idea of using a metaclass came from +a comment on Gary's blog (see +http://www.garyrobinson.net/2004/03/python_singleto.html#comments). +Not guaranteed to be fit for any particular purpose. +""" + +class SingletonException(Exception): + pass + +class MetaSingleton(type): + def __new__(metaclass, strName, tupBases, dict): + if '__new__' in dict: + raise SingletonException, 'Can not override __new__ in a Singleton' + return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict) + + def __call__(cls, *lstArgs, **dictArgs): + raise SingletonException, 'Singletons may only be instantiated through getInstance()' + +class Singleton(object): + __metaclass__ = MetaSingleton + + def getInstance(cls, *lstArgs): + """ + Call this to instantiate an instance or retrieve the existing instance. + If the singleton requires args to be instantiated, include them the first + time you call getInstance. + """ + if cls._isInstantiated(): + if len(lstArgs) != 0: + raise SingletonException, 'If no supplied args, singleton must already be instantiated, or __init__ must require no args' + else: + if len(lstArgs) != cls._getConstructionArgCountNotCountingSelf(): + raise SingletonException, 'If the singleton requires __init__ args, supply them on first instantiation' + instance = cls.__new__(cls) + instance.__init__(*lstArgs) + cls.cInstance = instance + return cls.cInstance + getInstance = classmethod(getInstance) + + def _isInstantiated(cls): + return hasattr(cls, 'cInstance') + _isInstantiated = classmethod(_isInstantiated) + + def _getConstructionArgCountNotCountingSelf(cls): + return cls.__init__.im_func.func_code.co_argcount - 1 + _getConstructionArgCountNotCountingSelf = classmethod(_getConstructionArgCountNotCountingSelf) + + def _forgetClassInstanceReferenceForTesting(cls): + """ + This is designed for convenience in testing -- sometimes you + want to get rid of a singleton during test code to see what + happens when you call getInstance() under a new situation. + + To really delete the object, all external references to it + also need to be deleted. + """ + try: + delattr(cls,'cInstance') + except AttributeError: + # run up the chain of base classes until we find the one that has the instance + # and then delete it there + for baseClass in cls.__bases__: + if issubclass(baseClass, Singleton): + baseClass._forgetClassInstanceReferenceForTesting() + _forgetClassInstanceReferenceForTesting = classmethod(_forgetClassInstanceReferenceForTesting) + + +if __name__ == '__main__': + import unittest + + class PublicInterfaceTest(unittest.TestCase): + def testReturnsSameObject(self): + """ + Demonstrates normal use -- just call getInstance and it returns a singleton instance + """ + + class A(Singleton): + def __init__(self): + super(A, self).__init__() + + a1 = A.getInstance() + a2 = A.getInstance() + self.assertEquals(id(a1), id(a2)) + + def testInstantiateWithMultiArgConstructor(self): + """ + If the singleton needs args to construct, include them in the first + call to get instances. + """ + + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + + b1 = B.getInstance('arg1 value', 'arg2 value') + b2 = B.getInstance() + self.assertEquals(b1.arg1, 'arg1 value') + self.assertEquals(b1.arg2, 'arg2 value') + self.assertEquals(id(b1), id(b2)) + + + def testTryToInstantiateWithoutNeededArgs(self): + + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + + self.assertRaises(SingletonException, B.getInstance) + + def testTryToInstantiateWithoutGetInstance(self): + """ + Demonstrates that singletons can ONLY be instantiated through + getInstance, as long as they call Singleton.__init__ during construction. + + If this check is not required, you don't need to call Singleton.__init__(). + """ + + class A(Singleton): + def __init__(self): + super(A, self).__init__() + + self.assertRaises(SingletonException, A) + + def testDontAllowNew(self): + + def instantiatedAnIllegalClass(): + class A(Singleton): + def __init__(self): + super(A, self).__init__() + + def __new__(metaclass, strName, tupBases, dict): + return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict) + + self.assertRaises(SingletonException, instantiatedAnIllegalClass) + + + def testDontAllowArgsAfterConstruction(self): + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + + b1 = B.getInstance('arg1 value', 'arg2 value') + self.assertRaises(SingletonException, B, 'arg1 value', 'arg2 value') + + def test_forgetClassInstanceReferenceForTesting(self): + class A(Singleton): + def __init__(self): + super(A, self).__init__() + class B(A): + def __init__(self): + super(B, self).__init__() + + # check that changing the class after forgetting the instance produces + # an instance of the new class + a = A.getInstance() + assert a.__class__.__name__ == 'A' + A._forgetClassInstanceReferenceForTesting() + b = B.getInstance() + assert b.__class__.__name__ == 'B' + + # check that invoking the 'forget' on a subclass still deletes the instance + B._forgetClassInstanceReferenceForTesting() + a = A.getInstance() + B._forgetClassInstanceReferenceForTesting() + b = B.getInstance() + assert b.__class__.__name__ == 'B' + + unittest.main() + + diff --git a/tools/axl/stfu.jpg b/tools/axl/stfu.jpg Binary files differnew file mode 100644 index 000000000..2cf38a54d --- /dev/null +++ b/tools/axl/stfu.jpg diff --git a/tools/axl/udpEater.py b/tools/axl/udpEater.py new file mode 100755 index 000000000..1440aadc4 --- /dev/null +++ b/tools/axl/udpEater.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# +# Copyright 2007, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" + udpEater.py: receives UDP traffic + +""" + +import time, socket, string + +def main(): + port = 9001 + + svrsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + svrsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + svrsocket.bind(('', port)) + + hostname = socket.gethostname() + ip = socket.gethostbyname(hostname) + print 'Server is at IP adress: ', ip + print 'Listening for requests on port %s ...' % port + + count = 0 + while count < 400: + data, address = svrsocket.recvfrom(8192) + print 'Received packet', count, data[:34] + count += 1 + +if __name__ == "__main__": + main() diff --git a/tools/axl/udpServer.py b/tools/axl/udpServer.py new file mode 100755 index 000000000..fc37ab85a --- /dev/null +++ b/tools/axl/udpServer.py @@ -0,0 +1,29 @@ +# UDP server example +import time, socket, string + +def main(): + + port = 9001 + buf = open("random.dat").read() + + svrsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + svrsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + svrsocket.bind(('', port)) + + # hostname = socket.gethostname() + hostname = "localhost" + ip = socket.gethostbyname(hostname) + print 'Server is at IP adress: ', ip + print 'Listening for requests on port %s ...' % port + + data, address = svrsocket.recvfrom(8192) + + count = 0 + while count < 500: + print 'Sending packet', count, 'to', address[0] + svrsocket.sendto("%3.3s%s" % (count, buf), address) + time.sleep(0.08) + count += 1 + +if __name__ == "__main__": + main() |
