# GS Mock Mode 模擬模式分析 ## 概述 為 GS (DtrGuiSrv) 新增 Mock 模擬模式,無需 RAID Driver 即可運行,用於: - 開發測試 - CI/CD 自動化測試 - 離線 Demo - 功能驗證 ## 需要模擬的關鍵函數 ### 1. Driver I/O 層 | 函數 | 用途 | 模擬難度 | |------|------|----------| | `DevIoControl()` | I/O Control 與 Driver 通訊 | 高 | | `QuaryDTR()` | 查詢 RAID 控制器資訊 | 中 | | `GetCtlrEvent()` | 取得控制器事件 | 中 | ### 2. 共享記憶體層 | 函數 | 用途 | 模擬難度 | |------|------|----------| | `InitialSHMForAllCtlr()` | 初始化共享記憶體 | 高 | | 相關 SHM 函數 | 共享記憶體操作 | 高 | ## 模擬模式架構 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ GS Mock Mode 架構 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ GS (DtrGuiSrv) │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ Mock Mode 開關 │ │ │ │ │ │ #define ENABLE_MOCK_MODE │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ┌──────────────────┼──────────────────┐ │ │ │ │ ▼ ▼ ▼ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ Real Driver │ │ Mock Driver │ │ Mock Data │ │ │ │ │ │ (Production)│ │ (Dev/Mock) │ │ (Static) │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ## 實現方案 ### 方案 1: 編譯時開關 (推薦) ```c // hInclude.h #ifdef ENABLE_MOCK_MODE #include "mock_driver.h" #define DevIoControl mock_DevIoControl #define QuaryDTR mock_QuaryDTR #define GetCtlrEvent mock_GetCtlrEvent #endif ``` ### 方案 2: 執行時開關 ```c // runtime_config.h extern BOOL g_bMockMode; // 初始化時檢查 if (g_bMockMode) { initMockDriver(); } else { initRealDriver(); } ``` ### 方案 3: 環境變數 ```bash # 啟動時設定 export DTR_GUI_MOCK_MODE=1 ./DtrGuiSrv01 ``` ## 需要實現的 Mock 函數 ### 1. mock_driver.h ```c #ifndef MOCK_DRIVER_H #define MOCK_DRIVER_H #include "hInclude.h" // Mock 初始化 void mock_init(void); void mock_cleanup(void); // Mock 控制器數據 typedef struct { UCHAR bStatus; UCHAR bCtlrSN[16]; UCHAR bModelName[32]; UCHAR bPage0Data[1024]; // Controller Info Page UCHAR bPage1Data[1024]; // RAID Snapshot // ... } MOCK_CTRL_INFO; // Mock DevIoControl UCHAR mock_DevIoControl( UCHAR bDevNo, ULONG lControlCode, ULONG lInSize, PCHAR pInBuf, ULONG lOutSize, PCHAR pOutBuf, USHORT *pusInBandErrCode ); // Mock QuaryDTR CHAR mock_QuaryDTR( UCHAR ucCtlrIndex, UCHAR *bPageBuf, UCHAR *pbHeatsink ); // Mock GetCtlrEvent UCHAR mock_GetCtlrEvent( UCHAR bCtlrNo, PEVENT_INFO pEvent_info ); // 設定模擬事件 void mock_set_event(UCHAR *eventData, int length); void mock_clear_events(void); // 控制器狀態控制 void mock_set_controller_online(BOOL online); void mock_set_controller_count(int count); #endif ``` ### 2. mock_driver.c ```c #include "mock_driver.h" // 單例 Mock 控制器資訊 static MOCK_CTRL_INFO g_mockCtrl[MAX_DTR_IN_HOST]; static BOOL g_bMockInitialized = FALSE; // 模擬的事件佇列 static UCHAR g_mockEventQueue[100][512]; static int g_mockEventCount = 0; void mock_init(void) { if (g_bMockInitialized) return; // 初始化 Mock 控制器 memset(g_mockCtrl, 0, sizeof(g_mockCtrl)); // 預設控制器 1 台,狀態上線 g_mockCtrl[0].bStatus = CTLR_STATUS_ALIVE; memcpy(g_mockCtrl[0].bCtlrSN, "MOCK00000001", 16); memcpy(g_mockCtrl[0].bModelName, "Accusys Mock RAID", 32); // 填充 Page 0 資料 (Controller Info) fill_mock_page0(g_mockCtrl[0].bPage0Data); g_bMockInitialized = TRUE; printf("[MOCK] Driver initialized\n"); } UCHAR mock_DevIoControl(...) { if (!g_bMockInitialized) mock_init(); // 根據 Control Code 處理 switch (lControlCode) { case IOCTL_DTR_GET_CONTROLLER_INFO: // 回傳控制器資訊 break; case IOCTL_DTR_GET_INBAND_EVENT: // 回傳模擬事件 break; case IOCTL_DTR_SET_INBAND_COMMAND: // 處理命令,回傳成功 break; default: // 預設回傳成功 *pusInBandErrCode = 0; return SYSOK; } return SYSOK; } CHAR mock_QuaryDTR(UCHAR ucCtlrIndex, UCHAR *bPageBuf, UCHAR *pbHeatsink) { if (!g_bMockInitialized) mock_init(); if (ucCtlrIndex >= MAX_DTR_IN_HOST) { return FALSE; } // 複製 Mock 資料 memcpy(bPageBuf, g_mockCtrl[ucCtlrIndex].bPage0Data, 1024); *pbHeatsink = 0x00; return TRUE; } UCHAR mock_GetCtlrEvent(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) { if (!g_bMockInitialized) mock_init(); // 從佇列取出事件 if (g_mockEventCount > 0) { memcpy(pEvent_info->bEventBuf, g_mockEventQueue[0], 512); pEvent_info->bStatus = TRUE; // 移除已取出的事件 g_mockEventCount--; // ... 佇列搬移 return SYSOK; } pEvent_info->bStatus = FALSE; return SYSFAIL_EVENT_EMPTY; } ``` ## 模擬的 Page 資料 ### Page 0: Controller Info ```c void fill_mock_page0(UCHAR *buf) { // Offset 0-31: Serial Number memcpy(buf + 0, "MOCK00000001", 16); // Offset 32-63: Model Name memcpy(buf + 32, "Accusys Mock RAID", 20); // Offset 64-95: Firmware Version memcpy(buf + 64, "1.0.0.0", 8); // 其他欄位... // 需要完整對應 Java GUI 解析的格式 } ``` ### 需要的 Page | Page | 大小 | 用途 | |------|------|------| | 0x00 | 1024 | Controller Info | | 0x01 | 1024 | RAID Snapshot | | 0x07 | 512 | LUN Map Table | | 0x0A-0x0E | 1024 | RAID Info | | 0x10-0x11 | 512 | Disk/Slice Names | | 0x14 | 512 | Array Info | | 0x1A | 512 | Enclosure Info | | 0x1B | 512 | Disk List | ## 模擬事件 ### 預設模擬事件 ```c // 初始化時註冊一些模擬事件 void mock_register_default_events(void) { // 磁碟上線事件 UCHAR diskOnlineEvent[] = { 0x01, 0x00, 0x00, 0x00, // Event Type 0x00, 0x00, 0x00, 0x00, // Timestamp 0x01, 0x02, 0x00, 0x00, // Slot 1, Online // ... }; mock_set_event(diskOnlineEvent, 32); // RAID 重建完成事件 UCHAR rebuildDoneEvent[] = { 0x02, 0x00, 0x00, 0x00, // Event Type // ... }; mock_set_event(rebuildDoneEvent, 32); } ``` ## 配置檔案 ### mock_config.json ```json { "mock_mode": true, "controller_count": 2, "controllers": [ { "serial_number": "MOCK00000001", "model_name": "Accusys GEN2", "firmware_version": "3.8.0", "status": "online", "raid_arrays": [ { "id": 0, "level": "RAID5", "disks": [0, 1, 2, 3], "status": "Normal", "capacity": 10000000 } ], "disks": [ {"slot": 0, "status": "Online", "capacity": 4000000}, {"slot": 1, "status": "Online", "capacity": 4000000}, {"slot": 2, "status": "Online", "capacity": 4000000}, {"slot": 3, "status": "Online", "capacity": 4000000}, {"slot": 4, "status": "Online", "capacity": 4000000, "spare": true} ] }, { "serial_number": "MOCK00000002", "model_name": "Accusys GEN2", "status": "online" } ], "events": [ { "type": "DiskOnline", "slot": 2, "timestamp": 1234567890 } ] } ``` ## 編譯選項 ### Makefile ```makefile # 一般編譯 build: gcc -o DtrGuiSrv01 *.c -lpthread -lm # Mock 模式編譯 build-mock: gcc -o DtrGuiSrv01_mock *.c -DENABLE_MOCK_MODE -lpthread -lm # 兩者區別 ifdef ENABLE_MOCK_MODE CFLAGS += -DENABLE_MOCK_MODE SRCS += mock_driver.c endif ``` ### CMake ```cmake option(ENABLE_MOCK "Enable mock mode for testing" OFF) if(ENABLE_MOCK) add_definitions(-DENABLE_MOCK_MODE) set(MOCK_SOURCES mock_driver.c) endif() add_executable(DtrGuiSrv01 ${SOURCES} ${MOCK_SOURCES}) ``` ## 執行模式 ### 1. 環境變數 ```bash # 啟用 Mock 模式 export DTR_GUI_MOCK_MODE=1 ./DtrGuiSrv01 # 指定 Mock 設定檔 export DTR_GUI_MOCK_CONFIG=./mock_config.json ./DtrGuiSrv01 ``` ### 2. 命令列參數 ```bash ./DtrGuiSrv01 --mock ./DtrGuiSrv01 -m ./DtrGuiSrv01 --mock-config ./mock_config.json ``` ### 3. 設定檔 ```ini # dtr_guiconf.ini [Server] Port=8922 MockMode=1 MockConfig=./mock_config.json ``` ## 測試案例 ### 1. 基本連線測試 ```python import socket def test_connection(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', 8922)) # 發送 GET_PAGE 請求 request = build_get_page_request(page_code=0x00) s.send(request) # 驗證回應 response = s.recv(4096) assert response[0] == 0x50 # Success s.close() ``` ### 2. 控制器查詢測試 ```python def test_query_controller(): # 查詢控制器資訊 response = send_inband_command(opcode=0x01, page=0x00) # 驗證資料格式 assert response['serial_number'] == 'MOCK00000001' assert response['model_name'] == 'Accusys Mock RAID' ``` ### 3. 事件測試 ```python def test_event_polling(): # 設定模擬事件 mock_set_event(disk_online_event) # 取得事件 response = send_event_request(opcode=0x02) # 驗證事件 assert response['event_type'] == 'DiskOnline' ``` ## 實作時間評估 | 工作項目 | 時間 | |----------|------| | 建立 mock_driver.h/c 框架 | 1 天 | | 實作基本 DevIoControl | 2 天 | | 實作 QuaryDTR / GetCtlrEvent | 1 天 | | 實作 Page 0 (Controller Info) | 1 天 | | 實作其他 Page 資料 | 2-3 天 | | 模擬事件系統 | 1 天 | | JSON 設定檔支援 | 1 天 | | 測試與除錯 | 2 天 | | **總計** | **9-10 天** | ## 風險與限制 ### 已知限制 1. **不完整模擬**: 無法完全模擬所有 RAID 操作 2. **狀態有限**: 只能模擬基本狀態 3. **Driver 特定**: 某些低層級錯誤無法模擬 ### 風險控制 1. **清晰標記**: Mock 模式下顯示明顯標識 2. **日誌區分**: Mock 日誌使用不同前綴 `[MOCK]` 3. **版本標記**: 回應中包含 Mock 標記 ```c // 回應中加入 Mock 標記 UCHAR mock_page0[] = { // ... 'M', 'O', 'C', 'K', // 識別碼 // ... }; ``` ## 結論 ### 可行性: ✅ 高 **結論**: 完全可行,預估 9-10 天可完成。 ### 實作策略 1. **先實現基本框架**: 快速建立可運行的 Mock 骨架 2. **逐步完善**: 按需求添加更多 Page 支援 3. **測試驅動**: 先寫測試案例,再實作對應 Mock ### 優點 - 開發期不需要實際 RAID 硬體 - CI/CD 可自動化測試 - 容易重現問題 - 教學演示方便 ### 產出 - `mock_driver.h` - Mock 驅動介面 - `mock_driver.c` - Mock 驅動實作 - `mock_config.json` - 模擬設定檔範例 - 編譯腳本更新