feat: add test
This commit is contained in:
parent
7da1973072
commit
fba243cfbd
|
|
@ -672,6 +672,101 @@ The v1 API supports a 3-tier alias resolution system for referencing images.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Response Formats
|
||||||
|
|
||||||
|
### Generation Response
|
||||||
|
|
||||||
|
Generation responses include fields for prompt enhancement tracking:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
|
"projectId": "57c7f7f4d-47de-4d70-9ebd-3807a0b63746",
|
||||||
|
"prompt": "A photorealistic establishing shot of a luxurious motor yacht...",
|
||||||
|
"originalPrompt": "шикарная моторная яхта движется по живописному озеру...",
|
||||||
|
"autoEnhance": true,
|
||||||
|
"aspectRatio": "16:9",
|
||||||
|
"status": "success",
|
||||||
|
"outputImageId": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||||
|
"outputImage": { ... },
|
||||||
|
"referenceImages": [],
|
||||||
|
"flowId": null,
|
||||||
|
"processingTimeMs": 8980,
|
||||||
|
"cost": null,
|
||||||
|
"retryCount": 0,
|
||||||
|
"errorMessage": null,
|
||||||
|
"meta": {},
|
||||||
|
"createdAt": "2025-11-23T13:47:00.127Z",
|
||||||
|
"updatedAt": "2025-11-23T13:47:09.107Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prompt Enhancement Fields:**
|
||||||
|
|
||||||
|
- `prompt` - The actual prompt used for generation (enhanced if `autoEnhance: true`, original if `autoEnhance: false`)
|
||||||
|
- `originalPrompt` - The user's original input prompt (always populated for transparency)
|
||||||
|
- `autoEnhance` - Boolean indicating if prompt enhancement was applied
|
||||||
|
|
||||||
|
**Semantics:**
|
||||||
|
- When `autoEnhance: true`:
|
||||||
|
- `originalPrompt` = user's original input
|
||||||
|
- `prompt` = AI-enhanced version used for generation
|
||||||
|
- Example: Original "a cat" → Enhanced "A photorealistic close-up portrait of a cat..."
|
||||||
|
|
||||||
|
- When `autoEnhance: false`:
|
||||||
|
- `originalPrompt` = user's original input
|
||||||
|
- `prompt` = same as originalPrompt (no enhancement)
|
||||||
|
- Both fields contain identical values
|
||||||
|
|
||||||
|
**Default Behavior:** `autoEnhance` defaults to `true` if not explicitly set to `false`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Image Response
|
||||||
|
|
||||||
|
Image responses include actual dimensions and storage access:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "7c4ccf47-41ce-4718-afbc-8c553b2c631a",
|
||||||
|
"projectId": "57c7f7f4d-47de-4d70-9ebd-3807a0b63746",
|
||||||
|
"flowId": null,
|
||||||
|
"storageKey": "default/57c7f7f4d-47de-4d70-9ebd-3807a0b63746/generated/2025-11/gen_fd14839b.png",
|
||||||
|
"storageUrl": "http://localhost:9000/banatie/default/57c7f7f4d-47de-4d70-9ebd-3807a0b63746/generated/gen_fd14839b.png",
|
||||||
|
"mimeType": "image/jpeg",
|
||||||
|
"fileSize": 1909246,
|
||||||
|
"width": 1792,
|
||||||
|
"height": 1024,
|
||||||
|
"source": "generated",
|
||||||
|
"alias": null,
|
||||||
|
"focalPoint": null,
|
||||||
|
"fileHash": null,
|
||||||
|
"generationId": "fd14839b-d42e-4be9-93b3-e2fb67f7af0d",
|
||||||
|
"apiKeyId": "988cb71e-0021-4217-a536-734b097a87b3",
|
||||||
|
"meta": {},
|
||||||
|
"createdAt": "2025-11-23T13:47:00.127Z",
|
||||||
|
"updatedAt": "2025-11-23T13:47:00.127Z",
|
||||||
|
"deletedAt": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Fields:**
|
||||||
|
|
||||||
|
- `width` / `height` - Actual image dimensions in pixels (automatically extracted from generated images)
|
||||||
|
- `storageUrl` - Direct URL to access the image file (use this for image display)
|
||||||
|
- `storageKey` - Internal MinIO storage path
|
||||||
|
- `source` - Image origin: "generated" (AI-generated) or "uploaded" (user upload)
|
||||||
|
- `alias` - Project-scoped alias (e.g., "@logo"), null if not assigned
|
||||||
|
- `focalPoint` - Cropping focal point {x: 0.0-1.0, y: 0.0-1.0}, null if not set
|
||||||
|
|
||||||
|
**Image Access:**
|
||||||
|
|
||||||
|
To display an image, use the `storageUrl` field which provides direct access to the image file in MinIO storage. For public CDN access, use the `/cdn/:orgSlug/:projectSlug/img/:alias` endpoint.
|
||||||
|
|
||||||
|
**Note:** Previous versions included a `url` field that pointed to a non-existent `/download` endpoint. This field has been removed. Always use `storageUrl` for direct image access.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Error Codes
|
## Error Codes
|
||||||
|
|
||||||
| Code | Description |
|
| Code | Description |
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,332 @@
|
||||||
|
@base = http://localhost:3000
|
||||||
|
@apiKey = bnt_727d2f4f72bd03ed96da5278bb971a00cb0a2454d4d70f9748b5c39f3f69d88d
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# IMAGE UPLOAD & CRUD TESTS
|
||||||
|
# Tests: Upload, list, filter, pagination, metadata updates, alias management
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
### Test 1.1: Upload image with project-scoped alias
|
||||||
|
# @name uploadWithAlias
|
||||||
|
POST {{base}}/api/v1/images/upload
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
Content-Disposition: form-data; name="file"; filename="test-image.png"
|
||||||
|
Content-Type: image/png
|
||||||
|
|
||||||
|
< ./fixture/test-image.png
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
Content-Disposition: form-data; name="alias"
|
||||||
|
|
||||||
|
@test-logo
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
Content-Disposition: form-data; name="description"
|
||||||
|
|
||||||
|
Test logo image for CRUD tests
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW--
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@uploadedImageId = {{uploadWithAlias.response.body.$.data.id}}
|
||||||
|
@uploadedImageAlias = {{uploadWithAlias.response.body.$.data.alias}}
|
||||||
|
@uploadedImageSource = {{uploadWithAlias.response.body.$.data.source}}
|
||||||
|
|
||||||
|
### Test 1.2: Verify uploaded image details
|
||||||
|
# Expected: alias = @test-logo, source = uploaded
|
||||||
|
GET {{base}}/api/v1/images/{{uploadedImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 2.1: Upload image without alias
|
||||||
|
# @name uploadWithoutAlias
|
||||||
|
POST {{base}}/api/v1/images/upload
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
Content-Disposition: form-data; name="file"; filename="test-image.png"
|
||||||
|
Content-Type: image/png
|
||||||
|
|
||||||
|
< ./fixture/test-image.png
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
||||||
|
Content-Disposition: form-data; name="description"
|
||||||
|
|
||||||
|
Image without alias
|
||||||
|
------WebKitFormBoundary7MA4YWxkTrZu0gW--
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@uploadedImageId2 = {{uploadWithoutAlias.response.body.$.data.id}}
|
||||||
|
|
||||||
|
### Test 2.2: Verify image has no alias
|
||||||
|
# Expected: alias = null
|
||||||
|
GET {{base}}/api/v1/images/{{uploadedImageId2}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 3: List all images
|
||||||
|
# Expected: Returns array with pagination
|
||||||
|
GET {{base}}/api/v1/images
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 4: List images - filter by source=uploaded
|
||||||
|
# Expected: All results have source="uploaded"
|
||||||
|
GET {{base}}/api/v1/images?source=uploaded
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 5: List images with pagination
|
||||||
|
# Expected: limit=3, offset=0, hasMore=true/false
|
||||||
|
GET {{base}}/api/v1/images?limit=3&offset=0
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 6: Get image by ID
|
||||||
|
# Expected: Returns full image details
|
||||||
|
GET {{base}}/api/v1/images/{{uploadedImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 7: Resolve project-scoped alias
|
||||||
|
# Expected: Resolves to uploadedImageId, scope=project
|
||||||
|
GET {{base}}/api/v1/images/resolve/@test-logo
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 8.1: Update image metadata (focal point + meta)
|
||||||
|
# @name updateMetadata
|
||||||
|
PUT {{base}}/api/v1/images/{{uploadedImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"focalPoint": {
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.3
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"description": "Updated description",
|
||||||
|
"tags": ["test", "logo", "updated"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 8.2: Verify metadata update
|
||||||
|
# Expected: focalPoint x=0.5, y=0.3, meta has tags
|
||||||
|
GET {{base}}/api/v1/images/{{uploadedImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 9.1: Update image alias (dedicated endpoint)
|
||||||
|
# @name updateAlias
|
||||||
|
PUT {{base}}/api/v1/images/{{uploadedImageId}}/alias
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"alias": "@new-test-logo"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 9.2: Verify new alias works
|
||||||
|
# Expected: Resolves to same uploadedImageId
|
||||||
|
GET {{base}}/api/v1/images/resolve/@new-test-logo
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 10: Verify old alias doesn't work after update
|
||||||
|
# Expected: 404 - Alias not found
|
||||||
|
GET {{base}}/api/v1/images/resolve/@test-logo
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 11.1: Remove image alias
|
||||||
|
# @name removeAlias
|
||||||
|
PUT {{base}}/api/v1/images/{{uploadedImageId}}/alias
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"alias": null
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 11.2: Verify image exists but has no alias
|
||||||
|
# Expected: alias = null
|
||||||
|
GET {{base}}/api/v1/images/{{uploadedImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 11.3: Verify alias resolution fails
|
||||||
|
# Expected: 404 - Alias not found
|
||||||
|
GET {{base}}/api/v1/images/resolve/@new-test-logo
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 12.1: Reassign alias for reference image test
|
||||||
|
# @name reassignAlias
|
||||||
|
PUT {{base}}/api/v1/images/{{uploadedImageId}}/alias
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"alias": "@reference-logo"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 12.2: Generate with manual reference image
|
||||||
|
# @name genWithReference
|
||||||
|
POST {{base}}/api/v1/generations
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"prompt": "A product photo with the logo in corner",
|
||||||
|
"aspectRatio": "1:1",
|
||||||
|
"referenceImages": ["@reference-logo"]
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@genWithReferenceId = {{genWithReference.response.body.$.data.id}}
|
||||||
|
|
||||||
|
### Test 12.3: Poll generation status
|
||||||
|
# Run this multiple times until status = success
|
||||||
|
GET {{base}}/api/v1/generations/{{genWithReferenceId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 12.4: Verify referenced images tracked
|
||||||
|
# Expected: referencedImages array contains @reference-logo
|
||||||
|
GET {{base}}/api/v1/generations/{{genWithReferenceId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 13.1: Generate with auto-detected reference in prompt
|
||||||
|
# @name genAutoDetect
|
||||||
|
POST {{base}}/api/v1/generations
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"prompt": "Create banner using @reference-logo with blue background",
|
||||||
|
"aspectRatio": "16:9"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@genAutoDetectId = {{genAutoDetect.response.body.$.data.id}}
|
||||||
|
|
||||||
|
### Test 13.2: Poll until complete
|
||||||
|
GET {{base}}/api/v1/generations/{{genAutoDetectId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 13.3: Verify auto-detection worked
|
||||||
|
# Expected: referencedImages contains @reference-logo
|
||||||
|
GET {{base}}/api/v1/generations/{{genAutoDetectId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 14.1: Generate with project alias assignment
|
||||||
|
# @name genWithAlias
|
||||||
|
POST {{base}}/api/v1/generations
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"prompt": "A hero banner image",
|
||||||
|
"aspectRatio": "21:9",
|
||||||
|
"alias": "@hero-banner"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@genWithAliasId = {{genWithAlias.response.body.$.data.id}}
|
||||||
|
|
||||||
|
### Test 14.2: Poll until complete
|
||||||
|
GET {{base}}/api/v1/generations/{{genWithAliasId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@heroImageId = {{genWithAlias.response.body.$.data.outputImageId}}
|
||||||
|
|
||||||
|
### Test 14.3: Verify alias assigned to output image
|
||||||
|
# Expected: alias = @hero-banner
|
||||||
|
GET {{base}}/api/v1/images/{{heroImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 14.4: Verify alias resolution works
|
||||||
|
# Expected: Resolves to heroImageId
|
||||||
|
GET {{base}}/api/v1/images/resolve/@hero-banner
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 15.1: Alias conflict - create second generation with same alias
|
||||||
|
# @name genConflict
|
||||||
|
POST {{base}}/api/v1/generations
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"prompt": "A different hero image",
|
||||||
|
"aspectRatio": "21:9",
|
||||||
|
"alias": "@hero-banner"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@genConflictId = {{genConflict.response.body.$.data.id}}
|
||||||
|
|
||||||
|
### Test 15.2: Poll until complete
|
||||||
|
GET {{base}}/api/v1/generations/{{genConflictId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
@secondHeroImageId = {{genConflict.response.body.$.data.outputImageId}}
|
||||||
|
|
||||||
|
### Test 15.3: Verify second image has the alias
|
||||||
|
# Expected: Resolves to secondHeroImageId (not heroImageId)
|
||||||
|
GET {{base}}/api/v1/images/resolve/@hero-banner
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### Test 15.4: Verify first image lost the alias but still exists
|
||||||
|
# Expected: alias = null, image still exists
|
||||||
|
GET {{base}}/api/v1/images/{{heroImageId}}
|
||||||
|
X-API-Key: {{apiKey}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# END OF IMAGE UPLOAD & CRUD TESTS
|
||||||
|
###############################################################################
|
||||||
Loading…
Reference in New Issue