# frozen_string_literal: true

require 'helper'
require 'fluent/test/driver/input'
require 'fluent/plugin/in_heroku_syslog_http'

require 'net/http'

class HerokuSyslogHttpInputTest < Test::Unit::TestCase
  class << self
    def startup
      socket_manager_path = ServerEngine::SocketManager::Server.generate_path
      @server = ServerEngine::SocketManager::Server.open(socket_manager_path)
      ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
    end

    def shutdown
      @server.close
    end
  end

  def setup
    Fluent::Test.setup
  end

  PORT = unused_port
  CONFIG = %(
    @type heroku_syslog_http
    port #{PORT}
    bind 127.0.0.1
    body_size_limit 10m
    keepalive_timeout 5
  )

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

  def test_configure
    d = create_driver
    assert_equal PORT, d.instance.port
    assert_equal '127.0.0.1', d.instance.bind
    assert_equal 10 * 1024 * 1024, d.instance.body_size_limit
    assert_equal 5, d.instance.keepalive_timeout
  end

  def test_time_format
    messages = [
      '59 <13>1 2014-01-29T06:25:52.589365+00:00 host app web.1 - foo',
      '59 <13>1 2014-01-30T07:35:00.123456+09:00 host app web.1 - bar'
    ]
    event_times = [
      Time.strptime('2014-01-29T06:25:52+00:00', '%Y-%m-%dT%H:%M:%S%z').to_i,
      Time.strptime('2014-01-30T07:35:00+09:00', '%Y-%m-%dT%H:%M:%S%z').to_i
    ]

    d = create_driver
    d.run(expect_records: 2, timeout: 5) do
      res = post(messages)
      assert_equal '', res.body
      assert_equal '200', res.code
    end

    assert_equal event_times[0], d.events[0][1]
    assert_equal event_times[1], d.events[1][1]
  end

  def test_msg_size
    messages = [
      '156 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - ' + 'x' * 100,
      '1080 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - ' + 'x' * 1024
    ]

    d = create_driver
    d.run(expect_records: 2, timeout: 5) do
      res = post(messages)
      assert_equal '200', res.code
    end

    assert_equal 'x' * 100, d.events[0][2]['message']
    assert_equal 'x' * 1024, d.events[1][2]['message']
  end

  def test_accept_matched_drain_id_multiple
    messages = [
      '59 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - foo',
      '59 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - bar'
    ]
    d = create_driver(CONFIG + %(
      drain_ids ["abc", "d.fc6b856b-3332-4546-93de-7d0ee272c3bd"]
    ))
    d.run(expect_records: 2, timeout: 5) do
      res = post(messages)
      assert_equal '200', res.code
    end

    assert_equal 2, d.events.length
  end

  def test_ignore_unmatched_drain_id
    messages = [
      '59 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - foo',
      '59 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - bar'
    ]
    d = create_driver(CONFIG + %(
      drain_ids ["abc"]
    ))
    d.run(expect_records: 0, timeout: 5) do
      res = post(messages)
      assert_equal '200', res.code
    end

    assert_equal 0, d.events.length
  end

  def test_logplex_metas
    messages = [
      '156 <13>1 2014-01-01T01:23:45.123456+00:00 host app web.1 - ' + 'x' * 100
    ]
    d = create_driver
    d.run(expect_records: 1, timeout: 5) do
      res = post(messages)
      assert_equal '200', res.code
    end

    assert_equal '09C557EAFCFB6CF2740EE62F62971098', d.events[0][2]['logplex.frame_id']
    assert_equal 'd.fc6b856b-3332-4546-93de-7d0ee272c3bd', d.events[0][2]['logplex.drain_id']
  end

  def post(messages)
    # https://github.com/heroku/logplex/blob/master/doc/README.http_drains.md
    http = Net::HTTP.new('127.0.0.1', PORT)
    headers = {
      'Content-Type' => 'application/logplex-1',
      'Logplex-Msg-Count' => messages.length.to_s,
      'Logplex-Frame-Id' => '09C557EAFCFB6CF2740EE62F62971098',
      'Logplex-Drain-Token' => 'd.fc6b856b-3332-4546-93de-7d0ee272c3bd',
      'User-Agent' => 'Logplex/v49'
    }
    req = Net::HTTP::Post.new('/heroku', headers)
    req.body = messages.join('')
    http.request(req)
  end
end