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
30 changes: 17 additions & 13 deletions droplet_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,7 @@ func (s *DropletActionsServiceOp) EnableBackupsWithPolicy(ctx context.Context, i
return nil, nil, NewArgError("policy", "policy can't be nil")
}

policyMap := map[string]interface{}{
"plan": policy.Plan,
"weekday": policy.Weekday,
}
if policy.Hour != nil {
policyMap["hour"] = policy.Hour
}

request := &ActionRequest{"type": "enable_backups", "backup_policy": policyMap}
request := &ActionRequest{"type": "enable_backups", "backup_policy": dropletBackupPolicyActionRequest(policy)}
return s.doAction(ctx, id, request)
}

Expand All @@ -195,16 +187,28 @@ func (s *DropletActionsServiceOp) ChangeBackupPolicy(ctx context.Context, id int
return nil, nil, NewArgError("policy", "policy can't be nil")
}

request := &ActionRequest{"type": "change_backup_policy", "backup_policy": dropletBackupPolicyActionRequest(policy)}
return s.doAction(ctx, id, request)
}

func dropletBackupPolicyActionRequest(policy *DropletBackupPolicyRequest) map[string]interface{} {
policyMap := map[string]interface{}{
"plan": policy.Plan,
"weekday": policy.Weekday,
"plan": policy.Plan,
}
if policy.Weekday != "" {
policyMap["weekday"] = policy.Weekday
}
if policy.Hour != nil {
policyMap["hour"] = policy.Hour
}
if policy.WindowLengthHours != 0 {
policyMap["window_length_hours"] = policy.WindowLengthHours
}
if policy.RetentionPeriodDays != 0 {
policyMap["retention_period_days"] = policy.RetentionPeriodDays
}

request := &ActionRequest{"type": "change_backup_policy", "backup_policy": policyMap}
return s.doAction(ctx, id, request)
return policyMap
}

// DisableBackups disables backups for a Droplet.
Expand Down
97 changes: 97 additions & 0 deletions droplet_actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,49 @@ func TestDropletAction_EnableBackupsWithPolicy(t *testing.T) {
}
}

func TestDropletAction_EnableBackupsWithPolicyUsageBasedRequest(t *testing.T) {
setup()
defer teardown()

policyRequest := newUsageBasedDropletBackupPolicyRequest(t)

request := &ActionRequest{
"type": "enable_backups",
"backup_policy": map[string]interface{}{
"hour": float64(0),
"plan": "intra_daily_4h",
"retention_period_days": float64(7),
"window_length_hours": float64(4),
},
}

mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
v := new(ActionRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatalf("decode json: %v", err)
}

testMethod(t, r, http.MethodPost)

if !reflect.DeepEqual(v, request) {
t.Errorf("Request body = %+v, expected %+v", v, request)
}

fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
})

action, _, err := client.DropletActions.EnableBackupsWithPolicy(ctx, 1, policyRequest)
if err != nil {
t.Errorf("DropletActions.EnableBackupsWithPolicy returned error: %v", err)
}

expected := &Action{Status: "in-progress"}
if !reflect.DeepEqual(action, expected) {
t.Errorf("DropletActions.EnableBackupsWithPolicy returned %+v, expected %+v", action, expected)
}
}

func TestDropletAction_ChangeBackupPolicy(t *testing.T) {
setup()
defer teardown()
Expand Down Expand Up @@ -688,6 +731,60 @@ func TestDropletAction_ChangeBackupPolicy(t *testing.T) {
}
}

func TestDropletAction_ChangeBackupPolicyUsageBasedRequest(t *testing.T) {
setup()
defer teardown()

policyRequest := newUsageBasedDropletBackupPolicyRequest(t)

request := &ActionRequest{
"type": "change_backup_policy",
"backup_policy": map[string]interface{}{
"hour": float64(0),
"plan": "intra_daily_4h",
"retention_period_days": float64(7),
"window_length_hours": float64(4),
},
}

mux.HandleFunc("/v2/droplets/1/actions", func(w http.ResponseWriter, r *http.Request) {
v := new(ActionRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatalf("decode json: %v", err)
}

testMethod(t, r, http.MethodPost)

if !reflect.DeepEqual(v, request) {
t.Errorf("Request body = %+v, expected %+v", v, request)
}

fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
})

action, _, err := client.DropletActions.ChangeBackupPolicy(ctx, 1, policyRequest)
if err != nil {
t.Errorf("DropletActions.ChangeBackupPolicy returned error: %v", err)
}

expected := &Action{Status: "in-progress"}
if !reflect.DeepEqual(action, expected) {
t.Errorf("DropletActions.ChangeBackupPolicy returned %+v, expected %+v", action, expected)
}
}

func newUsageBasedDropletBackupPolicyRequest(t *testing.T) *DropletBackupPolicyRequest {
t.Helper()

return &DropletBackupPolicyRequest{
Plan: "intra_daily_4h",
Hour: PtrTo(0),
RetentionPeriodDays: 7,
WindowLengthHours: 4,
}
}

