Skip to content

Commit

Permalink
MLPAB-1777 Add PERFECT update type and status (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
hawx authored Apr 25, 2024
1 parent 7dab199 commit e34df89
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 113 deletions.
1 change: 1 addition & 0 deletions docs/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ components:
- CERTIFICATE_PROVIDER_SIGN
- ATTORNEY_SIGN
- TRUST_CORPORATION_SIGN
- PERFECT
- REGISTER
changes:
type: array
Expand Down
1 change: 1 addition & 0 deletions internal/shared/lpa.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ type LpaStatus string

const (
LpaStatusProcessing = LpaStatus("processing")
LpaStatusPerfect = LpaStatus("perfect")
LpaStatusRegistered = LpaStatus("registered")
)
47 changes: 47 additions & 0 deletions lambda/update/perfect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"github.com/ministryofjustice/opg-data-lpa-store/internal/shared"
)

type Perfect struct{}

func (r Perfect) Apply(lpa *shared.Lpa) []shared.FieldError {
if lpa.Status != shared.LpaStatusProcessing {
return []shared.FieldError{{Source: "/type", Detail: "status must be processing to make perfect"}}
}

if lpa.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must be signed"}}
}

if lpa.CertificateProvider.SignedAt == nil || lpa.CertificateProvider.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must have a certificate"}}
}

for _, a := range lpa.Attorneys {
if a.SignedAt == nil || a.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by attorneys"}}
}
}

for _, t := range lpa.TrustCorporations {
for _, s := range t.Signatories {
if s.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by trust corporations"}}
}
}
}

lpa.Status = shared.LpaStatusPerfect

return nil
}

func validatePerfect(changes []shared.Change) (Perfect, []shared.FieldError) {
if len(changes) > 0 {
return Perfect{}, []shared.FieldError{{Source: "/changes", Detail: "expected empty"}}
}

return Perfect{}, nil
}
126 changes: 126 additions & 0 deletions lambda/update/perfect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package main

import (
"testing"
"time"

"github.com/ministryofjustice/opg-data-lpa-store/internal/shared"
"github.com/stretchr/testify/assert"
)

func TestPerfectApply(t *testing.T) {
now := time.Now()

lpa := &shared.Lpa{
Status: shared.LpaStatusProcessing,
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{
SignedAt: &now,
},
Attorneys: []shared.Attorney{{
SignedAt: &now,
}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{
SignedAt: now,
}},
}},
},
}

errors := Perfect{}.Apply(lpa)
assert.Nil(t, errors)
assert.Equal(t, shared.LpaStatusPerfect, lpa.Status)
}

