mirror of https://github.com/portainer/portainer
				
				
				
			
		
			
				
	
	
		
			236 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
package edgestacks
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"net/http/httptest"
 | 
						|
	"reflect"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	portainer "github.com/portainer/portainer/api"
 | 
						|
	"github.com/portainer/portainer/api/roar"
 | 
						|
 | 
						|
	"github.com/segmentio/encoding/json"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
// Update
 | 
						|
func TestUpdateAndInspect(t *testing.T) {
 | 
						|
	handler, rawAPIKey := setupHandler(t)
 | 
						|
 | 
						|
	endpoint := createEndpoint(t, handler.DataStore)
 | 
						|
	edgeStack := createEdgeStack(t, handler.DataStore, endpoint.ID)
 | 
						|
 | 
						|
	// Update edge stack: create new Endpoint, EndpointRelation and EdgeGroup
 | 
						|
	endpointID := portainer.EndpointID(6)
 | 
						|
	newEndpoint := createEndpointWithId(t, handler.DataStore, endpointID)
 | 
						|
 | 
						|
	err := handler.DataStore.Endpoint().Create(&newEndpoint)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	endpointRelation := portainer.EndpointRelation{
 | 
						|
		EndpointID: endpointID,
 | 
						|
		EdgeStacks: map[portainer.EdgeStackID]bool{
 | 
						|
			edgeStack.ID: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	err = handler.DataStore.EndpointRelation().Create(&endpointRelation)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	newEdgeGroup := portainer.EdgeGroup{
 | 
						|
		ID:           2,
 | 
						|
		Name:         "EdgeGroup 2",
 | 
						|
		Dynamic:      false,
 | 
						|
		TagIDs:       nil,
 | 
						|
		EndpointIDs:  roar.FromSlice([]portainer.EndpointID{newEndpoint.ID}),
 | 
						|
		PartialMatch: false,
 | 
						|
	}
 | 
						|
 | 
						|
	err = handler.DataStore.EdgeGroup().Create(&newEdgeGroup)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	payload := updateEdgeStackPayload{
 | 
						|
		StackFileContent: "update-test",
 | 
						|
		UpdateVersion:    true,
 | 
						|
		EdgeGroups:       append(edgeStack.EdgeGroups, newEdgeGroup.ID),
 | 
						|
		DeploymentType:   portainer.EdgeStackDeploymentCompose,
 | 
						|
	}
 | 
						|
 | 
						|
	jsonPayload, err := json.Marshal(payload)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	r := bytes.NewBuffer(jsonPayload)
 | 
						|
	req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("/edge_stacks/%d", edgeStack.ID), r)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	req.Header.Add("x-api-key", rawAPIKey)
 | 
						|
	rec := httptest.NewRecorder()
 | 
						|
	handler.ServeHTTP(rec, req)
 | 
						|
 | 
						|
	if rec.Code != http.StatusOK {
 | 
						|
		t.Fatalf("expected a %d response, found: %d", http.StatusOK, rec.Code)
 | 
						|
	}
 | 
						|
 | 
						|
	// Get updated edge stack
 | 
						|
	req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/edge_stacks/%d", edgeStack.ID), nil)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	req.Header.Add("x-api-key", rawAPIKey)
 | 
						|
	rec = httptest.NewRecorder()
 | 
						|
	handler.ServeHTTP(rec, req)
 | 
						|
 | 
						|
	if rec.Code != http.StatusOK {
 | 
						|
		t.Fatalf("expected a %d response, found: %d", http.StatusOK, rec.Code)
 | 
						|
	}
 | 
						|
 | 
						|
	updatedStack := portainer.EdgeStack{}
 | 
						|
	err = json.NewDecoder(rec.Body).Decode(&updatedStack)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	if payload.UpdateVersion && updatedStack.Version != edgeStack.Version+1 {
 | 
						|
		t.Fatalf("expected EdgeStack version %d, found %d", edgeStack.Version+1, updatedStack.Version+1)
 | 
						|
	}
 | 
						|
 | 
						|
	if updatedStack.DeploymentType != payload.DeploymentType {
 | 
						|
		t.Fatalf("expected DeploymentType %d, found %d", edgeStack.DeploymentType, updatedStack.DeploymentType)
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(updatedStack.EdgeGroups, payload.EdgeGroups) {
 | 
						|
		t.Fatalf("expected EdgeGroups to be equal")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestUpdateWithInvalidEdgeGroups(t *testing.T) {
 | 
						|
	handler, rawAPIKey := setupHandler(t)
 | 
						|
 | 
						|
	endpoint := createEndpoint(t, handler.DataStore)
 | 
						|
	edgeStack := createEdgeStack(t, handler.DataStore, endpoint.ID)
 | 
						|
 | 
						|
	newEdgeGroup := portainer.EdgeGroup{
 | 
						|
		ID:           2,
 | 
						|
		Name:         "EdgeGroup 2",
 | 
						|
		Dynamic:      false,
 | 
						|
		TagIDs:       nil,
 | 
						|
		EndpointIDs:  roar.FromSlice([]portainer.EndpointID{8889}),
 | 
						|
		PartialMatch: false,
 | 
						|
	}
 | 
						|
 | 
						|
	err := handler.DataStore.EdgeGroup().Create(&newEdgeGroup)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	cases := []struct {
 | 
						|
		Name               string
 | 
						|
		Payload            updateEdgeStackPayload
 | 
						|
		ExpectedStatusCode int
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			"Update with non-existing EdgeGroupID",
 | 
						|
			updateEdgeStackPayload{
 | 
						|
				StackFileContent: "error-test",
 | 
						|
				UpdateVersion:    true,
 | 
						|
				EdgeGroups:       []portainer.EdgeGroupID{9999},
 | 
						|
				DeploymentType:   edgeStack.DeploymentType,
 | 
						|
			},
 | 
						|
			http.StatusInternalServerError,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"Update with invalid EdgeGroup (non-existing Endpoint)",
 | 
						|
			updateEdgeStackPayload{
 | 
						|
				StackFileContent: "error-test",
 | 
						|
				UpdateVersion:    true,
 | 
						|
				EdgeGroups:       []portainer.EdgeGroupID{2},
 | 
						|
				DeploymentType:   edgeStack.DeploymentType,
 | 
						|
			},
 | 
						|
			http.StatusInternalServerError,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"Update DeploymentType from Docker to Kubernetes",
 | 
						|
			updateEdgeStackPayload{
 | 
						|
				StackFileContent: "error-test",
 | 
						|
				UpdateVersion:    true,
 | 
						|
				EdgeGroups:       []portainer.EdgeGroupID{1},
 | 
						|
				DeploymentType:   portainer.EdgeStackDeploymentKubernetes,
 | 
						|
			},
 | 
						|
			http.StatusBadRequest,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tc := range cases {
 | 
						|
		t.Run(tc.Name, func(t *testing.T) {
 | 
						|
			jsonPayload, err := json.Marshal(tc.Payload)
 | 
						|
			if err != nil {
 | 
						|
				t.Fatal("JSON marshal error:", err)
 | 
						|
			}
 | 
						|
 | 
						|
			r := bytes.NewBuffer(jsonPayload)
 | 
						|
			req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("/edge_stacks/%d", edgeStack.ID), r)
 | 
						|
			if err != nil {
 | 
						|
				t.Fatal("request error:", err)
 | 
						|
			}
 | 
						|
 | 
						|
			req.Header.Add("x-api-key", rawAPIKey)
 | 
						|
			rec := httptest.NewRecorder()
 | 
						|
			handler.ServeHTTP(rec, req)
 | 
						|
 | 
						|
			if rec.Code != tc.ExpectedStatusCode {
 | 
						|
				t.Fatalf("expected a %d response, found: %d", tc.ExpectedStatusCode, rec.Code)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestUpdateWithInvalidPayload(t *testing.T) {
 | 
						|
	handler, rawAPIKey := setupHandler(t)
 | 
						|
 | 
						|
	endpoint := createEndpoint(t, handler.DataStore)
 | 
						|
	edgeStack := createEdgeStack(t, handler.DataStore, endpoint.ID)
 | 
						|
 | 
						|
	cases := []struct {
 | 
						|
		Name               string
 | 
						|
		Payload            updateEdgeStackPayload
 | 
						|
		ExpectedStatusCode int
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			"Update with empty StackFileContent",
 | 
						|
			updateEdgeStackPayload{
 | 
						|
				StackFileContent: "",
 | 
						|
				UpdateVersion:    true,
 | 
						|
				EdgeGroups:       edgeStack.EdgeGroups,
 | 
						|
				DeploymentType:   edgeStack.DeploymentType,
 | 
						|
			},
 | 
						|
			http.StatusBadRequest,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"Update with empty EdgeGroups",
 | 
						|
			updateEdgeStackPayload{
 | 
						|
				StackFileContent: "error-test",
 | 
						|
				UpdateVersion:    true,
 | 
						|
				EdgeGroups:       []portainer.EdgeGroupID{},
 | 
						|
				DeploymentType:   edgeStack.DeploymentType,
 | 
						|
			},
 | 
						|
			http.StatusBadRequest,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tc := range cases {
 | 
						|
		t.Run(tc.Name, func(t *testing.T) {
 | 
						|
			jsonPayload, err := json.Marshal(tc.Payload)
 | 
						|
			require.NoError(t, err)
 | 
						|
 | 
						|
			r := bytes.NewBuffer(jsonPayload)
 | 
						|
			req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("/edge_stacks/%d", edgeStack.ID), r)
 | 
						|
			require.NoError(t, err)
 | 
						|
 | 
						|
			req.Header.Add("x-api-key", rawAPIKey)
 | 
						|
			rec := httptest.NewRecorder()
 | 
						|
			handler.ServeHTTP(rec, req)
 | 
						|
 | 
						|
			if rec.Code != tc.ExpectedStatusCode {
 | 
						|
				t.Fatalf("expected a %d response, found: %d", tc.ExpectedStatusCode, rec.Code)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |