From 715f208ba0c04711f0b003559c438bedd423fcc5 Mon Sep 17 00:00:00 2001 From: Zihang Chen Date: Mon, 10 Mar 2014 10:49:43 +0800 Subject: [PATCH 2/2] add documentation --- testenv/ChangeLog | 11 ++++ testenv/README | 68 +++++++++++++-------- testenv/conf/__init__.py | 10 +++ testenv/conf/hook_sample.py | 17 ++++++ testenv/conf/rule_sample.py | 11 ++++ .../http/__pycache__/__init__.cpython-33.pyc | Bin 140 -> 0 bytes .../http/__pycache__/http_server.cpython-33.pyc | Bin 24879 -> 0 bytes testenv/test/base_test.py | 52 ++++++++++++++-- testenv/test/http_test.py | 5 +- 9 files changed, 145 insertions(+), 29 deletions(-) create mode 100644 testenv/conf/hook_sample.py create mode 100644 testenv/conf/rule_sample.py delete mode 100644 testenv/server/http/__pycache__/__init__.cpython-33.pyc delete mode 100644 testenv/server/http/__pycache__/http_server.cpython-33.pyc diff --git a/testenv/ChangeLog b/testenv/ChangeLog index 85bd0f2..b379ca8 100644 --- a/testenv/ChangeLog +++ b/testenv/ChangeLog @@ -1,3 +1,14 @@ +2014-03-09 Zihang Chen + * HTTPServer.py: Move to server/http/http_server.py + * FTPServer.py: Move to server/ftp/ftp_server.py + * WgetTest.py: Refactor and split into test/base_test.py and test/http_test.py + (CommonMethods): Various changes are made to this class. Briefly, refactor to BaseTest. And the rule classes and methods are moved to conf/ in separated files. + (HTTPTest): Move to test/http_test.py. + (WgetFile): Move to misc/wget_file.py. + (TestFailed): Move to exc/test_failed.py. + * ColourTerm.py: Move to misc/colour_term.py. Add new functions print_blue, print_yellow, print_purple, print_red, print_green for simpler invocation. + + 2014-01-02 Darshit Shah * Makefile.am: Add new Test--https.py to list of tests and EXTRA_DIST. Also replace all tabs with spaces in file for conformity. diff --git a/testenv/README b/testenv/README index 0aee658..717c1db 100644 --- a/testenv/README +++ b/testenv/README @@ -10,25 +10,30 @@ Run the './configure' command to generate the Makefile and then run 'make check' to execute the Test Suite. Use the '-j n' option with 'make check' to execute n tests simultaneously. -File List: +Structure: ================================================================================ - * HTTPServer.py: This file contains a custom, programmatically configurable - HTTP Server for testing Wget. It runs an instance of Python's http.server - module. + * server: This package contains custom programmatically configurable servers + (both HTTP and FTP) for testing Wget. The HTTP server runs an instance of + Python's http.server module. The FTP server is to be implemented. - * WgetTest.py: This file contains various functions and global variables for - each instance of the server that is initiated. It includes functions to - start and stop the server, to initialze the test environment and to cleanup - after a test. + * test: This package contains the test case classes for HTTP and FTP. The + test case classes includes methods for initializing and cleaning up of the + test environment. + + * exc: This package contains custom exception classes used in this test + suite. + + * conf: This package contains the configuration classes for servers to be + configured with. + + * misc: This package contains several functions, classes and constants used + in this test suite. * Test-Proto.py: This is a prototype Test Case file. The file defines all the acceptable elements and their uses. Typically, one must copy this file and edit it for writing Test Cases. - * ColourTerm.py: A custom library for printing coloured output to the - terminal. Currently it only supports 4 colours in a *nix environment. - Working: ================================================================================ @@ -101,7 +106,7 @@ Next, is the const variable, TEST_NAME that defines the name of the Test. Each File in the Test must be represented as a WgetFile object. The WgetFile Class has the following prototype: -WgetFile (String name, String contents, String timestamp, dict rules) +WgetFile (str name, str contents, str timestamp, dict rules) None except name is a mandatory paramter, one may pass only those parameters that are required by the File object. @@ -138,10 +143,11 @@ Both, the HTTPTest and FTPTest modules have the same prototype: pre_hook, test_options, post_hook, - servers + protocols } -name expects the string name, and is usually passed the TEST_NAME variable, -the three hooks, expect python dictionary objects and servers is an integer. +name should be a string, and is usually passed to the TEST_NAME variable, +the three hooks should be Python dict objects and protocols should be a list of +protocols, like [HTTP, HTTPS]. Valid File Rules: ================================================================================ @@ -191,6 +197,7 @@ executed. The currently supported options are: * Urls : A list of the filenames that Wget must attempt to download. The complete URL will be created and passed to Wget automatically. + (alias URLs) * WgetCommands : A string consisting of the various commandline switches sent to Wget upon invokation. Any data placed between {{ }} in this string will be replaced with the contents of self. before being passed to @@ -207,7 +214,7 @@ hooks are usually used to run checks on the data, files downloaded, return code, etc. The following hooks are currently supported: * ExpectedRetcode : This is an integer value of the ReturnCode with which - Wget is expected to exit. + Wget is expected to exit. (alias: ExpectedRetCode) * ExpectedFiles : This is a list of WgetFile objects of the files that must exist locally on disk in the Test directory. * FilesCrawled : This requires a list of the Requests that the server is @@ -223,14 +230,27 @@ recommended method for writing new Test Case files is to copy Test-Proto.py and modify it to ones needs. In case you require any functionality that is not currently defined in List of -Rules defined above, you should add the required code in WgetTest.py. -In most cases, one requires a new Rule to be added for the Server to follow. -In such a case, create a new Class in WgetTest.py with the same name as the Rule -and define an __init__ () function to handle the data. A method must also be -defined in HTTPTest / FTPTest modules to handle the said Rule. - -Once a new Test File is created, it must be added to the TESTS variable in -akefile.am. This way the Test will be executed on running a 'make check'. +Rules defined above, you should implement a new class in the conf package. The +file name doesn't matters (though it's better to give it an appropriate name). +The new rule class should be like this: + +============================================================= +from conf import register + + address@hidden() +class MyNewRule: + + def __init__(self, rule_arg): + self.rule_arg = rule_arg + # your rule initialization code goes here +============================================================= + +Additionally, A method with the exact name of the newly created rule class must + also be defined in HTTPTest / FTPTest modules to handle the said Rule. + +Once a new Test File is created, it must be added to the TESTS variable in +Makefile.am. This way the Test will be executed on running a 'make check'. If a Test is expected to fail on the current master branch, then the Test should also be added to the XFAIL_TESTS variable. This will allow expected failures to pass through. If a test mentioned in the XFAIL_TESTS variable passes, it gets diff --git a/testenv/conf/__init__.py b/testenv/conf/__init__.py index bc2c638..f63a2ec 100644 --- a/testenv/conf/__init__.py +++ b/testenv/conf/__init__.py @@ -1,17 +1,24 @@ import os +# this file implements the mechanism of conf class auto-registration, +# don't modify this file if you have no idea what you're doing def gen_hook(): hook_table = {} class Wrapper: + """ + Decorator class which implements the conf class registration. + """ def __init__(self, alias=None): self.alias = alias def __call__(self, cls): + # register the class object with the name of the class hook_table[cls.__name__] = cls if self.alias: + # also register the alias of the class hook_table[self.alias] = cls return cls @@ -27,6 +34,9 @@ def gen_hook(): register, find_conf = gen_hook() for module in os.listdir(os.path.dirname(__file__)): + # import every module under this package except __init__.py, + # so that the decorator `register` applies + # (nothing happens if the script is not loaded) if module != '__init__.py' and module.endswith('.py'): module_name = module[:-3] mod = __import__('%s.%s' % (__name__, module_name), diff --git a/testenv/conf/hook_sample.py b/testenv/conf/hook_sample.py new file mode 100644 index 0000000..58db304 --- /dev/null +++ b/testenv/conf/hook_sample.py @@ -0,0 +1,17 @@ +from exc.test_failed import TestFailed +from conf import register + +# this file is a hook example + address@hidden(alias='SampleAlias') +class SampleHook: + def __init__(self, sample_hook_arg): + # do conf initialization here + self.arg = sample_hook_arg + + + def __call__(self, test_obj): + # implement hook here + # if you need the test case instance, refer to test_obj + pass + diff --git a/testenv/conf/rule_sample.py b/testenv/conf/rule_sample.py new file mode 100644 index 0000000..8052c70 --- /dev/null +++ b/testenv/conf/rule_sample.py @@ -0,0 +1,11 @@ +from conf import register + + address@hidden(alias='SampleRuleAlias') +class SampleRule: + def __init__(self, rule): + # do rule initialization here + # you may also need to implement a method the same name of this + # class in server/protocol/protocol_server.py to apply this rule. + self.rule = rule + diff --git a/testenv/server/http/__pycache__/__init__.cpython-33.pyc b/testenv/server/http/__pycache__/__init__.cpython-33.pyc deleted file mode 100644 index cd405236fe8543ed2690ea4d29b8e6998b64904b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmbQo!^`FMK`NMufq@|zh~a<{$Z`PUViq8g!oU!$0TS`k01^ynM5!)NOg|$(H&wqp zU%xy(wM4%pwYVfTuS~xbq(DDDJ~J<~BtBlRpt6($sKX{VKczG$)edBC IF%UBV0M`B+9RL6T diff --git a/testenv/server/http/__pycache__/http_server.cpython-33.pyc b/testenv/server/http/__pycache__/http_server.cpython-33.pyc deleted file mode 100644 index 690a4e7ed5ae638a7d47f26147dca8497aa7a562..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24879 zcmdU1TWlQHc|Nnei4 zc4oP>6)&BpBzJk{%sFSyIsgBE|K*%BzdJoMwR-Zwqey=lpQ!9P7vRrx zb>|wMTlHL{S5$gxnRF?_oun{BX`;bGs>NDp{KG(address@hiddenICFRZ`_mB$?EBCMq=ahR4x%a!^h;om(aK>#O*Nq2oGR2W_l4?^|(e zVjpf?M_#ki2)n$9+Vxr-ZpT(-lDE%28#b%0AhfJ;WOdMNt6|q8xNZcWTdMLI{NaCg z?*cy28`^3`M(address@hidden&*i8QRWUaaGx7Pfc)%8``x7yKyUuB2*!~gs& z;uFo_>s^oiD~orRHKHXO*M8g#JDqYPjH1eVXwx;yYGHk?+kY4NZk}J=r|@-lqtyt{ zZne&Ct%vd17=#F$x6Vc))7gzUZtJUT84K;(n)!0M)~v7KE;m|1x6aFH-MiVX)RX%Y$_QFj+_Z}JSQ|B2s$8zOs+D?FE^9KFpVI$+ zq;tc_5niMGnF#+$6PqHD>nqVn!Bw)address@hidden za$M;NgGi3DOA%U*TkUq`dR=g6{i+hH_{0Ah3b3Q^mJ$?5-~dnaz)CFB{T#mhaddress@hidden|oFdeo&1uAwsO z&a*FFQd77>5agYx%T$MtlKkoG<6#Q{+aCNFpTbAE(xlgY0RIO}(t?%EB!>NC6N~sn zr}4FYilBM%?T6i+l8Z&address@hidden)address@hidden zPX=j;8Zodv5|E`A z*P?jP7`r{*69(j_PsRHl|4FEzU7&!9HR51rOOvD1W7DI%Vg~8QAO0sFU%)address@hidden zK#W}!k!&g=$H03t;6Gh``w>d42ozeGw?k?=IF&Co%?B{Vd address@hidden&Xuk3K{n)((P2CzC0XZimb#pyg$2P^HSEMumsS?-pfkK&address@hidden address@hidden|rWS-N^CYFro1PI{uweAecBj^i)rnRl_QR8_TY;Y0uEZO{ z-pchzY4Yx7tJc)rRy(vFz|5pQ8Foi-JBsS+$yTS*E=TBe7^~SNNpPv1ccZefhqYt2AHkqAkp8rN>Y-Zc|1 z#R==aJy2;Gzp#+W%Zrz;u3Y}gtC!UAwN`srP+^;?sd*OZh$_Q*hrL`cqsoS+PW3XI=ouPf8+1|ZxzuWgeYOdCP<|p&y;COW56fZ120XD$Lq`p2Fno~n address@hidden>j&address@hidden&yah^W^+Szj zfcyI}rWF!F2!!cL20{?{U>ZRYL|address@hidden)?>9AX$u zqwt&yjwy}M$Z;1upfoBXr16l_2#!4Lf=84_BagbkR~q4w$6RniX*BpL7o1cY(UDUw zcwA{T{)7wWl|address@hidden(jV4DWxBB!P72yMrm~5vo3g6 z=|address@hidden;!g3>address@hidden|QW~B7k_*19^hp<-cfkdv z(cwiGTvYmT7hH0|Wu?*imm!T;zyPMol7NjY{S*_DJpZdXYzS&=YhfpB#(n}OKnAry zd^!8{!qYo=MUr(852DsaxI>^|ikm31B&ol0>HJ0GeJXQ=g#uZVduyxGMh;qKKI?0I z3Lo#h?kv8`$ygVX``IXnRHOK46b&Tuqj;<2?!fqw2hyn#-~xc)KG#`Pv69;yAvnU2 address@hidden>qnn_%Uk6#i#zINTi7U#H#Ag-F zMNTjPHYQoN-D>N99mX;(TUaf%Xe0GGKZ5DI6qPJ^E43g7l2Hue1ZW z*g_^rq$=la5ufNfzQ~$_-=9&EV6|l|z6sY3vH-6z5t7LQbMkphVopV%mX_wpjpBn( zmZ?$(address@hidden>address@hidden&!`!TGD9C9address@hiddenM_y;1d)8lR)Fx0>address@hidden;Z&mPi0E0CrmQ-ik{zYrCIP|J4A z>address@hidden&H4gNYFuCSW}T^{is^yKYiR4FK=Dv7`!ifU$z zd&m`GwlJnvfb zkQ+rs(Dye$*YXtxS8^$iPPWOsrphF%fz^dCXBVjylD##EA-puxAh&4c> zWc9_Eom{V6B#x8KZ$9d-K}Tui9PW~$roE>cK~v$(VlNg?wABfVVy6Bdb`Y?GJrF5Q zo503qao8CoaYa)av8h%0hs-2{INvtGpUo=Co-qSAPh`lExE6PDKgS^A zje%XzeDtPck5_Mq3PnTukC2lrMYPm{p5XV}@d;J}h9dC2pWP_v{b&6h475mZJY*1qw63f|`N< zL;}OdNN<#APbOT~<1Tbr=A(d$B}Y^eamG&`Lb7ZW-Iz=X)RmN)Ky%d{ZoP>QtOa%OAx}c!~noTrUEbMrp1%HGyd9k*RwGI&)i+r`JkWVQeR&BlU;t58^&u~HH zgg}Kgv2RL_2l-v>(d9M;Ybvd#8mIkc3p+DjJaH;IaoTUSE7&8a3z==F{hO`!izh1G zc;iI(I9k}{xu<=3{MW8sJ98dofsM5)*Xd{uB|#c^zSWINonDX`>DVAAV?Dy&2aXe7 address@hidden;|!tJ0p0qU!YSWiDfC9?tc-4-2*DOnfbb9IL0bE+s)wCTWp$Q&PE^tNX3 address@hidden&AP_X{w4oFXvdItcfVBPwF% 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 diff --git a/testenv/test/base_test.py b/testenv/test/base_test.py index d4784d4..dc69ac3 100644 --- a/testenv/test/base_test.py +++ b/testenv/test/base_test.py @@ -20,8 +20,14 @@ class BaseTest: """ def __init__(self, name, pre_hook, test_params, post_hook, protocols): + """ + Define the class-wide variables (or attributes). + Attributes should not be defined outside __init__. + """ self.name = name - self.pre_configs = pre_hook or {} + self.pre_configs = pre_hook or {} # if pre_hook == None, then + # {} (an empty dict object) is + # passed to self.pre_configs self.test_params = test_params or {} self.post_configs = post_hook or {} self.protocols = protocols @@ -62,6 +68,10 @@ class BaseTest: def hook_call(self, configs, name): for conf_name, conf_arg in configs.items(): try: + # conf.find_conf(conf_name) returns the required conf class, + # then the class is instantiated with conf_arg, then the + # conf instance is called with this test instance itself to + # invoke the desired hook conf.find_conf(conf_name)(conf_arg)(self) except AttributeError: self.stop_server() @@ -78,6 +88,10 @@ class BaseTest: def stop_server(self): + """ + Subclasses must implement this method in order to stop certain + servers of different types. + """ raise NotImplementedError @@ -97,15 +111,25 @@ class BaseTest: for protocol in self.protocols: instance = self.instantiate_server_by(protocol) self.servers.append(instance) + + # servers instantiated by different protocols may differ in + # ports and etc. + # so we should record different domains respect to servers. domain = self.get_domain_addr(instance.server_address) self.domains.append(domain) def instantiate_server_by(self, protocol): + """ + Subclasses must override this method to actually instantiate servers + for test cases. + """ raise NotImplementedError def get_domain_addr(self, addr): + # TODO if there's a multiple number of ports, wouldn't it be + # overridden to the port of the last invocation? self.port = str(addr[1]) return '%s:%s' % (addr[0], self.port) @@ -137,6 +161,16 @@ class BaseTest: for protocol, urls, domain in zip(self.protocols, self.urls, self.domains): + # zip is function for iterating multiple lists at the same time. + # e.g. for item1, item2 in zip([1, 2, 3, 4, 5], + # ['a', 'b', 'c', 'd', 'e']): + # print(item1, item2) + # generates the following output: + # 1 a + # 2 b + # 3 c + # 4 d + # 5 e protocol = protocol.lower() for url in urls: cmd_line += '%s://%s/%s ' % (protocol, domain, url) @@ -171,9 +205,10 @@ class BaseTest: @staticmethod def get_server_rules(file_obj): - """ The handling of expect header could be made much better when the - options are parsed in a true and better fashion. For an example, - see the commented portion in Test-basic-auth.py. + """ + The handling of expect header could be made much better when the + options are parsed in a true and better fashion. For an example, + see the commented portion in Test-basic-auth.py. """ server_rules = {} for rule_name, rule in file_obj.rules.items(): @@ -182,10 +217,17 @@ class BaseTest: def __enter__(self): + """ + Initialization for with statement. + """ return self def __exit__(self, exc_type, exc_val, exc_tb): + """ + If the with statement got executed with no exception raised, then + exc_type, exc_val, exc_tb are all None. + """ if exc_val: self.tests_passed = False if exc_type is TestFailed: @@ -196,6 +238,8 @@ class BaseTest: traceback.print_tb(exc_tb) self.__test_cleanup() + return True + # `ServerConf' is actually never referenced. # def ServerConf (self, server_settings): diff --git a/testenv/test/http_test.py b/testenv/test/http_test.py index 205238c..0b5dc24 100644 --- a/testenv/test/http_test.py +++ b/testenv/test/http_test.py @@ -24,6 +24,8 @@ class HTTPTest(BaseTest): post_hook, protocols) with self: + # if any exception occurs, self.__exit__ will be immediately + # called self.server_setup() self.do_test() print_green('Test Passed.') @@ -38,7 +40,8 @@ class HTTPTest(BaseTest): def request_remaining(self): - return [s.server_inst.get_req_headers() for s in self.servers] + return [s.server_inst.get_req_headers() + for s in self.servers] def stop_server(self): -- 1.8.3.2