Beispiel #1
0
    def test_cannotdecides(self):
        # https://github.com/psss/fmf/issues/117
        # CannotDecide and True = True and CannotDecide = CannotDecide
        # CannotDecide and False = False and CannotDecide = False
        # CannotDecide or True = True or CannotDecide = True
        # CannotDecide or False = False or CannotDecide = CannotDecide
        _true = "foo == bar"
        _false = "foo != bar"
        _cannot = "baz == bar"
        env = Context(foo="bar")
        for a, op, b in [
            (_cannot, 'and', _true),
            (_true, 'and', _cannot),
            (_cannot, 'or', _false),
            (_false, 'or', _cannot),
        ]:
            exp = "{0} {1} {2}".format(a, op, b)
            with pytest.raises(CannotDecide):
                env.matches(exp)
        for outcome, a, op, b in [
            (False, _cannot, 'and', _false),
            (False, _false, 'and', _cannot),
            (True, _cannot, 'or', _true),
            (True, _true, 'or', _cannot),
        ]:
            exp = "{0} {1} {2}".format(a, op, b)
            assert env.matches(exp) == outcome

        assert env.matches("{0} and {1} or {2}".format(_cannot, _false, _true))
        assert not env.matches("{0} or {1} and {2}".format(
            _false, _cannot, _false))
Beispiel #2
0
    def test_matches_groups(self):
        """ and/or in rules with yes/no/cannotdecide outcome """
        context = Context(distro="centos-8.2.0")

        # Clear outcome
        assert context.matches("distro = centos-8.2.0 or distro = fedora")
        assert context.matches("distro = fedora or distro = centos-8.2.0")
        assert not context.matches("distro != centos-8.2.0 or distro = fedora")
        assert context.matches("distro = centos-8 and distro = centos-8.2")
        assert not context.matches("distro = centos-8 and distro = centos-8.6")

        # Some operators cannot be decided
        assert context.matches("distro = centos-8.2.0 or foo=bar")
        assert context.matches("foo=bar or distro = centos-8.2.0")
        assert context.matches(
            "foo=bar and distro = centos-8.2.0"
        )  # skip over 'foo' part since it is not defined
        assert not context.matches("foo=bar and distro = rhel")
        assert not context.matches("foo=bar or distro = centos-8.9.0")

        # Whole rule cannot be decided
        for undecidable in [
                "foo = baz",
                "foo = baz and distro ~<= centos-7.2",  # both are CannotDecide
                "foo = baz and distro ~<= fedora-32 or do=done",
        ]:
            with pytest.raises(CannotDecide):
                context.matches(undecidable)
Beispiel #3
0
    def test_known_troublemakers(self):
        """ Do not regress on these expressions """

        # From fmf/issues/89:
        # following is true (missing left values are treated as lower)
        assert Context(distro='foo-1').matches('distro < foo-1.1')
        # but only if at least one version part is defined
        with pytest.raises(CannotDecide):
            Context(distro='fedora').matches('distro < fedora-33')
        # so use ~ if you need an explict Major check
        with pytest.raises(CannotDecide):
            Context(distro='fedora').matches('distro ~< fedora-33')

        assert Context(distro='fedora-33').matches('distro == fedora')
        with pytest.raises(CannotDecide):
            Context("module = py:5.28").matches("module > perl:5.28")
        with pytest.raises(CannotDecide):
            Context("module = py:5").matches("module > perl:5.28")
        with pytest.raises(CannotDecide):
            Context("module = py:5").matches("module >= perl:5.28")
        with pytest.raises(CannotDecide):
            Context("distro = centos").matches("distro >= fedora")

        assert Context("distro = centos").matches("distro != fedora")
        assert not Context("distro = centos").matches("distro == fedora")

        rhel7 = Context("distro = rhel-7")
        assert rhel7.matches("distro == rhel")
        assert rhel7.matches("distro == rhel-7")
        assert not rhel7.matches("distro == rhel-7.3")
        assert not rhel7.matches("distro == rhel-7.3.eus")
        assert rhel7.matches("distro >= rhel-7")
        assert not rhel7.matches("distro >= rhel-7.3")
        assert not rhel7.matches("distro >= rhel-7.3.eus")
        with pytest.raises(CannotDecide):
            rhel7.matches("distro ~> rhel-7.3")
        assert not rhel7.matches("distro > rhel")

        # https://github.com/psss/fmf/pull/128#pullrequestreview-631589335
        expr = "distro < fedora-33 or distro < centos-6.9"
        # Checking `CannotDecide or False`
        for distro in "fedora-33 fedora-34 centos-7.7".split():
            with pytest.raises(CannotDecide):
                Context(distro=distro).matches(expr)
        # Checking `CannotDecide or True`
        assert Context(distro="centos-6.5").matches(expr)
        assert Context(distro="fedora-32").matches(expr)
