Commit 24aed768 authored by Chris W's avatar Chris W
Browse files

Merge pull request #1 from cwacek/bug_7924

Merging fixes for #7924
parents 8c2259c9 7438c0e9
Loading
Loading
Loading
Loading
+27 −19
Original line number Diff line number Diff line
@@ -8,25 +8,30 @@ from flask import Flask, request, jsonify, render_template,Response
app = Flask(__name__)

class Opt(object):
    request_types = {
      'by_as':Boolean,
      'by_country':Boolean,
      'inactive':Boolean,
      'exits_only':Boolean,
      'guards_only': Boolean,
      'links':Boolean,
      'sort':NullFn,
      'sort_reverse':Boolean,
      'top':Int,
      'family':NullFn,
      'ases':List,
      'country':JSON,
      'exit_filter':NullFn
    option_details = {
      'by_as':(Boolean, False),
      'by_country':(Boolean, False),
      'inactive':( Boolean, False ),
      'exits_only':( Boolean, False ),
      'guards_only': ( Boolean, False),
      'links':( Boolean, True ),
      'sort':( NullFn, "cw" ),
      'sort_reverse':( Boolean, True ),
      'top':( Int , 10),
      'family':( NullFn, "" ),
      'ases':( List, [] ),
      'country':( JSON, [] ),
      'exit_filter':( NullFn, "all_relays" )
    }


    @staticmethod
    def convert(key,val):
      return Opt.request_types[key](val)
      return Opt.option_details[key][0](val)

    @staticmethod
    def default(key):
      return Opt.option_details[key][1]

    def __str__(self):
      return repr(self)
@@ -35,12 +40,11 @@ class Opt(object):
      return str(self.__dict__)

    def __init__(self,request):

      for key in Opt.request_types:
      for key in Opt.option_details:
        if key in request:
          setattr(self,key,Opt.convert(key,request[key]))
        else:
          setattr(self,key,Opt.convert(key,None))
          setattr(self,key,Opt.default(key))

def parse(output_string, grouping=False, sort_key=None):
    results = []
@@ -120,7 +124,11 @@ def index():
def json_result():
    options = Opt(dict(request.args.items()))

    if "TESTING_DATAFILE" in app.config and "TESTING" in app.config:
      stats = compass.RelayStats(options,app.config['TESTING_DATAFILE'])
    else:
      stats = compass.RelayStats(options)

    results = stats.select_relays(stats.relays, options)

    relays = stats.sort_and_reduce(results,
+14 −6
Original line number Diff line number Diff line
@@ -184,16 +184,17 @@ class InverseFilter(BaseFilter):
        return inverse_relays

class RelayStats(object):
    def __init__(self, options):
    def __init__(self, options, custom_datafile="details.json"):
        self._data = None
        self._filters = self._create_filters(options)
        self._get_group = self._get_group_function(options)
        self._relays = None
        self._datafile_name = custom_datafile

    @property
    def data(self):
      if not self._data:
            self._data = json.load(file(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'details.json')))
        self._data = json.load(file(os.path.join(os.path.dirname(os.path.abspath(__file__)), self._datafile_name)))
      return self._data

    @property
@@ -493,6 +494,10 @@ def create_option_parser():

    group.add_option("-s", "--short", action="store_const",dest='short',const=70,
                     help="cut the length of the line output at 70 chars")
    group.add_option("-j", "--json", action="store_true",
                     help="output in JSON rather than human-readable format")
    group.add_option("--datafile", default="details.json",
                     help="use a custom datafile (Default: 'details.json')")
    parser.add_option_group(group)
    return parser

@@ -549,10 +554,13 @@ if '__main__' == __name__:
    if not os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'details.json')):
        parser.error("Did not find details.json.  Re-run with --download.")

    stats = RelayStats(options)
    stats = RelayStats(options,options.datafile)
    results = stats.select_relays(stats.relays,options)

    sorted_results = stats.sort_and_reduce(results,options)

    if options.json:
      print(json.dumps(sorted_results,cls=util.ResultEncoder))
    else:
      stats.print_selection(sorted_results,options)

