Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions nexus3/nexus.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/datadrivers/go-nexus-client/nexus3/pkg/readonly"
"github.com/datadrivers/go-nexus-client/nexus3/pkg/repository"
"github.com/datadrivers/go-nexus-client/nexus3/pkg/security"
"github.com/datadrivers/go-nexus-client/nexus3/pkg/task"
)

const (
Expand All @@ -33,6 +34,7 @@ type NexusClient struct {
RoutingRule *RoutingRuleService
Script *ScriptService
Security *security.SecurityService
Task *task.TaskService
}

// NewClient returns an instance of client that implements the Client interface
Expand All @@ -50,5 +52,6 @@ func NewClient(config client.Config) *NexusClient {
RoutingRule: NewRoutingRuleService(client),
Script: NewScriptService(client),
Security: security.NewSecurityService(client),
Task: task.NewTaskService(client),
}
}
151 changes: 151 additions & 0 deletions nexus3/pkg/task/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package task

import (
"encoding/json"
"errors"
"fmt"
"github.com/datadrivers/go-nexus-client/nexus3/pkg/tools"
"github.com/datadrivers/go-nexus-client/nexus3/schema"
"net/http"
"net/url"

"github.com/datadrivers/go-nexus-client/nexus3/pkg/client"
"github.com/datadrivers/go-nexus-client/nexus3/schema/task"
)

const (
taskAPIEndpoint = client.BasePath + "v1/tasks"
)

var (
ErrTaskNotRunning = errors.New("task is not currently running")
)

type TaskService client.Service

func NewTaskService(c *client.Client) *TaskService {
return &TaskService{Client: c}
}

func (s *TaskService) ListTasks(taskType *string, continuationToken *string) ([]task.Task, *string, error) {
q := url.Values{}
if taskType != nil {
q.Set("type", *taskType)
}
if continuationToken != nil {
q.Set("continuationToken", *continuationToken)
}

body, resp, err := s.Client.Get(fmt.Sprintf("%s?%s", taskAPIEndpoint, q.Encode()), nil)
if err != nil {
return nil, nil, err
}

if resp.StatusCode != http.StatusOK {
return nil, nil, fmt.Errorf("could not list task: HTTP: %d, %s", resp.StatusCode, string(body))
}

var result schema.PaginationResult[task.Task]
if err := json.Unmarshal(body, &result); err != nil {
return nil, nil, fmt.Errorf("could not unmarshal tasks: %v", err)
}

return result.Items, result.ContinuationToken, nil
}

func (s *TaskService) GetTask(id string) (*task.Task, error) {
body, resp, err := s.Client.Get(fmt.Sprintf("%s/%s", taskAPIEndpoint, id), nil)
if err != nil {
return nil, err
}
switch resp.StatusCode {
case http.StatusOK:
var t task.Task
if err := json.Unmarshal(body, &t); err != nil {
return nil, fmt.Errorf("could not unmarshal task: %v", err)
}
return &t, nil
case http.StatusNotFound:
return nil, nil
default:
return nil, fmt.Errorf("could not get task '%s': HTTP: %d, %s", id, resp.StatusCode, string(body))
}
}

func (s *TaskService) RunTask(id string) error {
body, resp, err := s.Client.Post(fmt.Sprintf("%s/%s/run", taskAPIEndpoint, id), nil)
if err != nil {
return err
}
if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("could not run task '%s': HTTP: %d, %s", id, resp.StatusCode, string(body))
}
return nil
}

func (s *TaskService) StopTask(id string) error {
body, resp, err := s.Client.Post(fmt.Sprintf("%s/%s/stop", taskAPIEndpoint, id), nil)
if err != nil {
return err
}
switch resp.StatusCode {
case http.StatusNoContent:
return nil
case http.StatusConflict:
return ErrTaskNotRunning
default:
return fmt.Errorf("could not stop task '%s': HTTP: %d, %s", id, resp.StatusCode, string(body))
}
}

