test: add live acceptance CRUD test and document test flow
This commit is contained in:
@@ -52,6 +52,13 @@ cd terraform/provider
|
|||||||
go test ./...
|
go test ./...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Acceptance-тест (реальный кластер, опционально):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd terraform/provider
|
||||||
|
ACCEPTANCE_TEST=1 KUBECONFIG=/home/naeel/.kube/config go test ./internal/client -run TestAcceptanceFissionCRUD -v
|
||||||
|
```
|
||||||
|
|
||||||
Импорт существующего ресурса (пример):
|
Импорт существующего ресурса (пример):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -128,3 +128,14 @@
|
|||||||
|
|
||||||
### Следующий шаг
|
### Следующий шаг
|
||||||
- Добавить acceptance-тесты с опциональным запуском по env-флагу.
|
- Добавить acceptance-тесты с опциональным запуском по env-флагу.
|
||||||
|
|
||||||
|
### Обновление этапа (acceptance тест)
|
||||||
|
- Добавлен acceptance-тест `terraform/provider/internal/client/client_acceptance_test.go`.
|
||||||
|
- Тест выполняет живой CRUD в кластере для цепочки:
|
||||||
|
- Environment -> Package -> Function -> HTTPTrigger
|
||||||
|
- Запуск теста:
|
||||||
|
- `ACCEPTANCE_TEST=1 KUBECONFIG=/home/naeel/.kube/config go test ./internal/client -run TestAcceptanceFissionCRUD -v`
|
||||||
|
- Результат: PASS.
|
||||||
|
|
||||||
|
### Следующий шаг
|
||||||
|
- Расширить acceptance-тест проверкой реального HTTP-вызова функции через ingress.
|
||||||
|
|||||||
@@ -156,3 +156,19 @@
|
|||||||
- Повторный `terraform apply` успешен.
|
- Повторный `terraform apply` успешен.
|
||||||
- Финальная проверка endpoint:
|
- Финальная проверка endpoint:
|
||||||
- `GET /tf-hello` -> `hello from fission via terraform`.
|
- `GET /tf-hello` -> `hello from fission via terraform`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Агент: GitHub Copilot
|
||||||
|
Модель: GPT-5.3-Codex
|
||||||
|
|
||||||
|
## План (до действий, этап 9)
|
||||||
|
1. Добавить acceptance-тест для реального CRUD через `internal/client`.
|
||||||
|
2. Прогнать unit + acceptance тесты.
|
||||||
|
3. Зафиксировать результат в документации.
|
||||||
|
|
||||||
|
## Результат (после действий, этап 9)
|
||||||
|
- Добавлен `internal/client/client_acceptance_test.go`.
|
||||||
|
- Unit-тесты: PASS.
|
||||||
|
- Acceptance-тест `TestAcceptanceFissionCRUD`: PASS.
|
||||||
|
- Тест создает и удаляет Environment/Package/Function/HTTPTrigger в реальном кластере.
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestAcceptanceFissionCRUD выполняет интеграционный CRUD тест в реальном кластере.
|
||||||
|
func TestAcceptanceFissionCRUD(t *testing.T) {
|
||||||
|
if os.Getenv("ACCEPTANCE_TEST") != "1" {
|
||||||
|
t.Skip("set ACCEPTANCE_TEST=1 to run acceptance tests")
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeconfigPath := os.Getenv("KUBECONFIG")
|
||||||
|
if kubeconfigPath == "" {
|
||||||
|
kubeconfigPath = "/home/naeel/.kube/config"
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace := os.Getenv("FISSION_NAMESPACE")
|
||||||
|
if namespace == "" {
|
||||||
|
namespace = "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := New(kubeconfigPath, os.Getenv("KUBE_CONTEXT"), namespace)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("create client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
suffix := time.Now().UnixNano()
|
||||||
|
envName := fmt.Sprintf("acc-env-%d", suffix)
|
||||||
|
pkgName := fmt.Sprintf("acc-pkg-%d", suffix)
|
||||||
|
fnName := fmt.Sprintf("acc-fn-%d", suffix)
|
||||||
|
triggerName := fmt.Sprintf("acc-tr-%d", suffix)
|
||||||
|
urlPath := fmt.Sprintf("/acc-%d", suffix)
|
||||||
|
|
||||||
|
envObj := &unstructured.Unstructured{Object: map[string]interface{}{
|
||||||
|
"apiVersion": "fission.io/v1",
|
||||||
|
"kind": "Environment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": envName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"version": 3,
|
||||||
|
"runtime": map[string]interface{}{
|
||||||
|
"image": "ghcr.io/fission/python-env",
|
||||||
|
},
|
||||||
|
"poolsize": 1,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
if _, err = c.CreateEnvironment(ctx, envObj); err != nil {
|
||||||
|
t.Fatalf("create environment: %v", err)
|
||||||
|
}
|
||||||
|
defer func() { _ = c.DeleteEnvironment(ctx, namespace, envName) }()
|
||||||
|
|
||||||
|
if _, err = c.GetEnvironment(ctx, namespace, envName); err != nil {
|
||||||
|
t.Fatalf("get environment: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
literal := base64.StdEncoding.EncodeToString([]byte("def main():\n return 'ok from acceptance'\n"))
|
||||||
|
pkgObj := &unstructured.Unstructured{Object: map[string]interface{}{
|
||||||
|
"apiVersion": "fission.io/v1",
|
||||||
|
"kind": "Package",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": pkgName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"deployment": map[string]interface{}{
|
||||||
|
"type": "literal",
|
||||||
|
"literal": literal,
|
||||||
|
},
|
||||||
|
"environment": map[string]interface{}{
|
||||||
|
"name": envName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"source": map[string]interface{}{},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
if _, err = c.CreatePackage(ctx, pkgObj); err != nil {
|
||||||
|
t.Fatalf("create package: %v", err)
|
||||||
|
}
|
||||||
|
defer func() { _ = c.DeletePackage(ctx, namespace, pkgName) }()
|
||||||
|
|
||||||
|
if _, err = c.GetPackage(ctx, namespace, pkgName); err != nil {
|
||||||
|
t.Fatalf("get package: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fnObj := &unstructured.Unstructured{Object: map[string]interface{}{
|
||||||
|
"apiVersion": "fission.io/v1",
|
||||||
|
"kind": "Function",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": fnName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"environment": map[string]interface{}{
|
||||||
|
"name": envName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"InvokeStrategy": map[string]interface{}{
|
||||||
|
"ExecutionStrategy": map[string]interface{}{
|
||||||
|
"ExecutorType": "poolmgr",
|
||||||
|
},
|
||||||
|
"StrategyType": "execution",
|
||||||
|
},
|
||||||
|
"package": map[string]interface{}{
|
||||||
|
"packageref": map[string]interface{}{
|
||||||
|
"name": pkgName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"functionName": "main.main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
if _, err = c.CreateFunction(ctx, fnObj); err != nil {
|
||||||
|
t.Fatalf("create function: %v", err)
|
||||||
|
}
|
||||||
|
defer func() { _ = c.DeleteFunction(ctx, namespace, fnName) }()
|
||||||
|
|
||||||
|
if _, err = c.GetFunction(ctx, namespace, fnName); err != nil {
|
||||||
|
t.Fatalf("get function: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
trObj := &unstructured.Unstructured{Object: map[string]interface{}{
|
||||||
|
"apiVersion": "fission.io/v1",
|
||||||
|
"kind": "HTTPTrigger",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": triggerName,
|
||||||
|
"namespace": namespace,
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"relativeurl": urlPath,
|
||||||
|
"methods": []interface{}{"GET"},
|
||||||
|
"functionref": map[string]interface{}{
|
||||||
|
"type": "name",
|
||||||
|
"name": fnName,
|
||||||
|
},
|
||||||
|
"createingress": false,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
if _, err = c.CreateHTTPTrigger(ctx, trObj); err != nil {
|
||||||
|
t.Fatalf("create http trigger: %v", err)
|
||||||
|
}
|
||||||
|
defer func() { _ = c.DeleteHTTPTrigger(ctx, namespace, triggerName) }()
|
||||||
|
|
||||||
|
if _, err = c.GetHTTPTrigger(ctx, namespace, triggerName); err != nil {
|
||||||
|
t.Fatalf("get http trigger: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gvr := schema.GroupVersionResource{Group: "fission.io", Version: "v1", Resource: "httptriggers"}
|
||||||
|
if err = c.DynClient.Resource(gvr).Namespace(namespace).Delete(ctx, triggerName, metav1.DeleteOptions{}); err != nil {
|
||||||
|
t.Fatalf("delete trigger via dynamic client: %v", err)
|
||||||
|
}
|
||||||
|
if err = c.DeleteHTTPTrigger(ctx, namespace, triggerName); err == nil {
|
||||||
|
t.Fatalf("expected not found error after trigger deletion")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user