require "helper"
require "fluent/test/driver/input"

class SqlInputCustomTimeTest < Test::Unit::TestCase
  def setup
    Fluent::Test.setup
  end

  def teardown
  end

  CONFIG = %[
    adapter postgresql
    host localhost
    port 5432
    database fluentd_test

    username fluentd
    password fluentd

    schema_search_path public

    tag_prefix db

    <table>
      table messages_custom_time
      tag logs
      update_column updated_at
      time_column custom_time
    </table>
  ]

  def create_driver(conf = CONFIG)
    Fluent::Test::Driver::Input.new(Fluent::Plugin::SQLInput).configure(conf)
  end

  def test_configure
    d = create_driver
    expected = {
      host: "localhost",
      port: 5432,
      adapter: "postgresql",
      database: "fluentd_test",
      username: "fluentd",
      password: "fluentd",
      schema_search_path: "public",
      tag_prefix: "db"
    }
    actual = {
      host: d.instance.host,
      port: d.instance.port,
      adapter: d.instance.adapter,
      database: d.instance.database,
      username: d.instance.username,
      password: d.instance.password,
      schema_search_path: d.instance.schema_search_path,
      tag_prefix: d.instance.tag_prefix
    }
    assert_equal(expected, actual)
    tables = d.instance.instance_variable_get(:@tables)
    assert_equal(1, tables.size)
    messages_custom_time = tables.first
    assert_equal("messages_custom_time", messages_custom_time.table)
    assert_equal("logs", messages_custom_time.tag)
  end

  def test_message
    d = create_driver(CONFIG + "select_interval 1")

    start_time = Fluent::EventTime.now

    # Create one message with a valid timestamp containing milliseconds and a time zone
    Message.create!(message: "message 1", custom_time: '2020-08-27 15:00:16.100758000 -0400')

    # Create one message without a timestamp so that we can test auto-creation
    Message.create!(message: "message 2 (no timestamp)", custom_time: nil)

    # Create one message with an unparseable timestamp so that we can check that a valid
    # one is auto-generated.
    Message.create!(message: "message 3 (bad timestamp)", custom_time: 'foo')

    d.end_if do
      d.record_count >= 3
    end
    d.run(timeout: 5)

    assert_equal("db.logs", d.events[0][0])
    expected = [
      [d.events[0][1], "message 1"],
      [d.events[1][1], "message 2 (no timestamp)"],
      [d.events[2][1], "message 3 (bad timestamp)"],
    ]

    actual = [
      [Fluent::EventTime.parse(d.events[0][2]["custom_time"]), d.events[0][2]["message"]],
      d.events[1][2]["message"],
      d.events[2][2]["message"],
    ]

    assert_equal(expected[0], actual[0])

    # Messages 2 and 3 should have the same messages but (usually) a slightly later
    # timestamps because they are generated by the input plugin instead of the test
    # code
    [1,2].each do |i|
      assert_equal(expected[i][1], actual[i])
      assert_operator(expected[i][0], :>=, start_time)
    end
  end

  class Message < ActiveRecord::Base
    self.table_name = "messages_custom_time"
  end
end
