def test(top_xml, diag_xml, expected_error): root = qdom.parse( BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}"> <name>Top-level</name> <summary>Top-level</summary> <group> {top_xml} </group> </interface>""".format(top=top_uri, top_xml=top_xml).encode("utf-8"))) self.import_feed(top_uri, root) root = qdom.parse( BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}"> <name>Diagnostics</name> <summary>Diagnostics</summary> <group> {impls} </group> </interface>""".format(diag=diag_uri, impls=diag_xml).encode("utf-8"))) self.import_feed(diag_uri, root) root = qdom.parse( BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}"> <name>Old</name> <summary>Old</summary> <feed src='{diag}'/> <replaced-by interface='{diag}'/> </interface>""".format(diag=diag_uri, old=old_uri).encode("utf-8"))) self.import_feed(old_uri, root) r = Requirements(top_uri) r.os = "Windows" r.cpu = "x86_64" s = solver.DefaultSolver(self.config) s.solve_for(r) assert not s.ready, s.selections.selections if expected_error != str(s.get_failure_reason()): print(s.get_failure_reason()) self.assertEqual(expected_error, str(s.get_failure_reason())) return s
def test(top_xml, diag_xml, expected_error): root = qdom.parse(BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}"> <name>Top-level</name> <summary>Top-level</summary> <group> {top_xml} </group> </interface>""".format(top = top_uri, top_xml = top_xml).encode("utf-8"))) self.import_feed(top_uri, root) root = qdom.parse(BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}"> <name>Diagnostics</name> <summary>Diagnostics</summary> <group> {impls} </group> </interface>""".format(diag = diag_uri, impls = diag_xml).encode("utf-8"))) self.import_feed(diag_uri, root) root = qdom.parse(BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}"> <name>Old</name> <summary>Old</summary> <feed src='{diag}'/> <replaced-by interface='{diag}'/> </interface>""".format(diag = diag_uri, old = old_uri).encode("utf-8"))) self.import_feed(old_uri, root) r = Requirements(top_uri) r.os = "Windows" r.cpu = "x86_64" s = solver.DefaultSolver(self.config) s.solve_for(r) assert not s.ready, s.selections.selections if expected_error != str(s.get_failure_reason()): print(s.get_failure_reason()) self.assertEqual(expected_error, str(s.get_failure_reason())) return s
def testDiagnostics(self): top_uri = 'http://localhost/top.xml' old_uri = 'http://localhost/diagnostics-old.xml' diag_uri = 'http://localhost/diagnostics.xml' def test(top_xml, diag_xml, expected_error): root = qdom.parse( BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}"> <name>Top-level</name> <summary>Top-level</summary> <group> {top_xml} </group> </interface>""".format(top=top_uri, top_xml=top_xml).encode("utf-8"))) self.import_feed(top_uri, root) root = qdom.parse( BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}"> <name>Diagnostics</name> <summary>Diagnostics</summary> <group> {impls} </group> </interface>""".format(diag=diag_uri, impls=diag_xml).encode("utf-8"))) self.import_feed(diag_uri, root) root = qdom.parse( BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}"> <name>Old</name> <summary>Old</summary> <feed src='{diag}'/> <replaced-by interface='{diag}'/> </interface>""".format(diag=diag_uri, old=old_uri).encode("utf-8"))) self.import_feed(old_uri, root) r = Requirements(top_uri) r.os = "Windows" r.cpu = "x86_64" s = solver.DefaultSolver(self.config) s.solve_for(r) assert not s.ready, s.selections.selections if expected_error != str(s.get_failure_reason()): print(s.get_failure_reason()) self.assertEqual(expected_error, str(s.get_failure_reason())) return s # No implementations s = test( "", "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " No known implementations at all") # No retrieval method s = test( "<implementation version='1' id='1'><requires interface='{diag}'/></implementation>" .format(diag=diag_uri), "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " No usable implementations:\n" + " 1 (1): No retrieval methods") # No run command s = test( """<implementation version='1' id='1'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> <version not-before='100'/> </requires> </implementation>""".format(diag=diag_uri), "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " Rejected candidates:\n" + " 1: No run command") # Missing command from dependency s = test( """<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> <binding command='foo'/> </requires> </implementation>""".format(diag=diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation>""", "Can't find all required implementations:\n" + "- http://localhost/diagnostics.xml -> (problem)\n" + " http://localhost/top.xml 1 requires 'foo' command\n" + " Rejected candidates:\n" + " diag-5: No foo command\n" + "- http://localhost/top.xml -> 1 (1)") # Failing distribution requirement s = test( """<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}' distribution='foo'/> </implementation>""".format(diag=diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires distro foo\n" " No usable implementations satisfy the restrictions:\n" " diag-5 (5): incompatible with restrictions\n" "- http://localhost/top.xml -> 1 (1)") # Failing version requirement on library s = test( """<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}' version='100..!200'/> </implementation>""".format(diag=diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires version 100..!200\n" " No usable implementations satisfy the restrictions:\n" " diag-5 (5): incompatible with restrictions\n" "- http://localhost/top.xml -> 1 (1)") # Failing version requires on root s = test( """<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'/> </implementation>""".format(diag=diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> <restricts interface='{top_uri}' version='100..!200'/> </implementation> """.format(top_uri=top_uri), "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " Rejected candidates:\n" " diag-5: requires http://localhost/top.xml version 100..!200\n" "- http://localhost/top.xml -> 1 (1)") # Parse error in version restriction logger.setLevel(logging.ERROR) s = test( """<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}' version='100..200'/> </implementation>""".format(diag=diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires <impossible: Can't parse version restriction '100..200': End of range must be exclusive (use '..!200', not '..200')>\n" " No usable implementations satisfy the restrictions:\n" " diag-5 (5): incompatible with restrictions\n" "- http://localhost/top.xml -> 1 (1)") logger.setLevel(logging.WARNING) # Old-style version restriction s = test( """<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> <version not-before='100'/> </requires> </implementation>""".format(diag=diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires 100 <= version\n" " No usable implementations satisfy the restrictions:\n" " diag-5 (5): incompatible with restrictions\n" "- http://localhost/top.xml -> 1 (1)") # Mismatched machine types s = test( """<group> <requires interface='{diag}'/> <implementation version='1' id='1' main='foo' arch='Windows-i486'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag=diag_uri), """<group> <implementation version='5' id='diag-5' arch='Windows-x86_64'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> </group> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " Rejected candidates:\n" " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" "- http://localhost/top.xml -> 1 (1)") # Only show the first five unusable reasons s = test( """<group> <requires interface='{diag}'/> <implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag=diag_uri), """<group> <implementation version='1' id='diag-1'/> <implementation version='2' id='diag-2'/> <implementation version='3' id='diag-3'/> <implementation version='4' id='diag-4'/> <implementation version='5' id='diag-5'/> <implementation version='6' id='diag-6'/> </group> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " No usable implementations:\n" " diag-6 (6): No retrieval methods\n" " diag-5 (5): No retrieval methods\n" " diag-4 (4): No retrieval methods\n" " diag-3 (3): No retrieval methods\n" " diag-2 (2): No retrieval methods\n" " ...\n" "- http://localhost/top.xml -> 1 (1)") # Only show the first five rejection reasons s = test( """<group> <requires interface='{diag}'> <version before='6'/> </requires> <implementation version='1' id='1' main='foo' arch='Windows-i486'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag=diag_uri), """<group> <implementation version='5' id='diag-5' arch='Windows-x86_64'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> <implementation version='6' id='diag-6' arch='Windows-i486'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> {others} </group> """.format(others="\n".join( """<implementation version='{i}' id='diag-{i}' arch='Windows-x86_64'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation>""".format(i=i) for i in range(0, 5))), "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires version < 6\n" " Rejected candidates:\n" " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" " diag-4: Can't use x86_64 with selection of Top-level (i486)\n" " diag-3: Can't use x86_64 with selection of Top-level (i486)\n" " diag-2: Can't use x86_64 with selection of Top-level (i486)\n" " diag-1: Can't use x86_64 with selection of Top-level (i486)\n" " ...\n" "- http://localhost/top.xml -> 1 (1)") # Justify why a particular version can't be used iface = self.config.iface_cache.get_interface(diag_uri) impl = self.config.iface_cache.get_feed( diag_uri).implementations['diag-5'] r = Requirements(top_uri) r.os = 'Windows' r.cpu = 'x86_64' self.assertEqual( "There is no possible selection using Diagnostics 5.\n" "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires version < 6\n" " User requested implementation 5 (diag-5)\n" " Rejected candidates:\n" " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" "- http://localhost/top.xml -> 1 (1)", s.justify_decision(r, iface, impl)) # Can't select old and diag because they conflict test( """<group> <requires interface='{diag}'/> <requires interface='{old}'/> <implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag=diag_uri, old=old_uri), """<group> <implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> </group> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics-old.xml -> (problem)\n" " Replaced by (and therefore conflicts with) http://localhost/diagnostics.xml\n" " No usable implementations satisfy the restrictions:\n" " diag-5 (5): incompatible with restrictions\n" "- http://localhost/diagnostics.xml -> 5 (diag-5)\n" " Replaces (and therefore conflicts with) http://localhost/diagnostics-old.xml\n" "- http://localhost/top.xml -> 1 (1)")
def testDiagnostics(self): top_uri = 'http://localhost/top.xml' old_uri = 'http://localhost/diagnostics-old.xml' diag_uri = 'http://localhost/diagnostics.xml' def test(top_xml, diag_xml, expected_error): root = qdom.parse(BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{top}"> <name>Top-level</name> <summary>Top-level</summary> <group> {top_xml} </group> </interface>""".format(top = top_uri, top_xml = top_xml).encode("utf-8"))) self.import_feed(top_uri, root) root = qdom.parse(BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{diag}"> <name>Diagnostics</name> <summary>Diagnostics</summary> <group> {impls} </group> </interface>""".format(diag = diag_uri, impls = diag_xml).encode("utf-8"))) self.import_feed(diag_uri, root) root = qdom.parse(BytesIO("""<?xml version="1.0" ?> <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface" uri="{old}"> <name>Old</name> <summary>Old</summary> <feed src='{diag}'/> <replaced-by interface='{diag}'/> </interface>""".format(diag = diag_uri, old = old_uri).encode("utf-8"))) self.import_feed(old_uri, root) r = Requirements(top_uri) r.os = "Windows" r.cpu = "x86_64" s = solver.DefaultSolver(self.config) s.solve_for(r) assert not s.ready, s.selections.selections self.assertEqual(expected_error, str(s.get_failure_reason())) return s s = test("", "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " No known implementations at all") s = test("<implementation version='1' id='1'><requires interface='{diag}'/></implementation>".format(diag = diag_uri), "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " No usable implementations:\n" + " 1: No retrieval methods") s = test("""<implementation version='1' id='1'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> <version not-before='100'/> </requires> </implementation>""".format(diag = diag_uri), "", "Can't find all required implementations:\n" + "- http://localhost/top.xml -> (problem)\n" + " Rejected candidates:\n" + " 1: No run command") s = test("""<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}' version='100..!200'/> </implementation>""".format(diag = diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires version 100..!200\n" " No usable implementations satisfy the restrictions\n" "- http://localhost/top.xml -> 1 (1)") logger.setLevel(logging.ERROR) s = test("""<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}' version='100..200'/> </implementation>""".format(diag = diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires <impossible: Can't parse version restriction '100..200': End of range must be exclusive (use '..!200', not '..200')>\n" " No usable implementations satisfy the restrictions\n" "- http://localhost/top.xml -> 1 (1)") logger.setLevel(logging.WARNING) s = test("""<implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> <requires interface='{diag}'> <version not-before='100'/> </requires> </implementation>""".format(diag = diag_uri), """<implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires 100 <= version\n" " No usable implementations satisfy the restrictions\n" "- http://localhost/top.xml -> 1 (1)") s = test("""<group> <requires interface='{diag}'/> <implementation version='1' id='1' main='foo' arch='Windows-i486'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag = diag_uri), """<group> <implementation version='5' id='diag-5' arch='Windows-x86_64'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> </group> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " Rejected candidates:\n" " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" "- http://localhost/top.xml -> 1 (1)") s = test("""<group> <requires interface='{diag}'/> <implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag = diag_uri), """<group> <implementation version='1' id='diag-1'/> <implementation version='2' id='diag-2'/> <implementation version='3' id='diag-3'/> <implementation version='4' id='diag-4'/> <implementation version='5' id='diag-5'/> <implementation version='6' id='diag-6'/> </group> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " No usable implementations:\n" " diag-6: No retrieval methods\n" " diag-5: No retrieval methods\n" " diag-4: No retrieval methods\n" " diag-3: No retrieval methods\n" " diag-2: No retrieval methods\n" " ...\n" "- http://localhost/top.xml -> 1 (1)") s = test("""<group> <requires interface='{diag}'> <version before='6'/> </requires> <implementation version='1' id='1' main='foo' arch='Windows-i486'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag = diag_uri), """<group> <implementation version='5' id='diag-5' arch='Windows-x86_64'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> <implementation version='6' id='diag-6' arch='Windows-i486'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> {others} </group> """.format(others = "\n".join( """<implementation version='{i}' id='diag-{i}' arch='Windows-x86_64'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation>""".format(i = i) for i in range(0, 5))), "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires version < 6\n" " Rejected candidates:\n" " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" " diag-4: Can't use x86_64 with selection of Top-level (i486)\n" " diag-3: Can't use x86_64 with selection of Top-level (i486)\n" " diag-2: Can't use x86_64 with selection of Top-level (i486)\n" " diag-1: Can't use x86_64 with selection of Top-level (i486)\n" " ...\n" "- http://localhost/top.xml -> 1 (1)") iface = self.config.iface_cache.get_interface(diag_uri) impl = self.config.iface_cache.get_feed(diag_uri).implementations['diag-5'] r = Requirements(top_uri) r.os = 'Windows' self.assertEqual("There is no possible selection using Diagnostics 5.\n" "Can't find all required implementations:\n" "- http://localhost/diagnostics.xml -> (problem)\n" " http://localhost/top.xml 1 requires version < 6\n" " User requested implementation 5 (diag-5)\n" " Rejected candidates:\n" " diag-5: Can't use x86_64 with selection of Top-level (i486)\n" "- http://localhost/top.xml -> 1 (1)", s.justify_decision(r, iface, impl)) # Can't select old and diag because they conflict test("""<group> <requires interface='{diag}'/> <requires interface='{old}'/> <implementation version='1' id='1' main='foo'> <archive href='http://localhost:3000/foo.tgz' size='100'/> </implementation> </group>""".format(diag = diag_uri, old = old_uri), """<group> <implementation version='5' id='diag-5'> <archive href='http://localhost:3000/diag.tgz' size='100'/> </implementation> </group> """, "Can't find all required implementations:\n" "- http://localhost/diagnostics-old.xml -> (problem)\n" " Replaced by (and therefore conflicts with) http://localhost/diagnostics.xml\n" " No usable implementations satisfy the restrictions\n" "- http://localhost/diagnostics.xml -> 5 (diag-5)\n" " Replaces (and therefore conflicts with) http://localhost/diagnostics-old.xml\n" "- http://localhost/top.xml -> 1 (1)")