testing/__init__.py

0 → 100644
+0 −0

Empty file added.

testing/app_tests.py

0 → 100644
+53 −0
Original line number Diff line number Diff line
import unittest
import json
from app import app

class TestCase(unittest.TestCase):
  def setUp(self):
    app.config['TESTING'] = True
    app.config["TESTING_DATAFILE"] = "testing/testdata.json"
    self.app = app.test_client()

  def tearDown(self):
    pass

  def test_empty_query(self):
    response = self.app.get("/result.json")
    expected = json.loads(open("testing/expectations/noparam.expected").read())
    received = json.loads(response.data)
    self.assertItemsEqual(received,expected)


  def test_select_nonexistent_AS(self):
    received= json.loads(self.app.get("/result.json?ases=AS3320").data)
    expected = json.loads(
"""
{"total": {"fp": "", "index": null, "as_no": "", "nick": "", "cc": "", "p_exit": 0.0, "adv_bw": 0.0, "guard": "", "link": true, "p_guard": 0.0, "p_middle": 0.0, "exit": "", "as_info": "", "cw": 0.0, "as_name": ""}, "results": [], "excluded": null}
"""
    )
    self.assertItemsEqual(received,expected)

  def test_select_AS_by_number(self):
    received = json.loads(self.app.get("/result.json?ases=7922").data)
    expected = json.loads(
      """
      {"total": {"fp": "", "index": null, "as_no": "", "nick": "(total in selection)", "cc": "", "p_exit": 0.0018185999999999999, "adv_bw": 0.005388199999999999, "guard": "", "link": true, "p_guard": 0.0, "p_middle": 0.0034887, "exit": "", "as_info": "", "cw": 0.0017691999999999999, "as_name": ""}, "results": [{"fp": "CE9CC720B9300FC7E041CCC2B749F283AB5EE1C2", "index": 1, "as_no": "AS7922", "nick": "Tornearse", "cc": "US", "p_exit": 0.0018185999999999999, "adv_bw": 0.005388199999999999, "guard": "-", "link": null, "p_guard": 0.0, "p_middle": 0.0034887, "exit": "Exit", "as_info": "AS7922 Comcast Cable Communications, Inc.", "cw": 0.0017691999999999999, "as_name": "Comcast Cable Communications, Inc."}], "excluded": null}
      """)
    self.assertItemsEqual(received,expected)

  def test_select_AS_with_label(self):
    received = json.loads(self.app.get("/result.json?ases=AS7922").data)
    expected = json.loads(
      """
      {"total": {"fp": "", "index": null, "as_no": "", "nick": "(total in selection)", "cc": "", "p_exit": 0.0018185999999999999, "adv_bw": 0.005388199999999999, "guard": "", "link": true, "p_guard": 0.0, "p_middle": 0.0034887, "exit": "", "as_info": "", "cw": 0.0017691999999999999, "as_name": ""}, "results": [{"fp": "CE9CC720B9300FC7E041CCC2B749F283AB5EE1C2", "index": 1, "as_no": "AS7922", "nick": "Tornearse", "cc": "US", "p_exit": 0.0018185999999999999, "adv_bw": 0.005388199999999999, "guard": "-", "link": null, "p_guard": 0.0, "p_middle": 0.0034887, "exit": "Exit", "as_info": "AS7922 Comcast Cable Communications, Inc.", "cw": 0.0017691999999999999, "as_name": "Comcast Cable Communications, Inc."}], "excluded": null}
      """)
    self.assertItemsEqual(received,expected)

  def test_limit_dataset_size(self):
    received = json.loads(self.app.get("/result.json?top=5").data)
    self.assertEqual(len(received['results']),5)
    expected = json.loads(open("testing/expectations/top5.expected").read())
    self.assertItemsEqual(received,expected)

if __name__ == '__main':
  unittest.main()
+2 −0
Original line number Diff line number Diff line
A set of datafiles used by the unit tests in the parent directory to validate
responses
Loading