func (s *TaskService) CreateTask(newTask *task.TaskCreateStruct) (*task.Task, error) {
ioReader, err := tools.JsonMarshalInterfaceToIOReader(newTask)
if err != nil {
return nil, err
}
body, resp, err := s.Client.Post(taskAPIEndpoint, ioReader)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusCreated {
return nil, fmt.Errorf("could not create task: HTTP: %d, %s", resp.StatusCode, string(body))
}

var createdTask task.Task
if err := json.Unmarshal(body, &createdTask); err != nil {
return nil, fmt.Errorf("could not unmarshal created task: %v", err)
}

return &createdTask, nil
}

func (s *TaskService) UpdateTask(id string, updatedTask *task.TaskCreateStruct) error {
ioReader, err := tools.JsonMarshalInterfaceToIOReader(updatedTask)
if err != nil {
return err
}

body, resp, err := s.Client.Put(fmt.Sprintf("%s/%s", taskAPIEndpoint, id), ioReader)
if err != nil {
return err
}

if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("could not update task '%s': HTTP: %d, %s", id, resp.StatusCode, string(body))
}
return nil
}

func (s *TaskService) DeleteTask(id string) error {
body, resp, err := s.Client.Delete(fmt.Sprintf("%s/%s", taskAPIEndpoint, id))
if err != nil {
return err
}

if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("could not delete task '%s': HTTP: %d, %s", id, resp.StatusCode, string(body))
}

return nil
}
202 changes: 202 additions & 0 deletions nexus3/pkg/task/service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package task

import (
"testing"
"time"

"github.com/datadrivers/go-nexus-client/nexus3/schema/task"

"github.com/datadrivers/go-nexus-client/nexus3/pkg/client"
"github.com/datadrivers/go-nexus-client/nexus3/pkg/tools"
"github.com/stretchr/testify/assert"
)

const dummyTask = "dummy"

var (
testClient *client.Client = nil
)

func getTestClient() *client.Client {
if testClient != nil {
return testClient
}
return client.NewClient(getDefaultConfig())
}

func getTestService() *TaskService {
return NewTaskService(getTestClient())
}

func getDefaultConfig() client.Config {
timeout := tools.GetEnv("NEXUS_TIMEOUT", 30).(int)
return client.Config{
Insecure: tools.GetEnv("NEXUS_INSECURE_SKIP_VERIFY", true).(bool),
Password: tools.GetEnv("NEXUS_PASSWORD", "admin123").(string),
URL: tools.GetEnv("NEXUS_URL", "http://127.0.0.1:8081").(string),
Username: tools.GetEnv("NEXUS_USERNAME", "admin").(string),
Timeout: &timeout,
}
}

func TestFreezeAndReleaseTaskState(t *testing.T) {
s := getTestService()

tasks, _, err := s.ListTasks(nil, nil)
if err != nil {
assert.Failf(t, "fail to list task", err.Error())
return
}
for _, task := range tasks {
assert.NotEmpty(t, task.ID)
assert.NotEmpty(t, task.Name)
assert.NotEmpty(t, task.Type)
assert.NotEmpty(t, task.CurrentState)
}

// test get task api
if len(tasks) > 0 {
task, err := s.GetTask(tasks[0].ID)
if err != nil {
assert.Failf(t, "fail to run task", err.Error())
return
}
assert.NotEmpty(t, task.ID)
assert.NotEmpty(t, task.Name)
assert.NotEmpty(t, task.Type)
assert.NotEmpty(t, task.CurrentState)
}
}

func TestTaskService_CreateTask(t *testing.T) {
if tools.GetEnv("SKIP_PRO_TESTS", "false") == "true" {
t.Skip("Skipping Nexus Pro tests")
}
s := getTestService()
newTask := getTestTask()
createdTask, err := s.CreateTask(newTask)
if err != nil {
assert.Failf(t, "fail to create task", err.Error())
return
}
assert.NotNil(t, createdTask)
}

