Skip to content

Commit

Permalink
nha: include avleveringsidentifikator in receipts
Browse files Browse the repository at this point in the history
  • Loading branch information
sevein committed Mar 8, 2020
1 parent 2b2183b commit db42a36
Show file tree
Hide file tree
Showing 11 changed files with 336 additions and 30 deletions.
11 changes: 11 additions & 0 deletions hack/test-dpj/contents/metadata/identifiers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"file": "objects/DPJ/journal/avlxml.xml",
"identifiers": [
{
"identifier": "2.16.578.1.39.100.11.9876.33",
"identifierType": "avleveringsidentifikator"
}
]
}
]
2 changes: 2 additions & 0 deletions internal/nha/activities/activities.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package activities implements workflow activities specific to Norway Health
// Authority.
package activities

var (
Expand Down
35 changes: 27 additions & 8 deletions internal/nha/activities/hari.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var hariClient = &http.Client{
},
}

// UpdateHARIActivity delivers a receipt to HARI.
type UpdateHARIActivity struct {
manager *manager.Manager
}
Expand Down Expand Up @@ -73,7 +74,18 @@ func (a UpdateHARIActivity) Execute(ctx context.Context, params *UpdateHARIActiv
return wferrors.NonRetryableError(fmt.Errorf("error reading AVLXML file: %v", err))
}

if err := a.sendRequest(ctx, blob, apiURL, params.NameInfo.Type, params); err != nil {
var parentID string
{
if params.NameInfo.Type != nha.TransferTypeAVLXML {
const idtype = "avleveringsidentifikator"
parentID, err = readIdentifier(params.FullPath, params.NameInfo.Type.String()+"/journal/avlxml.xml", idtype)
if err != nil {
return wferrors.NonRetryableError(fmt.Errorf("error looking up avleveringsidentifikator: %v", err))
}
}
}

if err := a.sendRequest(ctx, blob, apiURL, params.NameInfo.Type, parentID, params); err != nil {
return fmt.Errorf("error sending request: %v", err)
}

Expand Down Expand Up @@ -132,13 +144,14 @@ func (a UpdateHARIActivity) url() (string, error) {
return bu.ResolveReference(p).String(), nil
}

func (a UpdateHARIActivity) sendRequest(ctx context.Context, blob []byte, apiURL string, kind nha.TransferType, params *UpdateHARIActivityParams) error {
func (a UpdateHARIActivity) sendRequest(ctx context.Context, blob []byte, apiURL string, kind nha.TransferType, parentID string, params *UpdateHARIActivityParams) error {
payload := &avlRequest{
XML: blob,
Message: fmt.Sprintf("AVLXML was processed by Archivematica pipeline %s", params.PipelineName),
Type: kind.Lower(),
Timestamp: avlRequestTime{params.StoredAt},
AIPID: params.SIPID,
Parent: parentID,
}

var buffer bytes.Buffer
Expand Down Expand Up @@ -179,23 +192,29 @@ func (a UpdateHARIActivity) sendRequest(ctx context.Context, blob []byte, apiURL
// buildMock returns a test server used when HARI's API is not available.
func (a UpdateHARIActivity) buildMock() *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
a.manager.Logger.Info(
blob, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()

a.manager.Logger.V(1).Info(
"Request received",
"method", r.Method,
"path", r.URL.Path,
"body", string(blob),
)

w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, `{"message": "ok"}`)
}))
}

// avlRequest is the payload of the HTTP request delivered to HARI.
type avlRequest struct {
XML []byte `json:"xml"` // AVLXML document encoded using base64.
Message string `json:"message"` // E.g.: "AVLXML was processed by DPJ Archivematica pipeline"
Type string `json:"type"` // Lowercase. E.g.: "dpj", "epj", "other" or "avlxml".
Timestamp avlRequestTime `json:"timestamp"` // E.g.: "2018-11-12T20:20:39+00:00".
AIPID string `json:"aip_id"`
XML []byte `json:"xml"` // AVLXML document encoded using base64.
Message string `json:"message"` // E.g.: "AVLXML was processed by DPJ Archivematica pipeline"
Type string `json:"type"` // Lowercase. E.g.: "dpj", "epj", "other" or "avlxml".
Timestamp avlRequestTime `json:"timestamp"` // E.g.: "2018-11-12T20:20:39+00:00".
AIPID string `json:"aip_id"` // Typically a UUID.
Parent string `json:"parent,omitempty"` // avleveringsidentifikator (only concerns DPJ and EPJ SIPs)
}

