From 8a928d173ebd5fe8ae08f239eac7818e22ce8837 Mon Sep 17 00:00:00 2001 From: wwanarif Date: Thu, 14 Aug 2025 11:05:24 +0000 Subject: [PATCH] fix dockerfiles, playwright tests and bugs Signed-off-by: wwanarif --- app-backend/Dockerfile | 5 +- .../src/components/File_Input/FileInput.tsx | 23 +++-- studio-backend/app/routers/debuglog_router.py | 85 ++++++++++++------- .../src/ui-component/table/FlowListTable.jsx | 4 +- .../002_test_sandbox_chatqna.spec.ts | 25 ++++-- .../003_test_sandbox_docsum.spec.ts | 4 +- .../004_test_sandbox_codegen.spec.ts | 4 +- 7 files changed, 92 insertions(+), 58 deletions(-) diff --git a/app-backend/Dockerfile b/app-backend/Dockerfile index 2f7d441..9688a4b 100644 --- a/app-backend/Dockerfile +++ b/app-backend/Dockerfile @@ -1,9 +1,8 @@ FROM python:3.11-slim RUN apt-get update -y && apt-get install -y --no-install-recommends --fix-missing \ - libsqlite3-0=3.40.1-2+deb12u1 \ - libgl1-mesa-glx=22.3.6-1+deb12u1 \ - libjemalloc-dev=5.3.0-1 \ + libsqlite3-0 \ + libjemalloc-dev \ git && \ rm -rf /var/lib/apt/lists/* diff --git a/app-frontend/react/src/components/File_Input/FileInput.tsx b/app-frontend/react/src/components/File_Input/FileInput.tsx index be4d88d..e5e65ce 100644 --- a/app-frontend/react/src/components/File_Input/FileInput.tsx +++ b/app-frontend/react/src/components/File_Input/FileInput.tsx @@ -232,16 +232,23 @@ const FileInput: React.FC = ({ const uploadFiles = async () => { dispatch(setUploadInProgress(true)); - const responses = await Promise.all( - filesToUpload.map((file: any) => { - dispatch(uploadFile({ file: file.file })); - }), - ); + try { + const responses = await Promise.all( + filesToUpload.map((file: any) => { + return dispatch(uploadFile({ file: file.file })); + }), + ); - dispatch(setUploadInProgress(false)); + // Wait a brief moment to ensure notifications are displayed + await new Promise(resolve => setTimeout(resolve, 100)); - setConfirmUpload(false); - setFilesToUpload([]); + dispatch(setUploadInProgress(false)); + setConfirmUpload(false); + setFilesToUpload([]); + } catch (error) { + dispatch(setUploadInProgress(false)); + setConfirmUpload(false); + } }; const showConfirmUpload = () => { diff --git a/studio-backend/app/routers/debuglog_router.py b/studio-backend/app/routers/debuglog_router.py index c18c76e..0d62100 100644 --- a/studio-backend/app/routers/debuglog_router.py +++ b/studio-backend/app/routers/debuglog_router.py @@ -218,15 +218,6 @@ async def get_all_pods_in_namespace(namespace: str): except Exception as e: pass - # Analyze pod dependencies - dependencies = [] - if services: - try: - dependencies = find_pod_dependencies(pod, pods, services, namespace, core_v1_api) - # print(f"Pod {pod_name} dependencies: {dependencies}") - except Exception as e: - pass - # Analyze pod dependencies dependencies = [] if services: @@ -260,41 +251,71 @@ async def get_all_pods_in_namespace(namespace: str): total_count = len(pod.status.container_statuses) ready_status = f"{ready_count}/{total_count}" - # Only check for error conditions if not already terminating or in terminal state - has_error = False + # Determine detailed pod status based on current container states + has_current_error = False + is_running = False + is_pending = False + if not is_terminating and pod.status.phase not in ["Failed", "Succeeded"]: - # Check init container statuses for errors + # Check init container statuses for current errors (not historical) if pod.status.init_container_statuses: for status in pod.status.init_container_statuses: if status.state and status.state.waiting and status.state.waiting.reason in ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff', 'Error']: - has_error = True + has_current_error = True break elif status.state and status.state.terminated and status.state.terminated.reason == 'Error': - has_error = True + has_current_error = True break - # Check main container statuses for errors - if pod.status.container_statuses: + # Check main container statuses for current state - prioritize running state + if pod.status.container_statuses and not has_current_error: + containers_running = 0 + containers_with_current_errors = 0 + containers_with_high_restarts = 0 + total_containers = len(pod.status.container_statuses) + for status in pod.status.container_statuses: - if status.state and status.state.waiting and status.state.waiting.reason in ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff', 'Error']: - has_error = True - break + # Priority 1: Check if container is currently running (this overrides restart history) + if status.state and status.state.running: + containers_running += 1 + # Even if running, check if it has excessive restarts (indicates instability) + if status.restart_count and status.restart_count > 1: + containers_with_high_restarts += 1 + # Priority 2: Check for current error states only if not running + elif status.state and status.state.waiting: + if status.state.waiting.reason in ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff']: + # These are current errors only if container is not running + containers_with_current_errors += 1 + elif status.state.waiting.reason in ['ContainerCreating', 'PodInitializing']: + is_pending = True + # Other waiting reasons are treated as pending, not errors elif status.state and status.state.terminated and status.state.terminated.reason == 'Error': - has_error = True - break - elif status.restart_count and status.restart_count > 0: - # Check if the pod is restarting frequently (possible error condition) - if status.state and status.state.waiting and status.state.waiting.reason == 'CrashLoopBackOff': - has_error = True - break - has_error = True - break + # Only count as error if container is currently terminated with error + containers_with_current_errors += 1 + + # Determine overall status based on current state (ignore restart history if currently running) + if containers_running == total_containers: + # All containers running - but check if any have high restart counts + if containers_with_high_restarts > 0: + # Containers are running but unstable (high restarts) + has_current_error = True # This will show as "Error" status + else: + is_running = True + elif containers_with_current_errors > 0: + has_current_error = True + elif containers_running > 0: + # Some containers running, some pending - consider it as pending/starting + is_pending = True - # Set pod status based on conditions - if has_error: - pod_status = "Error" - elif pod.metadata.deletion_timestamp: + # Set pod status based on current conditions (prioritize current state over history) + if pod.metadata.deletion_timestamp: pod_status = "Terminating" + elif has_current_error: + pod_status = "Error" + elif is_running: + pod_status = "Running" + elif is_pending: + pod_status = "Pending" elif pod.status.init_container_statuses: ready_count = sum(1 for status in pod.status.init_container_statuses if status.ready) total_count = len(pod.status.init_container_statuses) diff --git a/studio-frontend/packages/ui/src/ui-component/table/FlowListTable.jsx b/studio-frontend/packages/ui/src/ui-component/table/FlowListTable.jsx index a9b6603..a83a3a0 100644 --- a/studio-frontend/packages/ui/src/ui-component/table/FlowListTable.jsx +++ b/studio-frontend/packages/ui/src/ui-component/table/FlowListTable.jsx @@ -515,7 +515,7 @@ export const FlowListTable = ({ data, images, isLoading, filterFunction, updateF justifyContent='center' alignItems='center' > - {row.sandboxStatus === "Getting Ready" || row.sandboxStatus === "Stopping" || row.sandboxStatus === "Deleting existing namespace" ? ( + {row.sandboxStatus === "Getting Ready" || row.sandboxStatus === "Stopping" || row.sandboxStatus === "Deleting existing namespace" || row.sandboxStatus === "Sending Request" ? ( ) : null } @@ -549,7 +549,7 @@ export const FlowListTable = ({ data, images, isLoading, filterFunction, updateF window.open(`/debuglogs/sandbox-${row.id}`, '_blank'); handleRunSandbox(row.id); }} - disabled={row.sandboxStatus === 'Stopping'} + disabled={row.sandboxStatus === 'Stopping' || row.sandboxStatus === 'Sending Request'} > diff --git a/tests/playwright/studio-e2e/002_test_sandbox_chatqna.spec.ts b/tests/playwright/studio-e2e/002_test_sandbox_chatqna.spec.ts index c0809b6..e577a88 100644 --- a/tests/playwright/studio-e2e/002_test_sandbox_chatqna.spec.ts +++ b/tests/playwright/studio-e2e/002_test_sandbox_chatqna.spec.ts @@ -25,8 +25,10 @@ async function setupResponseListener(page, apiResponse) { const lines = event.split('\n'); for (const line of lines) { if (line.startsWith('data: ')) { - const cleanedData = line.slice(6, -1).trim(); // Remove 'data: ' prefix - apiResponse.value += cleanedData + " "; + const cleanedData = line.slice(6).trim(); // Remove 'data: ' prefix only + if (cleanedData && cleanedData !== '[DONE]') { + apiResponse.value += cleanedData; + } } } } @@ -212,31 +214,36 @@ test('002_test_sandbox_chatqna', async ({ browser, baseURL }) => { // } // } console.log ('Chat Attempt 2-------------------'); + apiResponse.value = ""; // Clear the response listener buffer await page2.getByRole('button', { name: 'New Chat' }).click(); await page2.getByRole('textbox', { name: 'Enter your message' }).fill(question); await page2.getByRole('button').filter({ hasText: /^$/ }).nth(2).click(); - await page2.waitForTimeout(30000); + + // Wait for the Copy button to appear, indicating response is complete + await page2.getByRole('button', { name: 'Copy' }).waitFor({ state: 'visible'}); responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords); console.log ('response:', apiResponse.value); console.log ("responseContainsKeyword:", responseContainsKeyword); - if (!responseContainsKeyword) { console.log('First attempt failed. Asking a follow-up question...'); apiResponse.value = ""; // Clear the response listener buffer - // Ask another question const followUpQuestion = "How is Intel performing in Q3 2024?"; await page2.getByRole('textbox', { name: 'Enter your message' }).fill(followUpQuestion); - await page2.getByRole('button').filter({ hasText: /^$/ }).nth(2).click(); - await page2.waitForTimeout(30000); + await page2.locator('.MuiButtonBase-root.MuiButton-root').click(); + + // Wait for the second Copy button to appear, indicating follow-up response is complete + await page2.getByRole('button', { name: 'Copy' }).nth(1).waitFor({ state: 'visible'}); responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords); - console.log ('response:', apiResponse.value); - console.log ("responseContainsKeyword:", responseContainsKeyword); + console.log ('Follow-up response:', apiResponse.value); + console.log ("Follow-up responseContainsKeyword:", responseContainsKeyword); if (!responseContainsKeyword) { throw new Error('RAG failed after follow-up question'); } + } else { + console.log('First attempt succeeded - RAG is working correctly'); } await page2.screenshot({ path: 'screenshot_chat_attempt2.png' }); diff --git a/tests/playwright/studio-e2e/003_test_sandbox_docsum.spec.ts b/tests/playwright/studio-e2e/003_test_sandbox_docsum.spec.ts index 5064d9c..ba7f1af 100644 --- a/tests/playwright/studio-e2e/003_test_sandbox_docsum.spec.ts +++ b/tests/playwright/studio-e2e/003_test_sandbox_docsum.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'; import { waitForStatusText } from '../utils'; import path from 'path'; -const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_workflow_docsum.json');//this workflow consists of Hugging Face token! cannot deploy as off now. +const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_docsum.json'); const uploadtxt1 = path.resolve(__dirname, '../../test-files/Little Red Riding Hood.txt'); const keywords = ["Little Red Riding Hood", "sick grandmother", "wolf", "woodcutter", "hunter", "closet", "food"]; // more keywords needed @@ -90,7 +90,7 @@ test('003_test_sandbox_docsum', async ({ browser, baseURL }) => { //Summarization Generation and Response Validation await page2.waitForTimeout(60000); let responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords); - console.log ('response:', apiResponse.value); + // console.log ('response:', apiResponse.value); await page2.screenshot({ path: 'screenshot_docsum_attempt1.png' }); if (!responseContainsKeyword) { diff --git a/tests/playwright/studio-e2e/004_test_sandbox_codegen.spec.ts b/tests/playwright/studio-e2e/004_test_sandbox_codegen.spec.ts index 5e213ac..e48afbc 100644 --- a/tests/playwright/studio-e2e/004_test_sandbox_codegen.spec.ts +++ b/tests/playwright/studio-e2e/004_test_sandbox_codegen.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'; import { waitForStatusText } from '../utils'; import path from 'path'; -const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_workflow_codegen.json'); +const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_codegen.json'); const question = "write me a python function for fibonacci loop"; const keywords = ["Python", "Fibonacci", "iterative", "if", "<=", "=", "(", ")", "[", "]"]; // more keywords needed @@ -81,7 +81,7 @@ test('004_test_sandbox_codegen', async ({ browser, baseURL }) => { await page2.getByRole('button').filter({ hasText: /^$/ }).nth(2).click(); //end here await page2.waitForTimeout(60000); let responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords); - console.log ('response:', apiResponse.value); + // console.log ('response:', apiResponse.value); await page2.screenshot({ path: 'screenshot_codegen_attempt1.png' }); if (!responseContainsKeyword) {