591 lines
15 KiB
ReStructuredText
591 lines
15 KiB
ReStructuredText
@base = http://localhost:3000
|
|
@apiKey = bnt_727d2f4f72bd03ed96da5278bb971a00cb0a2454d4d70f9748b5c39f3f69d88d
|
|
|
|
###############################################################################
|
|
# ALIAS RESOLUTION TESTS
|
|
# Tests: 3-Tier Alias Resolution (Technical -> Flow -> Project)
|
|
#
|
|
# Test Coverage:
|
|
# 1. Technical alias @last
|
|
# 2. Technical alias @first
|
|
# 3. Technical alias @upload
|
|
# 4. Technical alias requires flowId
|
|
# 5. Flow-scoped alias resolution
|
|
# 6. Project-scoped alias resolution
|
|
# 7. Alias precedence (flow > project)
|
|
# 8. Reserved aliases cannot be assigned
|
|
# 9. Alias reassignment removes old
|
|
# 10. Same alias in different flows
|
|
# 11. Technical alias in generation prompt
|
|
# 12. Upload with both project and flow alias
|
|
###############################################################################
|
|
|
|
|
|
###############################################################################
|
|
# SETUP: Create Test Flow
|
|
###############################################################################
|
|
|
|
### Setup: Create flow for alias tests
|
|
# @name setupGen
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Setup image for alias tests",
|
|
"aspectRatio": "1:1",
|
|
"flowAlias": "@alias-test-flow"
|
|
}
|
|
|
|
###
|
|
|
|
@aliasFlowId = {{setupGen.response.body.$.data.flowId}}
|
|
@setupGenId = {{setupGen.response.body.$.data.id}}
|
|
|
|
### Poll setup generation
|
|
# @name checkSetupGen
|
|
GET {{base}}/api/v1/generations/{{setupGenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@setupImageId = {{checkSetupGen.response.body.$.data.outputImageId}}
|
|
|
|
|
|
###############################################################################
|
|
# TEST 1: Technical Alias @last
|
|
# Resolves to last generated image in flow
|
|
###############################################################################
|
|
|
|
### Step 1.1: Resolve @last (requires flowId)
|
|
# @name resolveLast
|
|
GET {{base}}/api/v1/images/@last?flowId={{aliasFlowId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify:
|
|
# - Returns image (status 200)
|
|
# - Returns the most recently generated image in the flow
|
|
|
|
|
|
###############################################################################
|
|
# TEST 2: Technical Alias @first
|
|
# Resolves to first generated image in flow
|
|
###############################################################################
|
|
|
|
### Step 2.1: Resolve @first (requires flowId)
|
|
# @name resolveFirst
|
|
GET {{base}}/api/v1/images/@first?flowId={{aliasFlowId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify:
|
|
# - Returns image (status 200)
|
|
# - Returns the first generated image in the flow
|
|
|
|
|
|
###############################################################################
|
|
# TEST 3: Technical Alias @upload
|
|
# Resolves to last uploaded image in flow
|
|
###############################################################################
|
|
|
|
### Step 3.1: Upload image to flow
|
|
# @name uploadForTest
|
|
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="flowId"
|
|
|
|
{{aliasFlowId}}
|
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
|
Content-Disposition: form-data; name="description"
|
|
|
|
Uploaded for @upload test
|
|
------WebKitFormBoundary7MA4YWxkTrZu0gW--
|
|
|
|
###
|
|
|
|
@uploadedImageId = {{uploadForTest.response.body.$.data.id}}
|
|
|
|
### Step 3.2: Resolve @upload (requires flowId)
|
|
# @name resolveUpload
|
|
GET {{base}}/api/v1/images/@upload?flowId={{aliasFlowId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify:
|
|
# - Returns image (status 200)
|
|
# - Returns uploaded image (source = "uploaded")
|
|
|
|
|
|
###############################################################################
|
|
# TEST 4: Technical Alias Requires Flow Context
|
|
# @last, @first, @upload require flowId parameter
|
|
###############################################################################
|
|
|
|
### Step 4.1: Try @last without flowId (should fail)
|
|
# @name resolveLastNoFlow
|
|
GET {{base}}/api/v1/images/@last
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Expected: 404 with error "Technical aliases require flowId"
|
|
|
|
|
|
###############################################################################
|
|
# TEST 5: Flow-Scoped Alias Resolution
|
|
###############################################################################
|
|
|
|
### Step 5.1: Create generation with flow alias
|
|
# @name flowAliasGen
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Image for flow alias test",
|
|
"aspectRatio": "1:1",
|
|
"flowId": "{{aliasFlowId}}",
|
|
"flowAlias": "@flow-hero"
|
|
}
|
|
|
|
###
|
|
|
|
@flowAliasGenId = {{flowAliasGen.response.body.$.data.id}}
|
|
|
|
### Step 5.2: Poll generation
|
|
# @name checkFlowAliasGen
|
|
GET {{base}}/api/v1/generations/{{flowAliasGenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@flowHeroImageId = {{checkFlowAliasGen.response.body.$.data.outputImageId}}
|
|
|
|
### Step 5.3: Resolve flow alias
|
|
# @name resolveFlowAlias
|
|
GET {{base}}/api/v1/images/@flow-hero?flowId={{aliasFlowId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify:
|
|
# - Returns the image from step 5.1
|
|
# - Only works with flowId parameter
|
|
|
|
|
|
###############################################################################
|
|
# TEST 6: Project-Scoped Alias Resolution
|
|
###############################################################################
|
|
|
|
### Step 6.1: Create generation with project alias
|
|
# @name projectAliasGen
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Image for project alias test",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@project-logo",
|
|
"flowId": null
|
|
}
|
|
|
|
###
|
|
|
|
@projectAliasGenId = {{projectAliasGen.response.body.$.data.id}}
|
|
|
|
### Step 6.2: Poll generation
|
|
# @name checkProjectAliasGen
|
|
GET {{base}}/api/v1/generations/{{projectAliasGenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@projectLogoImageId = {{checkProjectAliasGen.response.body.$.data.outputImageId}}
|
|
|
|
### Step 6.3: Resolve project alias (no flowId needed)
|
|
# @name resolveProjectAlias
|
|
GET {{base}}/api/v1/images/@project-logo
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify:
|
|
# - Returns the image from step 6.1
|
|
# - Works without flowId parameter
|
|
|
|
|
|
###############################################################################
|
|
# TEST 7: Alias Precedence (Flow > Project)
|
|
###############################################################################
|
|
|
|
### Step 7.1: Create project-scoped alias @priority-test
|
|
# @name priorityProject
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Project scoped image for priority test",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@priority-test",
|
|
"flowId": null
|
|
}
|
|
|
|
###
|
|
|
|
@priorityProjectGenId = {{priorityProject.response.body.$.data.id}}
|
|
|
|
### Step 7.2: Poll generation
|
|
# @name checkPriorityProject
|
|
GET {{base}}/api/v1/generations/{{priorityProjectGenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@priorityProjectImageId = {{checkPriorityProject.response.body.$.data.outputImageId}}
|
|
|
|
### Step 7.3: Create flow-scoped alias @priority-test (same name)
|
|
# @name priorityFlow
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Flow scoped image for priority test",
|
|
"aspectRatio": "1:1",
|
|
"flowId": "{{aliasFlowId}}",
|
|
"flowAlias": "@priority-test"
|
|
}
|
|
|
|
###
|
|
|
|
@priorityFlowGenId = {{priorityFlow.response.body.$.data.id}}
|
|
|
|
### Step 7.4: Poll generation
|
|
# @name checkPriorityFlow
|
|
GET {{base}}/api/v1/generations/{{priorityFlowGenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@priorityFlowImageId = {{checkPriorityFlow.response.body.$.data.outputImageId}}
|
|
|
|
### Step 7.5: Resolve WITHOUT flowId (should get project)
|
|
# @name resolvePriorityNoFlow
|
|
GET {{base}}/api/v1/images/@priority-test
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns project image ({{priorityProjectImageId}})
|
|
|
|
### Step 7.6: Resolve WITH flowId (should get flow)
|
|
# @name resolvePriorityWithFlow
|
|
GET {{base}}/api/v1/images/@priority-test?flowId={{aliasFlowId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns flow image ({{priorityFlowImageId}})
|
|
|
|
|
|
###############################################################################
|
|
# TEST 8: Reserved Aliases Cannot Be Assigned
|
|
###############################################################################
|
|
|
|
### Step 8.1: Try to use @last as alias (should fail or warn)
|
|
# @name reservedLast
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Test reserved alias",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@last"
|
|
}
|
|
|
|
###
|
|
# Expected: 400 validation error OR generation succeeds but @last not assigned
|
|
|
|
### Step 8.2: Try to use @first as alias
|
|
# @name reservedFirst
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Test reserved alias",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@first"
|
|
}
|
|
|
|
###
|
|
|
|
### Step 8.3: Try to use @upload as alias
|
|
# @name reservedUpload
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Test reserved alias",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@upload"
|
|
}
|
|
|
|
###
|
|
|
|
|
|
###############################################################################
|
|
# TEST 9: Alias Reassignment (Override Behavior)
|
|
###############################################################################
|
|
|
|
### Step 9.1: Create first image with alias
|
|
# @name reassign1
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "First image for reassign test",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@reassign-test",
|
|
"flowId": null
|
|
}
|
|
|
|
###
|
|
|
|
@reassign1GenId = {{reassign1.response.body.$.data.id}}
|
|
|
|
### Step 9.2: Poll first generation
|
|
# @name checkReassign1
|
|
GET {{base}}/api/v1/generations/{{reassign1GenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@reassign1ImageId = {{checkReassign1.response.body.$.data.outputImageId}}
|
|
|
|
### Step 9.3: Create second image with SAME alias
|
|
# @name reassign2
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Second image for reassign test",
|
|
"aspectRatio": "1:1",
|
|
"alias": "@reassign-test",
|
|
"flowId": null
|
|
}
|
|
|
|
###
|
|
|
|
@reassign2GenId = {{reassign2.response.body.$.data.id}}
|
|
|
|
### Step 9.4: Poll second generation
|
|
# @name checkReassign2
|
|
GET {{base}}/api/v1/generations/{{reassign2GenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@reassign2ImageId = {{checkReassign2.response.body.$.data.outputImageId}}
|
|
|
|
### Step 9.5: Resolve alias (should be second image)
|
|
# @name resolveReassign
|
|
GET {{base}}/api/v1/images/@reassign-test
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns second image ({{reassign2ImageId}})
|
|
|
|
### Step 9.6: Check first image lost alias
|
|
# @name checkFirstLostAlias
|
|
GET {{base}}/api/v1/images/{{reassign1ImageId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: alias = null
|
|
|
|
|
|
###############################################################################
|
|
# TEST 10: Same Alias in Different Flows
|
|
###############################################################################
|
|
|
|
### Step 10.1: Create flow 1 with @shared-name alias
|
|
# @name sharedFlow1
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Flow 1 image with shared name",
|
|
"aspectRatio": "1:1",
|
|
"flowAlias": "@shared-name"
|
|
}
|
|
|
|
###
|
|
|
|
@sharedFlow1Id = {{sharedFlow1.response.body.$.data.flowId}}
|
|
@sharedGen1Id = {{sharedFlow1.response.body.$.data.id}}
|
|
|
|
### Step 10.2: Poll generation 1
|
|
# @name checkSharedGen1
|
|
GET {{base}}/api/v1/generations/{{sharedGen1Id}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@sharedImage1Id = {{checkSharedGen1.response.body.$.data.outputImageId}}
|
|
|
|
### Step 10.3: Create flow 2 with SAME @shared-name alias
|
|
# @name sharedFlow2
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "Flow 2 image with shared name",
|
|
"aspectRatio": "1:1",
|
|
"flowAlias": "@shared-name"
|
|
}
|
|
|
|
###
|
|
|
|
@sharedFlow2Id = {{sharedFlow2.response.body.$.data.flowId}}
|
|
@sharedGen2Id = {{sharedFlow2.response.body.$.data.id}}
|
|
|
|
### Step 10.4: Poll generation 2
|
|
# @name checkSharedGen2
|
|
GET {{base}}/api/v1/generations/{{sharedGen2Id}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
|
|
@sharedImage2Id = {{checkSharedGen2.response.body.$.data.outputImageId}}
|
|
|
|
### Step 10.5: Resolve @shared-name in flow 1
|
|
# @name resolveSharedFlow1
|
|
GET {{base}}/api/v1/images/@shared-name?flowId={{sharedFlow1Id}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns {{sharedImage1Id}}
|
|
|
|
### Step 10.6: Resolve @shared-name in flow 2
|
|
# @name resolveSharedFlow2
|
|
GET {{base}}/api/v1/images/@shared-name?flowId={{sharedFlow2Id}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns {{sharedImage2Id}} (different from flow 1)
|
|
|
|
|
|
###############################################################################
|
|
# TEST 11: Technical Alias in Generation Prompt
|
|
###############################################################################
|
|
|
|
### Step 11.1: Generate using @last in prompt
|
|
# @name techAliasPrompt
|
|
POST {{base}}/api/v1/generations
|
|
Content-Type: application/json
|
|
X-API-Key: {{apiKey}}
|
|
|
|
{
|
|
"prompt": "New variation based on @last",
|
|
"aspectRatio": "1:1",
|
|
"flowId": "{{aliasFlowId}}"
|
|
}
|
|
|
|
###
|
|
|
|
@techAliasGenId = {{techAliasPrompt.response.body.$.data.id}}
|
|
|
|
### Step 11.2: Poll generation
|
|
# @name checkTechAliasGen
|
|
GET {{base}}/api/v1/generations/{{techAliasGenId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify:
|
|
# - status = "success"
|
|
# - referencedImages contains @last alias
|
|
|
|
|
|
###############################################################################
|
|
# TEST 12: Upload with Both Project and Flow Alias
|
|
###############################################################################
|
|
|
|
### Step 12.1: Upload with both aliases
|
|
# @name dualAliasUpload
|
|
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"
|
|
|
|
@dual-project
|
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
|
Content-Disposition: form-data; name="flowId"
|
|
|
|
{{aliasFlowId}}
|
|
------WebKitFormBoundary7MA4YWxkTrZu0gW
|
|
Content-Disposition: form-data; name="flowAlias"
|
|
|
|
@dual-flow
|
|
------WebKitFormBoundary7MA4YWxkTrZu0gW--
|
|
|
|
###
|
|
|
|
@dualAliasImageId = {{dualAliasUpload.response.body.$.data.id}}
|
|
|
|
### Step 12.2: Resolve project alias
|
|
# @name resolveDualProject
|
|
GET {{base}}/api/v1/images/@dual-project
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns {{dualAliasImageId}}
|
|
|
|
### Step 12.3: Resolve flow alias
|
|
# @name resolveDualFlow
|
|
GET {{base}}/api/v1/images/@dual-flow?flowId={{aliasFlowId}}
|
|
X-API-Key: {{apiKey}}
|
|
|
|
###
|
|
# Verify: Returns {{dualAliasImageId}} (same image)
|
|
|
|
|
|
###############################################################################
|
|
# NOTES
|
|
###############################################################################
|
|
#
|
|
# 3-Tier Alias Resolution Order:
|
|
# 1. Technical (@last, @first, @upload) - require flowId
|
|
# 2. Flow-scoped (stored in flow.aliases) - require flowId
|
|
# 3. Project-scoped (stored in images.alias) - no flowId needed
|
|
#
|
|
# Alias Format:
|
|
# - Must start with @
|
|
# - Alphanumeric + hyphens only
|
|
# - Reserved: @last, @first, @upload
|
|
#
|
|
# Override Behavior (Section 5.2):
|
|
# - New alias assignment takes priority
|
|
# - Previous image loses its alias
|
|
# - Previous image is NOT deleted
|
|
#
|