func getTestTask() *task.TaskCreateStruct {
newTask := &task.TaskCreateStruct{
Name: "test-task",
Type: "tags.cleanup",
Enabled: true,
AlertEmail: "[email protected]",
NotificationCondition: "FAILURE",
Frequency: &task.FrequencyXO{
Schedule: "manual",
StartDate: int(time.Now().Unix()),
TimeZoneOffset: "-08:00",
CronExpression: "string",
},
Properties: map[string]interface{}{},
}
return newTask
}

func TestTaskService_UpdateTask(t *testing.T) {
if tools.GetEnv("SKIP_PRO_TESTS", "false") == "true" {
t.Skip("Skipping Nexus Pro tests")
}
s := getTestService()
newTask := getTestTask()
createdTask, err := s.CreateTask(newTask)
if err != nil {
assert.Failf(t, "fail to create task", err.Error())
return
}
assert.NotNil(t, createdTask)
newTask.Type = ""
newTask.Name = "test-task-updated"
err = s.UpdateTask(createdTask.ID, newTask)
if err != nil {
assert.Failf(t, "fail to update task", err.Error())
return
}
updatedTask, err := s.GetTask(createdTask.ID)
if err != nil {
assert.Failf(t, "fail to get task", err.Error())
return
}
assert.NotNil(t, updatedTask)
assert.Equal(t, newTask.Name, updatedTask.Name, "newTask.Name should be equal to updatedTask.Name")

err = s.UpdateTask(dummyTask, newTask)
assert.NotNil(t, err)
}

func TestTaskService_DeleteTaskTask(t *testing.T) {
if tools.GetEnv("SKIP_PRO_TESTS", "false") == "true" {
t.Skip("Skipping Nexus Pro tests")
}
s := getTestService()
newTask := getTestTask()
createdTask, err := s.CreateTask(newTask)
if err != nil {
assert.Failf(t, "fail to create task", err.Error())
return
}
assert.NotNil(t, createdTask)
err = s.DeleteTask(createdTask.ID)
removedTask, err := s.GetTask(createdTask.ID)
if err != nil {
assert.Failf(t, "fail to update task", err.Error())
return
}
assert.Nil(t, removedTask)
err = s.DeleteTask(dummyTask)
assert.NotNil(t, err)
}

func TestTaskService_RunTask(t *testing.T) {
if tools.GetEnv("SKIP_PRO_TESTS", "false") == "true" {
t.Skip("Skipping Nexus Pro tests")
}
s := getTestService()
newTask := getTestTask()
createdTask, err := s.CreateTask(newTask)
if err != nil {
assert.Failf(t, "fail to create task", err.Error())
return
}
assert.NotNil(t, createdTask)
err = s.RunTask(createdTask.ID)
if err != nil {
assert.Failf(t, "fail to run task", err.Error())
return
}
err = s.RunTask(dummyTask)
assert.NotNil(t, err)
}

func TestTaskService_StopTask(t *testing.T) {
if tools.GetEnv("SKIP_PRO_TESTS", "false") == "true" {
t.Skip("Skipping Nexus Pro tests")
}
s := getTestService()
newTask := getTestTask()
createdTask, err := s.CreateTask(newTask)
if err != nil {
assert.Failf(t, "fail to create task", err.Error())
return
}
assert.NotNil(t, createdTask)
err = s.RunTask(createdTask.ID)
if err != nil {
assert.Failf(t, "fail to run task", err.Error())
return
}
err = s.StopTask(createdTask.ID)
if err != nil {
assert.Failf(t, "fail to stop task", err.Error())
return
}
err = s.StopTask(dummyTask)
assert.NotNil(t, err)
}
6 changes: 6 additions & 0 deletions nexus3/schema/pagination.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package schema

type PaginationResult[T any] struct {
Items []T `json:"items"`
ContinuationToken *string `json:"continuationToken"`
}
Loading