Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* @vitest-environment jsdom */
import { render } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import ModelsAndEndpointsView from "./ModelsAndEndpointsView";

// Minimal stubs to avoid Next.js router and network usage during render
vi.mock("@/components/networking", () => ({
credentialListCall: vi.fn().mockResolvedValue({ credentials: [] }),
modelInfoCall: vi.fn().mockResolvedValue({ data: [] }),
modelCostMap: vi.fn().mockResolvedValue({}),
modelMetricsCall: vi.fn().mockResolvedValue({ data: [], all_api_bases: [] }),
streamingModelMetricsCall: vi.fn().mockResolvedValue({ data: [], all_api_bases: [] }),
modelExceptionsCall: vi.fn().mockResolvedValue({ data: [], exception_types: [] }),
modelMetricsSlowResponsesCall: vi.fn().mockResolvedValue([]),
getCallbacksCall: vi.fn().mockResolvedValue({ router_settings: {} }),
setCallbacksCall: vi.fn().mockResolvedValue(undefined),
modelSettingsCall: vi.fn().mockResolvedValue([]),
adminGlobalActivityExceptions: vi.fn().mockResolvedValue({ sum_num_rate_limit_exceptions: 0, daily_data: [] }),
adminGlobalActivityExceptionsPerDeployment: vi.fn().mockResolvedValue([]),
allEndUsersCall: vi.fn().mockResolvedValue([]),
latestHealthChecksCall: vi.fn().mockResolvedValue({ latest_health_checks: {} }),
getPassThroughEndpointsCall: vi.fn().mockResolvedValue({ endpoints: {} }),
getGuardrailsList: vi.fn().mockResolvedValue([]),
tagListCall: vi.fn().mockResolvedValue([]),
modelAvailableCall: vi.fn().mockResolvedValue({ data: [] }),
modelHubCall: vi.fn().mockResolvedValue({ data: [] }),
getModelCostMapReloadStatus: vi.fn().mockResolvedValue({
scheduled: false,
interval_hours: null,
last_run: null,
next_run: null,
}),
}));

vi.mock("@/app/(dashboard)/models-and-endpoints/components/ModelAnalyticsTab/ModelAnalyticsTab", () => ({
default: () => null,
}));

vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({
default: () => ({
token: "123",
accessToken: "123",
userId: "user-1",
userEmail: "[email protected]",
userRole: "Admin",
premiumUser: false,
disabledPersonalKeyCreation: null,
showSSOBanner: false,
}),
}));

vi.mock("@/app/(dashboard)/hooks/useTeams", () => ({
default: () => ({
teams: [],
setTeams: vi.fn(),
}),
}));

