Repository: ctreminiom/go-atlassian
Pull request #79 (2021-11-15 02:02:50)

:sparkles: Added the workflow scheme service.
1. Added the ability to CRUD the worflow schemes on the V2
2. Added the ability to assign workflow scheme to a project (v3,v2)
3. Added the ability to get the project/workflow scheme associations (v3,v2)


Patch:
diff --git a/jira/mocks/get-worflow-scheme-associations.json b/jira/mocks/get-worflow-scheme-associations.json
new file mode 100644
index 0000000..a539518
--- /dev/null
+++ b/jira/mocks/get-worflow-scheme-associations.json
@@ -0,0 +1,38 @@
+{
+  "values": [
+    {
+      "projectIds": [
+        "10001"
+      ],
+      "workflowScheme": {
+        "id": 10002,
+        "name": "Jira Service Management IT Support Workflow Scheme generated for Project DESK",
+        "description": "This Jira Service Management IT Support Workflow Scheme was generated for Project DESK",
+        "defaultWorkflow": "jira",
+        "issueTypeMappings": {
+          "10002": "DESK: Jira Service Management default workflow",
+          "10003": "DESK: Jira Service Management default workflow",
+          "10005": "DESK: Service Request Fulfilment workflow for Jira Service Management",
+          "10006": "DESK: Service Request Fulfilment workflow for Jira Service Management",
+          "10007": "DESK: Service Request Fulfilment with Approvals workflow for Jira Service Management"
+        },
+        "self": "https://ctreminiom.atlassian.net/rest/api/2/workflowscheme/10002"
+      }
+    },
+    {
+      "projectIds": [
+        "10003"
+      ],
+      "workflowScheme": {
+        "id": 10004,
+        "name": "K2: Software Simplified Workflow Scheme",
+        "description": "Generated by JIRA Software version 1001.0.0-SNAPSHOT. This workflow scheme is managed internally by Jira Software. Do not manually modify this workflow scheme.",
+        "defaultWorkflow": "Software Simplified Workflow for Project K2",
+        "issueTypeMappings": {
+
+        },
+        "self": "https://ctreminiom.atlassian.net/rest/api/2/workflowscheme/10004"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jira/mocks/get-workflow-scheme.json b/jira/mocks/get-workflow-scheme.json
new file mode 100644
index 0000000..c4ec16d
--- /dev/null
+++ b/jira/mocks/get-workflow-scheme.json
@@ -0,0 +1,12 @@
+{
+  "id": 101010,
+  "name": "Example workflow scheme",
+  "description": "The description of the example workflow scheme.",
+  "defaultWorkflow": "jira",
+  "issueTypeMappings": {
+    "10000": "scrum workflow",
+    "10001": "builds workflow"
+  },
+  "draft": false,
+  "self": "https://your-domain.atlassian.net/rest/api/2/workflowscheme/101010"
+}
\ No newline at end of file
diff --git a/jira/mocks/get-workflow-schemes.json b/jira/mocks/get-workflow-schemes.json
new file mode 100644
index 0000000..1c6b906
--- /dev/null
+++ b/jira/mocks/get-workflow-schemes.json
@@ -0,0 +1,30 @@
+{
+  "maxResults": 50,
+  "startAt": 0,
+  "total": 2,
+  "isLast": true,
+  "values": [
+    {
+      "id": 101010,
+      "name": "Example workflow scheme",
+      "description": "The description of the example workflow scheme.",
+      "defaultWorkflow": "jira",
+      "issueTypeMappings": {
+        "10000": "scrum workflow",
+        "10001": "builds workflow"
+      },
+      "self": "https://your-domain.atlassian.net/rest/api/2/workflowscheme/101010"
+    },
+    {
+      "id": 101011,
+      "name": "Another example workflow scheme",
+      "description": "The description of the another example workflow scheme.",
+      "defaultWorkflow": "jira",
+      "issueTypeMappings": {
+        "10000": "scrum workflow",
+        "10001": "builds workflow"
+      },
+      "self": "https://your-domain.atlassian.net/rest/api/2/workflowscheme/101011"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jira/v2/jira.go b/jira/v2/jira.go
index d3c3fce..935858e 100644
--- a/jira/v2/jira.go
+++ b/jira/v2/jira.go
@@ -149,7 +149,11 @@ func New(httpClient *http.Client, site string) (client *Client, err error) {
 	}
 
 	client.MySelf = &MySelfService{client: client}
-	client.Workflow = &WorkflowService{client: client}
+	client.Workflow = &WorkflowService{
+		client: client,
+		Scheme: &WorkflowSchemeService{client: client},
+	}
+
 	return
 }
 
diff --git a/jira/v2/workflow.go b/jira/v2/workflow.go
index 63b1c8e..6af12fc 100644
--- a/jira/v2/workflow.go
+++ b/jira/v2/workflow.go
@@ -12,6 +12,7 @@ import (
 
 type WorkflowService struct {
 	client *Client
+	Scheme *WorkflowSchemeService
 }
 
 func (w *WorkflowService) Create(ctx context.Context, payload *models.WorkflowPayloadScheme) (result *models.WorkflowCreatedResponseScheme,
diff --git a/jira/v2/workflowScheme.go b/jira/v2/workflowScheme.go
new file mode 100644
index 0000000..5305bf6
--- /dev/null
+++ b/jira/v2/workflowScheme.go
@@ -0,0 +1,224 @@
+package v2
+
+import (
+	"context"
+	"fmt"
+	models "github.com/ctreminiom/go-atlassian/pkg/infra/models/jira"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+type WorkflowSchemeService struct {
+	client *Client
+}
+
+// Gets returns a paginated list of all workflow schemes, not including draft workflow schemes.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-schemes/#api-rest-api-2-workflowscheme-get
+func (w *WorkflowSchemeService) Gets(ctx context.Context, startAt, maxResults int) (result *models.WorkflowSchemePageScheme,
+	response *ResponseScheme, err error) {
+
+	params := url.Values{}
+	params.Add("startAt", strconv.Itoa(startAt))
+	params.Add("maxResults", strconv.Itoa(maxResults))
+
+	endpoint := fmt.Sprintf("rest/api/2/workflowscheme?%v", params.Encode())
+
+	request, err := w.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = w.client.call(request, &result)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Create creates a workflow scheme.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-schemes/#api-rest-api-2-workflowscheme-post
+func (w *WorkflowSchemeService) Create(ctx context.Context, payload *models.WorkflowSchemePayloadScheme) (result *models.WorkflowSchemeScheme,
+	response *ResponseScheme, err error) {
+
+	payloadAsReader, err := transformStructToReader(payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	endpoint := "/rest/api/2/workflowscheme"
+	request, err := w.client.newRequest(ctx, http.MethodPost, endpoint, payloadAsReader)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = w.client.call(request, &result)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Get returns a workflow scheme.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-schemes/#api-rest-api-2-workflowscheme-id-get
+func (w *WorkflowSchemeService) Get(ctx context.Context, workflowSchemeID int, returnDraftIfExists bool) (result *models.WorkflowSchemeScheme,
+	response *ResponseScheme, err error) {
+
+	params := url.Values{}
+	if returnDraftIfExists {
+		params.Add("returnDraftIfExists", "true")
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("rest/api/2/workflowscheme/%v", workflowSchemeID))
+
+	if params.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", params.Encode()))
+	}
+
+	request, err := w.client.newRequest(ctx, http.MethodGet, endpoint.String(), nil)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = w.client.call(request, &result)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Update updates a workflow scheme, including the name, default workflow, issue type to project mappings, and more.
+// If the workflow scheme is active (that is, being used by at least one project), then a draft workflow scheme is
+// created or updated instead, provided that updateDraftIfNeeded is set to true.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-schemes/#api-rest-api-2-workflowscheme-id-put
+func (w *WorkflowSchemeService) Update(ctx context.Context, workflowSchemeID int, payload *models.WorkflowSchemePayloadScheme) (
+	result *models.WorkflowSchemeScheme, response *ResponseScheme, err error) {
+
+	payloadAsReader, err := transformStructToReader(payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("rest/api/2/workflowscheme/%v", workflowSchemeID))
+
+	request, err := w.client.newRequest(ctx, http.MethodPut, endpoint.String(), payloadAsReader)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = w.client.call(request, &result)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Delete deletes a workflow scheme.
+// Note that a workflow scheme cannot be deleted if it is active (that is, being used by at least one project).
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-schemes/#api-rest-api-2-workflowscheme-id-delete
+func (w *WorkflowSchemeService) Delete(ctx context.Context, workflowSchemeID int) (response *ResponseScheme, err error) {
+
+	endpoint := fmt.Sprintf("rest/api/2/workflowscheme/%v", workflowSchemeID)
+
+	request, err := w.client.newRequest(ctx, http.MethodDelete, endpoint, nil)
+	if err != nil {
+		return
+	}
+
+	response, err = w.client.call(request, nil)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Associations returns a list of the workflow schemes associated with a list of projects.
+// Each returned workflow scheme includes a list of the requested projects associated with it.
+// Any team-managed or non-existent projects in the request are ignored and no errors are returned.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-scheme-project-associations/#api-rest-api-2-workflowscheme-project-get
+func (w *WorkflowSchemeService) Associations(ctx context.Context, projectIDs []int) (result *models.WorkflowSchemeAssociationPageScheme,
+	response *ResponseScheme, err error) {
+
+	if len(projectIDs) == 0 {
+		return nil, nil, models.ErrNoProjectsError
+	}
+
+	params := url.Values{}
+	for _, projectID := range projectIDs {
+		params.Add("projectId", strconv.Itoa(projectID))
+	}
+
+	endpoint := fmt.Sprintf("rest/api/2/workflowscheme/project?%v", params.Encode())
+
+	request, err := w.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = w.client.call(request, &result)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Assign assigns a workflow scheme to a project.
+// This operation is performed only when there are no issues in the project.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-workflow-scheme-project-associations/#api-rest-api-2-workflowscheme-project-put
+func (w *WorkflowSchemeService) Assign(ctx context.Context, workflowSchemeID, projectID string) (response *ResponseScheme, err error) {
+
+	if len(projectID) == 0 {
+		return nil, models.ErrNoProjectIDError
+	}
+
+	if len(workflowSchemeID) == 0 {
+		return nil, models.ErrNoWorkflowSchemeIDError
+	}
+
+	payload := struct {
+		WorkflowSchemeID string `json:"workflowSchemeId"`
+		ProjectID        string `json:"projectId"`
+	}{
+		WorkflowSchemeID: workflowSchemeID,
+		ProjectID:        projectID,
+	}
+
+	payloadAsReader, _ := transformStructToReader(&payload)
+	endpoint := "rest/api/2/workflowscheme/project"
+
+	request, err := w.client.newRequest(ctx, http.MethodPut, endpoint, payloadAsReader)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = w.client.call(request, nil)
+	if err != nil {
+		return
+	}
+
+	return
+}
diff --git a/jira/v3/workflowScheme.go b/jira/v3/workflowScheme.go
index d76b1fa..c949e2c 100644
--- a/jira/v3/workflowScheme.go
+++ b/jira/v3/workflowScheme.go
@@ -147,3 +147,76 @@ func (w *WorkflowSchemeService) Delete(ctx context.Context, workflowSchemeID int
 
 	return
 }
+
+// Associations returns a list of the workflow schemes associated with a list of projects.
+// Each returned workflow scheme includes a list of the requested projects associated with it.
+// Any team-managed or non-existent projects in the request are ignored and no errors are returned.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflow-scheme-project-associations/#api-rest-api-3-workflowscheme-project-get
+func (w *WorkflowSchemeService) Associations(ctx context.Context, projectIDs []int) (result *models.WorkflowSchemeAssociationPageScheme,
+	response *ResponseScheme, err error) {
+
+	if len(projectIDs) == 0 {
+		return nil, nil, models.ErrNoProjectsError
+	}
+
+	params := url.Values{}
+	for _, projectID := range projectIDs {
+		params.Add("projectId", strconv.Itoa(projectID))
+	}
+
+	endpoint := fmt.Sprintf("rest/api/3/workflowscheme/project?%v", params.Encode())
+
+	request, err := w.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = w.client.call(request, &result)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// Assign assigns a workflow scheme to a project.
+// This operation is performed only when there are no issues in the project.
+// Docs: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflow-scheme-project-associations/#api-rest-api-3-workflowscheme-project-put
+func (w *WorkflowSchemeService) Assign(ctx context.Context, workflowSchemeID, projectID string) (response *ResponseScheme, err error) {
+
+	if len(projectID) == 0 {
+		return nil, models.ErrNoProjectIDError
+	}
+
+	if len(workflowSchemeID) == 0 {
+		return nil, models.ErrNoWorkflowSchemeIDError
+	}
+
+	payload := struct {
+		WorkflowSchemeID string `json:"workflowSchemeId"`
+		ProjectID        string `json:"projectId"`
+	}{
+		WorkflowSchemeID: workflowSchemeID,
+		ProjectID:        projectID,
+	}
+
+	payloadAsReader, _ := transformStructToReader(&payload)
+	endpoint := "rest/api/3/workflowscheme/project"
+
+	request, err := w.client.newRequest(ctx, http.MethodPut, endpoint, payloadAsReader)
+	if err != nil {
+		return
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = w.client.call(request, nil)
+	if err != nil {
+		return
+	}
+
+	return
+}
diff --git a/pkg/infra/models/jira/errors.go b/pkg/infra/models/jira/errors.go
index ca87530..29394ec 100644
--- a/pkg/infra/models/jira/errors.go
+++ b/pkg/infra/models/jira/errors.go
@@ -44,4 +44,5 @@ var (
 	ErrNoAccountSliceError            = errors.New("jira: no account id's set")
 	ErrNoProjectKeySliceError         = errors.New("jira: no project key's set")
 	ErrNoWorkflowIDError              = errors.New("jira: no workflow id set")
+	ErrNoWorkflowSchemeIDError        = errors.New("jira: no workflow scheme id set")
 )
diff --git a/pkg/infra/models/jira/workflowScheme.go b/pkg/infra/models/jira/workflowScheme.go
index 73d112d..5b6d0c0 100644
--- a/pkg/infra/models/jira/workflowScheme.go
+++ b/pkg/infra/models/jira/workflowScheme.go
@@ -28,3 +28,12 @@ type WorkflowSchemeScheme struct {
 	Self                string      `json:"self,omitempty"`
 	UpdateDraftIfNeeded bool        `json:"updateDraftIfNeeded,omitempty"`
 }
+
+type WorkflowSchemeAssociationPageScheme struct {
+	Values []*WorkflowSchemeAssociationsScheme `json:"values,omitempty"`
+}
+
+type WorkflowSchemeAssociationsScheme struct {
+	ProjectIds     []string              `json:"projectIds,omitempty"`
+	WorkflowScheme *WorkflowSchemeScheme `json:"workflowScheme,omitempty"`
+}


Test patch:
diff --git a/jira/v2/workflowScheme_test.go b/jira/v2/workflowScheme_test.go
new file mode 100644
index 0000000..aac7ce1
--- /dev/null
+++ b/jira/v2/workflowScheme_test.go
@@ -0,0 +1,1039 @@
+package v2
+
+import (
+	"context"
+	"fmt"
+	models "github.com/ctreminiom/go-atlassian/pkg/infra/models/jira"
+	"github.com/stretchr/testify/assert"
+	"log"
+	"net/http"
+	"net/url"
+	"testing"
+)
+
+func TestWorkflowSchemeService_Create(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		payload            *models.WorkflowSchemePayloadScheme
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:     "CreateWorkflowSchemeWhenTheParametersAreCorrect",
+			mockFile: "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/2/workflowscheme",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            false,
+		},
+
+		{
+			name:               "CreateWorkflowSchemeWhenThePayloadIsNotSet",
+			mockFile:           "../mocks/get-workflow-scheme.json",
+			payload:            nil,
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/2/workflowscheme",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:     "CreateWorkflowSchemeWhenTheContextIsNotSet",
+			mockFile: "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/2/workflowscheme",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:     "CreateWorkflowSchemeWhenTheRequestMethodIsIncorrect",
+			mockFile: "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodHead,
+			endpoint:           "/rest/api/2/workflowscheme",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:     "CreateWorkflowSchemeWhenTheStatusCodeIsIncorrect",
+			mockFile: "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/2/workflowscheme",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResult, gotResponse, err := i.Create(testCase.context, testCase.payload)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+
+	}
+
+}
+
+func TestWorkflowSchemeService_Get(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		workflowSchemeID   int
+		isExits            bool
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:               "GetWorkflowWorkflowSchemeWhenTheParametersAreCorrect",
+			workflowSchemeID:   1006,
+			isExits:            true,
+			mockFile:           "../mocks/get-workflow-scheme.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/1006?returnDraftIfExists=true",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            false,
+		},
+
+		{
+			name:               "GetWorkflowWorkflowSchemeWhenTheContextIsNotSet",
+			workflowSchemeID:   1006,
+			isExits:            true,
+			mockFile:           "../mocks/get-workflow-scheme.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/1006?returnDraftIfExists=true",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowWorkflowSchemeWhenTheRequestMethodIsIncorrect",
+			workflowSchemeID:   1006,
+			isExits:            true,
+			mockFile:           "../mocks/get-workflow-scheme.json",
+			wantHTTPMethod:     http.MethodHead,
+			endpoint:           "/rest/api/2/workflowscheme/1006?returnDraftIfExists=true",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowWorkflowSchemeWhenTheStatusCodeIsIncorrect",
+			workflowSchemeID:   1006,
+			isExits:            true,
+			mockFile:           "../mocks/get-workflow-scheme.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/1006?returnDraftIfExists=true",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowWorkflowSchemeWhenTheResponseBodyIsEmpty",
+			workflowSchemeID:   1006,
+			isExits:            true,
+			mockFile:           "../mocks/empty_json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/1006?returnDraftIfExists=true",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResult, gotResponse, err := i.Get(testCase.context, testCase.workflowSchemeID, testCase.isExits)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+
+	}
+
+}
+
+func TestWorkflowSchemeService_Update(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		workflowSchemeID   int
+		payload            *models.WorkflowSchemePayloadScheme
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:             "UpdateWorkflowSchemeWhenTheParametersAreCorrect",
+			workflowSchemeID: 1006,
+			mockFile:         "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            false,
+		},
+
+		{
+			name:             "UpdateWorkflowSchemeWhenTheContextIsNotSet",
+			workflowSchemeID: 1006,
+			mockFile:         "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:             "UpdateWorkflowSchemeWhenTheResponseBodyIsEmpty",
+			workflowSchemeID: 1006,
+			mockFile:         "../mocks/empty-json.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:             "UpdateWorkflowSchemeWhenTheRequestMethodIsIncorrect",
+			workflowSchemeID: 1006,
+			mockFile:         "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodHead,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:             "UpdateWorkflowSchemeWhenTheStatusCodeIsIncorrect",
+			workflowSchemeID: 1006,
+			mockFile:         "../mocks/get-workflow-scheme.json",
+			payload: &models.WorkflowSchemePayloadScheme{
+				DefaultWorkflow: "jira",
+				Name:            "Example workflow scheme",
+				Description:     "The description of the example workflow scheme.",
+				IssueTypeMappings: map[string]string{
+					"10000": "scrum workflow",
+					"10001": "builds workflow",
+				},
+			},
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "UpdateWorkflowSchemeWhenThePayloadIsNotSet",
+			workflowSchemeID:   1006,
+			mockFile:           "../mocks/get-workflow-scheme.json",
+			payload:            nil,
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResult, gotResponse, err := i.Update(testCase.context, testCase.workflowSchemeID, testCase.payload)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+
+	}
+
+}
+
+func TestWorkflowSchemeService_Gets(t *testing.T) {
+
+	testCases := []struct {
+		name                string
+		startAt, maxResults int
+		mockFile            string
+		wantHTTPMethod      string
+		endpoint            string
+		context             context.Context
+		wantHTTPCodeReturn  int
+		wantErr             bool
+	}{
+		{
+			name:               "GetWorkflowSchemesWhenTheParametersAreCorrect",
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "../mocks/get-workflow-schemes.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme?maxResults=50&startAt=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            false,
+		},
+
+		{
+			name:               "GetWorkflowSchemesWhenTheRequestMethodIsIncorrect",
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "../mocks/get-workflow-schemes.json",
+			wantHTTPMethod:     http.MethodHead,
+			endpoint:           "/rest/api/2/workflowscheme?maxResults=50&startAt=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowSchemesWhenTheStatusCodeIsIncorrect",
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "../mocks/get-workflow-schemes.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme?maxResults=50&startAt=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowSchemesWhenTheContextIsNotSet",
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "../mocks/get-workflow-schemes.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme?maxResults=50&startAt=0",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowSchemesWhenTheResponseBodyIsEmpty",
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "../mocks/empty_json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme?maxResults=50&startAt=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResult, gotResponse, err := i.Gets(testCase.context, testCase.startAt, testCase.maxResults)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+
+	}
+
+}
+
+func TestWorkflowSchemeService_Delete(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		workflowSchemeID   int
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:               "DeleteWorkflowSchemeWhenTheParametersAreCorrect",
+			workflowSchemeID:   1006,
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            false,
+		},
+
+		{
+			name:               "DeleteWorkflowSchemeWhenTheRequestMethodIsIncorrect",
+			workflowSchemeID:   1006,
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "DeleteWorkflowSchemeWhenTheStatusCodeIsIncorrect",
+			workflowSchemeID:   1006,
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "DeleteWorkflowSchemeWhenTheContextIsNotSet",
+			workflowSchemeID:   1006,
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/rest/api/2/workflowscheme/1006",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResponse, err := i.Delete(testCase.context, testCase.workflowSchemeID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+
+	}
+
+}
+
+func TestWorkflowSchemeService_Associations(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		projectIDs         []int
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:               "GetWorkflowAssociationsWhenTheParametersAreCorrect",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            false,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheProjectIDsAreNotSet",
+			projectIDs:         nil,
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheContextIsNotProvided",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheRequestMethodIsIncorrect",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/2/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheStatusCodeIsIncorrect",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheResponseBodyIsEmpty",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/2/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			getResult, gotResponse, err := i.Associations(testCase.context, testCase.projectIDs)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, getResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				for _, value := range getResult.Values {
+					log.Println(value.ProjectIds, value.WorkflowScheme.Name)
+				}
+			}
+
+		})
+	}
+}
+
+func TestWorkflowSchemeService_Assign(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		workflowSchemeID   string
+		projectID          string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheParametersAreCorrect",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            false,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheWorkflowSchemeIDIsNotSet",
+			workflowSchemeID:   "",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheProjectIDIsNotSet",
+			workflowSchemeID:   "10001",
+			projectID:          "",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheRequestMethodIsIncorrect",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodHead,
+			endpoint:           "/rest/api/2/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheStatusCodeIsIncorrect",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheContextIsNotProvided",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/2/workflowscheme/project",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResponse, err := i.Assign(testCase.context, testCase.workflowSchemeID, testCase.projectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+	}
+}
diff --git a/jira/v3/workflowScheme_test.go b/jira/v3/workflowScheme_test.go
index e9530a5..433274e 100644
--- a/jira/v3/workflowScheme_test.go
+++ b/jira/v3/workflowScheme_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	models "github.com/ctreminiom/go-atlassian/pkg/infra/models/jira"
 	"github.com/stretchr/testify/assert"
+	"log"
 	"net/http"
 	"net/url"
 	"testing"
@@ -754,3 +755,285 @@ func TestWorkflowSchemeService_Delete(t *testing.T) {
 	}
 
 }
+
+func TestWorkflowSchemeService_Associations(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		projectIDs         []int
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:               "GetWorkflowAssociationsWhenTheParametersAreCorrect",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/3/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            false,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheProjectIDsAreNotSet",
+			projectIDs:         nil,
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/3/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheContextIsNotProvided",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/3/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheRequestMethodIsIncorrect",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/rest/api/3/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheStatusCodeIsIncorrect",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/get-worflow-scheme-associations.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/3/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "GetWorkflowAssociationsWhenTheResponseBodyIsEmpty",
+			projectIDs:         []int{10001, 10002, 10003},
+			mockFile:           "../mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/rest/api/3/workflowscheme/project?projectId=10001&projectId=10002&projectId=10003",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			getResult, gotResponse, err := i.Associations(testCase.context, testCase.projectIDs)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, getResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				for _, value := range getResult.Values {
+					log.Println(value.ProjectIds, value.WorkflowScheme.Name)
+				}
+			}
+
+		})
+	}
+}
+
+func TestWorkflowSchemeService_Assign(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		workflowSchemeID   string
+		projectID          string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+	}{
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheParametersAreCorrect",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/3/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            false,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheWorkflowSchemeIDIsNotSet",
+			workflowSchemeID:   "",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/3/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheProjectIDIsNotSet",
+			workflowSchemeID:   "10001",
+			projectID:          "",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/3/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheRequestMethodIsIncorrect",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodHead,
+			endpoint:           "/rest/api/3/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheStatusCodeIsIncorrect",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/3/workflowscheme/project",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+		},
+
+		{
+			name:               "AssignWorkflowSchemeToProjectWhenTheContextIsNotProvided",
+			workflowSchemeID:   "10001",
+			projectID:          "10002",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/rest/api/3/workflowscheme/project",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			i := &WorkflowSchemeService{client: mockClient}
+
+			gotResponse, err := i.Assign(testCase.context, testCase.workflowSchemeID, testCase.projectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+			}
+		})
+	}
+}