// avlRequestTime encodes time in JSON using the format expected by HARI.
Expand Down
178 changes: 164 additions & 14 deletions internal/nha/activities/hari_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,33 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/journal"), fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/DPJ/aFoobar.jpg",
"identifiers": [{
"identifierType": "organisasjonsnummer",
"identifier": "123456789"
}]
}, {
"file": "objects/DPJ/journal/avlxml.xml",
"identifiers": [{
"identifierType": "organisasjonsnummer",
"identifier": "123456789"
}, {
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "dpj",
Timestamp: avlRequestTime{time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
AIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
Parent: "12345",
XML: []byte(`<xml/>`),
},
},
Expand All @@ -86,12 +107,24 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("EPJ/journal"), fs.WithFile("EPJ/journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("EPJ/journal"),
fs.WithFile("EPJ/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/EPJ/journal/avlxml.xml",
"identifiers": [{
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "epj",
Timestamp: avlRequestTime{time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
AIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
Parent: "12345",
XML: []byte(`<xml/>`),
},
},
Expand All @@ -106,7 +139,10 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("AVLXML/objekter"), fs.WithFile("AVLXML/objekter/avlxml-2.16.578.1.39.100.11.9876.4-20191104.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("AVLXML/objekter"),
fs.WithFile("AVLXML/objekter/avlxml-2.16.578.1.39.100.11.9876.4-20191104.xml", "<xml/>"),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "avlxml",
Expand All @@ -126,7 +162,10 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("AVLXML/objekter"), fs.WithFile("AVLXML/objekter/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("AVLXML/objekter"),
fs.WithFile("AVLXML/objekter/avlxml.xml", "<xml/>"),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "avlxml",
Expand All @@ -146,12 +185,24 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("OTHER/journal"), fs.WithFile("OTHER/journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("OTHER/journal"),
fs.WithFile("OTHER/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/OTHER/journal/avlxml.xml",
"identifiers": [{
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "other",
Timestamp: avlRequestTime{time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
AIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
Parent: "12345",
XML: []byte(`<xml/>`),
},
},
Expand All @@ -166,12 +217,24 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/Journal"), fs.WithFile("DPJ/Journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/Journal"),
fs.WithFile("DPJ/Journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/DPJ/Journal/avlxml.xml",
"identifiers": [{
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "dpj",
Timestamp: avlRequestTime{time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
AIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
Parent: "12345",
XML: []byte(`<xml/>`),
},
},
Expand All @@ -186,12 +249,24 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/journal"), fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/DPJ/journal/avlxml.xml",
"identifiers": [{
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "dpj",
Timestamp: avlRequestTime{time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
AIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
Parent: "12345",
XML: []byte(`<xml/>`),
},
},
Expand All @@ -206,7 +281,65 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{"mock": true},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/journal"), fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/DPJ/journal/avlxml.xml",
"identifiers": [{
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
},
"Failure when identifiers.json is missing (DPJ/EPJ/OTHER)": {
params: UpdateHARIActivityParams{
StoredAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
SIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
PipelineName: "zr-fig-pipe-001",
NameInfo: nha.NameInfo{
Identifier: "049d6a44-07d6-4aa9-9607-9347ec4d0b23",
Type: nha.TransferTypeDPJ,
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
},
wantErr: testutil.ActivityError{
NRE: true,
},
},
"Failure when identifier cannot be found (DPJ/EPJ/OTHER)": {
params: UpdateHARIActivityParams{
StoredAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
SIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
PipelineName: "zr-fig-pipe-001",
NameInfo: nha.NameInfo{
Identifier: "049d6a44-07d6-4aa9-9607-9347ec4d0b23",
Type: nha.TransferTypeDPJ,
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/DPJ/journal/avlxml.xml",
"identifiers": [{
"identifierType": "not-the-identifier-we-wanted",
"identifier": "12345"
}]
}]`),
},
wantErr: testutil.ActivityError{
Message: "error looking up avleveringsidentifikator: error reading identifier: not found",
NRE: true,
},
},
"Failure when HARI returns a server error": {
params: UpdateHARIActivityParams{
Expand All @@ -218,14 +351,26 @@ func TestHARIActivity(t *testing.T) {
Type: nha.TransferTypeDPJ,
},
},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/journal"), fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>")},
hariConfig: map[string]interface{}{},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
fs.WithDir("metadata"),
fs.WithFile("metadata/identifiers.json", `[{
"file": "objects/DPJ/journal/avlxml.xml",
"identifiers": [{
"identifierType": "avleveringsidentifikator",
"identifier": "12345"
}]
}]`),
},
wantResponse: &serverResponse{code: 500, status: "Backend server not available, try again later."},
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "dpj",
Timestamp: avlRequestTime{time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
AIPID: "1db240cc-3cea-4e55-903c-6280562e1866",
Parent: "12345",
XML: []byte(`<xml/>`),
},
wantErr: testutil.ActivityError{
Expand All @@ -243,7 +388,10 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{"baseURL": "http://192.168.1.50:12345"},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/journal"), fs.WithFile("DPJ/journal/_____other_name_____.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/_____other_name_____.xml", "<xml/>"),
},
wantErr: testutil.ActivityError{
Message: "error reading AVLXML file: not found",
NRE: true,
Expand All @@ -259,10 +407,12 @@ func TestHARIActivity(t *testing.T) {
},
},
hariConfig: map[string]interface{}{"baseURL": string([]byte{0x7f})},
dirOpts: []fs.PathOp{fs.WithDir("DPJ/journal"), fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>")},
dirOpts: []fs.PathOp{
fs.WithDir("DPJ/journal"),
fs.WithFile("DPJ/journal/avlxml.xml", "<xml/>"),
},
wantErr: testutil.ActivityError{
Message: fmt.Sprintf("error in URL construction: error looking up baseURL configuration attribute: parse %s/: net/url: invalid control character in URL", string(0x7f)),
NRE: true,
NRE: true,
},
},
}
Expand Down
Loading

0 comments on commit db42a36

Please sign in to comment.