diff --git a/Makefile b/Makefile index 6e2423eb9..e1a7d4ff3 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,6 @@ all: build test: vet lint staticcheck go test -coverprofile=coverage.txt ./pkg/... ./cmd/... go test ./references/appfile/... ./references/cli/... ./references/common/... ./references/plugins/... - go test -race -covermode=atomic ./references/apiserver/... @$(OK) unit-tests pass # Build vela cli binary diff --git a/go.mod b/go.mod index 0af818d84..3f21f0f59 100644 --- a/go.mod +++ b/go.mod @@ -62,7 +62,6 @@ require ( go.uber.org/zap v1.18.1 golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - google.golang.org/protobuf v1.26.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gotest.tools v2.2.0+incompatible diff --git a/pkg/apiserver/model/catalog.go b/pkg/apiserver/model/catalog.go index 76223608a..171b28d6d 100644 --- a/pkg/apiserver/model/catalog.go +++ b/pkg/apiserver/model/catalog.go @@ -1,6 +1,6 @@ package model -// Catalog defines +// Catalog defines the data model of a Catalog type Catalog struct { Name string `json:"name,omitempty"` Desc string `json:"desc,omitempty"` diff --git a/pkg/apiserver/rest/apis/catalog.go b/pkg/apiserver/rest/apis/catalog.go index 5670d0cd8..bb7b56221 100644 --- a/pkg/apiserver/rest/apis/catalog.go +++ b/pkg/apiserver/rest/apis/catalog.go @@ -22,7 +22,6 @@ import ( // CatalogRequest defines the body of catalog request type CatalogRequest struct { - Method string `json:"method"` Name string `json:"name"` Desc string `json:"desc,omitempty"` UpdateAt int64 `json:"updateAt,omitempty"` diff --git a/pkg/apiserver/rest/rest_server.go b/pkg/apiserver/rest/rest_server.go index c055bcecb..68cdc0236 100644 --- a/pkg/apiserver/rest/rest_server.go +++ b/pkg/apiserver/rest/rest_server.go @@ -21,12 +21,8 @@ import ( "fmt" "net/http" - echo "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/oam-dev/kubevela/pkg/apiserver/log" @@ -52,11 +48,6 @@ type restServer struct { cfg Config } -const ( - // DefaultUINamespace default namespace for configmap info management in velaux system - DefaultUINamespace = "velaux-system" -) - // New create restserver with config data func New(cfg Config) (APIServer, error) { client, err := k8sutil.NewK8sClient() @@ -100,22 +91,6 @@ func (s *restServer) Run(ctx context.Context) error { func (s *restServer) registerServices() error { - // create specific namespace for better resource management - var ns v1.Namespace - if err := s.k8sClient.Get(context.Background(), types.NamespacedName{Name: DefaultUINamespace}, &ns); err != nil && apierrors.IsNotFound(err) { - // not found - ns = v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: DefaultUINamespace, - }, - } - err := s.k8sClient.Create(context.Background(), &ns) - if err != nil { - log.Logger.Errorf("create namespace for velaux system failed %s ", err.Error()) - return err - } - } - // catalog catalogService := services.NewCatalogService(s.k8sClient) s.server.GET("/catalogs", catalogService.ListCatalogs) diff --git a/pkg/apiserver/rest/services/catalog.go b/pkg/apiserver/rest/services/catalog.go index ed688280c..9800e5132 100644 --- a/pkg/apiserver/rest/services/catalog.go +++ b/pkg/apiserver/rest/services/catalog.go @@ -23,7 +23,7 @@ import ( "strconv" "time" - echo "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -93,11 +93,11 @@ func (s *CatalogService) GetCatalog(c echo.Context) error { var cm v1.ConfigMap err := s.k8sClient.Get(context.Background(), client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: catalogName}, &cm) if err != nil { - return c.JSON(http.StatusInternalServerError, fmt.Sprintf("get config for %s failed %s", catalogName, err.Error())) + return c.JSON(http.StatusInternalServerError, fmt.Sprintf("get configMap for %s failed %s", catalogName, err.Error())) } UpdatedInt, err := strconv.ParseInt(cm.Data["UpdatedAt"], 10, 64) if err != nil { - return fmt.Errorf("unable to resolve update parameter in %s:%w ", catalogName, err) + return c.JSON(http.StatusInternalServerError, fmt.Errorf("unable to resolve update parameter in %s: %w ", catalogName, err)) } var catalog = model.Catalog{ Name: catalogName, @@ -128,7 +128,7 @@ func (s *CatalogService) AddCatalog(c echo.Context) error { configdata := map[string]string{ "Name": catalogReq.Name, "Desc": catalogReq.Desc, - "UpdatedAt": time.Now().String(), + "UpdatedAt": fmt.Sprintf("%d", time.Now().UnixNano()), } label := map[string]string{ diff --git a/pkg/apiserver/rest/services/catalog_test.go b/pkg/apiserver/rest/services/catalog_test.go new file mode 100644 index 000000000..5bfc7c8e8 --- /dev/null +++ b/pkg/apiserver/rest/services/catalog_test.go @@ -0,0 +1,64 @@ +package services + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + + "github.com/labstack/echo/v4" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis" +) + +var _ = Describe("Test Catalog Service", func() { + + var catalogService *CatalogService + + BeforeEach(func() { + catalogService = NewCatalogService(k8sClient) + }) + + AfterEach(func() { + }) + + It("should add catalog successfully", func() { + e := echo.New() + cr := &apis.CatalogRequest{ + Name: "test", + } + b, err := json.Marshal(cr) + Expect(err).To(BeNil()) + req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(b)) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + Expect(catalogService.AddCatalog(c)).To(BeNil()) + checkCatalogResponse(rec, cr, http.StatusCreated) + + req = httptest.NewRequest(http.MethodGet, "/", nil) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec = httptest.NewRecorder() + c = e.NewContext(req, rec) + c.SetPath("/catalogs/:catalogName") + c.SetParamNames("catalogName") + c.SetParamValues(cr.Name) + + Expect(catalogService.GetCatalog(c)).To(BeNil()) + checkCatalogResponse(rec, cr, http.StatusOK) + }) +}) + +func checkCatalogResponse(rec *httptest.ResponseRecorder, cr *apis.CatalogRequest, httpcode int) { + Expect(rec.Code).To(Equal(httpcode)) + + get := &apis.CatalogResponse{} + err := json.Unmarshal(rec.Body.Bytes(), get) + Expect(err).To(BeNil()) + + Expect(get.Catalog.Name).To(Equal(cr.Name)) + Expect(get.Catalog.UpdatedAt).NotTo(BeEmpty()) +} diff --git a/pkg/apiserver/rest/services/suite_test.go b/pkg/apiserver/rest/services/suite_test.go new file mode 100644 index 000000000..b774ecc53 --- /dev/null +++ b/pkg/apiserver/rest/services/suite_test.go @@ -0,0 +1,119 @@ +/* +Copyright 2021 The KubeVela Authors. + +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 services + +import ( + "context" + "fmt" + "math/rand" + "os" + "path/filepath" + "strconv" + "testing" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + oamcorealpha "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2" + oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" + oamstandard "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment +var testScheme = runtime.NewScheme() + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "APIServer Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter))) + rand.Seed(time.Now().UnixNano()) + By("bootstrapping test environment") + var yamlPath string + if _, set := os.LookupEnv("COMPATIBILITY_TEST"); set { + yamlPath = "../../../../../test/compatibility-test/testdata" + } else { + yamlPath = filepath.Join("../../../../..", "charts", "vela-core", "crds") + } + logf.Log.Info("start application suit test", "yaml_path", yamlPath) + testEnv = &envtest.Environment{ + ControlPlaneStartTimeout: time.Minute, + ControlPlaneStopTimeout: time.Minute, + UseExistingCluster: pointer.BoolPtr(false), + CRDDirectoryPaths: []string{yamlPath, "./testdata/crds/terraform.core.oam.dev_configurations.yaml"}, + } + + var err error + cfg, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + err = oamcorealpha.SchemeBuilder.AddToScheme(testScheme) + Expect(err).NotTo(HaveOccurred()) + + err = oamstandard.SchemeBuilder.AddToScheme(testScheme) + Expect(err).NotTo(HaveOccurred()) + + err = oamcore.SchemeBuilder.AddToScheme(testScheme) + Expect(err).NotTo(HaveOccurred()) + + err = clientgoscheme.AddToScheme(testScheme) + Expect(err).NotTo(HaveOccurred()) + + crdv1.AddToScheme(testScheme) + + // +kubebuilder:scaffold:scheme + k8sClient, err = client.New(cfg, client.Options{Scheme: testScheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + definitonNs := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}} + Expect(k8sClient.Create(context.Background(), definitonNs.DeepCopy())).Should(BeNil()) + +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) + +// randomNamespaceName generates a random name based on the basic name. +// Running each ginkgo case in a new namespace with a random name can avoid +// waiting a long time to GC namesapce. +func randomNamespaceName(basic string) string { + return fmt.Sprintf("%s-%s", basic, strconv.FormatInt(rand.Int63(), 16)) +}