<filename>scripts/obsolete/regtest.py
#!/usr/bin/env python

""" Downloads a selection of API paths to a specified directory.
Example usage:

./regtest.py -a pennapps.com/courses -o output-old
./regtest.py -a pennapps.com/courses-mjc -o output-new
diff -r output-old output-new

"""

import urllib2
import os
import json
import time
import sys
from optparse import OptionParser

def sort_lists(obj):
  """Recursively sort all lists that are part of this object. Returns
  a new object."""
  if type(obj) == list:
    return sorted(sort_lists(x) for x in obj)
  elif type(obj) == dict:
    return dict((k, sort_lists(v)) for (k,v) in obj.items())
  else:
    return obj

def test(options, path, lderror_ok=False):
  """ Load the given API path, and save consistently-formatted JSON
  to the output dir. Print status string. Return the object created
  from the JSON, or None on error. 

  The "consistent formatting" includes sorting all lists, since
  the API returns objects in no specified order.

  lderror_ok - if True, we won't print "XLoad" on load error
  """

  waserror = False

  path_nice = path or "index.html"
  
  print "%65s" % path_nice,
  sys.stdout.flush()
  try:
    fullpath = "%s/%s?token=%s" % (options.apiroot, path, options.token)
    start = time.time()
    intext = urllib2.urlopen(fullpath).read()
    print "%7.3f" % (time.time() - start),
  except Exception as e:
    intext = json.dumps({"load error": repr(e)}) # dummy message to save
    print "  -----",
    if not lderror_ok: print "XLoad",
    waserror = True

  try:
    obj = json.loads(intext)
  except Exception as e:
    obj = {"parse error": repr(e)} # dummy object to save
    print "XPars",
    waserror = True

  # format consistently
  obj["retrieved"] = "removed for consistency"
  text = json.dumps(sort_lists(obj), sort_keys=True, indent=4)
  outpath = os.path.join(options.output, path_nice.replace('/','+'))
  file = open(outpath, 'w')
  file.write(text)
  file.close()

  print
  return None if waserror else obj

def fraclist(l, percent):
  """ Return the first `percent`/100 elements from the list l. """
  return l[:int(round(len(l)*percent/100.0))]
  
