Back to Repositories

Testing Pattern Matching System in Fluentd

This test suite validates the pattern matching functionality in Fluentd’s event routing system, focusing on glob patterns, wildcards, and regular expressions. The tests ensure reliable event routing and pattern matching behavior across different matching scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of Fluentd’s pattern matching capabilities.

Key areas tested include:
  • Simple exact matching
  • Wildcard pattern matching
  • Recursive wildcard functionality
  • OR pattern combinations
  • Regular expression pattern support
Edge cases are thoroughly verified including nested patterns, boundary conditions, and pattern combinations.

Implementation Analysis

The testing approach uses Test::Unit framework with systematic verification of pattern matching rules. Each test method focuses on specific pattern types, implementing assert_glob_match and assert_glob_not_match helper methods for consistent validation.

The implementation leverages GlobMatchPattern and EventRouter::Rule classes to verify pattern matching behavior.

Technical Details

Testing tools and configuration:
  • Test::Unit framework
  • Custom assertion helpers for glob matching
  • GlobMatchPattern class for pattern evaluation
  • EventRouter::Rule class for routing rules
  • Integration with Fluentd’s core matching system

Best Practices Demonstrated

The test suite exemplifies strong testing practices through methodical organization and comprehensive coverage.

Notable practices include:
  • Systematic test case organization by pattern type
  • Thorough positive and negative test cases
  • Clear helper methods for test assertions
  • Comprehensive edge case coverage
  • Consistent testing patterns across different matching scenarios

fluent/fluentd

test/test_match.rb

            
require_relative 'helper'
require 'fluent/match'

class MatchTest < Test::Unit::TestCase
  include Fluent

  def test_simple
    assert_glob_match('a', 'a')
    assert_glob_match('a.b', 'a.b')
    assert_glob_not_match('a', 'b')
    assert_glob_not_match('a.b', 'aab')
  end

  def test_wildcard
    assert_glob_match('a*', 'a')
    assert_glob_match('a*', 'ab')
    assert_glob_match('a*', 'abc')

    assert_glob_match('*a', 'a')
    assert_glob_match('*a', 'ba')
    assert_glob_match('*a', 'cba')

    assert_glob_match('*a*', 'a')
    assert_glob_match('*a*', 'ba')
    assert_glob_match('*a*', 'ac')
    assert_glob_match('*a*', 'bac')

    assert_glob_not_match('a*', 'a.b')
    assert_glob_not_match('a*', 'ab.c')
    assert_glob_not_match('a*', 'ba')
    assert_glob_not_match('*a', 'ab')

    assert_glob_match('a.*', 'a.b')
    assert_glob_match('a.*', 'a.c')
    assert_glob_not_match('a.*', 'ab')

    assert_glob_match('a.*.c', 'a.b.c')
    assert_glob_match('a.*.c', 'a.c.c')
    assert_glob_not_match('a.*.c', 'a.c')
  end

  def test_recursive_wildcard
    assert_glob_match('a.**', 'a')
    assert_glob_not_match('a.**', 'ab')
    assert_glob_not_match('a.**', 'abc')
    assert_glob_match('a.**', 'a.b')
    assert_glob_not_match('a.**', 'ab.c')
    assert_glob_not_match('a.**', 'ab.d.e')

    assert_glob_match('a**', 'a')
    assert_glob_match('a**', 'ab')
    assert_glob_match('a**', 'abc')
    assert_glob_match('a**', 'a.b')
    assert_glob_match('a**', 'ab.c')
    assert_glob_match('a**', 'ab.d.e')

    assert_glob_match('**.a', 'a')
    assert_glob_not_match('**.a', 'ba')
    assert_glob_not_match('**.a', 'c.ba')
    assert_glob_match('**.a', 'b.a')
    assert_glob_match('**.a', 'cb.a')
    assert_glob_match('**.a', 'd.e.a')

    assert_glob_match('**a', 'a')
    assert_glob_match('**a', 'ba')
    assert_glob_match('**a', 'c.ba')
    assert_glob_match('**a', 'b.a')
    assert_glob_match('**a', 'cb.a')
    assert_glob_match('**a', 'd.e.a')
  end

  def test_or
    assert_glob_match('a.{b,c}', 'a.b')
    assert_glob_match('a.{b,c}', 'a.c')
    assert_glob_not_match('a.{b,c}', 'a.d')

    assert_glob_match('a.{b,c}.**', 'a.b')
    assert_glob_match('a.{b,c}.**', 'a.c')
    assert_glob_not_match('a.{b,c}.**', 'a.d')
    assert_glob_not_match('a.{b,c}.**', 'a.cd')

    assert_glob_match('a.{b.**,c}', 'a.b')
    assert_glob_match('a.{b.**,c}', 'a.b.c')
    assert_glob_match('a.{b.**,c}', 'a.c')
    assert_glob_not_match('a.{b.**,c}', 'a.c.d')
  end

  def test_multi_pattern_or
    assert_or_match('a.b a.c', 'a.b')
    assert_or_match('a.b a.c', 'a.c')
    assert_or_not_match('a.b a.c', 'a.d')

    assert_or_match('a.b.** a.c.**', 'a.b')
    assert_or_match('a.b.** a.c.**', 'a.c')
    assert_or_not_match('a.b.** a.c.**', 'a.d')
    assert_or_not_match('a.b.** a.c.**', 'a.cd')

    assert_or_match('a.b.** a.c', 'a.b')
    assert_or_match('a.b.** a.c', 'a.b.c')
    assert_or_match('a.b.** a.c', 'a.c')
    assert_or_not_match('a.b.** a.c', 'a.c.d')
  end

  def test_regex_pattern
    assert_glob_match('/a/', 'a')
    assert_glob_not_match('/a/', 'abc')
    assert_glob_match('/a.*/', 'abc')
    assert_glob_not_match('/b.*/', 'abc')
    assert_glob_match('/a\..*/', 'a.b.c')
    assert_glob_not_match('/(?!a\.).*/', 'a.b.c')
    assert_glob_not_match('/a\..*/', 'b.b.c')
    assert_glob_match('/(?!a\.).*/', 'b.b.c')
  end

  #def test_character_class
  #  assert_match('[a]', 'a')
  #  assert_match('[ab]', 'a')
  #  assert_match('[ab]', 'b')
  #  assert_not_match('[ab]', 'c')
  #
  #  assert_match('[a-b]', 'a')
  #  assert_match('[a-b]', 'a')
  #  assert_match('[a-b]', 'b')
  #  assert_not_match('[a-b]', 'c')
  #
  #  assert_match('[a-b0-9]', 'a')
  #  assert_match('[a-b0-9]', '0')
  #  assert_not_match('[a-b0-9]', 'c')
  #end

  def assert_glob_match(pat, str)
    assert_true GlobMatchPattern.new(pat).match(str)
    assert_true EventRouter::Rule.new(pat, nil).match?(str)
  end

  def assert_glob_not_match(pat, str)
    assert_false GlobMatchPattern.new(pat).match(str)
    assert_false EventRouter::Rule.new(pat, nil).match?(str)
  end

  def assert_or_match(pats, str)
    assert_true EventRouter::Rule.new(pats, nil).match?(str)
  end

  def assert_or_not_match(pats, str)
    assert_false EventRouter::Rule.new(pats, nil).match?(str)
  end
end