Beispiel #4
0
    def test_known_troublemakers(self):
        """ Do not regress on these expressions """

        # From fmf/issues/89:
        # following is true (missing left values are treated as lower)
        assert Context(distro='foo-1').matches('distro < foo-1.1')
        # but only if at least one version part is defined
        with pytest.raises(CannotDecide):
            Context(distro='fedora').matches('distro < fedora-33')
        # so use ~ if you need an explict Major check
        with pytest.raises(CannotDecide):
            Context(distro='fedora').matches('distro ~< fedora-33')

        assert Context(distro='fedora-33').matches('distro == fedora')
        with pytest.raises(CannotDecide):
            Context("module = py:5.28").matches("module > perl:5.28")
        with pytest.raises(CannotDecide):
            Context("module = py:5").matches("module > perl:5.28")
        with pytest.raises(CannotDecide):
            Context("module = py:5").matches("module >= perl:5.28")
        with pytest.raises(CannotDecide):
            Context("distro = centos").matches("distro >= fedora")

        assert Context("distro = centos").matches("distro != fedora")
        assert not Context("distro = centos").matches("distro == fedora")

        rhel7 = Context("distro = rhel-7")
        assert rhel7.matches("distro == rhel")
        assert rhel7.matches("distro == rhel-7")
        assert not rhel7.matches("distro == rhel-7.3")
        assert not rhel7.matches("distro == rhel-7.3.eus")
        assert rhel7.matches("distro >= rhel-7")
        assert not rhel7.matches("distro >= rhel-7.3")
        assert not rhel7.matches("distro >= rhel-7.3.eus")
        with pytest.raises(CannotDecide):
            rhel7.matches("distro ~> rhel-7.3")
        assert not rhel7.matches("distro > rhel")
Beispiel #5
0
    def test_module_streams(self):
        """ How you can use Context for modules """
        perl = Context("module = perl:5.28")
        mix = Context("module = perl:5.28,php:7.3")

        assert perl.matches("module >= perl:5")
        assert not perl.matches("module > perl:5")

        assert perl.matches("module > perl:5.7")
        assert perl.matches("module >= perl:5.28")

        assert not perl.matches("module > perl:6")
        assert not perl.matches("module > perl:6.2")
        assert not perl.matches("module >= perl:6.2")

        # Using ~ to compare only within same minor
        # e.g feature in 5.28+ but dropped in perl6
        assert perl.matches("module ~>= perl:5.28")
        with pytest.raises(CannotDecide):
            Context("module = perl:6.28").matches("module ~>= perl:5.28")