def alltests(opts):
  """ test ALL the paths
  (burn ALL the server IO bandwidth) """
  
  print "API Root:   %s" % options.apiroot
  print "Token:      %s" % options.token
  print "Output dir: %s" % options.output
  print "Running     %d%% of tests" % options.percent
  print
  
  # need to use DEPT-001, not ID#
  coursehistory_tests = [
    # basic tests:
    "cis-120", "math-114", "engl-101", "econ-001",
    # miscellaneously somewhat problematic:
    "engl-016", "law-205", "hpr-612", "rels-414", "nurs-322",
    "writ-030", "be-310", "psci-010", "psci-136",
    # crosslistings:
    "engl-135", "writ-135", "fnar-264", "cogs-001", "russ-048", "hist-048",
    # no reviews?:
    "afam-271", "ames-071", "slav-532", "afam-285", "prtg-213", "slav-533",
    # errors:
    "99999", "moo",
    ]

  instructor_tests = [
    # basic tests:
    "403", "631", "1883", "2217-FERNANDO-C--PEREIRA", "1602-BENJAMIN-PIERCE",
    # crosslistings:
    "1034-LYLE-H-UNGAR", "2709-DAVID-P--COMBERG",
    # miscellaneously somewhat problematic:
    "1040-DAVID-FOX", "4268-BART-GERARD-C-DE-JONGHE",
    # the instructors w/ the most sections
    "1883", "1619", "2869", "942", "1644", "541", "767", "434",
    # concerned citizens:
    "1759-MAX-C--CAVITCH", "2824-TIMOTHY-CORRIGAN",
    "1763-EMILY-R-STEINER", "1624-VALERIE-ROSS",
    # no reviews?:
    "416-LUDO-ROCHER", "715-ELIZABETH-ANN-POLLARD", "1094-MARIA-A-COWLES",
    "1500-ANDREW-GALLIA", "1888-RUSSELL-DILEO",
    "1450-SORMANE-PEREIRA-GOMES", "2188-HUI-YI-CHEN", "1165-DOMENIC-VITIELLO",
    "2359-CLAUDIA-CANCINO", "2737-SHEN-WANG", "3229-BERLE-WHITBY",
    # errors:
    "99999", "moo",
    ]

  dept_tests = [
    #fast
    "CSE", "LAW", "ANAT", "KORN", "LATN", "COGS", "MSCI", "GAS",
    #medium
    "CIS", "MATH", "FNAR", "ACCT", "FNCE", "BE", "MUSC", "OPIM",
    #slow
    #"SPAN", "NURS", "ENGL",
    #error
    "EROR"]

  index_tests = ["", "instructors", "coursehistories", "depts",
                 "semesters", "semesters/2010c"]

  course_tests = [] # filled in by coursehistory_tests

  for t in fraclist(index_tests, options.percent):
    test(opts, t)
    
  for t in fraclist(coursehistory_tests, options.percent):
    obj = test(opts, "coursehistories/%s" % t)
    test(opts, "coursehistories/%s/reviews" % t)

    # now "find" some courses
    course_tests.append("2010c-%s" % t)
    try:
      courseid = sorted(obj["result"]["courses"])[0]["id"]
      course_tests.append(courseid)
    except (TypeError, KeyError, IndexError):
      pass
    
  for t in course_tests: # don't fraclist an autogenerated list
    # Some of the autogenerated courses don't exist, so ignore errors.
    root_success = test(opts, "courses/%s" % t, lderror_ok=True)
    if root_success:
      # Course exists, don't expect errors.
      test(opts, "courses/%s/reviews" % t)
      test(opts, "courses/%s/coursehistories/" % t)
      test(opts, "courses/%s/sections" % t)
      
      if test(opts, "courses/%s/sections/001" % t, lderror_ok=True):
        test(opts, "courses/%s/sections/001/reviews" % t)        
        if '-' in str(t): # if we have a yyyys-dept-num test
          test(opts, "sections/%s-001" % t)
        # not tested: sections/001/reviews/instructor-id
      test(opts, "courses/%s/sections/401" % t, lderror_ok=True)
      
  for t in fraclist(instructor_tests, options.percent):
    test(opts, "instructors/%s" % t)
    test(opts, "instructors/%s/sections" % t)
    test(opts, "instructors/%s/reviews" % t)
    
  for t in fraclist(dept_tests, options.percent):
    test(opts, "depts/%s" % t)
    test(opts, "depts/%s/reviews" % t)
    test(opts, "semesters/2010c/%s" % t)
    
def fix_apiroot(root):
  """ Add default protocol and hostname to the root path. """
  if '://' in root:
    return root
  if ('/' not in root) or ('.' not in root.split('/')[0]):
    root = "www.pennapps.com/" + root
  return "http://%s" % root
  
if __name__ == "__main__":
  print """Use "./regtest.py -h" to see options."""

  parser = OptionParser()
  parser.add_option("-a", "--apiroot", default="courses", metavar="PATH",
                    help="e.g. \"courses\", \"pennapps.com/courses\", etc")
  parser.add_option("-o", "--output", default="output", metavar="DIR",
                    help="output directory")
  parser.add_option("-t", "--token", default="<PASSWORD>")
  parser.add_option("-p", "--percent", default=100, type="int",
                    help=("approx fraction of tests to run "
                          "(0...100, smaller=faster)"))
  
  (options, args) = parser.parse_args()
  options.apiroot = fix_apiroot(options.apiroot)

  if not os.path.exists(options.output):
    os.makedirs(options.output)
  
  alltests(options)

<filename>scripts/obsolete/regtest.py
#!/usr/bin/env python

""" Downloads a selection of API paths to a specified directory.
Example usage:

./regtest.py -a pennapps.com/courses -o output-old
./regtest.py -a pennapps.com/courses-mjc -o output-new
diff -r output-old output-new

"""

import urllib2
import os
import json
import time
import sys
from optparse import OptionParser

def sort_lists(obj):
  """Recursively sort all lists that are part of this object. Returns
  a new object."""
  if type(obj) == list:
    return sorted(sort_lists(x) for x in obj)
  elif type(obj) == dict:
    return dict((k, sort_lists(v)) for (k,v) in obj.items())
  else:
    return obj