func TestPerfectApplyWhenUnsigned(t *testing.T) {
now := time.Now()

testcases := map[string]struct {
lpa *shared.Lpa
errors []shared.FieldError
}{
"lpa": {
lpa: &shared.Lpa{
Status: shared.LpaStatusProcessing,
LpaInit: shared.LpaInit{
CertificateProvider: shared.CertificateProvider{SignedAt: &now},
Attorneys: []shared.Attorney{{SignedAt: &now}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must be signed"}},
},
"certificate provider": {
lpa: &shared.Lpa{
Status: shared.LpaStatusProcessing,
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{},
Attorneys: []shared.Attorney{{SignedAt: &now}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must have a certificate"}},
},
"attorney": {
lpa: &shared.Lpa{
Status: shared.LpaStatusProcessing,
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{SignedAt: &now},
Attorneys: []shared.Attorney{{SignedAt: &now}, {}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by attorneys"}},
},
"trust corporation": {
lpa: &shared.Lpa{
Status: shared.LpaStatusProcessing,
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{SignedAt: &now},
Attorneys: []shared.Attorney{{SignedAt: &now}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}, {}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by trust corporations"}},
},
}

for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
errors := Perfect{}.Apply(tc.lpa)
assert.Equal(t, tc.errors, errors)
})
}
}

func TestRegisterApplyWhenNotProcessing(t *testing.T) {
for _, status := range []shared.LpaStatus{shared.LpaStatusPerfect, shared.LpaStatusRegistered} {
t.Run(string(status), func(t *testing.T) {
errors := Perfect{}.Apply(&shared.Lpa{Status: status})
assert.Equal(t, []shared.FieldError{{Source: "/type", Detail: "status must be processing to make perfect"}}, errors)
})
}
}

func TestValidatePerfect(t *testing.T) {
_, errors := validatePerfect(nil)
assert.Nil(t, errors)
}

func TestValidatePerfectWhenChanges(t *testing.T) {
_, errors := validatePerfect([]shared.Change{{}})
assert.Equal(t, []shared.FieldError{{Source: "/changes", Detail: "expected empty"}}, errors)
}
26 changes: 2 additions & 24 deletions lambda/update/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,8 @@ import (
type Register struct{}

func (r Register) Apply(lpa *shared.Lpa) []shared.FieldError {
if lpa.RegistrationDate != nil && !lpa.RegistrationDate.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa already registered"}}
}

if lpa.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must be signed"}}
}

if lpa.CertificateProvider.SignedAt == nil || lpa.CertificateProvider.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must have a certificate"}}
}

for _, a := range lpa.Attorneys {
if a.SignedAt == nil || a.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by attorneys"}}
}
}

for _, t := range lpa.TrustCorporations {
for _, s := range t.Signatories {
if s.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by trust corporations"}}
}
}
if lpa.Status != shared.LpaStatusPerfect {
return []shared.FieldError{{Source: "/type", Detail: "status must be perfect to register"}}
}

now := time.Now().UTC()
Expand Down
95 changes: 6 additions & 89 deletions lambda/update/register_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,7 @@ func TestRegisterApply(t *testing.T) {
now := time.Now()

lpa := &shared.Lpa{
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{
SignedAt: &now,
},
Attorneys: []shared.Attorney{{
SignedAt: &now,
}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{
SignedAt: now,
}},
}},
},
Status: shared.LpaStatusPerfect,
}

errors := Register{}.Apply(lpa)
Expand All @@ -34,85 +21,15 @@ func TestRegisterApply(t *testing.T) {
assert.Equal(t, shared.LpaStatusRegistered, lpa.Status)
}

func TestRegisterApplyWhenUnsigned(t *testing.T) {
now := time.Now()

testcases := map[string]struct {
lpa *shared.Lpa
errors []shared.FieldError
}{
"lpa": {
lpa: &shared.Lpa{
LpaInit: shared.LpaInit{
CertificateProvider: shared.CertificateProvider{SignedAt: &now},
Attorneys: []shared.Attorney{{SignedAt: &now}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must be signed"}},
},
"certificate provider": {
lpa: &shared.Lpa{
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{},
Attorneys: []shared.Attorney{{SignedAt: &now}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must have a certificate"}},
},
"attorney": {
lpa: &shared.Lpa{
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{SignedAt: &now},
Attorneys: []shared.Attorney{{SignedAt: &now}, {}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by attorneys"}},
},
"trust corporation": {
lpa: &shared.Lpa{
LpaInit: shared.LpaInit{
SignedAt: now,
CertificateProvider: shared.CertificateProvider{SignedAt: &now},
Attorneys: []shared.Attorney{{SignedAt: &now}},
TrustCorporations: []shared.TrustCorporation{{
Signatories: []shared.Signatory{{SignedAt: now}, {}},
}},
},
},
errors: []shared.FieldError{{Source: "/type", Detail: "lpa must be signed by trust corporations"}},
},
}

for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
errors := Register{}.Apply(tc.lpa)
assert.Equal(t, tc.errors, errors)
func TestRegisterApplyWhenNotPerfect(t *testing.T) {
for _, status := range []shared.LpaStatus{shared.LpaStatusProcessing, shared.LpaStatusRegistered} {
t.Run(string(status), func(t *testing.T) {
errors := Register{}.Apply(&shared.Lpa{Status: status})
assert.Equal(t, []shared.FieldError{{Source: "/type", Detail: "status must be perfect to register"}}, errors)
})
}
}

func TestRegisterApplyWhenAlreadyRegistered(t *testing.T) {
now := time.Now()

lpa := &shared.Lpa{
RegistrationDate: &now,
}

errors := Register{}.Apply(lpa)
assert.Equal(t, []shared.FieldError{{Source: "/type", Detail: "lpa already registered"}}, errors)
}

func TestValidateRegister(t *testing.T) {
_, errors := validateRegister(nil)
assert.Nil(t, errors)
Expand Down
2 changes: 2 additions & 0 deletions lambda/update/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ func validateUpdate(update shared.Update, lpa *shared.Lpa) (Applyable, []shared.
return validateAttorneySign(update.Changes)
case "TRUST_CORPORATION_SIGN":
return validateTrustCorporationSign(update.Changes)
case "PERFECT":
return validatePerfect(update.Changes)
case "REGISTER":
return validateRegister(update.Changes)
default:
Expand Down

0 comments on commit e34df89

Please sign in to comment.