Files
2026-06-13 16:09:42 -04:00

467 lines
13 KiB
HTTP

###############################################################################
# DeepDrftAPI Phase 9 smoke tests
# IDE: VS 2022 / Rider / VS Code REST Client
#
# HOW TO USE:
# 1. Set @apiKey below. The real value is in DeepDrftAPI/environment/apikey.json
# under the key "ApiKeySettings.ApiKey". Do NOT commit a real key here.
# 2. Adjust @releaseId, @trackId, and @entryKey to IDs present in your DB.
# 3. Point the multipart upload requests at a real local file before sending.
#
# AUTH NOTE:
# Unauthenticated endpoints have no ApiKey header.
# ApiKey-gated endpoints use header "ApiKey: {{apiKey}}" (header name is literal
# "ApiKey", not "X-Api-Key" confirmed in ApiKeyAuthenticationMiddleware.cs).
###############################################################################
@host = http://localhost:5003
# REPLACE with value from DeepDrftAPI/environment/apikey.json ApiKeySettings.ApiKey
@apiKey = REPLACE_WITH_YOUR_API_KEY
# Placeholders edit these to match IDs in your local DB
@releaseId = 1
@trackId = 1
@entryKey = replace-with-real-entry-key
###############################################################################
# 1. RELEASE READS
###############################################################################
### 1a. List all releases (unauth) expect 200 PagedResult
# exercises: GET api/release (no medium filter)
GET {{host}}/api/release
Accept: application/json
###
### 1b. List Session releases (unauth) expect 200, only Session medium returned
# exercises: GET api/release?medium=session
GET {{host}}/api/release?medium=session
Accept: application/json
###
### 1c. List Mix releases (unauth) expect 200, only Mix medium returned
# exercises: GET api/release?medium=mix
GET {{host}}/api/release?medium=mix
Accept: application/json
###
### 1d. List Cut releases (unauth) expect 200, only Cut medium returned
# exercises: GET api/release?medium=cut
GET {{host}}/api/release?medium=cut
Accept: application/json
###
### 1e. Bad medium value (unauth) expect 400 "Unrecognised medium: bogus"
# exercises: GET api/release?medium=bogus BadRequest branch in ReleaseController
GET {{host}}/api/release?medium=bogus
Accept: application/json
###
### 1f. Single release by id (unauth) expect 200 ReleaseDto with both metadata navs
# exercises: GET api/release/{id:long}
GET {{host}}/api/release/{{releaseId}}
Accept: application/json
###
###############################################################################
# 2. TRACK READS
###############################################################################
### 2a. Paged track list all tracks (unauth) expect 200 PagedResult<TrackDto>
# exercises: GET api/track/page (no filters)
GET {{host}}/api/track/page
Accept: application/json
###
### 2b. Paged track list filtered by releaseId (unauth) expect 200, tracks for that release
# exercises: GET api/track/page?releaseId=
GET {{host}}/api/track/page?releaseId={{releaseId}}
Accept: application/json
###
### 2c. Paged track list filtered by album title (unauth) expect 200
# exercises: GET api/track/page?album=
GET {{host}}/api/track/page?album=My+Album+Name
Accept: application/json
###
### 2d. Paged track list filtered by genre (unauth) expect 200
# exercises: GET api/track/page?genre=
GET {{host}}/api/track/page?genre=Electronic
Accept: application/json
###
### 2e. Single track metadata by SQL id (ApiKey) expect 200 TrackDto
# exercises: GET api/track/meta/{id:long}
GET {{host}}/api/track/meta/{{trackId}}
ApiKey: {{apiKey}}
Accept: application/json
###
### 2f. Track audio stream full file (unauth) expect 200 with audio bytes
# exercises: GET api/track/{trackId} streams WAV from FileDatabase vault
GET {{host}}/api/track/{{entryKey}}
Accept: audio/wav
###
### 2g. Track audio stream Range request (unauth) expect 206 Partial Content
# exercises: GET api/track/{trackId} with Range header 206 + byte slice
GET {{host}}/api/track/{{entryKey}}
Range: bytes=44-
Accept: audio/wav
###
### 2h. Albums list (unauth) expect 200 List<ReleaseDto> with per-release track counts
# exercises: GET api/track/albums
GET {{host}}/api/track/albums
Accept: application/json
###
### 2i. Genres list (unauth) expect 200 List<string> distinct genres
# exercises: GET api/track/genres
GET {{host}}/api/track/genres
Accept: application/json
###
### 2j. Random track (unauth) expect 200 TrackDto (or 404 when library is empty)
# exercises: GET api/track/random
GET {{host}}/api/track/random
Accept: application/json
###
### 2k. Waveform profile for track (unauth) expect 200 WaveformProfileDto or 404 if not computed
# exercises: GET api/track/{trackId}/waveform
GET {{host}}/api/track/{{entryKey}}/waveform
Accept: application/json
###
### 2l. Waveform status for all tracks (ApiKey) expect 200 List<WaveformStatusDto>
# exercises: GET api/track/waveform-status (admin backfill view)
GET {{host}}/api/track/waveform-status
ApiKey: {{apiKey}}
Accept: application/json
###
###############################################################################
# 3. MEDIUM WRITE PATH
###############################################################################
### 3a. Upload a Cut track (ApiKey, multipart) expect 200 TrackDto
# exercises: POST api/track/upload with medium=Cut
# REPLACE ./path/to/test.wav with a real local .wav (or .mp3 / .flac) file path.
POST {{host}}/api/track/upload
ApiKey: {{apiKey}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="audioFile"; filename="test.wav"
Content-Type: audio/wav
< ./path/to/test.wav
--boundary
Content-Disposition: form-data; name="trackName"
Smoke Test Cut
--boundary
Content-Disposition: form-data; name="artist"
Test Artist
--boundary
Content-Disposition: form-data; name="album"
Smoke Test Album
--boundary
Content-Disposition: form-data; name="genre"
Electronic
--boundary
Content-Disposition: form-data; name="releaseDate"
2025-01-01
--boundary
Content-Disposition: form-data; name="createdByUserId"
1
--boundary
Content-Disposition: form-data; name="medium"
Cut
--boundary
Content-Disposition: form-data; name="releaseType"
Single
--boundary
Content-Disposition: form-data; name="trackNumber"
1
--boundary--
###
### 3b. Upload a Session track (ApiKey, multipart) expect 200 TrackDto
# exercises: POST api/track/upload with medium=Session
# NOTE: Session releases are single-track. Use a unique album name to create a new release.
# REPLACE ./path/to/test.wav with a real local .wav/.mp3/.flac file.
POST {{host}}/api/track/upload
ApiKey: {{apiKey}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="audioFile"; filename="test.wav"
Content-Type: audio/wav
< ./path/to/test.wav
--boundary
Content-Disposition: form-data; name="trackName"
Smoke Test Session
--boundary
Content-Disposition: form-data; name="artist"
Test Artist
--boundary
Content-Disposition: form-data; name="album"
Smoke Session Album 001
--boundary
Content-Disposition: form-data; name="createdByUserId"
1
--boundary
Content-Disposition: form-data; name="medium"
Session
--boundary
Content-Disposition: form-data; name="trackNumber"
1
--boundary--
###
### 3c. Upload a Mix track (ApiKey, multipart) expect 200 TrackDto
# exercises: POST api/track/upload with medium=Mix
# NOTE: Mix releases are also single-track. Use a unique album name.
# REPLACE ./path/to/test.wav with a real local .wav/.mp3/.flac file.
POST {{host}}/api/track/upload
ApiKey: {{apiKey}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="audioFile"; filename="test.wav"
Content-Type: audio/wav
< ./path/to/test.wav
--boundary
Content-Disposition: form-data; name="trackName"
Smoke Test Mix
--boundary
Content-Disposition: form-data; name="artist"
Test Artist
--boundary
Content-Disposition: form-data; name="album"
Smoke Mix Album 001
--boundary
Content-Disposition: form-data; name="createdByUserId"
1
--boundary
Content-Disposition: form-data; name="medium"
Mix
--boundary
Content-Disposition: form-data; name="trackNumber"
1
--boundary--
###
### 3d. Update track metadata flip Medium to Session (ApiKey, JSON) expect 200
# exercises: PUT api/track/meta/{id:long}
# Medium: null means "no change"; provide it to change the release medium.
PUT {{host}}/api/track/meta/{{trackId}}
ApiKey: {{apiKey}}
Content-Type: application/json
{
"TrackName": "Updated Track Name",
"Artist": "Updated Artist",
"Album": "Updated Album",
"Genre": "Electronic",
"ReleaseDate": "2025-06-01",
"ImagePath": null,
"ReleaseType": null,
"Medium": "Session",
"TrackNumber": 1
}
###
###############################################################################
# 4. WAVE 7 SESSION CARDINALITY 409 SEQUENCE
#
# Session and Mix releases enforce a single-track maximum. The sequence below
# demonstrates the enforcement:
# Step 1: upload the FIRST track to a Session release expect 200
# Step 2: upload a SECOND track to the SAME album+artist expect 409 Conflict
#
# The 409 body will contain: "A Session release holds a single track; '<album>'
# already has one edit the existing track or choose a different release."
#
# Cut-medium releases have no cardinality limit, so an identical sequence with
# medium=Cut would produce 200 on both requests.
###############################################################################
### 4a. [STEP 1] Upload first Session track expect 200 TrackDto
# The album "Cardinality Test Session" does not yet exist; this creates it.
# REPLACE ./path/to/test.wav with a real local file.
POST {{host}}/api/track/upload
ApiKey: {{apiKey}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="audioFile"; filename="test.wav"
Content-Type: audio/wav
< ./path/to/test.wav
--boundary
Content-Disposition: form-data; name="trackName"
Cardinality Track 1
--boundary
Content-Disposition: form-data; name="artist"
Cardinality Artist
--boundary
Content-Disposition: form-data; name="album"
Cardinality Test Session
--boundary
Content-Disposition: form-data; name="createdByUserId"
1
--boundary
Content-Disposition: form-data; name="medium"
Session
--boundary
Content-Disposition: form-data; name="trackNumber"
1
--boundary--
###
### 4b. [STEP 2] Upload second Session track to the SAME album+artist expect 409 Conflict
# Same album "Cardinality Test Session", same artist "Cardinality Artist".
# UnifiedTrackService.UploadAsync pre-checks cardinality before the vault write.
# REPLACE ./path/to/test.wav with a real local file.
POST {{host}}/api/track/upload
ApiKey: {{apiKey}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="audioFile"; filename="test.wav"
Content-Type: audio/wav
< ./path/to/test.wav
--boundary
Content-Disposition: form-data; name="trackName"
Cardinality Track 2
--boundary
Content-Disposition: form-data; name="artist"
Cardinality Artist
--boundary
Content-Disposition: form-data; name="album"
Cardinality Test Session
--boundary
Content-Disposition: form-data; name="createdByUserId"
1
--boundary
Content-Disposition: form-data; name="medium"
Session
--boundary
Content-Disposition: form-data; name="trackNumber"
2
--boundary--
###
###############################################################################
# 5. MIX WAVEFORM
###############################################################################
### 5a. Trigger waveform generation for a Mix release (ApiKey, no body) expect 200 or 404
# exercises: POST api/release/{id:long}/mix/waveform
# 404 if the release is not a Mix, has no track, or the track has no audio stored.
POST {{host}}/api/release/{{releaseId}}/mix/waveform
ApiKey: {{apiKey}}
Content-Length: 0
###
### 5b. Fetch stored mix waveform (unauth) expect 200 WaveformProfileDto or 404
# exercises: GET api/release/{id:long}/mix/waveform
# 404 when release is not a Mix, has no WaveformEntryKey, or datum not yet computed (run 5a first).
GET {{host}}/api/release/{{releaseId}}/mix/waveform
Accept: application/json
###
###############################################################################
# 6. SESSION HERO IMAGE
###############################################################################
### 6a. Upload hero image for a Session release (ApiKey, multipart) expect 200 or 404
# exercises: POST api/release/{id:long}/session/hero-image
# 404 if release not found. 400 if no image file or unsupported content type.
# The release must be a Session (enforced in UnifiedReleaseService.SetHeroImageAsync).
# REPLACE ./path/to/hero.jpg with a real local JPEG or PNG file.
POST {{host}}/api/release/{{releaseId}}/session/hero-image
ApiKey: {{apiKey}}
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="image"; filename="hero.jpg"
Content-Type: image/jpeg
< ./path/to/hero.jpg
--boundary--
###