Beispiel #6
0
    def test_minor_eq(self):
        centos = Context(distro="centos-8.2.0")
        for not_equal in ["fedora", "fedora-3", "centos-7"]:
            assert not centos.matches("distro ~= {}".format(not_equal))
        assert centos.matches("distro ~= centos")
        assert centos.matches("distro ~= centos-8")
        assert centos.matches("distro ~= centos-8.2")
        assert not centos.matches("distro ~= centos-8.3")
        assert centos.matches("distro ~= centos-8.2.0")
        assert not centos.matches("distro ~= centos-8.3.0")
        with pytest.raises(CannotDecide):
            centos.matches("distro ~= centos-8.2.0.0")

        multi = Context(distro=["centos-8.2.0", "centos-7.6.0"])
        for not_equal in [
                "fedora", "fedora-3", "rhel-7", "rhel-7.8.0", "centos-6",
                "centos-6.5"
        ]:
            assert not multi.matches("distro ~= {}".format(not_equal))
        assert multi.matches("distro ~= centos")
        assert multi.matches("distro ~= centos-8")
        assert not multi.matches("distro ~= centos-8.3")
        assert multi.matches("distro ~= centos-7")
        assert multi.matches("distro ~= centos-7.6")
        assert not multi.matches("distro ~= centos-7.5")

        multi_rh = Context(distro=["centos-8.2.0", "rhel-8.2.0", "fedora-40"])
        assert multi_rh.matches("distro ~= centos")
        assert multi_rh.matches("distro ~= rhel")
        assert multi_rh.matches("distro ~= fedora")

        assert multi_rh.matches("distro ~= centos-8")
        assert multi_rh.matches("distro ~= rhel-8")
        assert multi_rh.matches("distro ~= fedora-40")

        assert not multi_rh.matches("distro ~= centos-9")
        assert not multi_rh.matches("distro ~= rhel-9")
        assert not multi_rh.matches("distro ~= fedora-41")
Beispiel #7
0
    def test_minor_comparison_mode(self):
        """ How it minor comparison should work """
        fedora = Context(distro="fedora-33")
        centos = Context(distro="centos-7.3.0")
        centos6 = Context(distro="centos-6.9.0")

        # Simple version compare is not enough
        # Think about feature added in centos-7.4.0 and centos-6.9.0
        # so for 'centos' Context we want matches() == False
        # but for 'centos6' we want matches() == True
        #
        rule = "distro >= centos-7.4.0"
        assert not centos.matches(rule)
        assert not centos6.matches(rule)  # we need the opposite outcome

        rule = "distro >= centos-6.9.0"
        assert centos.matches(rule)  # we need the opposite outcome
        assert centos6.matches(rule)

        assert centos.matches(
            "distro >= centos-7.4.0 or distro >= centos-6.9.0"
        )  # we need the opposite outcome
        assert not centos.matches(
            "distro >= centos-7.4.0 and distro >= centos-6.9.0"
        )  # we need the opposite outcome
        assert centos6.matches(
            "distro >= centos-7.4.0 or distro >= centos-6.9.0")
        assert not centos6.matches(
            "distro >= centos-7.4.0 and distro >= centos-6.9.0")

        # Here comes minor compare into the play as it skip incomparable majors
        # All outcomes are exactly as we need them to be
        # tmt uses undecided='skip' so rule is skipped
        with pytest.raises(CannotDecide):
            centos.matches(
                "distro ~>= centos-7.4.0 or distro ~>= centos-6.9.0")
        assert not centos.matches(
            "distro ~>= centos-7.4.0 and distro ~>= centos-6.9.0")
        assert centos6.matches(
            "distro ~>= centos-7.4.0 or distro ~>= centos-6.9.0")
        # tmt uses undecided='skip' so rule is skipped
        with pytest.raises(CannotDecide):
            centos6.matches(
                "distro ~>= centos-7.4.0 and distro ~>= centos-6.9.0")
