CdrExporter using Value instead CdrFieldId for better flexibility

This commit is contained in:
DanB
2015-02-11 19:31:22 +01:00
parent 1fe2c60365
commit 654e0cfe12
5 changed files with 79 additions and 69 deletions

View File

@@ -36,17 +36,17 @@ const (
COST_DETAILS = "cost_details"
CONCATENATED_CDRFIELD = "concatenated_cdrfield"
DATETIME = "datetime"
META_EXPORTID = "export_id"
META_TIMENOW = "time_now"
META_FIRSTCDRATIME = "first_cdr_atime"
META_LASTCDRATIME = "last_cdr_atime"
META_NRCDRS = "cdrs_number"
META_DURCDRS = "cdrs_duration"
META_SMSUSAGE = "sms_usage"
META_DATAUSAGE = "data_usage"
META_COSTCDRS = "cdrs_cost"
META_MASKDESTINATION = "mask_destination"
META_FORMATCOST = "format_cost"
META_EXPORTID = "*export_id"
META_TIMENOW = "*time_now"
META_FIRSTCDRATIME = "*first_cdr_atime"
META_LASTCDRATIME = "*last_cdr_atime"
META_NRCDRS = "*cdrs_number"
META_DURCDRS = "*cdrs_duration"
META_SMSUSAGE = "*sms_usage"
META_DATAUSAGE = "*data_usage"
META_COSTCDRS = "*cdrs_cost"
META_MASKDESTINATION = "*mask_destination"
META_FORMATCOST = "*format_cost"
)
var err error
@@ -248,16 +248,12 @@ func (cdre *CdrExporter) composeHeader() error {
var outVal string
switch cfgFld.Type {
case utils.FILLER:
for _, rsrFld := range cfgFld.Value {
outVal += rsrFld.ParseValue("")
}
outVal = cfgFld.Value.Id()
cfgFld.Padding = "right"
case utils.CONSTANT:
for _, rsrFld := range cfgFld.Value {
outVal += rsrFld.ParseValue("")
}
outVal = cfgFld.Value.Id()
case utils.METATAG:
outVal, err = cdre.metaHandler(cfgFld.CdrFieldId, cfgFld.Layout)
outVal, err = cdre.metaHandler(cfgFld.Value.Id(), cfgFld.Layout)
default:
return fmt.Errorf("Unsupported field type: %s", cfgFld.Type)
}
@@ -281,16 +277,12 @@ func (cdre *CdrExporter) composeTrailer() error {
var outVal string
switch cfgFld.Type {
case utils.FILLER:
for _, rsrFld := range cfgFld.Value {
outVal += rsrFld.ParseValue("")
}
outVal = cfgFld.Value.Id()
cfgFld.Padding = "right"
case utils.CONSTANT:
for _, rsrFld := range cfgFld.Value {
outVal += rsrFld.ParseValue("")
}
outVal = cfgFld.Value.Id()
case utils.METATAG:
outVal, err = cdre.metaHandler(cfgFld.CdrFieldId, cfgFld.Layout)
outVal, err = cdre.metaHandler(cfgFld.Value.Id(), cfgFld.Layout)
default:
return fmt.Errorf("Unsupported field type: %s", cfgFld.Type)
}
@@ -328,25 +320,20 @@ func (cdre *CdrExporter) processCdr(cdr *utils.StoredCdr) error {
var outVal string
switch cfgFld.Type {
case utils.FILLER:
for _, rsrFld := range cfgFld.Value {
outVal += rsrFld.ParseValue("")
}
outVal = cfgFld.Value.Id()
cfgFld.Padding = "right"
case utils.CONSTANT:
for _, rsrFld := range cfgFld.Value {
outVal += rsrFld.ParseValue("")
}
outVal = cfgFld.Value.Id()
case utils.CDRFIELD:
outVal, err = cdre.cdrFieldValue(cdr, cfgFld)
case DATETIME:
outVal, err = cdre.getDateTimeFieldVal(cdr, cfgFld)
case utils.HTTP_POST:
var outValByte []byte
var httpAddr string
for _, rsrFld := range cfgFld.Value {
httpAddr += rsrFld.ParseValue("")
}
if outValByte, err = utils.HttpJsonPost(httpAddr, cdre.httpSkipTlsCheck, cdr); err == nil {
httpAddr := cfgFld.Value.Id()
if len(httpAddr) == 0 {
err = fmt.Errorf("Empty http address for field %s type %s", cfgFld.Tag, cfgFld.Type)
} else if outValByte, err = utils.HttpJsonPost(httpAddr, cdre.httpSkipTlsCheck, cdr); err == nil {
outVal = string(outValByte)
if len(outVal) == 0 && cfgFld.Mandatory {
err = fmt.Errorf("Empty result for http_post field: %s", cfgFld.Tag)
@@ -355,10 +342,10 @@ func (cdre *CdrExporter) processCdr(cdr *utils.StoredCdr) error {
case utils.COMBIMED:
outVal, err = cdre.getCombimedCdrFieldVal(cdr, cfgFld)
case utils.METATAG:
if cfgFld.CdrFieldId == META_MASKDESTINATION {
outVal, err = cdre.metaHandler(cfgFld.CdrFieldId, cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}))
if cfgFld.Value.Id() == META_MASKDESTINATION {
outVal, err = cdre.metaHandler(cfgFld.Value.Id(), cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}))
} else {
outVal, err = cdre.metaHandler(cfgFld.CdrFieldId, cfgFld.Layout)
outVal, err = cdre.metaHandler(cfgFld.Value.Id(), cfgFld.Layout)
}
}
if err != nil {

View File

@@ -30,21 +30,21 @@ import (
)
var hdrJsnCfgFlds = []*config.CdrFieldJsonCfg{
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^10"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("10"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(3)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^VOI"), Width: utils.IntPointer(3)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer("export_id"),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("VOI"), Width: utils.IntPointer(3)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_EXPORTID),
Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdr"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_LASTCDRATIME),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdr"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_LASTCDRATIME),
Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileCreationfTime"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer("time_now"),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileCreationfTime"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_TIMENOW),
Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileVersion"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^01"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileVersion"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("01"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(105)},
}
var contentJsnCfgFlds = []*config.CdrFieldJsonCfg{
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^20"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("20"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.ACCOUNT), Width: utils.IntPointer(12),
Strip: utils.StringPointer("left"), Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.SUBJECT), Width: utils.IntPointer(5),
@@ -53,20 +53,20 @@ var contentJsnCfgFlds = []*config.CdrFieldJsonCfg{
Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.DESTINATION), Width: utils.IntPointer(24),
Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^02"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("SubtypeTOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^11"), Width: utils.IntPointer(4),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("02"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("SubtypeTOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("11"), Width: utils.IntPointer(4),
Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.SETUP_TIME), Width: utils.IntPointer(12),
Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right"), Layout: utils.StringPointer("020106150400")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Duration"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.USAGE), Width: utils.IntPointer(6),
Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right"), Layout: utils.StringPointer(utils.SECONDS)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DataVolume"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(6)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TaxCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^1"), Width: utils.IntPointer(1)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TaxCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("1"), Width: utils.IntPointer(1)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("OperatorCode"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("opercode"), Width: utils.IntPointer(2),
Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("ProductId"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("productid"), Width: utils.IntPointer(5),
Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("NetworkId"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^3"), Width: utils.IntPointer(1)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("NetworkId"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("3"), Width: utils.IntPointer(1)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("CallId"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.ACCID), Width: utils.IntPointer(16),
Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(8)},
@@ -75,23 +75,23 @@ var contentJsnCfgFlds = []*config.CdrFieldJsonCfg{
Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.COST), Width: utils.IntPointer(9),
Padding: utils.StringPointer("zeroleft")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DestinationPrivacy"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_MASKDESTINATION),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DestinationPrivacy"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_MASKDESTINATION),
Width: utils.IntPointer(1)},
}
var trailerJsnCfgFlds = []*config.CdrFieldJsonCfg{
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^90"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("90"), Width: utils.IntPointer(2)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(3)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^VOI"), Width: utils.IntPointer(3)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_EXPORTID), Width: utils.IntPointer(5),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("VOI"), Width: utils.IntPointer(3)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_EXPORTID), Width: utils.IntPointer(5),
Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("NumberOfRecords"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_NRCDRS),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("NumberOfRecords"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_NRCDRS),
Width: utils.IntPointer(6), Padding: utils.StringPointer("zeroleft")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("CdrsDuration"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_DURCDRS),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("CdrsDuration"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_DURCDRS),
Width: utils.IntPointer(8), Padding: utils.StringPointer("zeroleft"), Layout: utils.StringPointer(utils.SECONDS)},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FirstCdrTime"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_FIRSTCDRATIME),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("FirstCdrTime"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_FIRSTCDRATIME),
Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdrTime"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_LASTCDRATIME),
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdrTime"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_LASTCDRATIME),
Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
&config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(93)},
}

