diff --git a/hack/test-dpj/contents/metadata/identifiers.json b/hack/test-dpj/contents/metadata/identifiers.json
new file mode 100644
index 00000000..41b8eae4
--- /dev/null
+++ b/hack/test-dpj/contents/metadata/identifiers.json
@@ -0,0 +1,11 @@
+[
+ {
+ "file": "objects/DPJ/journal/avlxml.xml",
+ "identifiers": [
+ {
+ "identifier": "2.16.578.1.39.100.11.9876.33",
+ "identifierType": "avleveringsidentifikator"
+ }
+ ]
+ }
+]
diff --git a/internal/nha/activities/activities.go b/internal/nha/activities/activities.go
index 44ed50fb..6f8da380 100644
--- a/internal/nha/activities/activities.go
+++ b/internal/nha/activities/activities.go
@@ -1,3 +1,5 @@
+// Package activities implements workflow activities specific to Norway Health
+// Authority.
package activities
var (
diff --git a/internal/nha/activities/hari.go b/internal/nha/activities/hari.go
index e694b9b3..41f5fe34 100644
--- a/internal/nha/activities/hari.go
+++ b/internal/nha/activities/hari.go
@@ -30,6 +30,7 @@ var hariClient = &http.Client{
},
}
+// UpdateHARIActivity delivers a receipt to HARI.
type UpdateHARIActivity struct {
manager *manager.Manager
}
@@ -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)
}
@@ -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
@@ -179,10 +192,14 @@ 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)
@@ -190,12 +207,14 @@ func (a UpdateHARIActivity) buildMock() *httptest.Server {
}))
}
+// 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.
diff --git a/internal/nha/activities/hari_test.go b/internal/nha/activities/hari_test.go
index 9091b2a7..fdd2c8da 100644
--- a/internal/nha/activities/hari_test.go
+++ b/internal/nha/activities/hari_test.go
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.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(``),
},
},
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("EPJ/journal"),
+ fs.WithFile("EPJ/journal/avlxml.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(``),
},
},
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("AVLXML/objekter"),
+ fs.WithFile("AVLXML/objekter/avlxml-2.16.578.1.39.100.11.9876.4-20191104.xml", ""),
+ },
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "avlxml",
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("AVLXML/objekter"),
+ fs.WithFile("AVLXML/objekter/avlxml.xml", ""),
+ },
wantReceipt: &avlRequest{
Message: "AVLXML was processed by Archivematica pipeline zr-fig-pipe-001",
Type: "avlxml",
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("OTHER/journal"),
+ fs.WithFile("OTHER/journal/avlxml.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(``),
},
},
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/Journal"),
+ fs.WithFile("DPJ/Journal/avlxml.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(``),
},
},
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.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(``),
},
},
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.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", ""),
+ },
+ 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", ""),
+ 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{
@@ -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", "")},
+ hariConfig: map[string]interface{}{},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.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(``),
},
wantErr: testutil.ActivityError{
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/_____other_name_____.xml", ""),
+ },
wantErr: testutil.ActivityError{
Message: "error reading AVLXML file: not found",
NRE: true,
@@ -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", "")},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.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,
},
},
}
diff --git a/internal/nha/activities/identifiers.go b/internal/nha/activities/identifiers.go
new file mode 100644
index 00000000..16209a9e
--- /dev/null
+++ b/internal/nha/activities/identifiers.go
@@ -0,0 +1,63 @@
+package activities
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+)
+
+// TransferIdentifiers is the type that maps to the JSON-encoded document found
+// in Archivematica transfers to list identifiers.
+type TransferIdentifiers []TransferIdentifier
+
+type TransferIdentifier struct {
+ File string `json:"file"`
+ Identifiers []TransferIdentifierPair `json:"identifiers"`
+}
+
+type TransferIdentifierPair struct {
+ // avleveringsidentifikator is the one we want
+ Type string `json:"identifierType"`
+ Value string `json:"identifier"`
+}
+
+// readIdentifiers returns the identifiers found in the given transfer path.
+func readIdentifiers(path string) (TransferIdentifiers, error) {
+ identifiers := TransferIdentifiers([]TransferIdentifier{})
+
+ blob, err := ioutil.ReadFile(filepath.Join(path, "metadata", "identifiers.json"))
+ if err != nil {
+ return nil, err
+ }
+
+ if err := json.Unmarshal(blob, &identifiers); err != nil {
+ return nil, err
+ }
+
+ return identifiers, nil
+}
+
+// readIdentifier returns the specified identifier found in the given transfer
+// path. file matching uses case-insensitive suffix matching.
+func readIdentifier(path string, fileSuffix string, idtype string) (string, error) {
+ identifiers, err := readIdentifiers(path)
+ if err != nil {
+ return "", fmt.Errorf("error reading identifier: %v", err)
+ }
+
+ for _, item := range identifiers {
+ if !strings.HasSuffix(strings.ToLower(item.File), strings.ToLower(fileSuffix)) {
+ continue
+ }
+ for _, pair := range item.Identifiers {
+ if pair.Type == idtype {
+ return pair.Value, nil
+ }
+ }
+ }
+
+ return "", errors.New("error reading identifier: not found")
+}
diff --git a/internal/nha/activities/prod.go b/internal/nha/activities/prod.go
index 55572b0e..fe99d80d 100644
--- a/internal/nha/activities/prod.go
+++ b/internal/nha/activities/prod.go
@@ -31,6 +31,7 @@ type UpdateProductionSystemActivityParams struct {
StoredAt time.Time
PipelineName string
NameInfo nha.NameInfo
+ FullPath string
}
func (a *UpdateProductionSystemActivity) Execute(ctx context.Context, params *UpdateProductionSystemActivityParams) error {
@@ -55,8 +56,19 @@ func (a *UpdateProductionSystemActivity) Execute(ctx context.Context, params *Up
return wferrors.NonRetryableError(fmt.Errorf("error creating receipt file: %v", err))
}
+ 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))
+ }
+ }
+ }
+
// Write receipt contents.
- if err := a.generateReceipt(params, file); err != nil {
+ if err := a.generateReceipt(params, file, parentID); err != nil {
return wferrors.NonRetryableError(fmt.Errorf("error writing receipt file: %v", err))
}
@@ -75,13 +87,14 @@ func (a *UpdateProductionSystemActivity) Execute(ctx context.Context, params *Up
return nil
}
-func (a UpdateProductionSystemActivity) generateReceipt(params *UpdateProductionSystemActivityParams, file *os.File) error {
+func (a UpdateProductionSystemActivity) generateReceipt(params *UpdateProductionSystemActivityParams, file *os.File, parentID string) error {
receipt := prodSystemReceipt{
Identifier: params.NameInfo.Identifier,
Type: params.NameInfo.Type.Lower(),
Accepted: true,
Message: fmt.Sprintf("Package was processed by Archivematica pipeline %s", params.PipelineName),
Timestamp: params.StoredAt,
+ Parent: parentID,
}
enc := json.NewEncoder(file)
@@ -98,9 +111,10 @@ func (a UpdateProductionSystemActivity) generateReceipt(params *UpdateProduction
}
type prodSystemReceipt struct {
- Identifier string `json:"identifier"` // Original identifier.
- Type string `json:"type"` // Lowercase. E.g. "dpj", "epj", "other" or "avlxml".
- Accepted bool `json:"accepted"` // Whether we have an error during processing.
- Message string `json:"message"` // E.g. "Package was processed by Archivematica pipeline am" or any other error message.
- Timestamp time.Time `json:"timestamp"` // RFC3339, e.g. "2006-01-02T15:04:05Z07:00"
+ Identifier string `json:"identifier"` // Original identifier.
+ Type string `json:"type"` // Lowercase. E.g. "dpj", "epj", "other" or "avlxml".
+ Accepted bool `json:"accepted"` // Whether we have an error during processing.
+ Message string `json:"message"` // E.g. "Package was processed by Archivematica pipeline am" or any other error message.
+ Timestamp time.Time `json:"timestamp"` // RFC3339, e.g. "2006-01-02T15:04:05Z07:00"
+ Parent string `json:"parent,omitempty"` // avleveringsidentifikator (only concerns DPJ and EPJ SIPs)
}
diff --git a/internal/nha/activities/prod_test.go b/internal/nha/activities/prod_test.go
index 9804785b..cd07f8d1 100644
--- a/internal/nha/activities/prod_test.go
+++ b/internal/nha/activities/prod_test.go
@@ -32,6 +32,7 @@ func TestProdActivity(t *testing.T) {
tests := map[string]struct {
params UpdateProductionSystemActivityParams
hookConfig *map[string]interface{}
+ dirOpts []fs.PathOp
wantContent string
wantErr testutil.ActivityError
}{
@@ -44,11 +45,46 @@ func TestProdActivity(t *testing.T) {
Type: nha.TransferTypeDPJ,
},
},
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.xml", ""),
+ fs.WithDir("metadata"),
+ fs.WithFile("metadata/identifiers.json", `[{
+ "file": "objects/DPJ/journal/avlxml.xml",
+ "identifiers": [{
+ "identifierType": "avleveringsidentifikator",
+ "identifier": "12345"
+ }]
+ }]`),
+ },
wantContent: `{
"identifier": "aa1df25d-1477-4085-8be3-a17fed20f843",
"type": "dpj",
"accepted": true,
"message": "Package was processed by Archivematica pipeline foo-bar-001",
+ "timestamp": "2009-11-10T23:00:00Z",
+ "parent": "12345"
+}
+`,
+ },
+ "Receipt does not include parentID in AVLXML SIP": {
+ params: UpdateProductionSystemActivityParams{
+ StoredAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
+ PipelineName: "foo-bar-001",
+ NameInfo: nha.NameInfo{
+ Identifier: "aa1df25d-1477-4085-8be3-a17fed20f843",
+ Type: nha.TransferTypeAVLXML,
+ },
+ },
+ dirOpts: []fs.PathOp{
+ fs.WithDir("DPJ/journal"),
+ fs.WithFile("DPJ/journal/avlxml.xml", ""),
+ },
+ wantContent: `{
+ "identifier": "aa1df25d-1477-4085-8be3-a17fed20f843",
+ "type": "avlxml",
+ "accepted": true,
+ "message": "Package was processed by Archivematica pipeline foo-bar-001",
"timestamp": "2009-11-10T23:00:00Z"
}
`,
@@ -93,6 +129,10 @@ func TestProdActivity(t *testing.T) {
t.Run(name, func(t *testing.T) {
t.Parallel()
+ transferDir := fs.NewDir(t, "enduro", tc.dirOpts...)
+ defer transferDir.Remove()
+ tc.params.FullPath = transferDir.Path()
+
tmpdir := fs.NewDir(t, "enduro")
defer tmpdir.Remove()
hookConfig := map[string]interface{}{"receiptPath": tmpdir.Path()}
diff --git a/internal/nha/doc.go b/internal/nha/doc.go
new file mode 100644
index 00000000..1fea6b5a
--- /dev/null
+++ b/internal/nha/doc.go
@@ -0,0 +1,2 @@
+// Package nha includes solutions that are specific to Norway Health Authority.
+package nha
diff --git a/internal/testutil/activity.go b/internal/testutil/activity.go
index f5ebf59b..07d70970 100644
--- a/internal/testutil/activity.go
+++ b/internal/testutil/activity.go
@@ -85,5 +85,8 @@ func (ae ActivityError) assertNonRetryableError(t *testing.T, err error) {
var result string
perr := err.(*cadence.CustomError)
assert.NilError(t, perr.Details(&result))
- assert.Equal(t, result, ae.message())
+
+ if ae.message() != "" {
+ assert.Equal(t, result, ae.message())
+ }
}
diff --git a/internal/workflow/receipts.go b/internal/workflow/receipts.go
index 762a01f7..93a0705a 100644
--- a/internal/workflow/receipts.go
+++ b/internal/workflow/receipts.go
@@ -53,6 +53,7 @@ func (w *ProcessingWorkflow) sendReceipts(ctx workflow.Context, params *sendRece
StoredAt: params.StoredAt,
PipelineName: params.PipelineName,
NameInfo: params.NameInfo,
+ FullPath: params.FullPath,
}).Get(ctx, nil)
if err != nil {
diff --git a/internal/workflow/receipts_test.go b/internal/workflow/receipts_test.go
index 4d00ff45..164789de 100644
--- a/internal/workflow/receipts_test.go
+++ b/internal/workflow/receipts_test.go
@@ -121,6 +121,7 @@ func TestSendReceipts(t *testing.T) {
StoredAt: params.StoredAt,
PipelineName: params.PipelineName,
NameInfo: params.NameInfo,
+ FullPath: params.FullPath,
},
).Return(nil).Once()