99from struct import pack
1010import base64
1111
12- from generator_lib import generators
12+ # Generator functions
13+ # Add your new generator function here
14+ # TODO: with some import syntax or clever moduling, it might be possible not
15+ # to have to do anything here?
16+ # F401 ignored for flake8 as those methods are called through eval
17+ from generators .ping_noauth import gen as ping_noauth # noqa: F401
18+ from generators .list_opcodes_bad1 import gen as list_opcodes_bad1 # noqa: F401
19+ from generators .list_opcodes_directauth import ( # noqa: F401
20+ gen as list_opcodes_directauth ,
21+ )
1322
1423
1524class TestSpec (object ):
@@ -27,71 +36,68 @@ def _traverse(key, element):
2736 self .__dict__ .update (objd )
2837 self .basedict = dictionary
2938
30- def is_valid (self ):
31- return True
32-
3339
3440def read_specs (folder ):
3541 """Read test specs from a folder"""
3642 specfiles = [f for f in listdir (folder ) if isfile (join (folder , f ))]
3743 specs = []
3844 for file in specfiles :
3945 print (f"Parsing spec file: { file } " )
40- with open (os .path .join (folder , file ), 'r' ) as f :
46+ # Only use the first part of the filename as spec name
47+ name = file .split ("." )[0 ]
48+ with open (os .path .join (folder , file ), "r" ) as f :
4149 spec = safe_load (f )
4250 testspec = TestSpec (spec ["spec" ])
43- if testspec .is_valid ():
44- specs .append (testspec )
45- else :
46- print (f"Error loading test spec from { file } " )
51+ specs .append ((name , testspec ))
4752 return specs
4853
4954
5055def generate_data (specs , output_folder ):
5156 """Generate test data for a list of specs"""
52- for spec in specs :
53- if spec .generator in generators :
54- print (f"Generating test { spec .name } " )
55- generate_spec_data (output_folder , spec , generators [spec .generator ])
56- else :
57- print (f"No generator function found for spec { spec .name } , skipping..." )
57+ for (name , spec ) in specs :
58+ generate_spec_data (output_folder , spec , name )
5859
5960
60- def generate_spec_data (output_folder , spec , generator_fn ):
61+ def generate_spec_data (output_folder , spec , name ):
6162 """Generates data for a single spec and outputs it into the specified output folder."""
62- (operation , result ) = generator_fn ()
63+ # The generator function has the same name as the test specification
64+ (operation , result ) = eval (name )()
6365
6466 request_auth = create_auth (spec .request .auth )
6567 request_content_len = spec .request .header .content_length
66- if request_content_len == ' auto' :
68+ if request_content_len == " auto" :
6769 request_content_len = len (operation )
6870
6971 request_auth_len = spec .request .header .auth_length
70- if request_auth_len == ' auto' :
72+ if request_auth_len == " auto" :
7173 request_auth_len = len (request_auth )
72- request_header = pack_header (spec .request .header , request_auth_len , request_content_len )
74+ request_header = pack_header (
75+ spec .request .header , request_auth_len , request_content_len
76+ )
7377
7478 response_content_len = spec .response .header .content_length
75- if response_content_len == ' auto' :
79+ if response_content_len == " auto" :
7680 response_content_len = len (result )
7781
7882 response_auth_len = spec .response .header .auth_length
79-
80- response_header = pack_header (spec .response .header , response_auth_len , response_content_len )
83+ response_header = pack_header (
84+ spec .response .header , response_auth_len , response_content_len
85+ )
8186
8287 request_buf = request_header + operation + request_auth
8388 response_buf = response_header + result
8489
90+ # The generator appends the base64 data at the end of the spec file
8591 out_data = {
8692 "spec" : spec .basedict ,
8793 "test_data" : {
88- "request" : base64 .b64encode (request_buf ).decode (' ascii' ),
89- "response" : base64 .b64encode (response_buf ).decode (' ascii' ),
90- }
94+ "request" : base64 .b64encode (request_buf ).decode (" ascii" ),
95+ "response" : base64 .b64encode (response_buf ).decode (" ascii" ),
96+ },
9197 }
92- out_path = os .path .join (output_folder , spec . name + ".test.yaml" )
93- print (f"Writing spec { spec . name } test data to { out_path } " )
94- with open (out_path , 'w' ) as f :
98+ out_path = os .path .join (output_folder , name + ".test.yaml" )
99+ print (f"Writing spec { name } test data to { out_path } " )
100+ with open (out_path , "w" ) as f :
95101 dump (out_data , f , sort_keys = False )
96102
97103
@@ -100,42 +106,48 @@ def pack_header(header, auth_len, body_len):
100106 # pack function converts arguments into binary string, based on format string.
101107 # < means integers are little endian. Rest of format string is one character per input to indicate
102108 # packed field interpretation. See struct.pack docs for details.
103- return pack ('<IHBBHBQBBBIHIHH' ,
104- header .magic_number ,
105- header .header_size ,
106- header .major_version_number ,
107- header .minor_version_number ,
108- header .flags ,
109- header .provider ,
110- header .session_handle ,
111- header .content_type ,
112- header .accept_type ,
113- header .auth_type ,
114- body_len ,
115- auth_len ,
116- header .opcode ,
117- header .status ,
118- 0
119- )
109+ # This should map to the Fixed Common Header defined here:
110+ # https://parallaxsecond.github.io/parsec-book/parsec_client/wire_protocol.html#the-fixed-common-header
111+ return pack (
112+ "<IHBBHBQBBBIHIHH" ,
113+ header .magic_number ,
114+ header .header_size ,
115+ header .major_version_number ,
116+ header .minor_version_number ,
117+ header .flags ,
118+ header .provider ,
119+ header .session_handle ,
120+ header .content_type ,
121+ header .accept_type ,
122+ header .auth_type ,
123+ body_len ,
124+ auth_len ,
125+ header .opcode ,
126+ header .status ,
127+ 0 ,
128+ )
120129
121130
122131def create_auth (auth_spec ):
123132 """Creates auth body of message"""
124- if auth_spec .type == ' none' :
125- return b''
126- if auth_spec .type == ' direct' :
127- return auth_spec .app_name .encode (' utf-8' )
128- return b''
133+ if auth_spec .type == " none" :
134+ return b""
135+ if auth_spec .type == " direct" :
136+ return auth_spec .app_name .encode (" utf-8" )
137+ return b""
129138
130139
131140def main ():
132- specdir = os .path .abspath (os .path .join (os .path .dirname (__file__ ), 'testspecs' ))
133- datadir = os .path .abspath (os .path .join (os .path .dirname (__file__ ), '../testdata' ))
134141 print ("Generating test data." )
142+
143+ specdir = os .path .abspath (os .path .join (os .path .dirname (__file__ ), "test_specs" ))
135144 print (f"Reading test specs from { specdir } " )
136- print (f"Generating test data to { datadir } " )
137145 specs = read_specs (specdir )
138146
147+ datadir = os .path .abspath (
148+ os .path .join (os .path .dirname (__file__ ), "../generator_output" )
149+ )
150+ print (f"Generating test data to { datadir } " )
139151 generate_data (specs , datadir )
140152
141153
0 commit comments