View File

@@ -79,17 +79,17 @@
{"tag": "ToR", "type": "constant", "value": "10", "width": 2},
{"tag": "Filler1", "type": "filler", "width": 3},
{"tag": "FileType", "type": "constant", "value": "SIP", "width": 3},
{"tag": "FileSeqNr", "type": "metatag", "value": "export_id", "padding": "zeroleft", "width": 5},
{"tag": "LastCdr", "type": "metatag", "value": "last_cdr_atime", "layout": "020106150405", "width": 12},
{"tag": "FileCreationfTime", "type": "metatag", "value": "time_now", "layout": "020106150405", "width": 12},
{"tag": "FileSeqNr", "type": "metatag", "cdr_field_id": "*export_id", "padding": "zeroleft", "width": 5},
{"tag": "LastCdr", "type": "metatag", "cdr_field_id": "*last_cdr_atime", "layout": "020106150405", "width": 12},
{"tag": "FileCreationfTime", "type": "metatag", "cdr_field_id": "*time_now", "layout": "020106150405", "width": 12},
{"tag": "FileVersion", "type": "constant", "value": "01", "width": 2},
{"tag": "Filler2", "type": "filler", "width": 105},
], // template of the exported header fields
"content_fields": [ // template of the exported content fields
{"tag": "ToR", "type": "constant", "value": "20", "width": 2},
{"tag": "Subject", "type": "cdrfield", "value": "subject", "width": 12, "padding": "right", "mandatory": true},
{"tag": "Subject", "type": "cdrfield", "cdr_field_id": "subject", "width": 12, "padding": "right", "mandatory": true},
{"tag": "ConnectionNumber", "type": "constant", "value": "00000", "width": 5},
{"tag": "CallerId", "type": "cdrfield", "value": "~callerid:s/\\+(\\d+)/00$1/", "strip": "xright", "width": 15, "padding": "right"},
{"tag": "CallerId", "type": "cdrfield", "cdr_field_id": "~callerid:s/\\+(\\d+)/00$1/", "strip": "xright", "width": 15, "padding": "right"},
{"tag": "Destination", "type": "cdrfield", "value": "~destination:s/^\\+311400(\\d+)/$1/:s/^\\+311412\\d\\d112/112/:s/^\\+31(\\d+)/0$1/:s/^\\+(\\d+)/00$1/",
"strip": "xright", "width": 24, "padding": "right", "mandatory": true},
{"tag": "TypeOfService", "type": "constant", "value": "00", "width": 2},
@@ -106,17 +106,17 @@
{"tag": "FillerVolume2", "type": "filler", "width": 8},
{"tag": "DestinationSubId", "type": "cdrfield", "value": "~cost_details:s/MatchedDestId:.+_(\\w{5})/$1/:s/(\\w{6})/$1/", "width": 5},
{"tag": "Cost", "type": "cdrfield", "value": "cost", "padding": "zeroleft", "width": 9},
{"tag": "MaskDestination", "type": "metatag", "value": "mask_destination", "width": 1},
{"tag": "MaskDestination", "cdr_field_id": "*mask_destination", "type": "metatag", "width": 1},
],
"trailer_fields": [
{"tag": "ToR", "type": "constant", "value": "90", "width": 2},
{"tag": "Filler1", "type": "filler", "width": 3},
{"tag": "FileType", "type": "constant", "value": "SIP", "width": 3},
{"tag": "FileSeqNr", "type": "metatag", "value": "export_id", "padding": "zeroleft", "width": 5},
{"tag": "TotalRecords", "type": "metatag", "value": "cdrs_number", "padding": "zeroleft", "width": 6},
{"tag": "TotalDuration", "type": "metatag", "value": "cdrs_duration", "padding": "zeroleft", "width": 8},
{"tag": "FirstCdrTime", "type": "metatag", "value": "first_cdr_atime", "layout": "020106150405", "width": 12},
{"tag": "LastCdrTime", "type": "metatag", "value": "last_cdr_atime", "layout": "020106150405", "width": 12},
{"tag": "FileSeqNr", "cdr_field_id":"*export_id", "type": "metatag", "padding": "zeroleft", "width": 5},
{"tag": "TotalRecords", "cdr_field_id":"*cdrs_number", "type": "metatag", "padding": "zeroleft", "width": 6},
{"tag": "TotalDuration", "cdr_field_id":"*cdrs_duration", "type": "metatag", "value": "", "padding": "zeroleft", "width": 8},
{"tag": "FirstCdrTime", "cdr_field_id":"*first_cdr_atime", "type": "metatag", "layout": "020106150405", "width": 12},
{"tag": "LastCdrTime", "cdr_field_id": "*last_cdr_atime", "type": "metatag", "layout": "020106150405", "width": 12},
{"tag": "Filler1", "type": "filler", "width": 93},
], // template of the exported trailer fields
}