describe("ModelsAndEndpointsView", () => {
it("should render the models and endpoints view", () => {
// JSDOM polyfill for libraries expecting ResizeObserver (e.g., recharts)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(global as any).ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
};
const { getByText } = render(
<ModelsAndEndpointsView
accessToken="123"
token="123"
userRole="123"
userID="123"
modelData={{ data: [] }}
keys={[]}
setModelData={() => {}}
premiumUser={false}
teams={[]}
/>,
);
expect(getByText("Model Management")).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,14 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
const setProviderModelsFn = (provider: Providers) => {
const _providerModels = getProviderModels(provider, modelMap);
setProviderModels(_providerModels);
console.log(`providerModels: ${_providerModels}`);
};

const fetchCredentials = async (accessToken: string) => {
try {
const response: CredentialsResponse = await credentialListCall(accessToken);
console.log(`credentials: ${JSON.stringify(response)}`);
setCredentialsList(response.credentials);
} catch (error) {
console.error("Error fetching credentials:", error);
NotificationsManager.fromBackend("Error fetching credentials");
}
};

Expand All @@ -188,9 +186,7 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
reader.onload = (e) => {
if (e.target) {
const jsonStr = e.target.result as string;
console.log(`Resetting vertex_credentials to JSON; jsonStr: ${jsonStr}`);
addModelForm.setFieldsValue({ vertex_credentials: jsonStr });
console.log("Form values right after setting:", addModelForm.getFieldsValue());
}
};
reader.readAsText(file);
Expand All @@ -199,12 +195,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
return false;
},
onChange(info) {
console.log("Upload onChange triggered with values:", info);
console.log("Current form values:", addModelForm.getFieldsValue());

if (info.file.status !== "uploading") {
console.log(info.file, info.fileList);
}
if (info.file.status === "done") {
NotificationsManager.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === "error") {
Expand All @@ -221,7 +211,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({

const handleSaveRetrySettings = async () => {
if (!accessToken) {
console.error("Access token is missing");
return;
}

Expand All @@ -232,14 +221,11 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({

if (selectedModelGroup === "global") {
// Only update global retry policy
console.log("Saving global retry policy:", globalRetryPolicy);
if (globalRetryPolicy) {
payload.router_settings.retry_policy = globalRetryPolicy;
}
NotificationsManager.success("Global retry settings saved successfully");
} else {
// Only update model group retry policy
console.log("Saving model group retry policy for", selectedModelGroup, ":", modelGroupRetryPolicy);
if (modelGroupRetryPolicy) {
payload.router_settings.model_group_retry_policy = modelGroupRetryPolicy;
}
Expand All @@ -248,7 +234,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({

await setCallbacksCall(accessToken, payload);
} catch (error) {
console.error("Failed to save retry settings:", error);
NotificationsManager.fromBackend("Failed to save retry settings");
}
};
Expand All @@ -261,7 +246,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
try {
// Replace with your actual API call for model data
const modelDataResponse = await modelInfoCall(accessToken, userID, userRole);
console.log("Model data response:", modelDataResponse.data);
setModelData(modelDataResponse);
const _providerSettings = await modelSettingsCall(accessToken);
if (_providerSettings) {
Expand All @@ -274,7 +258,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
const model = modelDataResponse.data[i];
all_model_groups.add(model.model_name);
}
console.log("all_model_groups:", all_model_groups);
let _array_model_groups = Array.from(all_model_groups);
// sort _array_model_groups alphabetically
_array_model_groups = _array_model_groups.sort();
Expand All @@ -297,17 +280,11 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({

setAvailableModelAccessGroups(Array.from(all_model_access_groups));

console.log("array_model_groups:", _array_model_groups);
let _initial_model_group = "all";
if (_array_model_groups.length > 0) {
// set selectedModelGroup to the last model group
_initial_model_group = _array_model_groups[_array_model_groups.length - 1];
console.log("_initial_model_group:", _initial_model_group);
//setSelectedModelGroup(_initial_model_group);
}

console.log("selectedModelGroup:", selectedModelGroup);

const modelMetricsResponse = await modelMetricsCall(
accessToken,
userID,
Expand All @@ -319,9 +296,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
selectedCustomer,
);

console.log("Model metrics response:", modelMetricsResponse);
// Sort by latency (avg_latency_per_token)

setModelMetrics(modelMetricsResponse.data);
setModelMetricsCategories(modelMetricsResponse.all_api_bases);

Expand All @@ -346,7 +320,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
selectedAPIKey?.token,
selectedCustomer,
);
console.log("Model exceptions response:", modelExceptionsResponse);
setModelExceptions(modelExceptionsResponse.data);
setAllExceptions(modelExceptionsResponse.exception_types);

Expand Down Expand Up @@ -378,30 +351,15 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
);

setGlobalExceptionPerDeployment(dailyExceptionsPerDeplyment);

console.log("dailyExceptions:", dailyExceptions);

console.log("dailyExceptionsPerDeplyment:", dailyExceptionsPerDeplyment);

console.log("slowResponses:", slowResponses);

setSlowResponsesData(slowResponses);

let all_end_users_data = await allEndUsersCall(accessToken);

setAllEndUsers(all_end_users_data?.map((u: any) => u.user_id));

const routerSettingsInfo = await getCallbacksCall(accessToken, userID, userRole);

let router_settings = routerSettingsInfo.router_settings;

console.log("routerSettingsInfo:", router_settings);
``;
let model_group_retry_policy = router_settings.model_group_retry_policy;
let default_retries = router_settings.num_retries;

console.log("model_group_retry_policy:", model_group_retry_policy);
console.log("default_retries:", default_retries);
setModelGroupRetryPolicy(model_group_retry_policy);
setGlobalRetryPolicy(router_settings.retry_policy);
setDefaultRetry(default_retries);
Expand All @@ -410,7 +368,7 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
const model_group_alias = router_settings.model_group_alias || {};
setModelGroupAlias(model_group_alias);
} catch (error) {
console.error("There was an error fetching the model data", error);
NotificationsManager.fromBackend("Error fetching model data: " + error);
}
};

Expand All @@ -420,7 +378,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({

const fetchModelMap = async () => {
const data = await modelCostMap(accessToken);
console.log(`received model cost map data: ${Object.keys(data)}`);
setModelMap(data);
};
if (modelMap == null) {
Expand Down Expand Up @@ -461,7 +418,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
* - check if model in model map
* - return it's litellm_provider, if so
*/
console.log(`GET PROVIDER CALLED! - ${modelMap}`);
if (modelMap !== null && modelMap !== undefined) {
if (typeof modelMap == "object" && model in modelMap) {
return modelMap[model]["litellm_provider"];
Expand Down Expand Up @@ -522,8 +478,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
modelData.data[i].cleanedLitellmParams = cleanedLitellmParams;

all_models_on_proxy.push(curr_model.model_name);

console.log(modelData.data[i]);
}
// when users click request access show pop up to allow them to request access

Expand Down Expand Up @@ -578,18 +532,12 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
};

const handleOk = () => {
console.log("🚀 handleOk called from model dashboard!");
console.log("Current form values:", addModelForm.getFieldsValue());

addModelForm
.validateFields()
.then((values: any) => {
console.log("✅ Validation passed, submitting:", values);
handleAddModelSubmit(values, accessToken, addModelForm, handleRefreshClick);
})
.catch((error: any) => {
console.error("❌ Validation failed:", error);
console.error("Form errors:", error.errorFields);
const errorMessages =
error.errorFields
?.map((field: any) => {
Expand All @@ -600,8 +548,6 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
});
};

console.log(`selectedProvider: ${selectedProvider}`);
console.log(`providerModels.length: ${providerModels.length}`);
Object.keys(Providers).find((key) => (Providers as { [index: string]: any })[key] === selectedProvider);
// If a team is selected, render TeamInfoView in full page layout
if (selectedTeamId) {
Expand Down
Loading