9
9
from struct import pack
10
10
import base64
11
11
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
+ )
13
22
14
23
15
24
class TestSpec (object ):
@@ -27,71 +36,68 @@ def _traverse(key, element):
27
36
self .__dict__ .update (objd )
28
37
self .basedict = dictionary
29
38
30
- def is_valid (self ):
31
- return True
32
-
33
39
34
40
def read_specs (folder ):
35
41
"""Read test specs from a folder"""
36
42
specfiles = [f for f in listdir (folder ) if isfile (join (folder , f ))]
37
43
specs = []
38
44
for file in specfiles :
39
45
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 :
41
49
spec = safe_load (f )
42
50
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 ))
47
52
return specs
48
53
49
54
50
55
def generate_data (specs , output_folder ):
51
56
"""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 )
58
59
59
60
60
- def generate_spec_data (output_folder , spec , generator_fn ):
61
+ def generate_spec_data (output_folder , spec , name ):
61
62
"""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 )()
63
65
64
66
request_auth = create_auth (spec .request .auth )
65
67
request_content_len = spec .request .header .content_length
66
- if request_content_len == ' auto' :
68
+ if request_content_len == " auto" :
67
69
request_content_len = len (operation )
68
70
69
71
request_auth_len = spec .request .header .auth_length
70
- if request_auth_len == ' auto' :
72
+ if request_auth_len == " auto" :
71
73
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
+ )
73
77
74
78
response_content_len = spec .response .header .content_length
75
- if response_content_len == ' auto' :
79
+ if response_content_len == " auto" :
76
80
response_content_len = len (result )
77
81
78
82
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
+ )
81
86
82
87
request_buf = request_header + operation + request_auth
83
88
response_buf = response_header + result
84
89
90
+ # The generator appends the base64 data at the end of the spec file
85
91
out_data = {
86
92
"spec" : spec .basedict ,
87
93
"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
+ },
91
97
}
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 :
95
101
dump (out_data , f , sort_keys = False )
96
102
97
103
@@ -100,42 +106,48 @@ def pack_header(header, auth_len, body_len):
100
106
# pack function converts arguments into binary string, based on format string.
101
107
# < means integers are little endian. Rest of format string is one character per input to indicate
102
108
# 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
+ )
120
129
121
130
122
131
def create_auth (auth_spec ):
123
132
"""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""
129
138
130
139
131
140
def 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' ))
134
141
print ("Generating test data." )
142
+
143
+ specdir = os .path .abspath (os .path .join (os .path .dirname (__file__ ), "test_specs" ))
135
144
print (f"Reading test specs from { specdir } " )
136
- print (f"Generating test data to { datadir } " )
137
145
specs = read_specs (specdir )
138
146
147
+ datadir = os .path .abspath (
148
+ os .path .join (os .path .dirname (__file__ ), "../generator_output" )
149
+ )
150
+ print (f"Generating test data to { datadir } " )
139
151
generate_data (specs , datadir )
140
152
141
153
0 commit comments