Feat: add get and delete method for app and test (#2127)

This commit is contained in:
wangyuan249
2021-08-20 20:41:19 +08:00
committed by GitHub
parent af04ca37a5
commit 8a334d7e82
4 changed files with 211 additions and 13 deletions
+8
View File
@@ -27,3 +27,11 @@ type ApplicationRequest struct {
Policies []v1beta1.AppPolicy `json:"policies,omitempty"`
Workflow *v1beta1.Workflow `json:"workflow,omitempty"`
}
// ApplicationResponse represents application response for APIServer
type ApplicationResponse struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Spec v1beta1.ApplicationSpec `json:"spec"`
Status common.AppStatus `json:"status"`
}
+2
View File
@@ -106,7 +106,9 @@ func (s *restServer) registerServices() error {
// application
applicationService := services.NewApplicationService(s.k8sClient)
openapi.GET("/namespaces/:namespace/applications/:appname", applicationService.GetApplication)
openapi.POST("/namespaces/:namespace/applications/:appname", applicationService.CreateOrUpdateApplication)
openapi.DELETE("/namespaces/:namespace/applications/:appname", applicationService.DeleteApplication)
return nil
}
+47 -1
View File
@@ -40,8 +40,34 @@ func NewApplicationService(kc client.Client) *ApplicationService {
}
}
// GetApplication will get application status
// GET /namespaces/<namespace>/applications/<appname>
func (s *ApplicationService) GetApplication(c echo.Context) error {
namespace := c.Param("namespace")
appName := c.Param("appname")
ctx := context.TODO()
var existApp v1beta1.Application
err := s.k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appName}, &existApp)
if err != nil {
if apierrors.IsNotFound(err) {
return c.JSON(http.StatusNotFound, map[string]string{"error": "application does not exist: " + err.Error()})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to get application: " + err.Error()})
}
var appResp = &apis.ApplicationResponse{
APIVersion: existApp.APIVersion,
Kind: existApp.Kind,
Spec: existApp.Spec,
Status: existApp.Status,
}
return c.JSON(http.StatusOK, appResp)
}
// CreateOrUpdateApplication will create or update application
// POST /v1/namespaces/<namespace>/applications/<appname>
// POST /namespaces/<namespace>/applications/<appname>
func (s *ApplicationService) CreateOrUpdateApplication(c echo.Context) error {
namespace := c.Param("namespace")
name := c.Param("appname")
@@ -74,3 +100,23 @@ func (s *ApplicationService) CreateOrUpdateApplication(c echo.Context) error {
}
return c.JSON(http.StatusOK, struct{}{})
}
// DeleteApplication will delete application
// delete /v1/namespaces/<namespace>/applications/<appname>
func (s *ApplicationService) DeleteApplication(c echo.Context) error {
namespace := c.Param("namespace")
appName := c.Param("appname")
ctx := context.TODO()
var existApp v1beta1.Application
existApp.Namespace = namespace
existApp.Name = appName
err := s.k8sClient.Delete(ctx, &existApp)
if err != nil {
if apierrors.IsNotFound(err) {
return c.JSON(http.StatusNotFound, map[string]string{"error": "application does not exist: " + err.Error()})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to delete application: " + err.Error()})
}
return c.JSON(http.StatusOK, struct{}{})
}
+154 -12
View File
@@ -27,6 +27,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -112,19 +113,160 @@ func TestApplicationCreateOrUpdate(t *testing.T) {
// check response
assert.Equal(t, c.expHttpCode, rec.Code, casename)
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
if c.expErr != "" {
if c.expErr != "" { // compare return error with map type
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
assert.True(t, strings.Contains(gotResp["error"], c.expErr), casename)
} else { // check app spec in fake cluster
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.NoError(t, err, casename)
assert.Equal(t, c.expApp.Spec, appObj.Spec, casename)
}
if len(c.expErr) > 0 {
continue
}
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.NoError(t, err, casename)
assert.Equal(t, c.expApp.Spec, appObj.Spec, casename)
}
}
func TestApplicationGet(t *testing.T) {
cw := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
appSvc := NewApplicationService(cw)
tests := map[string]struct {
rawReq []byte
name string
namespace string
expHttpCode int
expErr string
expApp *v1beta1.Application
}{
"normal get method for application": {
expHttpCode: 200,
name: "commonName",
namespace: "commonNamespace",
},
"get app failed with resource not found": {
expHttpCode: 404,
name: "notExistName",
namespace: "commonNamespace",
expErr: "application does not exist",
},
}
// create an application for get
createAppForTest(t, appSvc)
for casename, c := range tests {
var err error
req := httptest.NewRequest(http.MethodGet, "/", bytes.NewBuffer(c.rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues(c.namespace, c.name)
err = appSvc.GetApplication(echoCtx)
assert.NoError(t, err, casename)
// check response
assert.Equal(t, c.expHttpCode, rec.Code, casename)
if c.expErr != "" { // compare return error with map type
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
assert.True(t, strings.Contains(gotResp["error"], c.expErr), casename)
} else { // check app spec in fake cluster
var gotResp apis.ApplicationResponse
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.NoError(t, err, casename)
assert.Equal(t, gotResp.APIVersion, appObj.APIVersion, casename)
assert.Equal(t, gotResp.Kind, appObj.Kind, casename)
assert.Equal(t, gotResp.Spec, appObj.Spec, casename)
assert.Equal(t, gotResp.Status, appObj.Status, casename)
}
}
}
func TestApplicationDelete(t *testing.T) {
cw := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
appSvc := NewApplicationService(cw)
tests := map[string]struct {
rawReq []byte
name string
namespace string
expHttpCode int
expErr string
}{
"normal delete method for application": {
expHttpCode: 200,
name: "commonName",
namespace: "commonNamespace",
},
"delete app failed with resource not found": {
expHttpCode: 404,
name: "notExistName",
namespace: "commonNamespace",
expErr: "application does not exist",
},
}
for casename, c := range tests {
// create common app
createAppForTest(t, appSvc)
var err error
req := httptest.NewRequest(http.MethodDelete, "/", bytes.NewBuffer(c.rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues(c.namespace, c.name)
err = appSvc.DeleteApplication(echoCtx)
assert.NoError(t, err, casename)
// check response
assert.Equal(t, c.expHttpCode, rec.Code, casename)
if c.expErr != "" {
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
assert.True(t, strings.Contains(gotResp["error"], c.expErr), casename)
} else {
// checkout app status in fake cluster
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.Equal(t, apierrors.IsNotFound(err), true)
}
}
}
func createAppForTest(t *testing.T, appSvc *ApplicationService) {
appComp := common2.ApplicationComponent{
Name: "mycomp",
Type: "webservice",
Properties: runtime.RawExtension{Raw: []byte(`{"image":"nginx:v1"}`)},
}
var appReq = &apis.ApplicationRequest{
Components: []common2.ApplicationComponent{appComp},
}
var rawReq []byte
var err error
if appReq != nil {
rawReq, err = json.Marshal(appReq)
assert.NoError(t, err, "marshal request for create app")
}
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues("commonNamespace", "commonName")
err = appSvc.CreateOrUpdateApplication(echoCtx)
assert.NoError(t, err, "craete application in service")
}