Repository: datreeio/datree
Pull request #32 (2021-05-11 15:24:31)

fix: add infrastructure for multiple validation steps


Patch:
diff --git a/.gitignore b/.gitignore
index f68e458..cac91df 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ vendor
 datree
 .DS_STORE
 .vscode
+.idea
diff --git a/bl/evaluator.go b/bl/evaluator.go
index caa8aa2..f66fea6 100644
--- a/bl/evaluator.go
+++ b/bl/evaluator.go
@@ -18,6 +18,7 @@ type Printer interface {
 }
 type CLIClient interface {
 	RequestEvaluation(cliClient.EvaluationRequest) (cliClient.EvaluationResponse, error)
+	CreateEvaluation(request cliClient.CreateEvaluationRequest) (int, error)
 }
 
 type PropertiesExtractor interface {
@@ -71,7 +72,7 @@ func (e *Evaluator) Evaluate(paths []string, cliId string, evaluationConc int, c
 		filesProperties = append(filesProperties, *file)
 	}
 
-	evaluationRequest := cliClient.EvaluationRequest{
+	createEvaluationRequest := cliClient.CreateEvaluationRequest{
 		CliId: cliId,
 		Metadata: cliClient.Metadata{
 			CliVersion:      cliVersion,
@@ -79,6 +80,16 @@ func (e *Evaluator) Evaluate(paths []string, cliId string, evaluationConc int, c
 			PlatformVersion: e.osInfo.PlatformVersion,
 			KernelVersion:   e.osInfo.KernelVersion,
 		},
+	}
+
+	evaluationId, err := e.cliClient.CreateEvaluation(createEvaluationRequest)
+	if err != nil {
+		return nil, fileErrors, err
+	}
+
+
+	evaluationRequest := cliClient.EvaluationRequest{
+		EvaluationId: evaluationId,
 		Files: filesProperties,
 	}
 
diff --git a/pkg/cliClient/cliClient.go b/pkg/cliClient/cliClient.go
index 7937b94..a58b386 100644
--- a/pkg/cliClient/cliClient.go
+++ b/pkg/cliClient/cliClient.go
@@ -46,9 +46,8 @@ type Metadata struct {
 }
 
 type EvaluationRequest struct {
-	CliId    string                     `json:"cliId"`
-	Metadata Metadata                   `json:"metadata"`
-	Files    []extractor.FileProperties `json:"files"`
+	EvaluationId int                        `json:"evaluationId"`
+	Files        []extractor.FileProperties `json:"files"`
 }
 
 type Match struct {
@@ -72,9 +71,38 @@ type EvaluationResult struct {
 }
 
 type EvaluationResponse struct {
-	EvaluationId int                `json:"evaluationId"`
-	Results      []EvaluationResult `json:"results"`
-	Status       string             `json:"status"`
+	Results []EvaluationResult `json:"results"`
+	Status  string             `json:"status"`
+}
+
+type CreateEvaluationRequest struct {
+	CliId    string   `json:"cliId"`
+	Metadata Metadata `json:"metadata"`
+}
+
+type CreateEvaluationResponse struct {
+	EvaluationId int `json:"evaluationId"`
+}
+
+func (c *CliClient) CreateEvaluation(request CreateEvaluationRequest) (int, error) {
+	res, err := c.httpClient.Request(http.MethodPost, "/cli/evaluate/create", request, nil)
+	if err != nil {
+		return 0, err
+	}
+
+	var createEvaluationResponse = &CreateEvaluationResponse{}
+	err = json.Unmarshal(res.Body, &createEvaluationResponse)
+	if err != nil {
+		return 0, err
+	}
+
+	return createEvaluationResponse.EvaluationId, nil
+}
+
+type VersionMessage struct {
+	CliVersion   string `json:"cliVersion"`
+	MessageText  string `json:"messageText"`
+	MessageColor string `json:"messageColor"`
 }
 
 func (c *CliClient) RequestEvaluation(request EvaluationRequest) (EvaluationResponse, error) {
@@ -92,12 +120,6 @@ func (c *CliClient) RequestEvaluation(request EvaluationRequest) (EvaluationResp
 	return *evaluationResponse, nil
 }
 
-type VersionMessage struct {
-	CliVersion   string `json:"cliVersion"`
-	MessageText  string `json:"messageText"`
-	MessageColor string `json:"messageColor"`
-}
-
 func (c VersionMessageClient) GetVersionMessage(cliVersion string) (*VersionMessage, error) {
 	res, err := c.httpClient.Request(http.MethodGet, "/cli/messages/versions/"+cliVersion, nil, nil)
 	if err != nil {


Test patch:
diff --git a/bl/evaluator_test.go b/bl/evaluator_test.go
index 41cf491..49344a9 100644
--- a/bl/evaluator_test.go
+++ b/bl/evaluator_test.go
@@ -24,6 +24,11 @@ type mockCliClient struct {
 	mock.Mock
 }
 
+func (m *mockCliClient) CreateEvaluation(createEvaluationRequest cliClient.CreateEvaluationRequest) (int, error) {
+	args := m.Called(createEvaluationRequest)
+	return args.Get(0).(int), args.Error(1)
+}
+
 func (m *mockCliClient) RequestEvaluation(evaluationRequest cliClient.EvaluationRequest) (cliClient.EvaluationResponse, error) {
 	args := m.Called(evaluationRequest)
 	return args.Get(0).(cliClient.EvaluationResponse), args.Error(1)
@@ -50,6 +55,10 @@ type propertiesExtractorMockTestCase struct {
 }
 
 type cliClientMockTestCase struct {
+	createEvaluation struct {
+		EvaluationId int
+		errors       error
+	}
 	requestEvaluation struct {
 		response cliClient.EvaluationResponse
 		errors   error
@@ -59,10 +68,11 @@ type cliClientMockTestCase struct {
 type evaluateTestCase struct {
 	name string
 	args struct {
-		paths             []string
-		cliId             string
-		evaluationConc    int
-		evaluationRequest cliClient.EvaluationRequest
+		paths                   []string
+		cliId                   string
+		evaluationConc          int
+		evaluationRequest       cliClient.EvaluationRequest
+		createEvaluationRequest cliClient.CreateEvaluationRequest
 	}
 	mock struct {
 		propertiesExtractor propertiesExtractorMockTestCase
@@ -77,8 +87,9 @@ type evaluateTestCase struct {
 
 func TestEvaluate(t *testing.T) {
 	tests := []*evaluateTestCase{
-		test_evaluate_failedRequest(),
-		test_evaluate_success(),
+		test_create_evaluation_failedRequest(),
+		//test_evaluate_failedRequest(),
+		//test_evaluate_success(),
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -88,6 +99,7 @@ func TestEvaluate(t *testing.T) {
 
 			propertiesExtractor.On("ReadFilesFromPaths", mock.Anything, mock.Anything).Return(tt.mock.propertiesExtractor.readFilesFromPaths.properties, tt.mock.propertiesExtractor.readFilesFromPaths.filesErrors, tt.mock.propertiesExtractor.readFilesFromPaths.errors)
 			cliClient.On("RequestEvaluation", mock.Anything).Return(tt.mock.cliClient.requestEvaluation.response, tt.mock.cliClient.requestEvaluation.errors)
+			cliClient.On("CreateEvaluation", mock.Anything).Return(tt.mock.cliClient.createEvaluation.EvaluationId, tt.mock.cliClient.createEvaluation.errors)
 
 			evaluator := &Evaluator{
 				propertiesExtractor: propertiesExtractor,
@@ -103,7 +115,10 @@ func TestEvaluate(t *testing.T) {
 			actualResponse, actualFilesErrs, actualErr := evaluator.Evaluate(tt.args.paths, tt.args.cliId, tt.args.evaluationConc, "0.0.1")
 
 			propertiesExtractor.AssertCalled(t, "ReadFilesFromPaths", tt.args.paths, tt.args.evaluationConc)
-			cliClient.AssertCalled(t, "RequestEvaluation", tt.args.evaluationRequest)
+			cliClient.AssertCalled(t, "CreateEvaluation", tt.args.createEvaluationRequest)
+			if tt.mock.cliClient.createEvaluation.errors == nil {
+				cliClient.AssertCalled(t, "RequestEvaluation", tt.args.evaluationRequest)
+			}
 
 			assert.Equal(t, tt.expected.response, actualResponse)
 			assert.Equal(t, tt.expected.fileErrors, actualFilesErrs)
@@ -114,7 +129,6 @@ func TestEvaluate(t *testing.T) {
 
 func test_evaluate_success() *evaluateTestCase {
 	evaluationResponse := cliClient.EvaluationResponse{
-		EvaluationId: 1,
 		Results: []cliClient.EvaluationResult{
 			{
 				Passed: true,
@@ -128,18 +142,29 @@ func test_evaluate_success() *evaluateTestCase {
 			},
 		},
 	}
+	createEvaluationResponse := cliClient.CreateEvaluationResponse{
+		EvaluationId: 432,
+	}
 	return &evaluateTestCase{
 		name: "success",
 		args: struct {
-			paths             []string
-			cliId             string
-			evaluationConc    int
-			evaluationRequest cliClient.EvaluationRequest
+			paths                   []string
+			cliId                   string
+			evaluationConc          int
+			evaluationRequest       cliClient.EvaluationRequest
+			createEvaluationRequest cliClient.CreateEvaluationRequest
 		}{
 			paths:          []string{"path1/path2/file.yaml"},
 			cliId:          "cliId-test",
 			evaluationConc: 1,
 			evaluationRequest: cliClient.EvaluationRequest{
+				EvaluationId: createEvaluationResponse.EvaluationId,
+				Files: []propertiesExtractor.FileProperties{{
+					FileName:       "path1/path2/file.yaml",
+					Configurations: []propertiesExtractor.K8sConfiguration{{"apiVersion": "extensions/v1beta1"}},
+				}},
+			},
+			createEvaluationRequest: cliClient.CreateEvaluationRequest{
 				CliId: "cliId-test",
 				Metadata: cliClient.Metadata{
 					CliVersion:      "0.0.1",
@@ -147,11 +172,8 @@ func test_evaluate_success() *evaluateTestCase {
 					PlatformVersion: "1.2.3",
 					KernelVersion:   "4.5.6",
 				},
-				Files: []propertiesExtractor.FileProperties{{
-					FileName:       "path1/path2/file.yaml",
-					Configurations: []propertiesExtractor.K8sConfiguration{{"apiVersion": "extensions/v1beta1"}},
-				}},
-			}},
+			},
+		},
 		mock: struct {
 			propertiesExtractor propertiesExtractorMockTestCase
 			cliClient           cliClientMockTestCase
@@ -178,6 +200,12 @@ func test_evaluate_success() *evaluateTestCase {
 					response: evaluationResponse,
 					errors:   nil,
 				},
+				createEvaluation: struct {
+					EvaluationId int
+					errors       error
+				}{
+					EvaluationId: createEvaluationResponse.EvaluationId,
+				},
 			},
 		},
 		expected: struct {
@@ -199,19 +227,30 @@ func test_evaluate_success() *evaluateTestCase {
 }
 
 func test_evaluate_failedRequest() *evaluateTestCase {
+	createEvaluationResponse := cliClient.CreateEvaluationResponse{
+		EvaluationId: 432,
+	}
 	evaluationResponse := cliClient.EvaluationResponse{}
 	return &evaluateTestCase{
 		name: "fail",
 		args: struct {
-			paths             []string
-			cliId             string
-			evaluationConc    int
-			evaluationRequest cliClient.EvaluationRequest
+			paths                   []string
+			cliId                   string
+			evaluationConc          int
+			evaluationRequest       cliClient.EvaluationRequest
+			createEvaluationRequest cliClient.CreateEvaluationRequest
 		}{
 			paths:          []string{"path1/path2/file.yaml"},
 			cliId:          "cliId-test",
 			evaluationConc: 1,
 			evaluationRequest: cliClient.EvaluationRequest{
+				EvaluationId: createEvaluationResponse.EvaluationId,
+				Files: []propertiesExtractor.FileProperties{{
+					FileName:       "path1/path2/file.yaml",
+					Configurations: []propertiesExtractor.K8sConfiguration{{"apiVersion": "extensions/v1beta1"}},
+				}},
+			},
+			createEvaluationRequest: cliClient.CreateEvaluationRequest{
 				CliId: "cliId-test",
 				Metadata: cliClient.Metadata{
 					CliVersion:      "0.0.1",
@@ -219,11 +258,86 @@ func test_evaluate_failedRequest() *evaluateTestCase {
 					PlatformVersion: "1.2.3",
 					KernelVersion:   "4.5.6",
 				},
+			},
+		},
+		mock: struct {
+			propertiesExtractor propertiesExtractorMockTestCase
+			cliClient           cliClientMockTestCase
+		}{
+			propertiesExtractor: propertiesExtractorMockTestCase{
+				readFilesFromPaths: struct {
+					properties  []*propertiesExtractor.FileProperties
+					filesErrors []propertiesExtractor.FileError
+					errors      []error
+				}{
+					properties: []*propertiesExtractor.FileProperties{{
+						FileName:       "path1/path2/file.yaml",
+						Configurations: []propertiesExtractor.K8sConfiguration{{"apiVersion": "extensions/v1beta1"}}}},
+					filesErrors: []propertiesExtractor.FileError{},
+					errors:      []error{},
+				},
+			},
+			cliClient: cliClientMockTestCase{
+				requestEvaluation: struct {
+					response cliClient.EvaluationResponse
+					errors   error
+				}{
+					response: evaluationResponse,
+					errors:   fmt.Errorf("error"),
+				},
+				createEvaluation: struct {
+					EvaluationId int
+					errors       error
+				}{
+					EvaluationId: createEvaluationResponse.EvaluationId,
+					errors:       nil,
+				},
+			},
+		},
+		expected: struct {
+			response   *EvaluationResults
+			fileErrors []propertiesExtractor.FileError
+			err        error
+		}{
+			response:   nil,
+			fileErrors: []propertiesExtractor.FileError{},
+			err:        fmt.Errorf("error"),
+		},
+	}
+}
+
+func test_create_evaluation_failedRequest() *evaluateTestCase {
+	createEvaluationResponse := cliClient.CreateEvaluationResponse{}
+	evaluationResponse := cliClient.EvaluationResponse{}
+	return &evaluateTestCase{
+		name: "fail",
+		args: struct {
+			paths                   []string
+			cliId                   string
+			evaluationConc          int
+			evaluationRequest       cliClient.EvaluationRequest
+			createEvaluationRequest cliClient.CreateEvaluationRequest
+		}{
+			paths:          []string{"path1/path2/file.yaml"},
+			cliId:          "cliId-test",
+			evaluationConc: 1,
+			evaluationRequest: cliClient.EvaluationRequest{
+				EvaluationId: createEvaluationResponse.EvaluationId,
 				Files: []propertiesExtractor.FileProperties{{
 					FileName:       "path1/path2/file.yaml",
 					Configurations: []propertiesExtractor.K8sConfiguration{{"apiVersion": "extensions/v1beta1"}},
 				}},
-			}},
+			},
+			createEvaluationRequest: cliClient.CreateEvaluationRequest{
+				CliId: "cliId-test",
+				Metadata: cliClient.Metadata{
+					CliVersion:      "0.0.1",
+					Os:              "darwin",
+					PlatformVersion: "1.2.3",
+					KernelVersion:   "4.5.6",
+				},
+			},
+		},
 		mock: struct {
 			propertiesExtractor propertiesExtractorMockTestCase
 			cliClient           cliClientMockTestCase
@@ -249,6 +363,12 @@ func test_evaluate_failedRequest() *evaluateTestCase {
 					response: evaluationResponse,
 					errors:   fmt.Errorf("error"),
 				},
+				createEvaluation: struct {
+					EvaluationId int
+					errors       error
+				}{
+					errors: fmt.Errorf("create evaluation error"),
+				},
 			},
 		},
 		expected: struct {
@@ -258,7 +378,7 @@ func test_evaluate_failedRequest() *evaluateTestCase {
 		}{
 			response:   nil,
 			fileErrors: []propertiesExtractor.FileError{},
-			err:        fmt.Errorf("error"),
+			err:        fmt.Errorf("create evaluation error"),
 		},
 	}
 }
diff --git a/pkg/cliClient/cliClient_test.go b/pkg/cliClient/cliClient_test.go
index 451e100..0d72db7 100644
--- a/pkg/cliClient/cliClient_test.go
+++ b/pkg/cliClient/cliClient_test.go
@@ -45,6 +45,28 @@ type RequestEvaluationTestCase struct {
 	}
 }
 
+type CreateEvaluationTestCase struct {
+	name string
+	args struct {
+		createEvaluationRequest *CreateEvaluationRequest
+	}
+	mock struct {
+		response struct {
+			status int
+			body   *CreateEvaluationResponse
+		}
+	}
+	expected struct {
+		request struct {
+			method  string
+			uri     string
+			body    *CreateEvaluationRequest
+			headers map[string]string
+		}
+		response *CreateEvaluationResponse
+	}
+}
+
 type GetVersionMessageTestCase struct {
 	name string
 	args struct {
@@ -94,6 +116,33 @@ func TestRequestEvaluation(t *testing.T) {
 	}
 }
 
+func TestCreateRequestEvaluation(t *testing.T) {
+	tests := []*CreateEvaluationTestCase{
+		test_createEvaluation_success(),
+	}
+
+	httpClientMock := mockHTTPClient{}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			body, _ := json.Marshal(tt.mock.response.body)
+			mockedHTTPResponse := httpClient.Response{StatusCode: tt.mock.response.status, Body: body}
+			httpClientMock.On("Request", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockedHTTPResponse, nil)
+
+			client := &CliClient{
+				baseUrl:    "http://cli-service.test.io",
+				httpClient: &httpClientMock,
+			}
+
+			actualEvaluationId, _ := client.CreateEvaluation(*tt.args.createEvaluationRequest)
+
+			httpClientMock.AssertCalled(t, "Request", tt.expected.request.method, tt.expected.request.uri, *tt.expected.request.body, tt.expected.request.headers)
+			assert.Equal(t, tt.expected.response.EvaluationId, actualEvaluationId)
+
+		})
+	}
+}
+
 func TestGetVersionMessage(t *testing.T) {
 	tests := []*GetVersionMessageTestCase{
 		test_getVersionMessage_success(),
@@ -204,6 +253,7 @@ func test_getVersionMessage_success() *GetVersionMessageTestCase {
 		},
 	}
 }
+
 func test_requestEvaluation_success() *RequestEvaluationTestCase {
 	return &RequestEvaluationTestCase{
 		name: "success - request evaluation",
@@ -211,14 +261,8 @@ func test_requestEvaluation_success() *RequestEvaluationTestCase {
 			evaluationRequest *EvaluationRequest
 		}{
 			evaluationRequest: &EvaluationRequest{
-				CliId: "cli-id-test",
-				Files: castPropertiesMock("service_mock", "mocks/service_mock.yaml"),
-				Metadata: Metadata{
-					CliVersion:      "0.0.1",
-					Os:              "darwin",
-					PlatformVersion: "1.2.3",
-					KernelVersion:   "4.5.6",
-				},
+				EvaluationId: 321,
+				Files:        castPropertiesMock("service_mock", "mocks/service_mock.yaml"),
 			},
 		},
 		mock: struct {
@@ -253,8 +297,67 @@ func test_requestEvaluation_success() *RequestEvaluationTestCase {
 				method: http.MethodPost,
 				uri:    "/cli/evaluate",
 				body: &EvaluationRequest{
-					CliId: "cli-id-test",
-					Files: castPropertiesMock("service_mock", "mocks/service_mock.yaml"),
+					EvaluationId: 321,
+					Files:        castPropertiesMock("service_mock", "mocks/service_mock.yaml"),
+				},
+				headers: nil,
+			},
+			response: &EvaluationResponse{},
+		},
+	}
+}
+
+func test_createEvaluation_success() *CreateEvaluationTestCase {
+	return &CreateEvaluationTestCase{
+		name: "success - create evaluation",
+		args: struct {
+			createEvaluationRequest *CreateEvaluationRequest
+		}{
+			createEvaluationRequest: &CreateEvaluationRequest{
+				CliId: "cli_id",
+				Metadata: Metadata{
+					CliVersion:      "0.0.1",
+					Os:              "darwin",
+					PlatformVersion: "1.2.3",
+					KernelVersion:   "4.5.6",
+				},
+			},
+		},
+		mock: struct {
+			response struct {
+				status int
+				body   *CreateEvaluationResponse
+			}
+		}{
+			response: struct {
+				status int
+				body   *CreateEvaluationResponse
+			}{
+				status: http.StatusOK,
+				body:   &CreateEvaluationResponse{
+					EvaluationId: 123,
+				},
+			},
+		},
+		expected: struct {
+			request struct {
+				method  string
+				uri     string
+				body    *CreateEvaluationRequest
+				headers map[string]string
+			}
+			response *CreateEvaluationResponse
+		}{
+			request: struct {
+				method  string
+				uri     string
+				body    *CreateEvaluationRequest
+				headers map[string]string
+			}{
+				method: http.MethodPost,
+				uri:    "/cli/evaluate/create",
+				body: &CreateEvaluationRequest{
+					CliId: "cli_id",
 					Metadata: Metadata{
 						CliVersion:      "0.0.1",
 						Os:              "darwin",
@@ -264,7 +367,9 @@ func test_requestEvaluation_success() *RequestEvaluationTestCase {
 				},
 				headers: nil,
 			},
-			response: &EvaluationResponse{},
+			response: &CreateEvaluationResponse{
+				EvaluationId: 123,
+			},
 		},
 	}
 }