Files
wehub-resource-sync e0e362d700
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
Deploy Docs Pages / build (push) Has been cancelled
Deploy Docs Pages / deploy (push) Has been cancelled
Real E2E Tests / JavaScript E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Python E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Java E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / C# E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Go E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Real E2E CI (push) Has been cancelled
SDK Tests / SDK CI (push) Has been cancelled
SDK Tests / CLI Tests (push) Has been cancelled
SDK Tests / Python SDK Quality (code-interpreter) (push) Has been cancelled
SDK Tests / Python SDK Quality (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (sandbox) (push) Has been cancelled
SDK Tests / CLI Quality (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Go SDK Quality And Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:39:33 +08:00

327 lines
8.6 KiB
Go

// Copyright 2025 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package jupyter
import (
"fmt"
"net/http"
"os"
"testing"
"time"
"github.com/alibaba/opensandbox/execd/pkg/jupyter/execute"
)
// TestLiveServerIntegration tests SDK integration with a real Jupyter server
func TestLiveServerIntegration(t *testing.T) {
// Get configuration from environment variables, use default values if not set
jupyterURL := getEnv("JUPYTER_URL", "")
jupyterToken := getEnv("JUPYTER_TOKEN", "")
if jupyterURL == "" || jupyterToken == "" {
t.Skip("JUPYTER_URL and JUPYTER_TOKEN environment variables must be set to run this test")
}
// Output test information
t.Logf("Connecting to Jupyter server: %s", jupyterURL)
// Create HTTP client with authentication capability
httpClient := &http.Client{
Transport: &AuthTransport{
Token: jupyterToken,
Base: http.DefaultTransport,
},
}
// Create client and set authentication
client := NewClient(jupyterURL,
WithToken(jupyterToken), // Keep Token setting to support ValidateAuth and WebSocket connections
WithHTTPClient(httpClient))
// Test 1: Validate authentication
t.Run("Validate Authentication", func(t *testing.T) {
status, err := client.ValidateAuth()
if err != nil {
t.Fatalf("Authentication validation failed: %v", err)
}
if status != "ok" {
t.Errorf("Authentication status incorrect, expected 'ok', got '%s'", status)
}
t.Logf("Authentication validation successful! Status: %s", status)
})
// Test 2: Get kernel specs
var kernelName string
t.Run("Get Kernel Specs", func(t *testing.T) {
specs, err := client.GetKernelSpecs()
if err != nil {
t.Fatalf("Failed to get kernel specs: %v", err)
}
if specs.Default == "" {
t.Errorf("No default kernel")
}
if len(specs.Kernelspecs) == 0 {
t.Errorf("No available kernels")
}
// Use default kernel or Python kernel (if available)
kernelName = specs.Default
for name, spec := range specs.Kernelspecs {
if spec.Spec.Language == "python" {
kernelName = name
break
}
}
t.Logf("Get kernel specs successful! Default kernel: %s, Selected kernel: %s", specs.Default, kernelName)
t.Logf("Available kernels: %v", specs.Kernelspecs)
})
// Test 3: List sessions
t.Run("List Sessions", func(t *testing.T) {
sessions, err := client.ListSessions()
if err != nil {
t.Fatalf("Failed to list sessions: %v", err)
}
t.Logf("List sessions successful! Number of existing sessions: %d", len(sessions))
for i, s := range sessions {
t.Logf("Session %d: ID=%s, Path=%s, Kernel=%s", i+1, s.ID, s.Path, s.Kernel.Name)
}
})
// Test 4: Create new session
var sessionID string
t.Run("Create Session", func(t *testing.T) {
// Generate unique name for test session
sessionName := fmt.Sprintf("test-session-%d", time.Now().Unix())
sessionPath := "/test-notebook.ipynb"
session, err := client.CreateSession(sessionName, sessionPath, kernelName)
if err != nil {
t.Fatalf("Failed to create session: %v", err)
}
if session.ID == "" {
t.Errorf("Created session has no ID")
}
if session.Kernel.ID == "" {
t.Errorf("Created session has no kernel ID")
}
// Save session ID for subsequent tests
sessionID = session.ID
t.Logf("Create session successful! Session ID: %s, Kernel ID: %s", session.ID, session.Kernel.ID)
})
// Test 5: Get created session
var kernelID string
t.Run("Get Session", func(t *testing.T) {
if sessionID == "" {
t.Skip("No session ID, skipping test")
}
session, err := client.GetSession(sessionID)
if err != nil {
t.Fatalf("Failed to get session: %v", err)
}
if session.ID != sessionID {
t.Errorf("Session ID mismatch, expected '%s', got '%s'", sessionID, session.ID)
}
// Save kernel ID for subsequent tests
kernelID = session.Kernel.ID
t.Logf("Get session successful! Session name: %s, Kernel name: %s", session.Name, session.Kernel.Name)
})
// Test 6: List all kernels
t.Run("List Kernels", func(t *testing.T) {
kernels, err := client.ListKernels()
if err != nil {
t.Fatalf("Failed to list kernels: %v", err)
}
t.Logf("List kernels successful! Number of kernels: %d", len(kernels))
for i, k := range kernels {
t.Logf("Kernel %d: ID=%s, Name=%s, State=%s", i+1, k.ID, k.Name, k.ExecutionState)
}
// Verify that the created kernel is in the list
if kernelID != "" {
found := false
for _, k := range kernels {
if k.ID == kernelID {
found = true
break
}
}
if !found {
t.Errorf("Cannot find created kernel in kernel list ID=%s", kernelID)
}
}
})
// Test 7: Connect to kernel and execute code
t.Run("Execute Code", func(t *testing.T) {
if kernelID == "" {
t.Skip("No kernel ID, skipping test")
}
// Connect to kernel
err := client.ConnectToKernel(kernelID)
if err != nil {
t.Fatalf("Failed to connect to kernel: %v", err)
}
defer client.DisconnectFromKernel()
// Execute simple code
code := "print('Hello, Jupyter!')\nresult = 2 + 2\nresult"
t.Logf("Executing code:\n%s", code)
err = client.ExecuteCodeWithCallback(code, execute.CallbackHandler{})
if err != nil {
t.Fatalf("Failed to execute code: %v", err)
}
})
// Test 7: Connect to kernel and execute code
t.Run("Execute Code", func(t *testing.T) {
if kernelID == "" {
t.Skip("No kernel ID, skipping test")
}
// Connect to kernel
err := client.ConnectToKernel(kernelID)
if err != nil {
t.Fatalf("Failed to connect to kernel: %v", err)
}
defer client.DisconnectFromKernel()
// Execute simple code
code := "print(f'2 + 2 = {result}')\nresult"
t.Logf("Executing code:\n%s", code)
err = client.ExecuteCodeWithCallback(code, execute.CallbackHandler{})
if err != nil {
t.Fatalf("Failed to execute code: %v", err)
}
})
// Test 8: Execute complex code with different types of output
t.Run("Execute Complex Code", func(t *testing.T) {
if kernelID == "" {
t.Skip("No kernel ID, skipping test")
}
// Connect to kernel
err := client.ConnectToKernel(kernelID)
if err != nil {
t.Fatalf("Failed to connect to kernel: %v", err)
}
defer client.DisconnectFromKernel()
// Execute code that generates multiple output types
code := `
# Display table data
import pandas as pd
import numpy as np
try:
df = pd.DataFrame({
'A': np.random.rand(5),
'B': np.random.rand(5)
})
display(df)
print("DataFrame created successfully")
except Exception as e:
print(f"Error creating DataFrame: {e}")
# Generate error
try:
print(undefined_variable)
except Exception as e:
print(f"Expected error: {e}")
# Return dictionary
{'hello': 'world', 'number': 42}
`
t.Logf("Executing complex code...")
err = client.ExecuteCodeWithCallback(code, execute.CallbackHandler{})
if err != nil {
t.Fatalf("Failed to execute complex code: %v", err)
}
})
// Test 9: Restart kernel
t.Run("Restart Kernel", func(t *testing.T) {
if kernelID == "" {
t.Skip("No kernel ID, skipping test")
}
// Restart kernel
restarted, err := client.RestartKernel(kernelID)
if err != nil {
t.Fatalf("Failed to restart kernel: %v", err)
}
// Wait for kernel restart to complete
time.Sleep(2 * time.Second)
// Verify kernel state
kernel, err := client.GetKernel(kernelID)
if err != nil {
t.Fatalf("Failed to get kernel: %v", err)
}
t.Logf("Restart kernel successful! Restart status: %v, Kernel state: %s", restarted, kernel.ExecutionState)
})
// Test 10: Close session
t.Run("Close Session", func(t *testing.T) {
if sessionID == "" {
t.Skip("No session ID, skipping test")
}
// Delete session
err := client.DeleteSession(sessionID)
if err != nil {
t.Fatalf("Failed to delete session: %v", err)
}
// Verify session is deleted
sessions, err := client.ListSessions()
if err != nil {
t.Fatalf("Failed to list sessions: %v", err)
}
for _, s := range sessions {
if s.ID == sessionID {
t.Errorf("Session still exists, not properly deleted ID=%s", sessionID)
break
}
}
t.Logf("Close session successful!")
})
}
// Helper function: Get environment variable, use default value if not exists
func getEnv(key, defaultValue string) string {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value
}