func TestDropletAction_DisableBackups(t *testing.T) {
setup()
defer teardown()
Expand Down
8 changes: 5 additions & 3 deletions droplets.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,11 @@ type DropletMultiCreateRequest struct {

// DropletBackupPolicyRequest defines the backup policy when creating a Droplet.
type DropletBackupPolicyRequest struct {
Plan string `json:"plan,omitempty"`
Weekday string `json:"weekday,omitempty"`
Hour *int `json:"hour,omitempty"`
Plan string `json:"plan,omitempty"`
Weekday string `json:"weekday,omitempty"`
Hour *int `json:"hour,omitempty"`
WindowLengthHours int `json:"window_length_hours,omitempty"`
RetentionPeriodDays int `json:"retention_period_days,omitempty"`
}

// DropletAssociatedResource represents a billable resource associated with a Droplet.
Expand Down
174 changes: 174 additions & 0 deletions droplets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,89 @@ func TestDroplets_Create(t *testing.T) {
}
}

func TestDroplets_CreateWithUsageBasedBackupPolicy(t *testing.T) {
setup()
defer teardown()

createRequest := &DropletCreateRequest{
Name: "name",
Region: "region",
Size: "size",
Image: DropletCreateImage{
ID: 1,
},
Backups: true,
BackupPolicy: &DropletBackupPolicyRequest{
Plan: "intra_daily_4h",
Hour: PtrTo(0),
WindowLengthHours: 4,
RetentionPeriodDays: 7,
},
}

mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
expected := map[string]interface{}{
"name": "name",
"region": "region",
"size": "size",
"image": float64(1),
"ssh_keys": nil,
"backups": true,
"ipv6": false,
"private_networking": false,
"monitoring": false,
"tags": nil,
"backup_policy": map[string]interface{}{
"plan": "intra_daily_4h",
"hour": float64(0),
"window_length_hours": float64(4),
"retention_period_days": float64(7),
},
}
jsonBlob := `
{
"droplet": {
"id": 1
},
"links": {
"actions": [
{
"id": 1,
"href": "http://example.com",
"rel": "create"
}
]
}
}
`

var v map[string]interface{}
err := json.NewDecoder(r.Body).Decode(&v)
if err != nil {
t.Fatalf("decode json: %v", err)
}

if !reflect.DeepEqual(v, expected) {
t.Errorf("Request body\n got=%#v\nwant=%#v", v, expected)
}

fmt.Fprintf(w, jsonBlob)
})

droplet, resp, err := client.Droplets.Create(ctx, createRequest)
if err != nil {
t.Errorf("Droplets.Create returned error: %v", err)
}

if id := droplet.ID; id != 1 {
t.Errorf("expected id '%d', received '%d'", 1, id)
}

if a := resp.Links.Actions[0]; a.ID != 1 {
t.Errorf("expected action id '%d', received '%d'", 1, a.ID)
}
}

func TestDroplets_CreateWithoutDropletAgent(t *testing.T) {
setup()
defer teardown()
Expand Down Expand Up @@ -693,6 +776,97 @@ func TestDroplets_CreateMultiple(t *testing.T) {
}
}

func TestDroplets_CreateMultipleWithUsageBasedBackupPolicy(t *testing.T) {
setup()
defer teardown()

createRequest := &DropletMultiCreateRequest{
Names: []string{"name1", "name2"},
Region: "region",
Size: "size",
Image: DropletCreateImage{
ID: 1,
},
Backups: true,
BackupPolicy: &DropletBackupPolicyRequest{
Plan: "intra_daily_4h",
Hour: PtrTo(0),
WindowLengthHours: 4,
RetentionPeriodDays: 7,
},
}

mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
expected := map[string]interface{}{
"names": []interface{}{"name1", "name2"},
"region": "region",
"size": "size",
"image": float64(1),
"ssh_keys": nil,
"backups": true,
"ipv6": false,
"private_networking": false,
"monitoring": false,
"tags": nil,
"backup_policy": map[string]interface{}{
"plan": "intra_daily_4h",
"hour": float64(0),
"window_length_hours": float64(4),
"retention_period_days": float64(7),
},
}
jsonBlob := `
{
"droplets": [
{
"id": 1
},
{
"id": 2
}
],
"links": {
"actions": [
{
"id": 1,
"href": "http://example.com",
"rel": "multiple_create"
}
]
}
}
`

var v map[string]interface{}
err := json.NewDecoder(r.Body).Decode(&v)
if err != nil {
t.Fatalf("decode json: %v", err)
}

if !reflect.DeepEqual(v, expected) {
t.Errorf("Request body = %#v, expected %#v", v, expected)
}

fmt.Fprintf(w, jsonBlob)
})

droplets, resp, err := client.Droplets.CreateMultiple(ctx, createRequest)
if err != nil {
t.Errorf("Droplets.CreateMultiple returned error: %v", err)
}

if id := droplets[0].ID; id != 1 {
t.Errorf("expected id '%d', received '%d'", 1, id)
}
if id := droplets[1].ID; id != 2 {
t.Errorf("expected id '%d', received '%d'", 2, id)
}

if a := resp.Links.Actions[0]; a.ID != 1 {
t.Errorf("expected action id '%d', received '%d'", 1, a.ID)
}
}

func TestDroplets_Destroy(t *testing.T) {
setup()
defer teardown()
Expand Down