package resources import ( "encoding/base64" "testing" "github.com/hashicorp/terraform-plugin-framework/types" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) func TestFunctionToUnstructuredAndBack(t *testing.T) { input := functionResourceModel{ Name: types.StringValue("fn-a"), Environment: types.StringValue("env-a"), PackageName: types.StringValue("pkg-a"), Entrypoint: types.StringValue("main.main"), } obj := functionToUnstructured(input, "default") state := unstructuredToFunctionModel(obj, input) if state.Name.ValueString() != "fn-a" { t.Fatalf("unexpected name: %q", state.Name.ValueString()) } if state.Environment.ValueString() != "env-a" { t.Fatalf("unexpected environment: %q", state.Environment.ValueString()) } if state.PackageName.ValueString() != "pkg-a" { t.Fatalf("unexpected package_name: %q", state.PackageName.ValueString()) } if state.Entrypoint.ValueString() != "main.main" { t.Fatalf("unexpected entrypoint: %q", state.Entrypoint.ValueString()) } if state.ExecutorType.ValueString() != "poolmgr" { t.Fatalf("unexpected executor_type: %q", state.ExecutorType.ValueString()) } invoke, found, err := unstructured.NestedMap(obj.Object, "spec", "InvokeStrategy") if err != nil || !found || len(invoke) == 0 { t.Fatalf("InvokeStrategy not set correctly") } } func TestFunctionToUnstructuredWithTimeouts(t *testing.T) { input := functionResourceModel{ Name: types.StringValue("fn-b"), Environment: types.StringValue("env-a"), PackageName: types.StringValue("pkg-a"), Entrypoint: types.StringValue("main.main"), ExecutorType: types.StringValue("newdeploy"), FunctionTimeout: types.Int64Value(120), IdleTimeout: types.Int64Value(60), MinScale: types.Int64Value(1), MaxScale: types.Int64Value(5), } obj := functionToUnstructured(input, "default") state := unstructuredToFunctionModel(obj, input) if state.ExecutorType.ValueString() != "newdeploy" { t.Fatalf("unexpected executor_type: %q", state.ExecutorType.ValueString()) } if state.FunctionTimeout.ValueInt64() != 120 { t.Fatalf("unexpected function_timeout: %d", state.FunctionTimeout.ValueInt64()) } if state.IdleTimeout.ValueInt64() != 60 { t.Fatalf("unexpected idle_timeout: %d", state.IdleTimeout.ValueInt64()) } if state.MinScale.ValueInt64() != 1 { t.Fatalf("unexpected min_scale: %d", state.MinScale.ValueInt64()) } if state.MaxScale.ValueInt64() != 5 { t.Fatalf("unexpected max_scale: %d", state.MaxScale.ValueInt64()) } // Verify executor type in unstructured et, _, _ := unstructured.NestedString(obj.Object, "spec", "InvokeStrategy", "ExecutionStrategy", "ExecutorType") if et != "newdeploy" { t.Fatalf("unexpected ExecutorType in unstructured: %q", et) } } func TestValidateEntrypointAgainstPackageSourcePythonOK(t *testing.T) { source := "def main():\n return 'ok'\n" pkg := &unstructured.Unstructured{Object: map[string]interface{}{ "spec": map[string]interface{}{ "deployment": map[string]interface{}{ "literal": base64.StdEncoding.EncodeToString([]byte(source)), }, }, }} if err := validateEntrypointAgainstPackageSource("main.main", pkg); err != nil { t.Fatalf("expected valid entrypoint, got error: %v", err) } } func TestValidateEntrypointAgainstPackageSourcePythonMissing(t *testing.T) { source := "def another():\n return 'ok'\n" pkg := &unstructured.Unstructured{Object: map[string]interface{}{ "spec": map[string]interface{}{ "deployment": map[string]interface{}{ "literal": base64.StdEncoding.EncodeToString([]byte(source)), }, }, }} if err := validateEntrypointAgainstPackageSource("main.main", pkg); err == nil { t.Fatalf("expected validation error for missing python function") } } func TestValidateEntrypointAgainstPackageSourceBadFormat(t *testing.T) { pkg := &unstructured.Unstructured{} // Пустой entrypoint должен быть ошибкой if err := validateEntrypointAgainstPackageSource("", pkg); err == nil { t.Fatalf("expected validation error for empty entrypoint") } // Одиночное слово допустимо (Ruby, Perl) if err := validateEntrypointAgainstPackageSource("handler", pkg); err != nil { t.Fatalf("unexpected error for single-word entrypoint: %v", err) } }