Close File
----------
.. uml::
skinparam style strictuml
hide footbox
title Close file workflow
actor User
box "Client-side" #EDEDED
participant Frontend
end box
box "Server-side" #lightblue
participant Backend
end box
User -> Frontend: Open image
activate Frontend
Frontend -> Backend : 1. OPEN_FILE
activate Backend
Frontend <-- Backend : 2. OPEN_FILE_ACK
Frontend -> Backend : 3. ADD_REQUIRED_TILES
Frontend -> Backend : 4. SET_CURSOR
Frontend <-- Backend : 5. RASTER_TILE_DATA
Frontend <-- Backend : 5. SPATIAL_PROFILE_DATA
deactivate Backend
User <-- Frontend: Displays image
deactivate Frontend
User -> Frontend: Close image
activate Frontend
Frontend -> Backend : 6. CLOSE_FILE
activate Backend
deactivate Backend
deactivate Frontend
note over Frontend, Backend
After CLOSE_FILE, the backend should
stop sending messages for the closed file.
The backend should remain alive and responsive.
end note
User -> Frontend: Verify backend alive
activate Frontend
Frontend -> Backend : 7. FILE_LIST_REQUEST
activate Backend
Frontend <--[#red] Backend : 8. FILE_LIST_RESPONSE [Check 1]
deactivate Backend
User <-- Frontend: Backend confirmed alive
deactivate Frontend
CLOSE_FILE_SINGLE
~~~~~~~~~~~~~~~~~
See the `source code `__.
1. Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = -1
2. Frontend sends: **OPEN_FILE** (``OpenFile``)
.. code-block:: protobuf
directory = "set_QA"
file = "M17_SWex.fits"
hdu = ""
file_id = 0
render_mode = RASTER
3. Backend returns: **OPEN_FILE_ACK** (``OpenFileAck``) and **REGION_HISTOGRAM_DATA**
:red-text:`Check 1:` the OPEN_FILE_ACK should satisfy:
- OPEN_FILE_ACK.success = True
- OPEN_FILE_ACK.file_info.name = "M17_SWex.fits"
4. Frontend sends: **ADD_REQUIRED_TILES** (``AddRequiredTiles``)
.. code-block:: protobuf
file_id = 0
compression_quality = 11
compression_type = ZFP
tiles = [0]
5. Frontend sends: **SET_CURSOR** and **SET_SPATIAL_REQUIREMENTS**
.. code-block:: protobuf
file_id = 0
point = {x: 1, y: 1}
6. Backend returns: **RASTER_TILE_DATA** and **SPATIAL_PROFILE_DATA**
:red-text:`Check 2:` the RASTER_TILE_DATA stream should satisfy:
- Total length = 3 (RasterTileSync start + 1 tile + RasterTileSync end)
7. Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = 0
:red-text:`Check 3:` after closing the file:
- No additional messages should be received from the backend (message count should not change after 1000 ms)
:red-text:`Check 4:` the backend should remain alive:
- FILE_LIST_RESPONSE.success = True
- FILE_LIST_RESPONSE.directory should contain "set_QA"
CLOSE_FILE_ANIMATION
~~~~~~~~~~~~~~~~~~~~
See the `source code `__.
1. Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = -1
2. Frontend sends: **OPEN_FILE** (``OpenFile``)
.. code-block:: protobuf
directory = "set_QA"
file = "M17_SWex.fits"
hdu = "0"
file_id = 0
render_mode = RASTER
3. Backend returns: **OPEN_FILE_ACK** (``OpenFileAck``) and **REGION_HISTOGRAM_DATA**
:red-text:`Check 1:` the OPEN_FILE_ACK should satisfy:
- OPEN_FILE_ACK.success = True
- OPEN_FILE_ACK.file_info.name = "M17_SWex.fits"
4. Frontend sends: **ADD_REQUIRED_TILES** (``AddRequiredTiles``)
.. code-block:: protobuf
file_id = 0
compression_quality = 11
compression_type = ZFP
tiles = [33558529, 33558528, 33562625, 33554433, 33562624,
33558530, 33554432, 33562626, 33554434, 33566721,
33566720, 33566722]
5. Frontend sends: **SET_CURSOR** and **SET_SPATIAL_REQUIREMENTS**
.. code-block:: protobuf
file_id = 0
point = {x: 320, y: 400}
6. Backend returns: **RASTER_TILE_DATA** stream (12 tiles + 2 sync = 14 messages)
:red-text:`Check 2:` the RASTER_TILE_DATA stream should satisfy:
- Total length = 14 (12 tiles + RasterTileSync start + RasterTileSync end)
7. Frontend sends: **START_ANIMATION** (``StartAnimation``)
.. code-block:: protobuf
file_id = 0
start_frame = {channel: 1, stokes: 0}
first_frame = {channel: 0, stokes: 0}
last_frame = {channel: 24, stokes: 0}
delta_frame = {channel: 1, stokes: 0}
required_tiles = {file_id: 0, tiles: [12 tiles], compression_type: ZFP, compression_quality: 9}
looping = true
reverse = false
frame_rate = 5
8. Backend returns: **START_ANIMATION_ACK** (``StartAnimationAck``)
:red-text:`Check 3:` the START_ANIMATION_ACK should satisfy:
- START_ANIMATION_ACK.success = True
9. Animation plays for 2 channel frames with **ANIMATION_FLOW_CONTROL** sent per frame
10. Frontend sends: **CLOSE_FILE** (``CloseFile``) during animation (without STOP_ANIMATION)
.. code-block:: protobuf
file_id = 0
:red-text:`Check 4:` after closing the file during animation:
- The backend should remain alive
- FILE_LIST_RESPONSE.success = True
- FILE_LIST_RESPONSE.directory should contain "set_QA"
CLOSE_FILE_ERROR
~~~~~~~~~~~~~~~~
See the `source code `__.
**Case 1: Requesting ICD message of a closed file**
1. Frontend sends: **OPEN_FILE** (``OpenFile``) for two files
File 1:
.. code-block:: protobuf
directory = "set_QA"
file = "M17_SWex.fits"
hdu = "0"
file_id = 0
render_mode = RASTER
File 2:
.. code-block:: protobuf
directory = "set_QA"
file = "M17_SWex.hdf5"
hdu = "0"
file_id = 1
render_mode = RASTER
2. Backend returns: **OPEN_FILE_ACK** for each file
:red-text:`Check 1:` both OPEN_FILE_ACK should satisfy:
- success = True
3. Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = 1
4. Frontend sends: **SET_CURSOR** targeting the closed file
.. code-block:: protobuf
file_id = 1
point = {x: 1, y: 1}
5. Backend returns: **ERROR_DATA** (``ErrorData``)
:red-text:`Check 2:` the ERROR_DATA should satisfy:
.. code-block:: protobuf
tags = ["cursor"]
message = "File id 1 not found"
:red-text:`Check 3:` the backend should remain alive:
- FILE_LIST_RESPONSE.success = True
:red-text:`Check 4:` file_id = 0 should still function normally:
- ADD_REQUIRED_TILES, SET_CURSOR, and SET_SPATIAL_REQUIREMENTS should all receive valid responses
- RASTER_TILE_DATA stream length = 3
**Case 2: Open → Close → Reopen cycle**
6. Frontend sends: **OPEN_FILE** (file_id = 0), loads tiles and sets cursor
7. Frontend sends: **CLOSE_FILE** (file_id = 0)
8. Frontend sends: **OPEN_FILE** again (same file, file_id = 0)
:red-text:`Check 5:` the reopened file should function normally:
- OPEN_FILE_ACK.success = True
- ADD_REQUIRED_TILES, SET_CURSOR, and SET_SPATIAL_REQUIREMENTS receive valid responses
- RASTER_TILE_DATA stream length = 3
:red-text:`Check 6:` the backend should remain alive after the cycle:
- FILE_LIST_RESPONSE.success = True
- FILE_LIST_RESPONSE.directory should contain "set_QA"
CLOSE_FILE_SPECTRAL_PROFILE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See the `source code `__.
**Case 1: Close during single image spectral profile streaming**
1. Frontend sends: **OPEN_FILE** (``OpenFile``)
.. code-block:: protobuf
directory = "set_QA"
file = "S255_IR_sci.spw29.cube.I.pbcor.fits"
hdu = "0"
file_id = 0
render_mode = RASTER
2. Backend returns: **OPEN_FILE_ACK** and **REGION_HISTOGRAM_DATA**
:red-text:`Check 1:` the OPEN_FILE_ACK should satisfy:
- success = True
3. Frontend loads tiles, sets cursor and spatial requirements
4. Frontend sends: **SET_REGION** (``SetRegion``)
.. code-block:: protobuf
file_id = 0
region_id = -1
region_info = {
region_type = RECTANGLE,
control_points = [{x: 630.0, y: 1060.0}, {x: 600.0, y: 890.0}],
rotation = 0.0
}
5. Backend returns: **SET_REGION_ACK** (``SetRegionAck``)
:red-text:`Check 2:` the SET_REGION_ACK should satisfy:
.. code-block:: protobuf
success = True
region_id = 1
6. Frontend sends: **SET_SPECTRAL_REQUIREMENTS** (``SetSpectralRequirements``)
.. code-block:: protobuf
file_id = 0
region_id = 1
spectral_profiles = [{coordinate: "z", stats_types: [Mean]}]
7. Backend streams: **SPECTRAL_PROFILE_DATA** with increasing progress
8. Once progress > 0.3, Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = 0
:red-text:`Check 3:` after closing the file during spectral profile streaming:
- The backend should remain alive
- FILE_LIST_RESPONSE.success = True
- FILE_LIST_RESPONSE.directory should contain "set_QA"
**Case 2: Close during dual image spectral profile streaming**
9. Frontend opens two images:
.. code-block:: protobuf
file = "S255_IR_sci.spw29.cube.I.pbcor.fits" (file_id = 0)
file = "S255_IR_sci.spw25.cube.I.pbcor.fits" (file_id = 1)
10. Frontend loads tiles and sets up spatial requirements for both images
11. Frontend sends: **SET_REGION** on file_id = 0
12. Frontend sends: **SET_SPECTRAL_REQUIREMENTS** on file_id = 0
.. code-block:: protobuf
file_id = 0
region_id = 1
spectral_profiles = [{coordinate: "z", stats_types: [Mean]}]
13. Once progress > 0.3, cancel first image spectral requirements
14. Frontend sends: **SET_SPECTRAL_REQUIREMENTS** on file_id = 1 (via matching region)
.. code-block:: protobuf
file_id = 1
region_id = 1
spectral_profiles = [{coordinate: "z", stats_types: [Mean]}]
15. Once progress > 0.3, Frontend sends: **CLOSE_FILE** for both images
.. code-block:: protobuf
file_id = 0
file_id = 1
:red-text:`Check 4:` after closing both files:
- No additional messages should be received from the backend
:red-text:`Check 5:` the backend should remain alive:
- FILE_LIST_RESPONSE.success = True
- FILE_LIST_RESPONSE.directory should contain "set_QA"
CLOSE_FILE_TILE
~~~~~~~~~~~~~~~
See the `source code `__.
1. Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = -1
2. Frontend sends: **OPEN_FILE** (``OpenFile``)
.. code-block:: protobuf
directory = "set_QA"
file = "M17_SWex.fits"
hdu = ""
file_id = 0
render_mode = RASTER
3. Backend returns: **OPEN_FILE_ACK** and **REGION_HISTOGRAM_DATA**
:red-text:`Check 1:` the OPEN_FILE_ACK should satisfy:
- success = True
4. Frontend sends: **ADD_REQUIRED_TILES** (``AddRequiredTiles``)
.. code-block:: protobuf
file_id = 0
compression_quality = 11
compression_type = ZFP
tiles = [0]
5. Frontend sends: **SET_CURSOR** and **SET_SPATIAL_REQUIREMENTS**
.. code-block:: protobuf
file_id = 0
point = {x: 1, y: 1}
6. Backend returns: **RASTER_TILE_DATA** and **SPATIAL_PROFILE_DATA**
:red-text:`Check 2:` the RASTER_TILE_DATA stream should satisfy:
- Total length = 3 (RasterTileSync start + 1 tile + RasterTileSync end)
7. Frontend sends: **SET_IMAGE_CHANNELS** (``SetImageChannels``) to trigger large tile streaming
.. code-block:: protobuf
file_id = 0
channel = 10
stokes = 0
required_tiles = {
file_id: 0,
compression_type: ZFP,
compression_quality: 11,
tiles: [33558529, 33558528, 33562625, 33554433, 33562624,
33558530, 33554432, 33562626, 33554434, 33566721,
33566720, 33566722]
}
8. During tile streaming, Frontend sends: **CLOSE_FILE** (``CloseFile``)
.. code-block:: protobuf
file_id = 0
:red-text:`Check 3:` after closing the file during tile streaming:
- The backend should remain alive
- FILE_LIST_RESPONSE.success = True
- FILE_LIST_RESPONSE.directory should contain "set_QA"
CLOSE_FILE_MULTI_FILES
~~~~~~~~~~~~~~~~~~~~~~
See the `source code `__.
This test verifies that multiple files can be closed in various orders and combinations, and that the backend remains alive and responsive after each scenario.
1. Frontend sends: **OPEN_FILE** (``OpenFile``) for 3 files
.. code-block:: protobuf
file = "M17_SWex.fits", file_id = 0
file = "M17_SWex.hdf5", file_id = 1
file = "M17_SWex.image", file_id = 2
2. Backend returns: **OPEN_FILE_ACK** and **REGION_HISTOGRAM_DATA** for each file
3. For each file: Frontend sends **ADD_REQUIRED_TILES**, **SET_CURSOR**, and **SET_SPATIAL_REQUIREMENTS**
**Case 1: Close files in reverse order (2 -> 1 -> 0)**
4. Frontend sends: **CLOSE_FILE** (file_id = 2), then verifies remaining files respond to spatial requirements
5. Frontend sends: **CLOSE_FILE** (file_id = 1), then verifies remaining file responds
6. Frontend sends: **CLOSE_FILE** (file_id = 0)
:red-text:`Check 1:` after all files closed:
- Backend should remain alive: FILE_LIST_RESPONSE.success = True
- No additional ICD messages should arrive (message count stable for 500 ms)
**Case 2: Close two files simultaneously, then close the last**
7. Reopen all 3 files with the same setup
8. Frontend sends: **CLOSE_FILE** (file_id = 0) and **CLOSE_FILE** (file_id = 1) simultaneously
:red-text:`Check 2:` after simultaneous close:
- No additional ICD messages should arrive (message count stable for 500 ms)
9. Frontend sends: **CLOSE_FILE** (file_id = 2)
:red-text:`Check 3:` the backend should remain alive:
- FILE_LIST_RESPONSE.success = True
**Case 3: Close all three files simultaneously**
10. Reopen all 3 files with the same setup
11. Frontend sends: **CLOSE_FILE** for file_id = 0, 1, and 2 simultaneously
:red-text:`Check 4:` after simultaneous close of all files:
- Backend should remain alive: FILE_LIST_RESPONSE.success = True
- No additional ICD messages should arrive (message count stable for 500 ms)