Merge p9-api-http-smokes into dev (Phase 9 API .http smoke file)
This commit is contained in:
@@ -0,0 +1,466 @@
|
||||
###############################################################################
|
||||
# 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--
|
||||
|
||||
###
|
||||
Reference in New Issue
Block a user