def test_is_match_with_headers_and_no_request_headers():
    """ Test a matching rule with headers not in request """
    match_rule = MatchRule('GET /test-match', headers={'Etag': 'A123'})
    mock_request = create_request('GET /test-match')
    
    assert_false(match_rule.matches(mock_request))
    assert_true(match_rule.rule_matches(mock_request['rule']))
    assert_false(match_rule.headers_match(mock_request['headers']))
def test_is_match_with_no_headers():
    """ Test a matching rule with no headers """
    match_rule = MatchRule('GET /test-match')
    mock_request = create_request('GET /test-match', {'Etag': 'A123'})
    
    assert_true(match_rule.matches(mock_request))
    assert_true(match_rule.rule_matches(mock_request['rule']))
    assert_true(match_rule.headers_match(mock_request['headers']))
def test_is_match_headers_is_false():
    """ Test a matching rule with non-matching headers """
    match_rule = MatchRule(
        'GET /test-match', headers={'ETag': 'A123'}
    )
    mock_request = create_request('GET /test-match',{'ETag': 'XXXX'})

    assert_false(match_rule.matches(mock_request))
    assert_true(match_rule.rule_matches(mock_request['rule']))
    assert_false(match_rule.headers_match(mock_request['headers']))
def test_is_match_headers_with_extra_headers():
    """ Test a matching rule with an unmatched extra header """
    match_rule = MatchRule(
        'GET /test-match', 
        headers={'ETag': 'A123', 'Another-Header': 'XX'}
    )
    mock_request = create_request('GET /test-match', {'ETag': 'A123'})

    assert_false(match_rule.matches(mock_request))
    assert_true(match_rule.rule_matches(mock_request['rule']))
    assert_false(match_rule.headers_match(mock_request['headers']))