View File

@@ -142,3 +142,11 @@ func ParseRSRFieldsFromSlice(flds []string) (RSRFields, error) {
}
type RSRFields []*RSRField
// Return first Id of the rsrFields, used in cdre
func (self RSRFields) Id() string {
if len(self) == 0 {
return ""
}
return self[0].Id
}

View File

@@ -206,3 +206,18 @@ func TestFilterPasses(t *testing.T) {
t.Error("Passing filter")
}
}
func TestRSRFieldsId(t *testing.T) {
fieldsStr1 := `~account:s/^\w+[mpls]\d{6}$//;~subject:s/^0\d{9}$//;^destination/+4912345/;~mediation_runid:s/^default$/default/`
if rsrFlds, err := ParseRSRFields(fieldsStr1, INFIELD_SEP); err != nil {
t.Error("Unexpected error: ", err)
} else if idRcv := rsrFlds.Id(); idRcv != "account" {
t.Errorf("Received id: %s", idRcv)
}
fieldsStr2 := ""
if rsrFlds, err := ParseRSRFields(fieldsStr2, INFIELD_SEP); err != nil {
t.Error("Unexpected error: ", err)
} else if idRcv := rsrFlds.Id(); idRcv != "" {
t.Errorf("Received id: %s", idRcv)
}
}