---
id: TST-PFM-DJE-178
title: Upload sessions
kind: integration
product_area: platform
module: data-job-engine
revision: 1
status: draft
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
repository: services-platform
files:
  - modules/data-jobs/tests/integration/services/uploads/upload-sessions.integration.spec.js
implements:
  - ATS-PFM-DJE-011-02
  - ATS-PFM-DJE-011-04
  - ATS-PFM-DJE-011-05
  - ATS-PFM-DJE-011-06
  - ATS-PFM-DJE-011-07
  - ATS-PFM-DJE-011-08
  - ATS-PFM-DJE-011-09
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 5
isolation: >-
  Suite-owned fixture records, job identifiers and workspace contexts; teardown removes the fixture
  data.
evidence:
  - >-
    services-platform:modules/data-jobs/tests/integration/services/uploads/upload-sessions.integration.spec.js
assertion_inventory:
  - 'data-job uploads: opening a session'
  - 'answers the upload id, the part size and the part count the client uploads by'
  - 'answers when the session expires, which is the day the bucket abandons its parts'
  - 'answers nothing about where the file is going: no bucket, no key, no S3 upload id'
  - 'creates the multipart upload under a key of this tenant and this session, built by the server'
  - 'creates it in the bucket the function was told about, with the declared content type'
  - 'tags the object as one the inbound lifecycle rule may expire, from the moment it exists'
  - 'records the upload id S3 issued, which every later call names'
  - >-
    refuses a declaration before it creates anything in S3, so a refused request leaves no upload
    behind
  - 'data-job uploads: presigning the parts'
  - 'answers one URL per part asked for, in the order asked'
  - signs each URL for its own part of this session\u2019s key and upload
  - 'signs each URL for one hour, which is how long a client has to use it'
  - answers the one instant every URL of the answer stops working
  - 'presigns the same part again, which is how a client whose hour ran out carries on'
  - refuses a part number this file does not have
  - 'refuses a part number below one, which S3 has no part for'
  - refuses a request naming the same part twice
  - refuses a request for no parts at all
  - 'refuses more than a hundred parts at a time, which is the page the protocol presigns'
  - refuses to presign a session that is no longer open
  - 'data-job uploads: resuming a session'
  - 'answers the parts S3 already holds, so a client knows which to send'
  - 'answers the session itself beside them, still open'
  - 'answers no parts for a session that has settled, and does not ask S3 about one'
  - 'settles a session S3 has already abandoned as expired, rather than leaving it open for ever'
  - refuses to read another tenant\u2019s session as one that could not be located
  - 'data-job uploads: completing a session'
  - answers the completed session with what S3 stored
  - assembles the object S3 holds under this session\u2019s key
  - 'tells S3 exactly the parts the client named, in part order'
  - >-
    records no digest of its own when none was declared, because a multipart SHA-256 is not the
    file\u2019s
  - refuses a completion that does not name every part of the file
  - 'refuses a completion whose part carries no ETag, which S3 could not assemble'
  - refuses a completion whose object is not the size that was declared
  - >-
    aborts the session after refusing it for its size, so no client is left holding the wrong file
    open
  - >-
    refuses in words a completion naming a part S3 does not hold, rather than failing as a server
    fault
  - records the digest it measured over the stored object when it is the one that was declared
  - measures the digest over the object version the completion just stored
  - 'refuses a completion whose object is not the file the declared SHA-256 describes, naming sha256'
  - >-
    leaves the session open after refusing parts S3 does not hold, so the client can upload them
    again
  - 'aborts the session after refusing it for its digest, recording no completion'
  - refuses as no longer open a completion of a session whose parts S3 has abandoned
  - settles as expired a session whose parts S3 abandoned when a completion meets it
  - measures no digest when none was declared
  - completes a file over the measured size with its declared digest recorded and no verified digest
  - refuses a second completion of a session that is already completed
  - 'refuses to complete another tenant\u2019s session, and makes no S3 call for it'
  - 'data-job uploads: abandoning a session'
  - answers the session aborted
  - tells S3 to drop the parts of this session\u2019s upload
  - answers the same session a second time rather than refusing a client that aborts twice
  - 'aborts a session S3 no longer has, because abandoned parts are what aborted means'
  - 'refuses to abort a completed session, whose object a job may already be reading'
  - refuses to abort another tenant\u2019s session
  - 'data-job uploads: listing what a tenant has uploaded'
  - 'lists every session of the tenant, whatever its state'
  - lists one state alone when one is asked for
  - 'lists nothing for a tenant with no sessions, which is what the other tenant is'
registration_note: Registration describes existing source; the suite is not executed by this documentation job.
---

# Upload sessions

## Verification Boundary

The suite checks the production service or shared engine against its database fixture. The structured assertion inventory records the checks present at the pinned revision.

## What This Suite Proves

The existing checks exercise upload sessions. The specification bindings identify the narrower outcomes supported by those assertions.

## What It Does Not Prove

Local execution does not establish deployed queue, storage or service behavior. Independent test cases do not establish a complete cross-feature process.

## Real Dependencies and Test Doubles

The owning service exercises production persistence and domain behavior against real Postgres. The fixture supplies caller contexts; queue delivery, storage and external calls are doubled where the file installs a test port.

## Must Not Be Doubled

The database effects, security context and production operation under examination remain real. Their outcomes cannot be replaced with canned success responses.