Beispiel #8
0
    def test_matches(self):
        """ yes/no/skip test per operator for matches """

        context = Context(
            distro="fedora-32",
            arch=["x86_64", "ppc64le"],
            component="bash-5.0.17-1.fc32",
        )

        # defined
        assert context.matches("distro is defined")
        assert not context.matches("FOOBAR is defined")
        # skip not possible for this operator

        # !defined
        assert context.matches("FOOBAR is not defined")
        assert not context.matches("distro is not defined")
        # skip not possible for this operator

        # ==
        assert context.matches("distro == fedora-32")
        assert context.matches("distro == fedora")
        assert not context.matches("distro == centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product == fedora-32")

        # !=
        assert not context.matches("distro != fedora-32")
        assert not context.matches("distro != fedora")
        assert context.matches("distro != centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product != fedora-32")

        # ~= aka major/minor mode
        assert context.matches("distro ~= fedora")
        assert context.matches("distro ~= fedora-32")
        assert not context.matches("distro ~= fedora-45")
        assert not context.matches(
            "distro ~= centos-8")  # fedora is not centos
        with pytest.raises(CannotDecide):  # dimension product is not defined
            context.matches("product ~= fedora-32")

        # '<'
        assert context.matches("distro < fedora-33")
        assert not context.matches("distro < fedora-32")
        with pytest.raises(CannotDecide):
            context.matches("product < centos-8")
        # missing version parts are allowed but at least one needs to be defined
        with pytest.raises(CannotDecide):
            Context(distro='fedora').matches("distro < fedora-33")
        assert Context(distro='foo-1').matches("distro < foo-1.1")

        # '~<':
        assert Context(distro='centos-8.3').matches("distro ~< centos-8.4")
        assert context.matches("distro ~< fedora-33")
        with pytest.raises(CannotDecide):
            context.matches("distro ~< centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product ~< centos-8")
        assert not context.matches(
            "distro ~< fedora")  # right side ignores major
        assert not context.matches("distro ~> fedora")

        # '<=':
        assert context.matches("distro <= fedora-32")
        assert context.matches("distro <= fedora")
        assert not context.matches("distro <= fedora-30")
        with pytest.raises(CannotDecide):
            context.matches("product <= centos-8")

        # '~<='
        assert context.matches("distro ~<= fedora-33")
        assert context.matches("distro ~<= fedora")
        with pytest.raises(CannotDecide):
            context.matches("distro ~<= centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product ~<= centos-8")

        # '~!=':
        assert context.matches("distro ~!= fedora-33")
        assert not context.matches("distro ~!= fedora-32")
        assert not context.matches("distro ~!= fedora")
        assert context.matches("distro ~!= centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product ~!= centos-8")

        # '>=':
        assert context.matches("distro >= fedora-32")
        assert context.matches("distro >= fedora")
        assert not context.matches("distro >= fedora-40")
        with pytest.raises(CannotDecide):
            context.matches("product >= centos-8")

        # '~>=':
        assert context.matches("distro ~>= fedora-32")
        assert context.matches("distro ~>= fedora")
        assert not context.matches("distro ~>= fedora-33")
        with pytest.raises(CannotDecide):
            context.matches("distro ~>= centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product ~>= centos-8")

        # '>':
        assert context.matches("distro > fedora-30")
        assert not context.matches("distro > fedora-40")
        assert not context.matches("distro > fedora")
        with pytest.raises(CannotDecide):
            context.matches("product > centos-8")

        # '~>':
        assert context.matches("distro ~> fedora-30")
        assert not context.matches("distro ~> fedora-42")
        with pytest.raises(CannotDecide):
            context.matches("distro ~> centos-8")
        with pytest.raises(CannotDecide):
            context.matches("product ~> centos-8")
        assert not context.matches("distro ~> fedora")
Beispiel #9
0
    def test_right_side_defines_precision_tilda(self):
        """ Right side defines how many version parts need to match (~ operations) """
        bar_830 = Context(dimension="bar-8.3.0")
        bar_800 = Context(dimension="bar-8.0.0")
        bar_ = Context(dimension="bar")  # missing major
        bar_8 = Context(dimension="bar-8")  # so essentially bar-8.0.0

        # these are equal
        for value in "bar bar-8 bar-8.3 bar-8.3.0".split():
            for op in "~= ~<= ~>=".split():
                assert bar_830.matches('dimension {0} {1}'.format(op, value))
            for op in "~< ~> ~!=".split():
                if value == 'bar' and op != '~!=':
                    continue
                assert not bar_830.matches('dimension {0} {1}'.format(
                    op, value))
            # value prefixed so name doesn't match -> not equal
            assert not bar_830.matches('dimension ~= prefix_{0}'.format(value))
            assert bar_830.matches('dimension ~!= prefix_{0}'.format(value))
            # value prefix so name doesn't match -> cannot be compared
            for op in "~<= ~>=".split():
                with pytest.raises(CannotDecide):
                    bar_830.matches('dimension {0} prefix_{1}'.format(
                        op, value))

        # different major with minor comparison
        for value in "bar-7.2 bar-7.2.0".split():
            for op in "~< ~<= ~> ~>=".split():
                with pytest.raises(CannotDecide):
                    bar_830.matches("dimension {0} {1}".format(op, value))
        # no minor compare required, so major comparison is allowed
        for op in "~< ~<=".split():
            assert not bar_830.matches("dimension {0} bar-7".format(op))
        for op in "~> ~>=".split():
            assert bar_830.matches("dimension {0} bar-7".format(op))

        # these are newer
        for value in "bar-8.4 bar-8.4.0".split():
            for op in "~> ~>= ~=".split():
                assert not bar_830.matches('dimension {0} {1}'.format(
                    op, value))
            for op in "~< ~<= ~!=".split():
                assert bar_830.matches('dimension {0} {1}'.format(op, value))

        # missing enough data to decide
        for value in "bar-8 bar-8.3 bar-8.3.0".split():
            for op in "~= ~<= ~>= ~< ~> ~!=".split():
                with pytest.raises(CannotDecide):
                    bar_.matches("dimension {0} {1}".format(op, value))
                if value != "bar-8":
                    with pytest.raises(CannotDecide):
                        bar_8.matches("dimension {0} {1}".format(op, value))
