# frozen_string_literal: true

require "test/unit"
require "grpc"
require "spamcheck"

abort "SPAMCHECK_HOSTNAME not set" unless ENV["SPAMCHECK_HOSTNAME"]
abort "SPAMCHECK_API_TOKEN not set" unless ENV["SPAMCHECK_API_TOKEN"]

class TestSpamcheck < Test::Unit::TestCase
  def setup
    host = ENV["SPAMCHECK_HOSTNAME"]
    jwt = ENV["SPAMCHECK_API_TOKEN"]

    tls_creds = GRPC::Core::ChannelCredentials.new(File.read("/etc/ssl/certs/ca-certificates.crt"))
    auth_proc = proc { { "authorization" => "#{jwt}" } }
    jwt_creds = GRPC::Core::CallCredentials.new(auth_proc)
    credentials = tls_creds.compose(jwt_creds)

    @auth_stub = Spamcheck::SpamcheckService::Stub.new(host, credentials)
    @unauth_stub = Spamcheck::SpamcheckService::Stub.new(host, tls_creds)
  end

  # Check that authentication is required
  def test_no_authentication
    issue = Spamcheck::Issue.new
    assert_raise(GRPC::PermissionDenied) { @unauth_stub.check_for_spam_issue(issue) }
  end

  # Check that an invalid issue returns an error
  def test_invalid_issue
    issue = Spamcheck::Issue.new(description: "test issue")
    exception = assert_raise(GRPC::InvalidArgument) { @auth_stub.check_for_spam_issue(issue) }
    assert_match(/Issue title is required/, exception.message)
  end

  # Check that project not allowed is NOOP
  def test_project_not_allowed
    issue = Spamcheck::Issue.new(
      title: "test issue",
      description: "test issue",
      project: {project_id: 1, project_path: "test/project"},
    )
    resp = @auth_stub.check_for_spam_issue(issue)
    verdict = ::Spamcheck::SpamVerdict::Verdict.resolve(resp.verdict)
    assert_equal(::Spamcheck::SpamVerdict::Verdict::NOOP, verdict,
                 "Issue with project not in allow list should be NOOP")
  end

  # Check that user in project is allowed
  def test_user_in_project
    issue = Spamcheck::Issue.new(
      title: "test issue",
      description: "test issue",
      project: {project_id: 278_964, project_path: "gitlab-org/gitlab"},
      user_in_project: true
    )
    resp = @auth_stub.check_for_spam_issue(issue)
    verdict = ::Spamcheck::SpamVerdict::Verdict.resolve(resp.verdict)
    assert_equal(::Spamcheck::SpamVerdict::Verdict::ALLOW, verdict, "Issue with user in project should be ALLOWED")
  end

  # Check that ham is allowed
  def test_issue_ham
    issue = Spamcheck::Issue.new(
      title: "Dependency update needed",
      description: "The dependencies for this application are outdated and need to be updated.",
      project: {project_id: 278_964, project_path: "gitlab-org/gitlab"}
    )
    resp = @auth_stub.check_for_spam_issue(issue)
    verdict = ::Spamcheck::SpamVerdict::Verdict.resolve(resp.verdict)
    assert_equal(::Spamcheck::SpamVerdict::Verdict::ALLOW, verdict, 'Ham issue verdict not "ALLOW"')
  end

  # Check that spam is blocked
  def test_issue_spam
    issue = Spamcheck::Issue.new(
      title: "fifa xxx porn stream fifa xxx porn stream",
      description: "fifa xxx porn stream fifa xxx porn stream",
      project: {project_id: 278_964, project_path: "gitlab-org/gitlab"}
    )
    resp = @auth_stub.check_for_spam_issue(issue)
    verdict = ::Spamcheck::SpamVerdict::Verdict.resolve(resp.verdict)
    assert_equal(::Spamcheck::SpamVerdict::Verdict::CONDITIONAL_ALLOW, verdict, 'Spam issue verdict not "CONDITIONAL_ALLOW"')
  end

  # Check that snippet ham is allowed
  def test_snippet_ham
    issue = Spamcheck::Snippet.new(
      title: "Example SQL queries",
      description: "",
      project: {project_id: 278_964, project_path: "gitlab-org/gitlab"},
      files: [{path: "snippetfile1.txt"}]
    )
    resp = @auth_stub.check_for_spam_snippet(issue)
    verdict = ::Spamcheck::SpamVerdict::Verdict.resolve(resp.verdict)
    assert_equal(::Spamcheck::SpamVerdict::Verdict::ALLOW, verdict, 'Ham snippet verdict not "ALLOW"')
  end

  # Check that snippet spam is blocked
  def test_snippet_spam
    issue = Spamcheck::Snippet.new(
      title: "Slot Online",
      description: "",
      project: {project_id: 278_964, project_path: "gitlab-org/gitlab"},
      files: [{path: "snippetfile1.txt"}]
    )
    issue.files << Spamcheck::File.new(path: "snippetfile1.txt")
    resp = @auth_stub.check_for_spam_snippet(issue)
    verdict = ::Spamcheck::SpamVerdict::Verdict.resolve(resp.verdict)
    assert_equal(::Spamcheck::SpamVerdict::Verdict::CONDITIONAL_ALLOW, verdict, 'Spam snippet verdict not "CONDITIONAL_ALLOW"')
  end
end
