def test_lookup_alternate(self): dtab = Dtab.read("""/zk# => /$/com.twitter.serverset; /zk => /zk#; /s## => /zk/zk.local.twitter.com:2181; /s# => /s##/prod; /s => /s#; /s# => /s##/staging;""") one = NameTree.read("/s/crawler") two = dtab.lookup(one) self.assertEqual(two, NameTree.read("/s#/crawler")) alternates = dtab.lookup(two) self.assertIsInstance(alternates, NameTree.Alt) self.assertEqual(len(alternates), 2) self.assertEqual(alternates.trees[0], NameTree.read("/s##/staging/crawler")) three0 = dtab.lookup(alternates.trees[0]) self.assertEqual( three0, NameTree.read("/zk/zk.local.twitter.com:2181/staging/crawler")) four0 = dtab.lookup(three0) self.assertEqual( four0, NameTree.read("/zk#/zk.local.twitter.com:2181/staging/crawler")) five0 = dtab.lookup(four0) self.assertEqual( five0, NameTree.read( "/$/com.twitter.serverset/zk.local.twitter.com:2181/staging/crawler" ), ) self.assertEqual(alternates.trees[1], NameTree.read("/s##/prod/crawler")) three1 = dtab.lookup(alternates.trees[1]) self.assertEqual( three1, NameTree.read("/zk/zk.local.twitter.com:2181/prod/crawler")) four1 = dtab.lookup(three1) self.assertEqual( four1, NameTree.read("/zk#/zk.local.twitter.com:2181/prod/crawler")) five1 = dtab.lookup(four1) self.assertEqual( five1, NameTree.read( "/$/com.twitter.serverset/zk.local.twitter.com:2181/prod/crawler" ), )
def parse_simple(self): self.eat_whitespace() c = chr(self.peek) if c == u('('): self.next() tree = self.parse_tree() self.eat_whitespace() self.eat(')') return tree if c == u('/'): return NameTree.Leaf(self.parse_path()) if c == u('!'): self.next() return NameTree.Fail if c == u('~'): self.next() return NameTree.Neg if c == u('$'): self.next() return NameTree.Empty self.illegal("simple", c)
def test_dtab_read_ignores_comment_line(self): withComments = Dtab.read(""" # a comment /#foo => /biz # another comment | ( /bliz & # yet another comment /bluth ) # duh bluths ; #finalmente #/ignore=>/me; """) dtab = Dtab([ Dentry( Path.Utf8("#foo"), NameTree.Alt( NameTree.Leaf(Path.Utf8("biz")), NameTree.Union( NameTree.Weighted( NameTree.Weighted.defaultWeight, NameTree.Leaf(Path.Utf8("bliz")), ), NameTree.Weighted( NameTree.Weighted.defaultWeight, NameTree.Leaf(Path.Utf8("bluth")), ), ), ), ) ]) s = "Dtab(Label(#foo)=>NameTree.Leaf(Path(/biz))," s += "NameTree.Union(NameTree.Weighted(1.0,NameTree.Leaf(Path(/bliz)))," s += "NameTree.Weighted(1.0,NameTree.Leaf(Path(/bluth)))))" self.assertEqual(repr(dtab), s) self.assertEqual(withComments, dtab)
def lookup(self, path): """Lookup the given `path` with this dtab""" if isinstance(path, NameTree) and hasattr(path, "value"): path = path.value elif not isinstance(path, Path): raise TypeError("Input must be a `dtab.path.Path`") matches = [] # don't use public dentries for dentry in self._dentries: if dentry.prefix.matches(path): suffix = path.elems[dentry.prefix.size:] matches.append( dentry.nametree.map( lambda pfx: NameTree.Leaf(Name.Path(pfx + suffix)))) if not len(matches): return NameTree.Neg elif len(matches) == 1: return matches[0] return NameTree.Alt(*matches)
def parse_tree1(self): trees = [] while True: trees.append(self.parse_weighted()) self.eat_whitespace() if not self.maybe_eat('&'): break if len(trees) > 1: return NameTree.Union(*trees) return trees[0].tree
def parse_weighted(self): self.eat_whitespace() weight = None if not self.is_number_char(self.peek): weight = NameTree.Weighted.defaultWeight else: weight = self.parse_number() self.eat_whitespace() self.eat('*') self.eat_whitespace() return NameTree.Weighted(weight, self.parse_simple())
def parse_tree(self): trees = [] while True: trees.append(self.parse_tree1()) self.eat_whitespace() if not self.maybe_eat('|'): break if len(trees) > 1: return NameTree.Alt(*trees) return trees[0]
def test_lookup_simple(self): dtab = Dtab.read("""/zk# => /$/com.twitter.serverset; /zk => /zk#; /s## => /zk/zk.local.twitter.com:2181; /s# => /s##/prod; /s => /s#;""") one = NameTree.read("/s/crawler") two = dtab.lookup(one) self.assertEqual(two, NameTree.read("/s#/crawler")) three = dtab.lookup(two) self.assertEqual(three, NameTree.read("/s##/prod/crawler")) four = dtab.lookup(three) self.assertEqual( four, NameTree.read("/zk/zk.local.twitter.com:2181/prod/crawler")) five = dtab.lookup(four) self.assertEqual( five, NameTree.read("/zk#/zk.local.twitter.com:2181/prod/crawler")) six = dtab.lookup(five) self.assertEqual( six, NameTree.read( "/$/com.twitter.serverset/zk.local.twitter.com:2181/prod/crawler" ), )
def lookup(self, path): """Lookup the given `path` with this dtab""" matches = [] # don't use public dentries for dentry in self._dentries: if dentry.prefix.matches(path): suffix = path.elems[dentry.prefix.size:] matches.append( dentry.nametree.map(lambda pfx: Name.Path(pfx + suffix))) if not len(matches): return NameTree.Neg elif len(matches) == 1: return matches[0] return NameTree.Alt(*matches)
def test_parseDtab(self): self.assertTrue(NameTreeParsers.parseDtab("") == Dtab.empty) self.assertTrue( NameTreeParsers.parseDtab(" /=>! ") == Dtab( [Dentry(Path.empty, NameTree.Fail)])) self.assertTrue( NameTreeParsers.parseDtab("/=>!;") == Dtab( [Dentry(Path.empty, NameTree.Fail)])) self.assertTrue( NameTreeParsers.parseDtab("/=>!;/foo=>/bar") == Dtab([ Dentry(Path.empty, NameTree.Fail), Dentry(Path.Utf8("foo"), NameTree.Leaf(Path.Utf8("bar"))) ]))
def test_parseNameTree(self): defaultWeight = NameTree.Weighted.defaultWeight self.assertTrue( NameTreeParsers.parseNameTree("! | ~ | $") == NameTree.Alt( NameTree.Fail, NameTree.Neg, NameTree.Empty)) self.assertTrue( NameTreeParsers.parseNameTree("/foo/bar") == NameTree.Leaf( Path.Utf8("foo", "bar"))) self.assertTrue( NameTreeParsers.parseNameTree(" /foo & /bar ") == NameTree.Union( NameTree.Weighted(defaultWeight, NameTree.Leaf(Path.Utf8( "foo"))), NameTree.Weighted(defaultWeight, NameTree.Leaf(Path.Utf8( "bar"))))) self.assertTrue( NameTreeParsers.parseNameTree(" /foo | /bar ") == NameTree.Alt( NameTree.Leaf(Path.Utf8("foo")), NameTree.Leaf(Path.Utf8( "bar")))) self.assertTrue( NameTreeParsers.parseNameTree("/foo & /bar | /bar & /baz") == NameTree.Alt( NameTree.Union( NameTree.Weighted(defaultWeight, NameTree.Leaf(Path.Utf8("foo"))), NameTree.Weighted(defaultWeight, NameTree.Leaf(Path.Utf8("bar")))), NameTree.Union( NameTree.Weighted(defaultWeight, NameTree.Leaf(Path.Utf8("bar"))), NameTree.Weighted(defaultWeight, NameTree.Leaf(Path.Utf8("baz")))))) self.assertTrue( NameTreeParsers.parseNameTree( "1 * /foo & 2 * /bar | .5 * /bar & .5 * /baz") == NameTree.Alt( NameTree.Union( NameTree.Weighted(1, NameTree.Leaf(Path.Utf8("foo"))), NameTree.Weighted(2, NameTree.Leaf(Path.Utf8("bar")))), NameTree.Union( NameTree.Weighted(0.5, NameTree.Leaf(Path.Utf8("bar"))), NameTree.Weighted(0.5, NameTree.Leaf(Path.Utf8("baz")))))) with self.assertRaises(IllegalArgumentException): NameTreeParsers.parseNameTree("") with self.assertRaises(IllegalArgumentException): NameTreeParsers.parseNameTree("#") with self.assertRaises(IllegalArgumentException): NameTreeParsers.parseNameTree("/foo &") with self.assertRaises(IllegalArgumentException): NameTreeParsers.parseNameTree("/foo & 0.1.2 * /bar") with self.assertRaises(IllegalArgumentException): NameTreeParsers.parseNameTree("/foo & . * /bar")
def test_dtab_rewrites_with_wildcard(self): dtab = Dtab.read("/a/*/c => /d") nametree = dtab.lookup(Path.read("/a/b/c/e/f")) leaf = NameTree.Leaf(Name.Path(Path.read("/d/e/f"))) self.assertEqual(nametree, leaf)