Beispiel #10
0
    def test_right_side_defines_precision(self):
        """ Right side defines how many version parts need to match """
        bar_830 = Context(dimension="bar-8.3.0")
        bar_800 = Context(dimension="bar-8.0.0")
        bar_ = Context(dimension="bar")  # so essentially bar-0.0.0
        bar_8 = Context(dimension="bar-8")  # so essentially bar-8.0.0

        # these are equal
        for value in "bar bar-8 bar-8.3 bar-8.3.0".split():
            for op in "== <= >=".split():
                assert bar_830.matches('dimension {0} {1}'.format(op, value))
            for op in "< > !=".split():
                if value == 'bar' and op != '!=':
                    continue
                assert not bar_830.matches('dimension {0} {1}'.format(
                    op, value))
            # value prefixed so name doesn't match -> not equal
            assert not bar_830.matches('dimension == prefix_{0}'.format(value))
            assert bar_830.matches('dimension != prefix_{0}'.format(value))
            # value prefix so name doesn't match -> cannot be compared
            for op in "<= >=".split():
                with pytest.raises(CannotDecide):
                    bar_830.matches('dimension {0} prefix_{1}'.format(
                        op, value))

        # valid comparison
        for value in "bar-7 bar-7.2 bar-8.1 bar-7.2.0 bar-8.1.0".split():
            for op in "< <= ==".split():
                assert not bar_830.matches("dimension {0} {1}".format(
                    op, value))
            for op in "> >= !=".split():
                assert bar_830.matches("dimension {0} {1}".format(op, value))
            assert bar_.matches("dimension != {0}".format(value))
            assert not bar_.matches("dimension == {0}".format(value))

        # these are newer
        for value in "bar-9 bar-9.2 bar-9.2.0".split():
            for op in "> >= ==".split():
                assert not bar_830.matches('dimension {0} {1}'.format(
                    op, value))
            for op in "< <= !=".split():
                assert bar_830.matches('dimension {0} {1}'.format(op, value))

        # cannot be compared
        for op in "< <= > >=".split():
            with pytest.raises(CannotDecide):
                bar_.matches("dimension {0} {1}".format(op, value))
Beispiel #11
0
    def test_comma(self):
        """ Comma is sugar for OR """
        con = Context(single="foo", multi=["first", "second"])
        # First as longer line, then using comma
        assert con.matches("single == foo or single == bar")
        assert con.matches("single == foo, bar")

        assert not con.matches("single == baz or single == bar")
        assert not con.matches("single == baz, bar")

        assert con.matches("single != foo or single != bar")
        assert con.matches("single != foo, bar")

        # And now with multiple values in the dimension
        assert con.matches("multi == first, value")
        assert con.matches("multi == second, value")
        assert con.matches("multi != third, value")

        # True because each first vs second value compare is false
        assert con.matches("multi != first, second")
        assert con.matches("multi != first or multi != second")

        # More real-life example
        distro = Context(distro="centos-stream-8")
        assert distro.matches("distro < centos-stream-9, fedora-34")
        assert not distro.matches("distro < fedora-34, centos-stream-8")