Back to Repositories

Testing BareOutput Plugin Lifecycle and Event Processing in Fluentd

This test suite validates the core functionality of Fluentd’s BareOutput plugin, focusing on lifecycle management, configuration, and event stream handling. The tests ensure proper plugin initialization, event processing, and metric tracking capabilities.

Test Coverage Overview

The test suite provides comprehensive coverage of the BareOutput plugin’s essential features:
  • Plugin lifecycle states including configuration, start/stop, shutdown, and termination
  • Plugin ID generation and configuration
  • Event stream processing and data handling
  • Metric tracking and monitoring capabilities

Implementation Analysis

The testing approach utilizes Test::Unit framework for Ruby, implementing systematic verification of plugin functionality:
  • DummyPlugin class extends BareOutput for testing specific behaviors
  • Isolated test cases for each feature component
  • Event stream simulation using OneEventStream and ArrayEventStream

Technical Details

Testing infrastructure includes:
  • Fluent::Test setup for environment initialization
  • Custom DummyPlugin implementation for test isolation
  • Event time helpers for timestamp management
  • Configuration element builders for plugin setup

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Proper test isolation and setup/teardown management
  • Comprehensive lifecycle state verification
  • Error handling and edge case coverage
  • Clear test naming and organization

fluent/fluentd

test/plugin/test_bare_output.rb

            
require_relative '../helper'
require 'fluent/plugin/bare_output'
require 'fluent/event'

module FluentPluginBareOutputTest
  class DummyPlugin < Fluent::Plugin::BareOutput
    attr_reader :store
    def initialize
      super
      @store = []
    end
    def process(tag, es)
      es.each do |time, record|
        @store << [tag, time, record]
      end
    end
  end
end

class BareOutputTest < Test::Unit::TestCase
  setup do
    Fluent::Test.setup
    @p = FluentPluginBareOutputTest::DummyPlugin.new
  end

  test 'has healthy lifecycle' do
    assert [email protected]?
    @p.configure(config_element())
    assert @p.configured?

    assert [email protected]?
    @p.start
    assert @p.start

    assert [email protected]?
    @p.stop
    assert @p.stopped?

    assert [email protected]_shutdown?
    @p.before_shutdown
    assert @p.before_shutdown?

    assert [email protected]?
    @p.shutdown
    assert @p.shutdown?

    assert [email protected]_shutdown?
    @p.after_shutdown
    assert @p.after_shutdown?

    assert [email protected]?
    @p.close
    assert @p.closed?

    assert [email protected]?
    @p.terminate
    assert @p.terminated?
  end

  test 'has plugin_id automatically generated' do
    assert @p.respond_to?(:plugin_id_configured?)
    assert @p.respond_to?(:plugin_id)

    @p.configure(config_element())

    assert [email protected]_id_configured?
    assert @p.plugin_id
    assert{ @p.plugin_id != 'mytest' }
  end

  test 'has plugin_id manually configured' do
    @p.configure(config_element('ROOT', '', {'@id' => 'mytest'}))
    assert @p.plugin_id_configured?
    assert_equal 'mytest', @p.plugin_id
  end

  test 'has plugin logger' do
    assert @p.respond_to?(:log)
    assert @p.log

    # default logger
    original_logger = @p.log

    @p.configure(config_element('ROOT', '', {'@log_level' => 'debug'}))

    assert(@p.log.object_id != original_logger.object_id)
    assert_equal Fluent::Log::LEVEL_DEBUG, @p.log.level
  end

  test 'can load plugin helpers' do
    assert_nothing_raised do
      class FluentPluginBareOutputTest::DummyPlugin2 < Fluent::Plugin::BareOutput
        helpers :storage
      end
    end
  end

  test 'can use metrics plugins and fallback methods' do
    @p.configure(config_element('ROOT', '', {'@log_level' => 'debug'}))

    %w[num_errors_metrics emit_count_metrics emit_size_metrics emit_records_metrics].each do |metric_name|
      assert_true @p.instance_variable_get(:"@#{metric_name}").is_a?(Fluent::Plugin::Metrics)
    end

    assert_equal 0, @p.num_errors
    assert_equal 0, @p.emit_count
    assert_equal 0, @p.emit_size
    assert_equal 0, @p.emit_records
  end

  test 'can get input event stream to write' do
    @p.configure(config_element('ROOT'))
    @p.start

    es1 = Fluent::OneEventStream.new(event_time('2016-05-21 18:37:31 +0900'), {'k1' => 'v1'})
    es2 = Fluent::ArrayEventStream.new([
        [event_time('2016-05-21 18:38:33 +0900'), {'k2' => 'v2'}],
        [event_time('2016-05-21 18:39:10 +0900'), {'k3' => 'v3'}],
      ])
    @p.emit_events('mytest1', es1)
    @p.emit_events('mytest2', es2)

    all_events = [
      ['mytest1', event_time('2016-05-21 18:37:31 +0900'), {'k1' => 'v1'}],
      ['mytest2', event_time('2016-05-21 18:38:33 +0900'), {'k2' => 'v2'}],
      ['mytest2', event_time('2016-05-21 18:39:10 +0900'), {'k3' => 'v3'}],
    ]

    assert_equal all_events, @p.store
  end
end