/ tests / go / code_interpreter_e2e_test.go
code_interpreter_e2e_test.go
  1  // Copyright 2026 Alibaba Group Holding Ltd.
  2  //
  3  // Licensed under the Apache License, Version 2.0 (the "License");
  4  // you may not use this file except in compliance with the License.
  5  // You may obtain a copy of the License at
  6  //
  7  //     http://www.apache.org/licenses/LICENSE-2.0
  8  //
  9  // Unless required by applicable law or agreed to in writing, software
 10  // distributed under the License is distributed on an "AS IS" BASIS,
 11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  // See the License for the specific language governing permissions and
 13  // limitations under the License.
 14  
 15  package e2e
 16  
 17  import (
 18  	"context"
 19  	"testing"
 20  	"time"
 21  
 22  	"github.com/alibaba/OpenSandbox/sdks/sandbox/go"
 23  	"github.com/stretchr/testify/require"
 24  )
 25  
 26  func createCodeInterpreter(t *testing.T) (context.Context, *opensandbox.CodeInterpreter) {
 27  	t.Helper()
 28  	config := connectionConfigForStreaming(t)
 29  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
 30  	t.Cleanup(cancel)
 31  
 32  	ci, err := opensandbox.CreateCodeInterpreter(ctx, config, opensandbox.CodeInterpreterCreateOptions{
 33  		Metadata: map[string]string{
 34  			"test": "go-e2e-code-interpreter",
 35  		},
 36  		ReadyTimeout:        60 * time.Second,
 37  		HealthCheckInterval: 500 * time.Millisecond,
 38  	})
 39  	require.NoError(t, err)
 40  	t.Cleanup(func() { ci.Kill(context.Background()) })
 41  	return ctx, ci
 42  }
 43  
 44  func TestCodeInterpreter_CreateAndPing(t *testing.T) {
 45  	ctx, ci := createCodeInterpreter(t)
 46  
 47  	require.True(t, ci.IsHealthy(ctx), "code interpreter should be healthy")
 48  
 49  	metrics, err := ci.GetMetrics(ctx)
 50  	require.NoError(t, err)
 51  	t.Logf("Code interpreter metrics: cpu=%.0f, mem=%.0fMiB", metrics.CPUCount, metrics.MemTotalMB)
 52  }
 53  
 54  func TestCodeInterpreter_PythonExecution(t *testing.T) {
 55  	ctx, ci := createCodeInterpreter(t)
 56  
 57  	exec, err := ci.Execute(ctx, "python", `print("hello from python")`, nil)
 58  	require.NoError(t, err)
 59  
 60  	text := exec.Text()
 61  	require.Contains(t, text, "hello from python")
 62  	t.Logf("Python output: %s", text)
 63  }
 64  
 65  func TestCodeInterpreter_PythonContextPersistence(t *testing.T) {
 66  	ctx, ci := createCodeInterpreter(t)
 67  
 68  	codeCtx, err := ci.CreateContext(ctx, opensandbox.CreateContextRequest{Language: "python"})
 69  	require.NoError(t, err)
 70  	t.Logf("Created context: %s", codeCtx.ID)
 71  
 72  	exec, err := ci.ExecuteInContext(ctx, codeCtx.ID, "python", `x = 42`, nil)
 73  	require.NoError(t, err)
 74  	_ = exec
 75  
 76  	exec, err = ci.ExecuteInContext(ctx, codeCtx.ID, "python", `print(f"x is {x}")`, nil)
 77  	require.NoError(t, err)
 78  
 79  	text := exec.Text()
 80  	require.Contains(t, text, "x is 42")
 81  	t.Logf("Context persistence: %s", text)
 82  
 83  	err = ci.DeleteContext(ctx, codeCtx.ID)
 84  	if err != nil {
 85  		t.Logf("DeleteContext: %v", err)
 86  	}
 87  }
 88  
 89  func TestCodeInterpreter_ContextManagement(t *testing.T) {
 90  	ctx, ci := createCodeInterpreter(t)
 91  
 92  	codeCtx, err := ci.CreateContext(ctx, opensandbox.CreateContextRequest{Language: "python"})
 93  	require.NoError(t, err)
 94  
 95  	contexts, err := ci.ListContexts(ctx, "python")
 96  	require.NoError(t, err)
 97  	require.NotEmpty(t, contexts, "expected at least one context")
 98  	t.Logf("Listed %d python contexts", len(contexts))
 99  
100  	err = ci.DeleteContext(ctx, codeCtx.ID)
101  	require.NoError(t, err)
102  	t.Log("Context management passed")
103  }
104  
105  func TestCodeInterpreter_ContextIsolation(t *testing.T) {
106  	config := connectionConfigForStreaming(t)
107  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
108  	defer cancel()
109  
110  	ci, err := opensandbox.CreateCodeInterpreter(ctx, config, opensandbox.CodeInterpreterCreateOptions{
111  		ReadyTimeout:        60 * time.Second,
112  		HealthCheckInterval: 500 * time.Millisecond,
113  	})
114  	require.NoError(t, err)
115  	defer ci.Kill(context.Background())
116  
117  	ctx1, err := ci.CreateContext(ctx, opensandbox.CreateContextRequest{Language: "python"})
118  	require.NoError(t, err)
119  	ctx2, err := ci.CreateContext(ctx, opensandbox.CreateContextRequest{Language: "python"})
120  	require.NoError(t, err)
121  
122  	ci.ExecuteInContext(ctx, ctx1.ID, "python", `isolated_var = "ctx1_only"`, nil)
123  
124  	exec, err := ci.ExecuteInContext(ctx, ctx2.ID, "python", `print("ISOLATED") if "isolated_var" not in dir() else print(isolated_var)`, nil)
125  	require.NoError(t, err)
126  
127  	text := exec.Text()
128  	require.Contains(t, text, "ISOLATED")
129  	t.Log("Context isolation verified")
130  
131  	ci.DeleteContext(ctx, ctx1.ID)
132  	ci.DeleteContext(ctx, ctx2.ID)
133  }
134  
135  func TestCodeInterpreter_ExecutionWithHandlers(t *testing.T) {
136  	ctx, ci := createCodeInterpreter(t)
137  
138  	var stdoutLines []string
139  	handlers := &opensandbox.ExecutionHandlers{
140  		OnStdout: func(msg opensandbox.OutputMessage) error {
141  			stdoutLines = append(stdoutLines, msg.Text)
142  			return nil
143  		},
144  	}
145  
146  	_, err := ci.Execute(ctx, "python", `
147  for i in range(3):
148      print(f"line {i}")
149  `, handlers)
150  	require.NoError(t, err)
151  
152  	require.NotEmpty(t, stdoutLines, "expected handler to receive stdout")
153  	t.Logf("Handler received %d stdout events", len(stdoutLines))
154  }
155  
156  func TestCodeInterpreter_GetContextAndDeleteByLanguage(t *testing.T) {
157  	ctx, ci := createCodeInterpreter(t)
158  	execd := newExecdClientForSandbox(t, ctx, ci.Sandbox)
159  
160  	codeCtx, err := ci.CreateContext(ctx, opensandbox.CreateContextRequest{Language: "python"})
161  	require.NoError(t, err)
162  
163  	got, err := execd.GetContext(ctx, codeCtx.ID)
164  	require.NoError(t, err)
165  	require.Equal(t, codeCtx.ID, got.ID)
166  
167  	_, err = ci.CreateContext(ctx, opensandbox.CreateContextRequest{Language: "python"})
168  	require.NoError(t, err)
169  
170  	require.NoError(t, execd.DeleteContextsByLanguage(ctx, "python"))
171  
172  	contexts, err := ci.ListContexts(ctx, "python")
173  	require.NoError(t, err)
174  	require.Len(t, contexts, 0)
175  }