github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/engine/trancode/trancode.go (about) 1 package trancode 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "time" 9 10 "database/sql" 11 12 dbconn "github.com/mdaxf/iac/databases" 13 "github.com/mdaxf/iac/documents" 14 15 funcgroup "github.com/mdaxf/iac/engine/funcgroup" 16 17 "github.com/mdaxf/iac/engine/types" 18 "github.com/mdaxf/iac/logger" 19 "go.mongodb.org/mongo-driver/bson" 20 21 "github.com/mdaxf/iac-signalr/signalr" 22 "github.com/mdaxf/iac/com" 23 tcom "github.com/mdaxf/iac/engine/com" 24 "github.com/mdaxf/iac/framework/callback_mgr" 25 ) 26 27 type TranFlow struct { 28 Tcode types.TranCode 29 DBTx *sql.Tx 30 Ctx context.Context 31 CtxCancel context.CancelFunc 32 Externalinputs map[string]interface{} // {sessionanme: value} 33 externaloutputs map[string]interface{} // {sessionanme: value} 34 SystemSession map[string]interface{} 35 ilog logger.Log 36 DocDBCon *documents.DocDB 37 SignalRClient signalr.Client 38 ErrorMessage string 39 TestwithSc bool 40 TestResults map[string]interface{} 41 } 42 43 func Execute(trancode string, data map[string]interface{}, systemsessions map[string]interface{}) (map[string]interface{}, error) { 44 iLog := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TransCode"} 45 startTime := time.Now() 46 defer func() { 47 elapsed := time.Since(startTime) 48 iLog.PerformanceWithDuration("engine.TranCode.Execute", elapsed) 49 }() 50 51 defer func() { 52 if err := recover(); err != nil { 53 iLog.Error(fmt.Sprintf("There is error to engine.TranCode.Execute with error: %s", err)) 54 // f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.ThrowErrorFuncs.Execute with error: %s", err) 55 56 } 57 }() 58 59 tranobj, err := getTranCodeData(trancode, documents.DocDBCon) 60 if err != nil { 61 return nil, err 62 } 63 tf := NewTranFlow(tranobj, data, systemsessions, nil, nil) 64 65 if callback_mgr.CallBackMap["TranCode_Execute"] == nil { 66 iLog.Debug("Register the trancode execution interface") 67 tfr := TranFlowstr{} 68 callback_mgr.RegisterCallBack("TranCode_Execute", tfr.Execute) 69 70 } 71 72 return tf.Execute() 73 74 } 75 76 // ExecuteUnitTest executes a unit test for a given trancode with the provided systemsessions. 77 // It returns a map[string]interface{} containing the result of the unit test and an error, if any. 78 // The result contains the following fields: 79 // - Name: the name of the unit test 80 // - Inputs: the inputs of the unit test 81 // - ExpectedOutputs: the expected outputs of the unit test 82 // - ExpectError: a boolean value indicating whether the unit test is expected to return an error 83 // - ExpectedError: the expected error message 84 // - ActualOutputs: the actual outputs of the unit test 85 // - ActualError: the actual error message 86 // - Result: the result of the unit test, either "Pass" or "Fail" 87 88 func ExecuteUnitTest(trancode string, systemsessions map[string]interface{}) (map[string]interface{}, error) { 89 iLog := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TransCode"} 90 startTime := time.Now() 91 defer func() { 92 elapsed := time.Since(startTime) 93 iLog.PerformanceWithDuration("engine.TranCode.ExecuteUnitTest", elapsed) 94 }() 95 96 defer func() { 97 if err := recover(); err != nil { 98 iLog.Error(fmt.Sprintf("There is error to engine.TranCode.ExecuteUnitTest with error: %s", err)) 99 // f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.ThrowErrorFuncs.Execute with error: %s", err) 100 101 } 102 }() 103 104 tranobj, err := getTranCodeData(trancode, documents.DocDBCon) 105 if err != nil { 106 return nil, err 107 } 108 tf := NewTranFlow(tranobj, map[string]interface{}{}, systemsessions, nil, nil) 109 tf.TestwithSc = true 110 111 result, err := tf.UnitTest() 112 113 if err != nil { 114 return nil, err 115 } 116 return result, nil 117 } 118 119 // ExecuteUnitTestWithTestData executes a unit test with the given test data for a specific trancode. 120 // It takes the trancode string, testcase map, and systemsessions map as input parameters. 121 // It returns a map[string]interface{} containing the test result and an error if any. 122 // The test result contains the following fields: 123 // - Name: the name of the unit test 124 // - Inputs: the inputs of the unit test 125 // - ExpectedOutputs: the expected outputs of the unit test 126 // - ExpectError: a boolean value indicating whether the unit test is expected to return an error 127 // - ExpectedError: the expected error message 128 // - ActualOutputs: the actual outputs of the unit test 129 // - ActualError: the actual error message 130 // - Result: the result of the unit test, either "Pass" or "Fail" 131 132 func ExecuteUnitTestWithTestData(trancode string, testcase map[string]interface{}, systemsessions map[string]interface{}) (map[string]interface{}, error) { 133 iLog := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TransCode"} 134 startTime := time.Now() 135 defer func() { 136 elapsed := time.Since(startTime) 137 iLog.PerformanceWithDuration("engine.TranCode.ExecuteUnitTestWithTestData", elapsed) 138 }() 139 140 defer func() { 141 if err := recover(); err != nil { 142 iLog.Error(fmt.Sprintf("There is error to engine.TranCode.ExecuteUnitTestWithTestData with error: %s", err)) 143 // f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.ThrowErrorFuncs.Execute with error: %s", err) 144 145 } 146 }() 147 tranobj, err := getTranCodeData(trancode, documents.DocDBCon) 148 if err != nil { 149 return nil, err 150 } 151 tf := NewTranFlow(tranobj, map[string]interface{}{}, systemsessions, nil, nil) 152 tf.TestwithSc = true 153 154 var testdata types.TestData 155 156 testdata.Inputs = testcase["inputs"].([]types.Input) 157 testdata.Outputs = testcase["outputs"].([]types.Output) 158 testdata.Name = testcase["name"].(string) 159 testdata.WantErr = testcase["wanterr"].(bool) 160 testdata.WantedErr = testcase["wantederr"].(string) 161 162 result, err := tf.UnitTestbyTestData(testdata) 163 164 if err != nil { 165 return nil, err 166 } 167 return result, nil 168 } 169 170 // ExecutebyExternal executes a transaction code by calling an external service. 171 // It takes a trancode string, a data map, a DBTx transaction, a DBCon database connection, 172 // and a sc signalr client as input parameters. 173 // It returns a map of outputs and an error. 174 // The outputs map contains the outputs of the transaction code. 175 // The error contains the error message if any. 176 // The function also logs the performance of the transaction code execution. 177 178 func ExecutebyExternal(trancode string, data map[string]interface{}, DBTx *sql.Tx, DBCon *documents.DocDB, sc signalr.Client) (map[string]interface{}, error) { 179 iLog := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TransCode"} 180 startTime := time.Now() 181 defer func() { 182 elapsed := time.Since(startTime) 183 iLog.PerformanceWithDuration("engine.TranCode.ExecutebyExternal", elapsed) 184 }() 185 186 defer func() { 187 if err := recover(); err != nil { 188 iLog.Error(fmt.Sprintf("There is error to engine.TranCode.ExecutebyExternal with error: %s", err)) 189 // f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.ThrowErrorFuncs.Execute with error: %s", err) 190 191 } 192 }() 193 194 tranobj, err := getTranCodeData(trancode, DBCon) 195 if err != nil { 196 return nil, err 197 } 198 tf := NewTranFlow(tranobj, data, map[string]interface{}{}, nil, nil, DBTx) 199 tf.DocDBCon = DBCon 200 tf.SignalRClient = sc 201 202 if callback_mgr.CallBackMap["TranCode_Execute"] == nil { 203 iLog.Debug("Register the trancode execution interface") 204 tfr := TranFlowstr{} 205 callback_mgr.RegisterCallBack("TranCode_Execute", tfr.Execute) 206 207 } 208 209 outputs, err := tf.Execute() 210 211 if err != nil { 212 return nil, err 213 } 214 return outputs, nil 215 } 216 217 // NewTranFlow creates a new instance of TranFlow. 218 // It takes the following parameters: 219 // - tcode: the transaction code (types.TranCode) 220 // - externalinputs: a map of external inputs (map[string]interface{}) 221 // - systemSession: a map of system session data (map[string]interface{}) 222 // - ctx: the context (context.Context) 223 // - ctxcancel: the cancel function for the context (context.CancelFunc) 224 // - dbTx: optional parameter for the database transaction (*sql.Tx) 225 // It returns a pointer to TranFlow. 226 227 func NewTranFlow(tcode types.TranCode, externalinputs, systemSession map[string]interface{}, ctx context.Context, ctxcancel context.CancelFunc, dbTx ...*sql.Tx) *TranFlow { 228 log := logger.Log{} 229 log.ModuleName = logger.TranCode 230 log.ControllerName = "Trancode" 231 if systemSession["UserNo"] != nil { 232 log.User = systemSession["UserNo"].(string) 233 } else { 234 log.User = "System" 235 } 236 237 startTime := time.Now() 238 defer func() { 239 elapsed := time.Since(startTime) 240 log.PerformanceWithDuration("engine.TranCode.ExecutebyExternal", elapsed) 241 }() 242 243 /* defer func() { 244 if err := recover(); err != nil { 245 log.Error(fmt.Sprintf("There is error to engine.TranCode.ExecutebyExternal with error: %s", err)) 246 // f.ErrorMessage = fmt.Sprintf("There is error to engine.funcs.ThrowErrorFuncs.Execute with error: %s", err) 247 248 } 249 }() 250 */ 251 idbTx := append(dbTx, nil)[0] 252 if callback_mgr.CallBackMap["TranCode_Execute"] == nil { 253 log.Debug("Register the trancode execution interface") 254 tfr := TranFlowstr{} 255 callback_mgr.RegisterCallBack("TranCode_Execute", tfr.Execute) 256 257 } 258 /* 259 tfr := TranFlowstr{} 260 callback.RegisterCallBack("TranFlowstr_Execute", tfr.Execute) 261 */ 262 return &TranFlow{ 263 Tcode: tcode, 264 DBTx: idbTx, 265 Ctx: ctx, 266 CtxCancel: ctxcancel, 267 ilog: log, 268 Externalinputs: externalinputs, 269 externaloutputs: map[string]interface{}{}, 270 SystemSession: systemSession, 271 DocDBCon: documents.DocDBCon, 272 SignalRClient: com.IACMessageBusClient, 273 ErrorMessage: "", 274 TestwithSc: false, 275 TestResults: map[string]interface{}{}, 276 } 277 } 278 279 // Execute executes the transaction flow. 280 // It starts the timer to measure the execution time and logs the performance duration. 281 // It recovers from any panics and logs the error message. 282 // It retrieves the system session, external inputs, and external outputs from the transaction flow. 283 // It starts a new database transaction if one doesn't exist. 284 // It starts a new context with a timeout if one doesn't exist. 285 // It executes the first function group of the transaction code and iterates through subsequent function groups until the code is no longer 1. 286 // It commits the database transaction if it was started in this function. 287 // It returns the external outputs and nil error if successful. 288 func (t *TranFlow) Execute() (map[string]interface{}, error) { 289 startTime := time.Now() 290 defer func() { 291 elapsed := time.Since(startTime) 292 t.ilog.PerformanceWithDuration("engine.TranCode.Execute", elapsed) 293 }() 294 defer func() { 295 if r := recover(); r != nil { 296 t.ilog.Error(fmt.Sprintf("Error in Trancode.Execute: %s", r)) 297 t.ErrorMessage = fmt.Sprintf("Error in Trancode.Execute: %s", r) 298 t.DBTx.Rollback() 299 t.CtxCancel() 300 return 301 } 302 }() 303 304 t.ilog.Info(fmt.Sprintf("Start process transaction code %s's %s ", t.Tcode.Name, "Execute")) 305 t.ilog.Debug(fmt.Sprintf("systemSession: %s", logger.ConvertJson(t.SystemSession))) 306 t.ilog.Debug(fmt.Sprintf("externalinputs: %s", logger.ConvertJson(t.Externalinputs))) 307 t.ilog.Debug(fmt.Sprintf("externaloutputs: %s", logger.ConvertJson(t.externaloutputs))) 308 systemSession := t.SystemSession 309 externalinputs := t.Externalinputs 310 externaloutputs := t.externaloutputs 311 userSession := map[string]interface{}{} 312 var err error 313 newTransaction := false 314 315 if t.DBTx == nil { 316 317 t.DBTx, err = dbconn.DB.Begin() 318 newTransaction = true 319 if err != nil { 320 t.ilog.Error(fmt.Sprintf("Error in Trancode.Execute during DB transaction beginning: %s", err.Error())) 321 return map[string]interface{}{}, err 322 } 323 324 defer t.DBTx.Rollback() 325 } 326 327 if t.Ctx == nil { 328 t.Ctx, t.CtxCancel = context.WithTimeout(context.Background(), time.Second*time.Duration(com.TransactionTimeout)) 329 330 defer t.CtxCancel() 331 } 332 333 if t.TestwithSc { 334 t.TestResults = map[string]interface{}{} 335 t.TestResults["Name"] = t.Tcode.Name 336 t.TestResults["Version"] = t.Tcode.Version 337 t.TestResults["Inputs"] = t.Externalinputs 338 t.TestResults["SystemSession"] = t.SystemSession 339 t.TestResults["UserSession"] = userSession 340 t.TestResults["Outputs"] = t.externaloutputs 341 t.TestResults["FunctionGroups"] = []map[string]interface{}{} 342 t.TestResults["Error"] = t.ErrorMessage 343 344 tcom.SendTestResultMessageBus(t.Tcode.Name, "", "", "UnitTest", "Start", 345 t.Externalinputs, t.externaloutputs, t.SystemSession, map[string]interface{}{}, nil, t.SystemSession["ClientID"].(string), t.SystemSession["UserNo"].(string)) 346 } 347 348 t.ilog.Debug(fmt.Sprintf("Start process transaction code %s's first func group: %s ", t.Tcode.Name, t.Tcode.Firstfuncgroup)) 349 fgroup, code := t.getFGbyName(t.Tcode.Firstfuncgroup) 350 t.ilog.Debug(fmt.Sprintf("start first function group:", logger.ConvertJson(fgroup))) 351 352 for code == 1 { 353 fg := funcgroup.NewFGroup(t.DocDBCon, t.SignalRClient, t.DBTx, fgroup, "", systemSession, userSession, externalinputs, externaloutputs, t.Ctx, t.CtxCancel) 354 355 fg.TestwithSc = t.TestwithSc 356 357 fg.Execute() 358 359 if t.TestwithSc { 360 t.TestResults["FunctionGroups"] = append(t.TestResults["FunctionGroups"].([]map[string]interface{}), fg.TestResults) 361 } 362 363 externalinputs = fg.Externalinputs 364 externaloutputs = fg.Externaloutputs 365 userSession = fg.UserSession 366 367 if fg.Nextfuncgroup == "" { 368 code = 0 369 break 370 } else { 371 fgroup, code = t.getFGbyName(fg.Nextfuncgroup) 372 t.ilog.Debug(fmt.Sprintf("function group:%s, Code:%d", logger.ConvertJson(fgroup), code)) 373 } 374 } 375 376 if newTransaction { 377 err := t.DBTx.Commit() 378 if err != nil { 379 t.ilog.Error(fmt.Sprintf("Error in Trancode.Execute during DB transaction commit: %s", err.Error())) 380 t.CtxCancel() 381 return map[string]interface{}{}, err 382 } 383 } 384 385 if t.TestwithSc { 386 t.TestResults["Outputs"] = externaloutputs 387 t.TestResults["Error"] = t.ErrorMessage 388 } 389 return externaloutputs, nil 390 391 } 392 393 // getFGbyName retrieves the FuncGroup by its name from the TranFlow. 394 // It returns the found FuncGroup and a flag indicating whether the FuncGroup was found or not. 395 396 func (t *TranFlow) getFGbyName(name string) (types.FuncGroup, int) { 397 startTime := time.Now() 398 defer func() { 399 elapsed := time.Since(startTime) 400 t.ilog.PerformanceWithDuration("engine.TranCode.getFGbyName", elapsed) 401 }() 402 /* defer func() { 403 if r := recover(); r != nil { 404 t.ilog.Error(fmt.Sprintf("Error in Trancode.getFGbyName: %s", r)) 405 t.ErrorMessage = fmt.Sprintf("Error in Trancode.getFGbyName: %s", r) 406 t.DBTx.Rollback() 407 t.CtxCancel() 408 return 409 } 410 }() 411 */ 412 t.ilog.Debug(fmt.Sprintf("Get the Func group by name: %s", name)) 413 for _, fgroup := range t.Tcode.Functiongroups { 414 if fgroup.Name == name { 415 416 return fgroup, 1 417 } 418 } 419 t.ilog.Debug(fmt.Sprintf("Can't find the Func group by name: %s", name)) 420 return types.FuncGroup{}, 0 421 } 422 423 // GetTransCode retrieves the transaction code for the given name. 424 // It reads the transaction code configuration file and returns the corresponding TranCode object. 425 // If an error occurs during the process, it returns an empty TranCode object and an error. 426 func GetTransCode(name string) (types.TranCode, error) { 427 log := logger.Log{} 428 log.ModuleName = logger.TranCode 429 log.ControllerName = "Trancode" 430 log.User = "System" 431 432 startTime := time.Now() 433 defer func() { 434 elapsed := time.Since(startTime) 435 log.PerformanceWithDuration("engine.TranCode.GetTranCode", elapsed) 436 }() 437 defer func() { 438 if r := recover(); r != nil { 439 log.Error(fmt.Sprintf("Error in Trancode.GetTranCode: %s", r)) 440 return 441 } 442 }() 443 444 log.Info(fmt.Sprintf("Start get transaction code %s", name)) 445 446 log.Info(fmt.Sprintf("./%s/%s%s", "trancodes", name, ".json")) 447 data, err := ioutil.ReadFile(fmt.Sprintf("./%s/%s%s", "trancodes", name, ".json")) 448 if err != nil { 449 log.Error(fmt.Sprintf("failed to read configuration file: %v", err)) 450 return types.TranCode{}, fmt.Errorf("failed to read configuration file: %v", err) 451 } 452 log.Debug(fmt.Sprintf("Read the tran code configuration:%s", string(data))) 453 // fmt.Println(string(data)) 454 return Bytetoobj(data) 455 } 456 457 // Bytetoobj converts a byte slice to a TranCode object. 458 // It parses the transaction code configuration from the provided byte slice and returns a TranCode object. 459 // If there is an error during parsing, it returns an empty TranCode object and an error. 460 461 func Bytetoobj(config []byte) (types.TranCode, error) { 462 log := logger.Log{} 463 log.ModuleName = logger.TranCode 464 log.ControllerName = "Trancode" 465 log.User = "System" 466 startTime := time.Now() 467 defer func() { 468 elapsed := time.Since(startTime) 469 log.PerformanceWithDuration("engine.TranCode.Bytetoobj", elapsed) 470 }() 471 /* defer func() { 472 if r := recover(); r != nil { 473 log.Error(fmt.Sprintf("Error in Trancode.Byetoobj: %s", r)) 474 return 475 } 476 }() 477 */ 478 log.Info(fmt.Sprintf("Start parse transaction code configuration")) 479 480 var tranCode types.TranCode 481 if err := json.Unmarshal(config, &tranCode); err != nil { 482 return types.TranCode{}, fmt.Errorf("failed to parse configuration file: %v", err) 483 } 484 log.Debug(fmt.Sprintf("Parse the tran code configuration:%s", logger.ConvertJson(tranCode))) 485 return tranCode, nil 486 } 487 488 func Configtoobj(config string) (types.TranCode, error) { 489 490 return Bytetoobj([]byte(config)) 491 } 492 493 type TranCodeData struct { 494 TranCode string `json:"code"` 495 inputs map[string]interface{} `json:"Inputs"` 496 } 497 498 type TranFlowstr struct { 499 TestwithSc bool `json:"TestwithSc,omitempty"` 500 } 501 502 func (t *TranFlowstr) Execute(tcode string, inputs map[string]interface{}, sc signalr.Client, docdbconn *documents.DocDB, ctx context.Context, ctxcancel context.CancelFunc, dbTx ...*sql.Tx) (map[string]interface{}, error) { 503 log := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TransCode.TranFlow"} 504 startTime := time.Now() 505 defer func() { 506 elapsed := time.Since(startTime) 507 log.PerformanceWithDuration("engine.TranCode.Tranflow.Execute", elapsed) 508 }() 509 defer func() { 510 if r := recover(); r != nil { 511 log.Error(fmt.Sprintf("Error in Trancode.TranFLow.Execute: %s", r)) 512 return 513 } 514 }() 515 516 tc, err := GetTranCodeDatabyCode(tcode) 517 518 if err != nil { 519 return nil, err 520 } 521 systemSession := map[string]interface{}{} 522 externalinputs := inputs 523 524 idbTx := append(dbTx, nil)[0] 525 526 tf := NewTranFlow(tc, externalinputs, systemSession, ctx, ctxcancel, idbTx) 527 tf.SignalRClient = sc 528 tf.TestwithSc = t.TestwithSc 529 530 tf.DocDBCon = docdbconn 531 532 return tf.Execute() 533 } 534 535 func (t *TranFlow) UnitTestbyTestData(testdata types.TestData) (map[string]interface{}, error) { 536 537 startTime := time.Now() 538 defer func() { 539 elapsed := time.Since(startTime) 540 t.ilog.PerformanceWithDuration("engine.TranCode.Tranflow.UnitTestbyTestData", elapsed) 541 }() 542 543 defer func() { 544 if r := recover(); r != nil { 545 t.ilog.Error(fmt.Sprintf("Error in Trancode.UnitTestbyTestData: %s", r)) 546 t.ErrorMessage = fmt.Sprintf("Error in Trancode.UnitTestbyTestData: %s", r) 547 t.DBTx.Rollback() 548 t.CtxCancel() 549 return 550 } 551 }() 552 553 t.ilog.Debug(fmt.Sprintf("Start process transaction code %s's with test data: %s ", t.Tcode.Name, testdata)) 554 t.ilog.Debug(fmt.Sprintf("externalinputs: %s", logger.ConvertJson(testdata.Inputs))) 555 t.ilog.Debug(fmt.Sprintf("expected externaloutputs: %s", logger.ConvertJson(testdata.Outputs))) 556 557 t.Externalinputs = convertInputsToMap(testdata.Inputs) 558 t.externaloutputs = map[string]interface{}{} 559 testresult := map[string]interface{}{} 560 testresult["Name"] = testdata.Name 561 testresult["Inputs"] = testdata.Inputs 562 testresult["ExpectedOutputs"] = testdata.Outputs 563 testresult["ExpectError"] = testdata.WantErr 564 testresult["ExpectedError"] = testdata.WantedErr 565 566 tcom.SendTestResultMessageBus(t.Tcode.Name, "", "", "UnitTest", "Start", 567 t.Externalinputs, t.externaloutputs, t.SystemSession, map[string]interface{}{}, nil, t.SystemSession["ClientID"].(string), t.SystemSession["UserNo"].(string)) 568 569 outputs, err := t.Execute() 570 571 tcom.SendTestResultMessageBus(t.Tcode.Name, "", "", "UnitTest", "Complete", 572 t.Externalinputs, outputs, t.SystemSession, map[string]interface{}{}, err, t.SystemSession["ClientID"].(string), t.SystemSession["UserNo"].(string)) 573 574 t.ilog.Debug(fmt.Sprintf("actual externaloutputs: %v, expected outputs: %v", outputs, testdata.Outputs)) 575 if err != nil { 576 t.ilog.Error(fmt.Sprintf("Error in Trancode.Execute: %s", err.Error())) 577 578 if testdata.WantErr { 579 if testdata.WantedErr == err.Error() { 580 testresult["ActualError"] = err.Error() 581 testresult["Result"] = "Pass" 582 583 } else { 584 testresult["ActualError"] = err.Error() 585 testresult["Result"] = "Pass" 586 587 } 588 589 } else { 590 testresult["ActualError"] = err.Error() 591 testresult["Result"] = "Fail" 592 593 } 594 } 595 596 if !testdata.WantErr { 597 if !compareMap(outputs, convertOutputsToMap(testdata.Outputs)) { 598 testresult["ActualOutputs"] = outputs 599 testresult["Result"] = "Fail" 600 601 } else { 602 testresult["ActualOutputs"] = outputs 603 testresult["Result"] = "Pass" 604 605 } 606 } else { 607 testresult["Result"] = "Fail" 608 testresult["ActualOutputs"] = outputs 609 testresult["ActualError"] = "" 610 611 } 612 613 return testresult, nil 614 } 615 616 func (t *TranFlow) UnitTest() (map[string]interface{}, error) { 617 startTime := time.Now() 618 defer func() { 619 elapsed := time.Since(startTime) 620 t.ilog.PerformanceWithDuration("engine.TranCode.Tranflow.UnitTest", elapsed) 621 }() 622 623 defer func() { 624 if r := recover(); r != nil { 625 t.ilog.Error(fmt.Sprintf("Error in Trancode.UnitTest: %s", r)) 626 t.ErrorMessage = fmt.Sprintf("Error in Trancode.UnitTest: %s", r) 627 t.DBTx.Rollback() 628 t.CtxCancel() 629 return 630 } 631 }() 632 633 result := make(map[string]interface{}) 634 635 t.ilog.Info(fmt.Sprintf("Start Process for transaction code %s's %s ", t.Tcode.Name, "Unit Test")) 636 t.ilog.Debug(fmt.Sprintf("systemSession: %s", logger.ConvertJson(t.SystemSession))) 637 testdatalist := t.Tcode.TestDatas 638 639 for _, testdata := range testdatalist { 640 641 testresult, _ := t.UnitTestbyTestData(testdata) 642 result[testdata.Name] = testresult 643 644 } 645 646 return result, nil 647 } 648 649 func GetTranCodeDatabyCode(Code string) (types.TranCode, error) { 650 log := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TransCode"} 651 startTime := time.Now() 652 defer func() { 653 elapsed := time.Since(startTime) 654 log.PerformanceWithDuration("engine.TranCode.GetTranCodeDatabyCode", elapsed) 655 }() 656 defer func() { 657 if r := recover(); r != nil { 658 log.Error(fmt.Sprintf("Error in Trancode.GetTranCodeDatabyCode: %s", r)) 659 return 660 } 661 }() 662 663 trancodeobj, err := getTranCodeData(Code, documents.DocDBCon) 664 if err != nil { 665 return types.TranCode{}, err 666 } 667 return trancodeobj, nil 668 } 669 670 func getTranCodeData(Code string, DBConn *documents.DocDB) (types.TranCode, error) { 671 iLog := logger.Log{ModuleName: logger.API, User: "System", ControllerName: "TranCode"} 672 673 startTime := time.Now() 674 defer func() { 675 elapsed := time.Since(startTime) 676 iLog.PerformanceWithDuration("engine.TranCode.getTranCodeData", elapsed) 677 }() 678 defer func() { 679 if r := recover(); r != nil { 680 iLog.Error(fmt.Sprintf("Error in Trancode.getTranCodeData: %s", r)) 681 return 682 } 683 }() 684 685 iLog.Info(fmt.Sprintf("Get the trancode code for %s ", Code)) 686 687 iLog.Info(fmt.Sprintf("Start process transaction code %s's %s ", Code, "Execute")) 688 689 filter := bson.M{"trancodename": Code, "isdefault": true} 690 691 tcode, err := DBConn.QueryCollection("Transaction_Code", filter, nil) 692 693 if err != nil { 694 iLog.Error(fmt.Sprintf("Get transaction code %s's error", Code)) 695 696 return types.TranCode{}, err 697 } 698 iLog.Debug(fmt.Sprintf("transaction code %s's data: %s", Code, tcode)) 699 jsonString, err := json.Marshal(tcode[0]) 700 if err != nil { 701 702 iLog.Error(fmt.Sprintf("Error marshaling json:", err.Error())) 703 return types.TranCode{}, err 704 } 705 706 trancodeobj, err := Configtoobj(string(jsonString)) 707 if err != nil { 708 iLog.Error(fmt.Sprintf("Error unmarshaling json:", err.Error())) 709 return types.TranCode{}, err 710 } 711 712 iLog.Debug(fmt.Sprintf("transaction code %s's json: %s", trancodeobj, string(jsonString))) 713 714 if err != nil { 715 iLog.Error(fmt.Sprintf("Error unmarshaling json:", err.Error())) 716 return types.TranCode{}, err 717 } 718 719 return trancodeobj, nil 720 } 721 722 func convertInputsToMap(inputs []types.Input) map[string]interface{} { 723 iLog := logger.Log{ModuleName: logger.API, User: "System", ControllerName: "TranCode"} 724 725 startTime := time.Now() 726 defer func() { 727 elapsed := time.Since(startTime) 728 iLog.PerformanceWithDuration("engine.TranCode.convertInputsToMap", elapsed) 729 }() 730 defer func() { 731 if r := recover(); r != nil { 732 iLog.Error(fmt.Sprintf("Error in Trancode.convertInputsToMap: %s", r)) 733 return 734 } 735 }() 736 737 result := map[string]interface{}{} 738 739 for _, input := range inputs { 740 result[input.Name] = input.Value 741 } 742 743 return result 744 } 745 746 func convertOutputsToMap(outputs []types.Output) map[string]interface{} { 747 iLog := logger.Log{ModuleName: logger.API, User: "System", ControllerName: "TranCode"} 748 749 startTime := time.Now() 750 defer func() { 751 elapsed := time.Since(startTime) 752 iLog.PerformanceWithDuration("engine.TranCode.convertOutputsToMap", elapsed) 753 }() 754 defer func() { 755 if r := recover(); r != nil { 756 iLog.Error(fmt.Sprintf("Error in Trancode.convertOutputsToMap: %s", r)) 757 return 758 } 759 }() 760 761 result := map[string]interface{}{} 762 763 for _, output := range outputs { 764 result[output.Name] = output.Value 765 } 766 767 return result 768 } 769 770 func compareMap(map1, map2 map[string]interface{}) bool { 771 iLog := logger.Log{ModuleName: logger.TranCode, User: "System", ControllerName: "TranCode"} 772 773 startTime := time.Now() 774 defer func() { 775 elapsed := time.Since(startTime) 776 iLog.PerformanceWithDuration("engine.TranCode.compareMap", elapsed) 777 }() 778 defer func() { 779 if r := recover(); r != nil { 780 iLog.Error(fmt.Sprintf("Error in Trancode.compareMap: %s", r)) 781 return 782 } 783 }() 784 785 if len(map1) != len(map2) { 786 return false 787 } 788 789 for key1, value1 := range map1 { 790 value2, ok := map2[key1] 791 if !ok { 792 return false 793 } 794 795 if value1 != value2 { 796 return false 797 } 798 } 799 800 return true 801 }