def test(options, path, lderror_ok=False):
  """ Load the given API path, and save consistently-formatted JSON
  to the output dir. Print status string. Return the object created
  from the JSON, or None on error. 

  The "consistent formatting" includes sorting all lists, since
  the API returns objects in no specified order.

  lderror_ok - if True, we won't print "XLoad" on load error
  """

  waserror = False

  path_nice = path or "index.html"
  
  print "%65s" % path_nice,
  sys.stdout.flush()
  try:
    fullpath = "%s/%s?token=%s" % (options.apiroot, path, options.token)
    start = time.time()
    intext = urllib2.urlopen(fullpath).read()
    print "%7.3f" % (time.time() - start),
  except Exception as e:
    intext = json.dumps({"load error": repr(e)}) # dummy message to save
    print "  -----",
    if not lderror_ok: print "XLoad",
    waserror = True

  try:
    obj = json.loads(intext)
  except Exception as e:
    obj = {"parse error": repr(e)} # dummy object to save
    print "XPars",
    waserror = True

  # format consistently
  obj["retrieved"] = "removed for consistency"
  text = json.dumps(sort_lists(obj), sort_keys=True, indent=4)
  outpath = os.path.join(options.output, path_nice.replace('/','+'))
  file = open(outpath, 'w')
  file.write(text)
  file.close()

  print
  return None if waserror else obj

def fraclist(l, percent):
  """ Return the first `percent`/100 elements from the list l. """
  return l[:int(round(len(l)*percent/100.0))]
  
def alltests(opts):
  """ test ALL the paths
  (burn ALL the server IO bandwidth) """
  
  print "API Root:   %s" % options.apiroot
  print "Token:      %s" % options.token
  print "Output dir: %s" % options.output
  print "Running     %d%% of tests" % options.percent
  print
  
  # need to use DEPT-001, not ID#
  coursehistory_tests = [
    # basic tests:
    "cis-120", "math-114", "engl-101", "econ-001",
    # miscellaneously somewhat problematic:
    "engl-016", "law-205", "hpr-612", "rels-414", "nurs-322",
    "writ-030", "be-310", "psci-010", "psci-136",
    # crosslistings:
    "engl-135", "writ-135", "fnar-264", "cogs-001", "russ-048", "hist-048",
    # no reviews?:
    "afam-271", "ames-071", "slav-532", "afam-285", "prtg-213", "slav-533",
    # errors:
    "99999", "moo",
    ]

  instructor_tests = [
    # basic tests:
    "403", "631", "1883", "2217-FERNANDO-C--PEREIRA", "1602-BENJAMIN-PIERCE",
    # crosslistings:
    "1034-LYLE-H-UNGAR", "2709-DAVID-P--COMBERG",
    # miscellaneously somewhat problematic:
    "1040-DAVID-FOX", "4268-BART-GERARD-C-DE-JONGHE",
    # the instructors w/ the most sections
    "1883", "1619", "2869", "942", "1644", "541", "767", "434",
    # concerned citizens:
    "1759-MAX-C--CAVITCH", "2824-TIMOTHY-CORRIGAN",
    "1763-EMILY-R-STEINER", "1624-VALERIE-ROSS",
    # no reviews?:
    "416-LUDO-ROCHER", "715-ELIZABETH-ANN-POLLARD", "1094-MARIA-A-COWLES",
    "1500-ANDREW-GALLIA", "1888-RUSSELL-DILEO",
    "1450-SORMANE-PEREIRA-GOMES", "2188-HUI-YI-CHEN", "1165-DOMENIC-VITIELLO",
    "2359-CLAUDIA-CANCINO", "2737-SHEN-WANG", "3229-BERLE-WHITBY",
    # errors:
    "99999", "moo",
    ]

  dept_tests = [
    #fast
    "CSE", "LAW", "ANAT", "KORN", "LATN", "COGS", "MSCI", "GAS",
    #medium
    "CIS", "MATH", "FNAR", "ACCT", "FNCE", "BE", "MUSC", "OPIM",
    #slow
    #"SPAN", "NURS", "ENGL",
    #error
    "EROR"]

  index_tests = ["", "instructors", "coursehistories", "depts",
                 "semesters", "semesters/2010c"]

  course_tests = [] # filled in by coursehistory_tests

  for t in fraclist(index_tests, options.percent):
    test(opts, t)
    
  for t in fraclist(coursehistory_tests, options.percent):
    obj = test(opts, "coursehistories/%s" % t)
    test(opts, "coursehistories/%s/reviews" % t)

    # now "find" some courses
    course_tests.append("2010c-%s" % t)
    try:
      courseid = sorted(obj["result"]["courses"])[0]["id"]
      course_tests.append(courseid)
    except (TypeError, KeyError, IndexError):
      pass
    
  for t in course_tests: # don't fraclist an autogenerated list
    # Some of the autogenerated courses don't exist, so ignore errors.
    root_success = test(opts, "courses/%s" % t, lderror_ok=True)
    if root_success:
      # Course exists, don't expect errors.
      test(opts, "courses/%s/reviews" % t)
      test(opts, "courses/%s/coursehistories/" % t)
      test(opts, "courses/%s/sections" % t)
      
      if test(opts, "courses/%s/sections/001" % t, lderror_ok=True):
        test(opts, "courses/%s/sections/001/reviews" % t)        
        if '-' in str(t): # if we have a yyyys-dept-num test
          test(opts, "sections/%s-001" % t)
        # not tested: sections/001/reviews/instructor-id
      test(opts, "courses/%s/sections/401" % t, lderror_ok=True)
      
  for t in fraclist(instructor_tests, options.percent):
    test(opts, "instructors/%s" % t)
    test(opts, "instructors/%s/sections" % t)
    test(opts, "instructors/%s/reviews" % t)
    
  for t in fraclist(dept_tests, options.percent):
    test(opts, "depts/%s" % t)
    test(opts, "depts/%s/reviews" % t)
    test(opts, "semesters/2010c/%s" % t)
    
