e0e362d700
SDK Tests / SDK CI (push) Blocked by required conditions
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
SDK Tests / Python SDK Tests (sandbox) (push) Waiting to run
SDK Tests / CLI Quality (push) Waiting to run
SDK Tests / CLI Tests (push) Waiting to run
SDK Tests / Python SDK Quality (code-interpreter) (push) Waiting to run
SDK Tests / Python SDK Quality (sandbox) (push) Waiting to run
SDK Tests / Python SDK Tests (code-interpreter) (push) Waiting to run
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Waiting to run
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Waiting to run
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Waiting to run
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Waiting to run
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Waiting to run
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Waiting to run
SDK Tests / Go SDK Quality And Tests (push) Waiting to run
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
132 lines
4.0 KiB
Go
132 lines
4.0 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 controller
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/alibaba/opensandbox/execd/pkg/web/model"
|
|
)
|
|
|
|
func setupMetricController(method, path string) (*MetricController, *httptest.ResponseRecorder) {
|
|
ctx, w := newTestContext(method, path, nil)
|
|
ctrl := NewMetricController(ctx)
|
|
return ctrl, w
|
|
}
|
|
|
|
// TestReadMetrics exercises readMetrics end-to-end.
|
|
func TestReadMetrics(t *testing.T) {
|
|
ctrl := &MetricController{}
|
|
|
|
metrics, err := ctrl.readMetrics()
|
|
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, metrics)
|
|
|
|
// Validate CPU count
|
|
assert.Greater(t, metrics.CpuCount, 0.0)
|
|
|
|
// Validate CPU utilization
|
|
assert.GreaterOrEqual(t, metrics.CpuUsedPct, 0.0)
|
|
assert.Less(t, metrics.CpuUsedPct, 100.1) // CPU usage should be under 100% with small float tolerance
|
|
|
|
// Validate memory information
|
|
assert.Greater(t, metrics.MemTotalMiB, 0.0)
|
|
assert.GreaterOrEqual(t, metrics.MemUsedMiB, 0.0)
|
|
assert.LessOrEqual(t, metrics.MemUsedMiB, metrics.MemTotalMiB) // Used memory should not exceed total
|
|
|
|
// Validate timestamps
|
|
currentTime := time.Now().UnixMilli()
|
|
oneMinuteAgo := currentTime - 60*1000
|
|
assert.GreaterOrEqual(t, metrics.Timestamp, oneMinuteAgo) // Should be within the last minute
|
|
assert.LessOrEqual(t, metrics.Timestamp, currentTime) // Should not be in the future
|
|
}
|
|
|
|
// TestGetMetricsEndpoint covers the happy path.
|
|
func TestGetMetricsEndpoint(t *testing.T) {
|
|
ctrl, w := setupMetricController("GET", "/api/metrics")
|
|
|
|
ctrl.GetMetrics()
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var metrics model.Metrics
|
|
err := json.Unmarshal(w.Body.Bytes(), &metrics)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Greater(t, metrics.CpuCount, 0.0)
|
|
assert.GreaterOrEqual(t, metrics.CpuUsedPct, 0.0)
|
|
assert.Greater(t, metrics.MemTotalMiB, 0.0)
|
|
assert.GreaterOrEqual(t, metrics.MemUsedMiB, 0.0)
|
|
assert.NotZero(t, metrics.Timestamp)
|
|
}
|
|
|
|
// TestWatchMetricsHeaders verifies SSE header defaults.
|
|
func TestWatchMetricsHeaders(t *testing.T) {
|
|
ctrl, w := setupMetricController("GET", "/api/watch-metrics")
|
|
|
|
ctrl.setupSSEResponse()
|
|
|
|
contentType := w.Header().Get("Content-Type")
|
|
assert.Equal(t, "text/event-stream", contentType)
|
|
|
|
cacheControl := w.Header().Get("Cache-Control")
|
|
assert.Equal(t, "no-cache", cacheControl)
|
|
|
|
connection := w.Header().Get("Connection")
|
|
assert.Equal(t, "keep-alive", connection)
|
|
|
|
buffering := w.Header().Get("X-Accel-Buffering")
|
|
assert.Equal(t, "no", buffering)
|
|
}
|
|
|
|
// TestMetricSerialization ensures metrics marshal and unmarshal cleanly.
|
|
func TestMetricSerialization(t *testing.T) {
|
|
metrics := &model.Metrics{
|
|
CpuCount: 4,
|
|
CpuUsedPct: 25.5,
|
|
MemTotalMiB: 8192,
|
|
MemUsedMiB: 4096,
|
|
Timestamp: time.Now().UnixMilli(),
|
|
}
|
|
|
|
data, err := json.Marshal(metrics)
|
|
assert.NoError(t, err)
|
|
|
|
var decodedMetrics model.Metrics
|
|
err = json.Unmarshal(data, &decodedMetrics)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, metrics.CpuCount, decodedMetrics.CpuCount)
|
|
assert.Equal(t, metrics.CpuUsedPct, decodedMetrics.CpuUsedPct)
|
|
assert.Equal(t, metrics.MemTotalMiB, decodedMetrics.MemTotalMiB)
|
|
assert.Equal(t, metrics.MemUsedMiB, decodedMetrics.MemUsedMiB)
|
|
assert.Equal(t, metrics.Timestamp, decodedMetrics.Timestamp)
|
|
|
|
errorMsg := map[string]string{"error": "test error"}
|
|
errorData, err := json.Marshal(errorMsg)
|
|
assert.NoError(t, err)
|
|
|
|
var decodedError map[string]string
|
|
err = json.Unmarshal(errorData, &decodedError)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "test error", decodedError["error"])
|
|
}
|