Class AnnotationSetPersistenceIT

java.lang.Object
ubic.gemma.core.util.test.BaseTest5
ubic.gemma.core.util.test.BaseIntegrationTest5
ubic.gemma.persistence.service.common.auditAndSecurity.curation.AnnotationSetPersistenceIT

@Transactional public class AnnotationSetPersistenceIT extends BaseIntegrationTest5
Integration test for the V20/V21 ANNOTATION_SET schema migration and the unified AnnotationSet entity + service. Runs against the real MySQL gemdtest via BaseIntegrationTest5 — proves that:
  1. Flyway migration V20/V21 applies cleanly on a fresh schema.
  2. The three roles (PROPOSAL/DRAFT/SNAPSHOT) and four sources persist via @Enumerated(EnumType.STRING) against the VARCHAR(32) columns.
  3. Idempotency on (investigation, role, runId) works: a repeat attach returns the existing row.
  4. AnnotationSetService.upsertDraft(Investigation, String, String, String, AnnotationSet) updates an existing DRAFT for the same (investigation, curator) rather than creating a duplicate.
  5. Lineage (self-FK on PARENT_FK) survives a round-trip.
  6. Finalize / reopen flips finalizedAt idempotently.
  7. The summary projection populates every field from the HQL SELECT NEW ... constructor.

Class-level Transactional opens a per-test transaction that Spring rolls back at end-of-test, so no persistent cleanup is needed.

  • Constructor Details

    • AnnotationSetPersistenceIT

      public AnnotationSetPersistenceIT()
  • Method Details

    • seedPreboarded

      @BeforeEach public void seedPreboarded()
    • proposal_attachAndIdempotency

      @Test @DisplayName("PROPOSAL attach + idempotent retry on same runId") public void proposal_attachAndIdempotency()
    • draft_upsertReplacesInPlace

      @Test @DisplayName("DRAFT upsert: second call updates the same row in place") public void draft_upsertReplacesInPlace()
    • draft_parentLineageRoundTrip

      @Test @DisplayName("DRAFT parent lineage round-trips through the self-FK") public void draft_parentLineageRoundTrip()
    • snapshot_appendOnly

      @Test @DisplayName("SNAPSHOT with generated UUID runId is append-only across calls") public void snapshot_appendOnly()
    • finalize_reopen

      @Test @DisplayName("finalize / reopen flip finalizedAt idempotently") public void finalize_reopen()
    • summariesProjection

      @Test @DisplayName("findSummariesByInvestigation populates every projected field") public void summariesProjection()
    • countByRole

      @Test @DisplayName("countByRoleSince groups the three roles separately") public void countByRole()
    • runProvenance_roundTrips

      @Test @DisplayName("run provenance (sha + agent name) survives a persist/reload") public void runProvenance_roundTrips()
    • legacyAttachOverload_leavesRunProvenanceNull

      @Test @DisplayName("the pre-provenance attach overload still works and leaves the new columns null") public void legacyAttachOverload_leavesRunProvenanceNull()
    • updateProvenance_correctsInPlace

      @Test @DisplayName("updateProvenance corrects the envelope in place, keeps the id, and leaves content alone") public void updateProvenance_correctsInPlace()
      The reason the route exists: correcting a mis-stamped envelope used to mean delete + recreate, which mints a new id, and set ids are quoted across handoffs. So the id staying put is the assertion that matters, alongside the untouched fields.
    • updateProvenance_blankClears

      @Test @DisplayName("a blank string clears an envelope field, which null cannot express") public void updateProvenance_blankClears()
    • updateProvenance_unknownId

      @Test @DisplayName("updateProvenance on an id that does not exist returns null, not an exception") public void updateProvenance_unknownId()
    • status_defaultsToPendingOnProposalsOnly

      @Test @DisplayName("a proposal starts pending; a role that is not reviewed has no status at all") public void status_defaultsToPendingOnProposalsOnly()
      A queue is ordered by when the RUN happened, not by when the row was stored, and the two disagree: a set carrying August's run can be written today. Ordering by `ranAt` was hardcoded to `createdAt desc` until cab asked for the queue view.

      🛑 Runs on real MySQL deliberately. The claim that a null `ranAt` sorts LAST under `desc` is MySQL's null-ordering rule; H2 is emulation and is not evidence for it.

    • status_isNotAClosedSet

      @Test @DisplayName("any status value is stored -- the vocabulary is open on purpose") public void status_isNotAClosedSet()
    • counts_areDerivedAndStayInStepWithThePayload

      @Test @DisplayName("counts come off the payload, and are refreshed when the payload is rewritten") public void counts_areDerivedAndStayInStepWithThePayload()
    • listSummaries_filtersByKindAndStatus

      @Test @DisplayName("kind separates audit output from proposals, which role alone does not") public void listSummaries_filtersByKindAndStatus()
    • listSummaries_leftJoinKeepsNonExperimentRows

      @Test @DisplayName("a set on a non-experiment investigation still lists, with no short name") public void listSummaries_leftJoinKeepsNonExperimentRows()
    • listSummaries_sortsByRanAt

      @Test @DisplayName("Cross-experiment list sorts by ranAt, nulls last, independent of createdAt") public void listSummaries_sortsByRanAt()