gen-query-testdata.py 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #!/usr/bin/env python3
  2. # Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  3. #
  4. # Permission to use, copy, modify, and/or distribute this software for any
  5. # purpose with or without fee is hereby granted, provided that the above
  6. # copyright notice and this permission notice appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  9. # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13. # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. # PERFORMANCE OF THIS SOFTWARE.
  15. """\
  16. This is a supplemental script to auto generate test data in the form of
  17. C++ source code from a DNS zone file.
  18. Usage: python gen-query-testdata.py source_file output-cc-file
  19. The usage doesn't matter much, though, because it's expected to be invoked
  20. from Makefile, and that would be only use case of this script.
  21. """
  22. import sys
  23. import re
  24. # Markup for variable definition
  25. re_start_rr = re.compile('^;var=(.*)')
  26. # Skip lines starting with ';' (comments) or empty lines. re_start_rr
  27. # will also match this expression, so it should be checked first.
  28. re_skip = re.compile('(^;)|(^\s*$)')
  29. def parse_input(input_file):
  30. '''Build an internal list of RR data from the input source file.
  31. It generates a list of (variable_name, list of RR) tuples, where
  32. variable_name is the expected C++ variable name for the subsequent RRs
  33. if they are expected to be named. It can be an empty string if the RRs
  34. are only expected to appear in the zone file.
  35. The second element of the tuple is a list of strings, each of which
  36. represents a single RR, e.g., "example.com 3600 IN A 192.0.2.1".
  37. '''
  38. result = []
  39. rrs = None
  40. with open(input_file) as f:
  41. for line in f:
  42. m = re_start_rr.match(line)
  43. if m:
  44. if rrs is not None:
  45. result.append((rr_varname, rrs))
  46. rrs = []
  47. rr_varname = m.group(1)
  48. elif re_skip.match(line):
  49. continue
  50. else:
  51. rrs.append(line.rstrip('\n'))
  52. # if needed, store the last RRs (they are not followed by 'var=' mark)
  53. if rrs is not None:
  54. result.append((rr_varname, rrs))
  55. return result
  56. def generate_variables(out_file, rrsets_data):
  57. '''Generate a C++ source file containing a C-string variables for RRs.
  58. This produces a definition of C-string for each RRset that is expected
  59. to be named as follows:
  60. const char* const var_name =
  61. "example.com. 3600 IN A 192.0.2.1\n"
  62. "example.com. 3600 IN A 192.0.2.2\n";
  63. Escape character '\' in the string will be further escaped so it will
  64. compile.
  65. '''
  66. with open(out_file, 'w') as out:
  67. for (var_name, rrs) in rrsets_data:
  68. if len(var_name) > 0:
  69. out.write('const char* const ' + var_name + ' =\n')
  70. # Combine all RRs, escaping '\' as a C-string
  71. out.write('\n'.join([' \"%s\\n\"' %
  72. (rr.replace('\\', '\\\\'))
  73. for rr in rrs]))
  74. out.write(';\n')
  75. if __name__ == "__main__":
  76. if len(sys.argv) < 3:
  77. sys.stderr.write('gen-query-testdata.py require 2 args\n')
  78. sys.exit(1)
  79. rrsets_data = parse_input(sys.argv[1])
  80. generate_variables(sys.argv[2], rrsets_data)