// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package google.registry.schema.integration;

import static com.google.common.truth.Truth.assert_;

import google.registry.bsa.persistence.BsaDomainRefreshTest;
import google.registry.bsa.persistence.BsaDownloadTest;
import google.registry.bsa.persistence.BsaLabelTest;
import google.registry.bsa.persistence.BsaUnblockableDomainTest;
import google.registry.model.billing.BillingBaseTest;
import google.registry.model.common.CursorTest;
import google.registry.model.common.DnsRefreshRequestTest;
import google.registry.model.common.FeatureFlagTest;
import google.registry.model.console.ConsoleUpdateHistoryTest;
import google.registry.model.console.PasswordResetRequestTest;
import google.registry.model.console.UserTest;
import google.registry.model.domain.DomainSqlTest;
import google.registry.model.domain.token.AllocationTokenTest;
import google.registry.model.domain.token.BulkPricingPackageTest;
import google.registry.model.history.DomainHistoryTest;
import google.registry.model.history.HostHistoryTest;
import google.registry.model.poll.PollMessageTest;
import google.registry.model.rde.RdeRevisionTest;
import google.registry.model.reporting.Spec11ThreatMatchTest;
import google.registry.model.server.LockTest;
import google.registry.model.server.ServerSecretTest;
import google.registry.model.smd.SignedMarkRevocationListDaoTest;
import google.registry.model.tld.RegistryLockDaoTest;
import google.registry.model.tld.TldTest;
import google.registry.model.tld.label.PremiumListDaoTest;
import google.registry.model.tld.label.ReservedListDaoTest;
import google.registry.model.tmch.ClaimsListDaoTest;
import google.registry.model.tmch.TmchCrlTest;
import google.registry.persistence.transaction.JpaEntityCoverageExtension;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationWithCoverageExtension;
import google.registry.schema.integration.SqlIntegrationTestSuite.AfterSuiteTest;
import google.registry.schema.integration.SqlIntegrationTestSuite.BeforeSuiteTest;
import google.registry.schema.registrar.RegistrarDaoTest;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;

/**
 * Groups all JPA entity tests in one suite for easy invocation. This suite is used for
 * server/schema compatibility tests between releases.
 *
 * <p>Suite members are typically DAO tests, which perform simple create/update/delete operations on
 * JPA entities. Each member class must register a {@link
 * google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationWithCoverageExtension}
 * and have at least one test method that persists a JPA entity declared in persistence.xml.
 *
 * <p>Note that with {@link JpaIntegrationWithCoverageExtension}, each method starts with an empty
 * database. Therefore, this is not the right place for verifying backwards data compatibility in
 * end-to-end functional tests.
 */
@Suite
@SelectClasses({
  // BeforeSuiteTest must be the first entry. See class javadoc for details.
  BeforeSuiteTest.class,
  AllocationTokenTest.class,
  BillingBaseTest.class,
  BsaDomainRefreshTest.class,
  BsaDownloadTest.class,
  BsaLabelTest.class,
  BsaUnblockableDomainTest.class,
  BulkPricingPackageTest.class,
  ClaimsListDaoTest.class,
  ConsoleUpdateHistoryTest.class,
  CursorTest.class,
  DnsRefreshRequestTest.class,
  DomainSqlTest.class,
  DomainHistoryTest.class,
  FeatureFlagTest.class,
  HostHistoryTest.class,
  LockTest.class,
  PasswordResetRequestTest.class,
  PollMessageTest.class,
  PremiumListDaoTest.class,
  RdeRevisionTest.class,
  RegistrarDaoTest.class,
  ReservedListDaoTest.class,
  RegistryLockDaoTest.class,
  ServerSecretTest.class,
  SignedMarkRevocationListDaoTest.class,
  Spec11ThreatMatchTest.class,
  TldTest.class,
  TmchCrlTest.class,
  UserTest.class,
  // AfterSuiteTest must be the last entry. See class javadoc for details.
  AfterSuiteTest.class
})
public final class SqlIntegrationTestSuite {

  private SqlIntegrationTestSuite() {}

  @BeforeAll // Not yet supported in JUnit 5. Called through BeforeSuiteTest.
  public static void initJpaEntityCoverage() {
    JpaEntityCoverageExtension.init();
  }

  @AfterAll // Not yet supported in JUnit 5. Called through AfterSuiteTest.
  public static void checkJpaEntityCoverage() {
    // TODO(weiminyu): collect both assertion errors like Truth's Expect does in JUnit 4.
    assert_()
        .withMessage("Tests are missing for the following JPA entities:")
        .that(JpaEntityCoverageExtension.getUncoveredEntities())
        .isEmpty();
    assert_()
        .withMessage(
            "The following classes do not test JPA entities. Please remove them from this suite")
        .that(JpaEntityCoverageExtension.getIrrelevantTestClasses())
        .isEmpty();
  }

  /**
   * Hack for calling {@link SqlIntegrationTestSuite#initJpaEntityCoverage()} before all real tests
   * in suite. See outer class javadoc for details.
   *
   * <p>The 'Test' suffix in class name is required.
   */
  static class BeforeSuiteTest {

    @Test
    void beforeAll() {
      initJpaEntityCoverage();
    }
  }

  /**
   * Hack for invoking {@link SqlIntegrationTestSuite#checkJpaEntityCoverage()} after all real tests
   * in suite. See outer class javadoc for details.
   *
   * <p>The 'Test' suffix in class name is required.
   */
  static class AfterSuiteTest {

    @Test
    void afterSuite() {
      checkJpaEntityCoverage();
    }
  }
}