def fix_apiroot(root):
  """ Add default protocol and hostname to the root path. """
  if '://' in root:
    return root
  if ('/' not in root) or ('.' not in root.split('/')[0]):
    root = "www.pennapps.com/" + root
  return "http://%s" % root
  
if __name__ == "__main__":
  print """Use "./regtest.py -h" to see options."""

  parser = OptionParser()
  parser.add_option("-a", "--apiroot", default="courses", metavar="PATH",
                    help="e.g. \"courses\", \"pennapps.com/courses\", etc")
  parser.add_option("-o", "--output", default="output", metavar="DIR",
                    help="output directory")
  parser.add_option("-t", "--token", default="<PASSWORD>")
  parser.add_option("-p", "--percent", default=100, type="int",
                    help=("approx fraction of tests to run "
                          "(0...100, smaller=faster)"))
  
  (options, args) = parser.parse_args()
  options.apiroot = fix_apiroot(options.apiroot)

  if not os.path.exists(options.output):
    os.makedirs(options.output)
  
  alltests(options)

#!/usr/bin/env python Downloads a selection of API paths to a specified directory. Example usage:  ./regtest.py -a pennapps.com/courses -o output-old ./regtest.py -a pennapps.com/courses-mjc -o output-new diff -r output-old output-new Recursively sort all lists that are part of this object. Returns   a new object. Load the given API path, and save consistently-formatted JSON   to the output dir. Print status string. Return the object created   from the JSON, or None on error.     The "consistent formatting" includes sorting all lists, since   the API returns objects in no specified order.    lderror_ok - if True, we won't print "XLoad" on load error # dummy message to save # dummy object to save # format consistently Return the first `percent`/100 elements from the list l. test ALL the paths   (burn ALL the server IO bandwidth) # need to use DEPT-001, not ID# # basic tests: # miscellaneously somewhat problematic: # crosslistings: # no reviews?: # errors: # basic tests: # crosslistings: # miscellaneously somewhat problematic: # the instructors w/ the most sections # concerned citizens: # no reviews?: # errors: #fast #medium #slow #"SPAN", "NURS", "ENGL", #error # filled in by coursehistory_tests # now "find" some courses # don't fraclist an autogenerated list # Some of the autogenerated courses don't exist, so ignore errors. # Course exists, don't expect errors. # if we have a yyyys-dept-num test # not tested: sections/001/reviews/instructor-id Add default protocol and hostname to the root path. Use "./regtest.py -h" to see options.