diff --git a/cmd/agent/main.go b/cmd/agent/main.go deleted file mode 100644 index 79058077776c2ae70a619e5eef9ae972247a4576..0000000000000000000000000000000000000000 --- a/cmd/agent/main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - -} diff --git a/cmd/command/main.go b/cmd/command/main.go index 0ee0915413dfbffe6042ae4146d4b454f1486cb9..95772b0ffa36a077d9ce4153e2cf7779467cb326 100644 --- a/cmd/command/main.go +++ b/cmd/command/main.go @@ -11,7 +11,6 @@ import ( logUtils "github.com/easysoft/zentaoatf/pkg/lib/log" stringUtils "github.com/easysoft/zentaoatf/pkg/lib/string" "github.com/fatih/color" - "log" "os" "os/signal" "strings" @@ -83,58 +82,33 @@ func main() { switch os.Args[1] { case "set", "-set": flagSet.Parse(os.Args[2:]) - if commConsts.Verbose { - log.Println("WorkDir=" + commConsts.WorkDir) - log.Println("ZtfDir=" + commConsts.ZtfDir) - } action.Set() case "expect": files := fileUtils.GetFilesFromParams(os.Args[2:]) action.GenExpectFiles(files) + case "extract": files := fileUtils.GetFilesFromParams(os.Args[2:]) action.Extract(files) case "checkout", "co": - if err := flagSet.Parse(os.Args[2:]); err == nil { - action.Checkout(productId, moduleId, suiteId, taskIdOrName, independentFile, language) - } + checkout() case "ci": - files := fileUtils.GetFilesFromParams(os.Args[2:]) - if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { - action.CheckIn(files) - } + ci() case "cr": - files := fileUtils.GetFilesFromParams(os.Args[2:]) - if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { - action.CommitZTFTestResult(files, stringUtils.ParseInt(productId), - taskIdOrName, noNeedConfirm) - } + cr() case "cb": - files := fileUtils.GetFilesFromParams(os.Args[2:]) - if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { - action.CommitBug(files, stringUtils.ParseInt(productId), noNeedConfirm) - } + cb() case "list", "ls", "-l": - files := fileUtils.GetFilesFromParams(os.Args[2:]) - if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { - if len(files) == 0 { - files = append(files, ".") - } - - action.List(files, keywords) - } + list() case "view", "-v": - files := fileUtils.GetFilesFromParams(os.Args[2:]) - if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { - action.View(files, keywords) - } + view() case "clean", "-clean", "-c": action.Clean() @@ -160,6 +134,52 @@ func main() { } } +func checkout() { + if err := flagSet.Parse(os.Args[2:]); err == nil { + action.Checkout(productId, moduleId, suiteId, taskIdOrName, independentFile, language) + } +} + +func ci() { + files := fileUtils.GetFilesFromParams(os.Args[2:]) + if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { + action.CheckIn(files) + } +} + +func cr() { + files := fileUtils.GetFilesFromParams(os.Args[2:]) + if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { + action.CommitZTFTestResult(files, stringUtils.ParseInt(productId), + taskIdOrName, noNeedConfirm) + } +} + +func cb() { + files := fileUtils.GetFilesFromParams(os.Args[2:]) + if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { + action.CommitBug(files, stringUtils.ParseInt(productId), noNeedConfirm) + } +} + +func list() { + files := fileUtils.GetFilesFromParams(os.Args[2:]) + if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { + if len(files) == 0 { + files = append(files, ".") + } + + action.List(files, keywords) + } +} + +func view() { + files := fileUtils.GetFilesFromParams(os.Args[2:]) + if err := flagSet.Parse(os.Args[len(files)+2:]); err == nil { + action.View(files, keywords) + } +} + func run(args []string) { if len(args) >= 3 && stringUtils.FindInArr(args[2], commConsts.UnitTestTypes) { // unit test runUnitTest(args) diff --git a/demo/sample/2_with_group.php b/demo/sample/2_with_group.php index 46db10b0953fdbed063ba5812272a6c481020cf5..fce71dfa5f8aa079e18b6fd8cacc4f12847c8817 100755 --- a/demo/sample/2_with_group.php +++ b/demo/sample/2_with_group.php @@ -4,7 +4,7 @@ title=with multi groups cid=2 -pid=0 +pid=1 step 1 >> expect 1 step 2 >> expect 2 diff --git a/internal/command/config/config.go b/internal/command/config/config.go index b0d279bb386579c008c6e6c900298f026019ed54..3176129e5e05569d73a70f64453cfce84588cfd0 100644 --- a/internal/command/config/config.go +++ b/internal/command/config/config.go @@ -72,6 +72,7 @@ func Init() { i118Utils.Init(commConsts.Language, commConsts.AppServer) langHelper.GetExtToNameMap() + langHelper.GetEditorExtToLangMap() commConsts.ExecFrom = commConsts.FromCmd return diff --git a/internal/pkg/grpc/proto/greater/greater.pb.go b/internal/pkg/grpc/proto/greater/greater.pb.go deleted file mode 100644 index a7e3be78a6f463c3cf146635835ff18ac5e51ee8..0000000000000000000000000000000000000000 --- a/internal/pkg/grpc/proto/greater/greater.pb.go +++ /dev/null @@ -1,213 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.27.1 -// protoc v3.17.3 -// source: greater/greater.proto - -package greater - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// The request message containing the user's name. -type HelloRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` -} - -func (x *HelloRequest) Reset() { - *x = HelloRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_greater_greater_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HelloRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloRequest) ProtoMessage() {} - -func (x *HelloRequest) ProtoReflect() protoreflect.Message { - mi := &file_greater_greater_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. -func (*HelloRequest) Descriptor() ([]byte, []int) { - return file_greater_greater_proto_rawDescGZIP(), []int{0} -} - -func (x *HelloRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -// The response message containing the greetings -type HelloReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *HelloReply) Reset() { - *x = HelloReply{} - if protoimpl.UnsafeEnabled { - mi := &file_greater_greater_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HelloReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloReply) ProtoMessage() {} - -func (x *HelloReply) ProtoReflect() protoreflect.Message { - mi := &file_greater_greater_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. -func (*HelloReply) Descriptor() ([]byte, []int) { - return file_greater_greater_proto_rawDescGZIP(), []int{1} -} - -func (x *HelloReply) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -var File_greater_greater_proto protoreflect.FileDescriptor - -var file_greater_greater_proto_rawDesc = []byte{ - 0x0a, 0x15, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x2f, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, - 0x22, 0x22, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x43, 0x0a, 0x07, - 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, - 0x6c, 0x6c, 0x6f, 0x12, 0x15, 0x2e, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x2e, 0x48, 0x65, - 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_greater_greater_proto_rawDescOnce sync.Once - file_greater_greater_proto_rawDescData = file_greater_greater_proto_rawDesc -) - -func file_greater_greater_proto_rawDescGZIP() []byte { - file_greater_greater_proto_rawDescOnce.Do(func() { - file_greater_greater_proto_rawDescData = protoimpl.X.CompressGZIP(file_greater_greater_proto_rawDescData) - }) - return file_greater_greater_proto_rawDescData -} - -var file_greater_greater_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_greater_greater_proto_goTypes = []interface{}{ - (*HelloRequest)(nil), // 0: greater.HelloRequest - (*HelloReply)(nil), // 1: greater.HelloReply -} -var file_greater_greater_proto_depIdxs = []int32{ - 0, // 0: greater.Greeter.SayHello:input_type -> greater.HelloRequest - 1, // 1: greater.Greeter.SayHello:output_type -> greater.HelloReply - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_greater_greater_proto_init() } -func file_greater_greater_proto_init() { - if File_greater_greater_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_greater_greater_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HelloRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_greater_greater_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HelloReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_greater_greater_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_greater_greater_proto_goTypes, - DependencyIndexes: file_greater_greater_proto_depIdxs, - MessageInfos: file_greater_greater_proto_msgTypes, - }.Build() - File_greater_greater_proto = out.File - file_greater_greater_proto_rawDesc = nil - file_greater_greater_proto_goTypes = nil - file_greater_greater_proto_depIdxs = nil -} diff --git a/internal/pkg/grpc/proto/greater/greater.proto b/internal/pkg/grpc/proto/greater/greater.proto deleted file mode 100644 index e95a6e7b99bad86375be06cc6cd4c73df1fe50d9..0000000000000000000000000000000000000000 --- a/internal/pkg/grpc/proto/greater/greater.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto3"; - -package greater; -option go_package="./greater"; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; -} \ No newline at end of file diff --git a/internal/pkg/grpc/proto/greater/greater_grpc.pb.go b/internal/pkg/grpc/proto/greater/greater_grpc.pb.go deleted file mode 100644 index 35b438f726289a4dbc723b5bf6649620b60423fc..0000000000000000000000000000000000000000 --- a/internal/pkg/grpc/proto/greater/greater_grpc.pb.go +++ /dev/null @@ -1,103 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package greater - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// GreeterClient is the client API for Greeter service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type GreeterClient interface { - // Sends a greeting - SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) -} - -type greeterClient struct { - cc grpc.ClientConnInterface -} - -func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { - return &greeterClient{cc} -} - -func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { - out := new(HelloReply) - err := c.cc.Invoke(ctx, "/greater.Greeter/SayHello", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// GreeterServer is the server API for Greeter service. -// All implementations must embed UnimplementedGreeterServer -// for forward compatibility -type GreeterServer interface { - // Sends a greeting - SayHello(context.Context, *HelloRequest) (*HelloReply, error) - mustEmbedUnimplementedGreeterServer() -} - -// UnimplementedGreeterServer must be embedded to have forward compatible implementations. -type UnimplementedGreeterServer struct { -} - -func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") -} -func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {} - -// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to GreeterServer will -// result in compilation errors. -type UnsafeGreeterServer interface { - mustEmbedUnimplementedGreeterServer() -} - -func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { - s.RegisterService(&Greeter_ServiceDesc, srv) -} - -func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(HelloRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(GreeterServer).SayHello(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/greater.Greeter/SayHello", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Greeter_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "greater.Greeter", - HandlerType: (*GreeterServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "SayHello", - Handler: _Greeter_SayHello_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "greater/greater.proto", -} diff --git a/internal/pkg/helper/exec/report-unit.go b/internal/pkg/helper/exec/report-unit.go index 9eda53cef8e12c90d2fb256f76deecbc979aeefc..e161f389eaed0de9a30c2c75cc20b60c7b0950b8 100644 --- a/internal/pkg/helper/exec/report-unit.go +++ b/internal/pkg/helper/exec/report-unit.go @@ -274,14 +274,10 @@ func GetSuiteFiles(resultDir string, startTime int64, testTool commConsts.TestTo continue } - if testTool == commConsts.Allure && ext == ".json" { - pth := filepath.Join(resultDir, name) - resultFiles = append(resultFiles, pth) - } else if ext == ".xml" { + if (testTool == commConsts.Allure && ext == ".json") || ext == ".xml" { pth := filepath.Join(resultDir, name) resultFiles = append(resultFiles, pth) } - } } } else { @@ -344,17 +340,11 @@ func GetTestSuite(xmlFile string, testTool commConsts.TestTool) ( if err == nil { testSuite = ConvertRobotResult(robotResult) } - } else if testTool == commConsts.Cypress { - cyResult := commDomain.CypressTestsuites{} - err = xml.Unmarshal([]byte(content), &cyResult) - if err == nil { - testSuite = ConvertCyResult(cyResult) - } - } else if testTool == commConsts.Playwright { - cyResult := commDomain.CypressTestsuites{} - err = xml.Unmarshal([]byte(content), &cyResult) + } else if testTool == commConsts.Cypress || testTool == commConsts.Playwright { + result := commDomain.CypressTestsuites{} + err = xml.Unmarshal([]byte(content), &result) if err == nil { - testSuite = ConvertCyResult(cyResult) + testSuite = ConvertCyResult(result) } } else if testTool == commConsts.Puppeteer { cyResult := commDomain.CypressTestsuites{} @@ -477,11 +467,7 @@ func GetAllureCaseSuiteName(cs commDomain.AllureCase) (name string) { if label.Value != "" { suiteArr = append(suiteArr, label.Value) } - } else if label.Name == "suite" { - if label.Value != "" && (len(suiteArr) == 0 || label.Value != suiteArr[len(suiteArr)-1]) { - suiteArr = append(suiteArr, label.Value) - } - } else if label.Name == "subSuite" { + } else if label.Name == "suite" || label.Name == "subSuite" { if label.Value != "" && (len(suiteArr) == 0 || label.Value != suiteArr[len(suiteArr)-1]) { suiteArr = append(suiteArr, label.Value) } diff --git a/internal/pkg/helper/exec/result.go b/internal/pkg/helper/exec/result.go index a399822a18b02e92ebe889fe0a170b4baaadf086..8a620615dda868ab934a7a195312fc34f71505d8 100644 --- a/internal/pkg/helper/exec/result.go +++ b/internal/pkg/helper/exec/result.go @@ -25,24 +25,16 @@ func CheckCaseResult(scriptFile string, logs string, report *commDomain.ZtfRepor total int, secs string, pathMaxWidth int, numbMaxWidth int, wsMsg *websocket.Message, errOutput string) { - steps, isOldFormat := scriptHelper.GetStepAndExpectMap(scriptFile) + steps := scriptHelper.GetStepAndExpectMap(scriptFile) isIndependent, expectIndependentContent := scriptHelper.GetDependentExpect(scriptFile) if isIndependent { - if isOldFormat { - scriptHelper.GetExpectMapFromIndependentFileObsolete(&steps, expectIndependentContent, false) - } else { - scriptHelper.GetExpectMapFromIndependentFile(&steps, expectIndependentContent, false) - } + scriptHelper.GetExpectMapFromIndependentFile(&steps, expectIndependentContent, false) } skip := false actualArr := make([][]string, 0) - if isOldFormat { - skip, actualArr = scriptHelper.ReadLogArrObsolete(logs) - } else { - skip, actualArr = scriptHelper.ReadLogArr(logs) - } + skip, actualArr = scriptHelper.ReadLogArr(logs) language := langHelper.GetLangByFile(scriptFile) ValidateCaseResult(scriptFile, language, steps, skip, actualArr, report, diff --git a/internal/pkg/helper/script/generator.go b/internal/pkg/helper/script/generator.go index b9e33c8ef90ab979d105fb86af50be1a3704c67a..511abf1f3cbd035b5185c4f5b926d48af054e79e 100644 --- a/internal/pkg/helper/script/generator.go +++ b/internal/pkg/helper/script/generator.go @@ -55,20 +55,12 @@ func GenerateScript(cs commDomain.ZtfCase, langType string, independentFile bool targetDir = filepath.Join(targetDir, strconv.Itoa(moduleId)) } - content := "" - isOldFormat := false - scriptPath = cs.ScriptPath if scriptPath == "" { fileUtils.MkDirIfNeeded(targetDir) scriptPath = filepath.Join(targetDir, fmt.Sprintf("%d.%s", caseId, commConsts.LangMap[langType]["extName"])) } - if fileUtils.FileExist(scriptPath) { // update title and steps - content = fileUtils.ReadFile(scriptPath) - isOldFormat = strings.Index(content, "[esac]") > -1 - } - *caseIds = append(*caseIds, strconv.Itoa(caseId)) info := make([]string, 0) @@ -84,12 +76,8 @@ func GenerateScript(cs commDomain.ZtfCase, langType string, independentFile bool StepWidth := 20 stepDisplayMaxWidth := 0 computerTestStepWidth(cs.Steps, &stepDisplayMaxWidth, StepWidth) + generateTestStepAndScript(cs.Steps, &steps, &independentExpects, independentFile) - if isOldFormat { - generateTestStepAndScriptObsolete(cs.Steps, &steps, &independentExpects, independentFile) - } else { - generateTestStepAndScript(cs.Steps, &steps, &independentExpects, independentFile) - } info = append(info, strings.Join(steps, "\n")) if independentFile { @@ -128,108 +116,6 @@ func GenEmptyScript(name, lang, pth string, productId int) { fileUtils.WriteFile(pth, out) } -func generateTestStepAndScriptObsolete(testSteps []commDomain.ZtfStep, steps *[]string, independentExpects *[]string, independentFile bool) { - nestedSteps := make([]commDomain.ZtfStep, 0) - currGroup := commDomain.ZtfStep{} - idx := 0 - - // convert steps to nested - for true { - if idx >= len(testSteps) { - break - } - - ts := testSteps[idx] - if ts.Parent == 0 && ts.Type != "group" { // flat step - currGroup = commDomain.ZtfStep{Id: -1, Desc: "group", Children: make([]commDomain.ZtfStep, 0)} - currGroup.Children = append(currGroup.Children, ts) - idx++ - - mutiLine := false - for true { - if idx >= len(testSteps) { - currGroup.MultiLine = mutiLine - nestedSteps = append(nestedSteps, currGroup) - break - } - - child := testSteps[idx] - if child.Type != "group" { // flat step - if !mutiLine { - mutiLine = IsMultiLine(child) - } - - currGroup.Children = append(currGroup.Children, child) - } else { // found a group step - currGroup.MultiLine = mutiLine - nestedSteps = append(nestedSteps, currGroup) - break - } - idx++ - } - } else if ts.Type == "group" { - currGroup = commDomain.ZtfStep{Desc: ts.Desc, Children: make([]commDomain.ZtfStep, 0)} - idx++ - - mutiLine := false - for true { - if idx >= len(testSteps) { - nestedSteps = append(nestedSteps, currGroup) - break - } - - child := testSteps[idx] - if child.Type != "group" && child.Parent == ts.Id { // child step - if !mutiLine { - mutiLine = IsMultiLine(child) - } - - currGroup.Children = append(currGroup.Children, child) - } else { // found a group step - currGroup.MultiLine = mutiLine - nestedSteps = append(nestedSteps, currGroup) - break - } - idx++ - } - } - } - - stepNumb := 1 - // print nested steps, only one level - for _, group := range nestedSteps { - if group.Id == -1 { // [group] - *steps = append(*steps, fmt.Sprintf("\n[group]")) - - for _, child := range group.Children { - stepContent, expectContent := GetCaseContent(child, strconv.Itoa(stepNumb), independentFile, group.MultiLine) - *steps = append(*steps, stepContent) - - if independentFile && strings.TrimSpace(child.Expect) != "" { - *independentExpects = append(*independentExpects, expectContent) - } - - stepNumb++ - } - } else { // [1. title] - *steps = append(*steps, "\n"+fmt.Sprintf("[%d. %s]", stepNumb, group.Desc)) - - for childNo, child := range group.Children { - numbStr := fmt.Sprintf("%d.%d", stepNumb, childNo+1) - - stepContent, expectContent := GetCaseContent(child, numbStr, independentFile, group.MultiLine) - *steps = append(*steps, stepContent) - - if independentFile && strings.TrimSpace(child.Expect) != "" { - *independentExpects = append(*independentExpects, expectContent) - } - } - - stepNumb++ - } - } -} - func generateTestStepAndScript(testSteps []commDomain.ZtfStep, steps *[]string, independentExpects *[]string, independentFile bool) { nestedSteps := make([]commDomain.ZtfStep, 0) diff --git a/internal/pkg/helper/script/parser.go b/internal/pkg/helper/script/parser.go index bc73464ffe8382fcb8d347e81fa5dd81fb132745..b369b7597dd7866a7c56a339457aad14c5b3ba6d 100644 --- a/internal/pkg/helper/script/parser.go +++ b/internal/pkg/helper/script/parser.go @@ -34,7 +34,7 @@ func ReplaceCaseDesc(desc, file string) { fileUtils.WriteFile(file, out) } -func GetStepAndExpectMap(file string) (steps []commDomain.ZentaoCaseStep, isOldFormat bool) { +func GetStepAndExpectMap(file string) (steps []commDomain.ZentaoCaseStep) { if !fileUtils.FileExist(file) { return } @@ -42,63 +42,20 @@ func GetStepAndExpectMap(file string) (steps []commDomain.ZentaoCaseStep, isOldF lang := langHelper.GetLangByFile(file) txt := fileUtils.ReadFile(file) - isOldFormat = strings.Index(txt, "[esac]") > -1 - _, checkpoints := ReadCaseInfo(txt, lang, isOldFormat) + _, checkpoints := ReadCaseInfo(txt, lang) lines := strings.Split(checkpoints, "\n") - if isOldFormat { - groupBlockArr := getGroupBlockArr(lines) - groupArr := getStepNestedArrObsolete(groupBlockArr) - _, steps = getSortedTextFromNestedStepsObsolete(groupArr) - } else { - groupArr := getStepNestedArr(lines) - _, steps = getSortedTextFromNestedSteps(groupArr) - } + groupArr := getStepNestedArr(lines) + _, steps = getSortedTextFromNestedSteps(groupArr) isIndependent, expectIndependentContent := GetDependentExpect(file) if isIndependent { - if isOldFormat { - GetExpectMapFromIndependentFileObsolete(&steps, expectIndependentContent, false) - } else { - GetExpectMapFromIndependentFile(&steps, expectIndependentContent, false) - } + GetExpectMapFromIndependentFile(&steps, expectIndependentContent, false) } return } -//func SortFile(file string) { -// stepsTxt := "" -// -// if fileUtils.FileExist(file) { -// txt := fileUtils.ReadFile(file) -// lang := langUtils.GetLangByFile(file) -// isOldFormat := strings.Index(txt, "[esac]") > -1 -// info, content := ReadCaseInfo(txt, lang, isOldFormat) -// lines := strings.Split(content, "\n") -// -// groupBlockArr := getGroupBlockArr(lines) -// groupArr := getStepNestedArrObsolete(groupBlockArr) -// stepsTxt, _, _, _ = getSortedTextFromNestedStepsObsolete(groupArr) -// -// // replace info -// from := "" -// to := "" -// if isOldFormat { -// from = `(?s)\[case\].*\[esac\]` -// to = "[case]\n" + info + "\n" + stepsTxt + "\n\n[esac]" -// } else { -// from = fmt.Sprintf(`(?s)%s.*%s`, langUtils.LangCommentsRegxMap[lang][0], langUtils.LangCommentsRegxMap[lang][1]) -// to = fmt.Sprintf("%s\n"+info+"\n"+stepsTxt+"\n\n%s", -// langUtils.LangCommentsRegxMap[lang][0], langUtils.LangCommentsRegxMap[lang][1]) -// } -// re, _ := regexp.Compile(from) -// script := re.ReplaceAllString(txt, to) -// -// fileUtils.WriteFile(file, script) -// } -//} - func getGroupBlockArr(lines []string) [][]string { groupBlockArr := make([][]string, 0) @@ -141,28 +98,6 @@ func getGroupBlockArr(lines []string) [][]string { return groupBlockArr } -func getStepNestedArrObsolete(blocks [][]string) (ret []commDomain.ZtfStep) { - for _, block := range blocks { - name := block[0] - group := commDomain.ZtfStep{Desc: name} - - if isStepsIdent(block[1]) { // muti line - group.MultiLine = true - childs := loadMultiLineSteps(block[1:]) - - group.Children = append(group.Children, childs...) - } else { - childs := loadSingleLineSteps(block[1:]) - - group.Children = append(group.Children, childs...) - } - - ret = append(ret, group) - } - - return ret -} - func getStepNestedArr(lines []string) (ret []commDomain.ZtfStep) { parent := commDomain.ZtfStep{} increase := 0 @@ -346,125 +281,6 @@ func isGroup(str string) bool { return ret } -func getSortedTextFromNestedStepsObsolete(groups []commDomain.ZtfStep) (stepsText string, steps []commDomain.ZentaoCaseStep) { - ret := make([]string, 0) - - groupNumb := 1 - for _, group := range groups { - desc := group.Desc - - if desc == "[group]" { - ret = append(ret, "\n"+desc) - - for idx, child := range group.Children { // level 1 item - step := commDomain.ZentaoCaseStep{} - - if group.MultiLine { - // steps - tag := replaceNumb("[steps]", groupNumb, -1, true) - ret = append(ret, " "+tag) - - stepTxt := printMutiStepOrExpect(child.Desc) - ret = append(ret, stepTxt) - - step.Desc = stepTxt - - // expects - tag = replaceNumb("[expects]", groupNumb, -1, true) - ret = append(ret, " "+tag) - - expectTxt := printMutiStepOrExpect(child.Expect) - ret = append(ret, expectTxt) - if idx < len(group.Children)-1 { - ret = append(ret, "") - } - - step.Expect = expectTxt - } else { - stepTxt := strings.TrimSpace(child.Desc) - stepTxtWithNumb := replaceNumb(stepTxt, groupNumb, -1, false) - - step.Desc = stepTxt - - expectTxt := child.Expect - expectTxt = strings.TrimSpace(expectTxt) - - step.Expect = expectTxt - - if expectTxt != "" { - expectTxt = ">> " + expectTxt - } - - ret = append(ret, fmt.Sprintf(" %s %s", stepTxtWithNumb, expectTxt)) - } - - steps = append(steps, step) - - groupNumb++ - } - } else { - groupStep := commDomain.ZentaoCaseStep{} - - desc = replaceNumb(group.Desc, groupNumb, -1, true) - ret = append(ret, "\n"+desc) - - groupStep.Type = commConsts.Group - groupStep.Desc = getGroupName(group.Desc) - groupStep.Expect = "" - - steps = append(steps, groupStep) - - childNumb := 1 - for _, child := range group.Children { - itemStep := commDomain.ZentaoCaseStep{} - - itemStep.Type = commConsts.Item - - if group.MultiLine { - // steps - tag := replaceNumb("[steps]", groupNumb, childNumb, true) - ret = append(ret, " "+tag) - - stepTxt := printMutiStepOrExpect(child.Desc) - ret = append(ret, stepTxt) - - itemStep.Desc = stepTxt - - // expects - tag = replaceNumb("[expects]", groupNumb, childNumb, true) - ret = append(ret, " "+tag) - - expectTxt := printMutiStepOrExpect(child.Expect) - ret = append(ret, expectTxt) - - itemStep.Expect = expectTxt - } else { - stepTxt := strings.TrimSpace(child.Desc) - itemStep.Desc = stepTxt - - expectTxt := child.Expect - expectTxt = strings.TrimSpace(expectTxt) - itemStep.Expect = expectTxt - - if expectTxt != "" { - expectTxt = ">> " + expectTxt - } - - ret = append(ret, fmt.Sprintf(" %s %s", stepTxt, expectTxt)) - } - - childNumb++ - } - - groupNumb++ - } - } - - stepsText = strings.Join(ret, "\n") - - return -} - func getSortedTextFromNestedSteps(groups []commDomain.ZtfStep) (ret string, steps []commDomain.ZentaoCaseStep) { arr := make([]string, 0) @@ -565,20 +381,6 @@ func printMutiStepOrExpect(str string) string { return strings.Join(ret, "\r\n") } -func GetExpectMapFromIndependentFileObsolete(steps *[]commDomain.ZentaoCaseStep, content string, withEmptyExpect bool) { - expectArr := ReadExpectIndependentArrObsolete(content) - - for idx, step := range *steps { - if len(expectArr) > idx { - step.Expect = strings.Join(expectArr[idx], "\r\n") - } else { - if withEmptyExpect { - step.Expect = "" - } - } - } -} - func GetExpectMapFromIndependentFile(steps *[]commDomain.ZentaoCaseStep, content string, withEmptyExpect bool) { expectArr := ReadExpectIndependentArr(content) @@ -752,105 +554,6 @@ func GetCaseInfo(file string) (pass bool, caseId, productId int, title string) { return } -//func ReadScriptCheckpoints(file string) ([]string, [][]string) { -// _, expectIndependentContent := GetDependentExpect(file) -// -// content := fileUtils.ReadFile(file) -// _, checkpoints := ReadCaseInfo(content) -// -// cpStepArr, expectArr := getCheckpointStepArr(checkpoints, expectIndependentContent) -// -// return cpStepArr, expectArr -//} -//func getCheckpointStepArr(content string, expectIndependentContent string) ([]string, [][]string) { -// cpStepArr := make([]string, 0) -// expectArr := make([][]string, 0) -// -// independentExpect := expectIndependentContent != "" -// -// lines := strings.Split(content, "\n") -// i := 0 -// for i < len(lines) { -// step := "" -// expects := make([]string, 0) -// -// line := strings.TrimSpace(lines[i]) -// -// regx := regexp.MustCompile(`(?U:[\d\.]*)(.+)>>(.*)`) -// arr := regx.FindStringSubmatch(line) -// if len(arr) > 2 { -// step = arr[1] -// if !independentExpect { -// expects = append(expects, strings.TrimSpace(arr[2])) -// } -// } else { -// regx = regexp.MustCompile(`\[([\d\.]*).*expects\]`) -// arr = regx.FindStringSubmatch(line) -// if len(arr) > 1 { -// step = arr[1] -// -// if !independentExpect { -// for i+1 < len(lines) { -// ln := strings.TrimSpace(lines[i+1]) -// -// if strings.Index(ln, "[") == 0 || strings.Index(ln, ">>") > 0 || ln == "" { -// break -// } else { -// expects = append(expects, ln) -// i++ -// } -// } -// } -// } -// } -// -// if step != "" && len(expects) > 0 { -// cpStepArr = append(cpStepArr, step) -// if !independentExpect { -// expectArr = append(expectArr, expects) -// } -// } -// i++ -// } -// -// if independentExpect { -// expectArr = ReadExpectIndependentArrObsolete(expectIndependentContent) -// } -// -// return cpStepArr, expectArr -//} - -func ReadExpectIndependentArrObsolete(content string) [][]string { - lines := strings.Split(content, "\n") - - ret := make([][]string, 0) - var cpArr []string - - for idx, line := range lines { - line = strings.TrimSpace(line) - - if line == ">>" { // more than one line - cpArr = make([]string, 0) - } else if strings.Index(line, ">>") == 0 { // single line - line = strings.Replace(line, ">>", "", -1) - line = strings.TrimSpace(line) - - cpArr = append(cpArr, line) - ret = append(ret, cpArr) - cpArr = make([]string, 0) - } else { // under >> - cpArr = append(cpArr, line) - - if idx == len(lines)-1 || strings.Index(lines[idx+1], ">>") > -1 { - ret = append(ret, cpArr) - cpArr = make([]string, 0) - } - } - } - - return ret -} - func ReadExpectIndependentArr(content string) [][]string { //正常显示6 //E2.16 @@ -889,8 +592,6 @@ func ReadExpectIndependentArr(content string) [][]string { idx += 1 } - } else if line == ">>" { - continue } else { currModel = "single" @@ -907,51 +608,6 @@ func ReadExpectIndependentArr(content string) [][]string { return ret } -func ReadLogArrObsolete(content string) (isSkip bool, ret [][]string) { - lines := strings.Split(content, "\n") - - ret = make([][]string, 0) - var cpArr []string - - model := "" - for idx, line := range lines { - line = strings.TrimSpace(line) - - if line == "skip" { - isSkip = true - return - } - - if line == ">>" { // more than one line - model = "multi" - cpArr = make([]string, 0) - } else if strings.Index(line, ">>") == 0 { // single line - model = "single" - - line = strings.Replace(line, ">>", "", -1) - line = strings.TrimSpace(line) - - cpArr = append(cpArr, line) - ret = append(ret, cpArr) - cpArr = make([]string, 0) - } else { - if model == "" || model == "single" { - continue - } - - // under >> - cpArr = append(cpArr, line) - - if idx == len(lines)-1 || strings.Index(lines[idx+1], ">>") > -1 { - ret = append(ret, cpArr) - cpArr = make([]string, 0) - } - } - } - - return -} - func ReadLogArr(content string) (isSkip bool, ret [][]string) { lines := strings.Split(content, "\n") @@ -983,8 +639,6 @@ func ReadLogArr(content string) (isSkip bool, ret [][]string) { idx = idx + 1 model = "" } - } else if line == ">>" { - continue } else { model = "single" @@ -1013,14 +667,10 @@ func CheckFileContentIsScript(content string) bool { return pass } -func ReadCaseInfo(content, lang string, isOldFormat bool) (info, checkpoints string) { - regStr := "" - if isOldFormat { - regStr = `(?s)\[case\]((?U:.*pid.*))\n(.*)\[esac\]` - } else { - regStr = fmt.Sprintf(`(?smU)%s((?U:.*pid.*))\n(.*)%s`, - commConsts.LangCommentsRegxMap[lang][0], commConsts.LangCommentsRegxMap[lang][1]) - } +func ReadCaseInfo(content, lang string) (info, checkpoints string) { + regStr := fmt.Sprintf(`(?smU)%s((?U:.*pid.*))\n(.*)%s`, + commConsts.LangCommentsRegxMap[lang][0], commConsts.LangCommentsRegxMap[lang][1]) + myExp := regexp.MustCompile(regStr) arr := myExp.FindStringSubmatch(content) diff --git a/internal/pkg/helper/zentao/bug.go b/internal/pkg/helper/zentao/bug.go index 90c7103440fcd67ebb1d0b9d2f432a20d3ced77b..ac379ee7ed5ef1bccaa824f835310ec48c6904ef 100644 --- a/internal/pkg/helper/zentao/bug.go +++ b/internal/pkg/helper/zentao/bug.go @@ -58,7 +58,7 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug } for _, cs := range report.FuncResult { - if cs.Id != caseId { + if cs.Id != caseId || cs.Status != commConsts.FAIL { continue } diff --git a/internal/pkg/helper/zentao/case.go b/internal/pkg/helper/zentao/case.go index ed9f88cd44cc7d97fab868a45aa9ffaa392ed87f..c20980aa9fc4b254f4322d1d20bdab812c72198f 100644 --- a/internal/pkg/helper/zentao/case.go +++ b/internal/pkg/helper/zentao/case.go @@ -22,8 +22,8 @@ import ( "github.com/kataras/iris/v12" ) -func CommitCase(caseId int, title string, - steps []commDomain.ZentaoCaseStep, config commDomain.WorkspaceConf) (err error) { +func CommitCase(caseId int, title string, steps []commDomain.ZentaoCaseStep, script serverDomain.TestScript, + config commDomain.WorkspaceConf) (err error) { err = Login(config) if err != nil { @@ -39,9 +39,11 @@ func CommitCase(caseId int, title string, url := GenApiUrl(uri, nil, config.Url) requestObj := map[string]interface{}{ - "type": "feature", - "title": title, - "steps": steps, + "type": "feature", + "title": title, + "steps": steps, + "script": script.Code, + "lang": script.Lang, } json, err := json.Marshal(requestObj) diff --git a/internal/pkg/helper/zentao/sync.go b/internal/pkg/helper/zentao/sync.go index 39c4915fd7c7b894334ffc8711d4a810cb656b7a..6108b9b8883f54eb1f7a214150633274407aee59 100644 --- a/internal/pkg/helper/zentao/sync.go +++ b/internal/pkg/helper/zentao/sync.go @@ -76,8 +76,9 @@ func SyncToZentao(cases []string, config commDomain.WorkspaceConf) (count int, e continue } - steps, _ := scriptHelper.GetStepAndExpectMap(cs) - err = CommitCase(id, title, steps, config) + steps := scriptHelper.GetStepAndExpectMap(cs) + script, _ := scriptHelper.GetScriptContent(cs, -1) + err = CommitCase(id, title, steps, script, config) if err == nil { count++ diff --git a/internal/server/config/log.go b/internal/server/config/log.go index f0553d9c23e3416b2eb03663e9deaf312e23f1e2..cfbf9a2cdd32d3ebd2cddaed9aa3bc333758b047 100644 --- a/internal/server/config/log.go +++ b/internal/server/config/log.go @@ -15,6 +15,10 @@ import ( "go.uber.org/zap/zapcore" ) +const ( + WinFileSchema = "winfile:///" +) + func InitLog() { CONFIG.Zap.Director = filepath.Join(commConsts.WorkDir, CONFIG.Zap.Director) if !dir.IsExist(CONFIG.Zap.Director) { // 判断是否有Director文件夹 @@ -50,7 +54,7 @@ func InitExecLog(workspacePath string) { // print to test log file logPath := filepath.Join(commConsts.ExecLogDir, commConsts.LogText) if commonUtils.IsWin() { - logPath = filepath.Join("winfile:///", logPath) + logPath = filepath.Join(WinFileSchema, logPath) zap.RegisterSink("winfile", newWinFileSink) } @@ -69,7 +73,7 @@ func InitExecLog(workspacePath string) { // print to test result file logPathResult := filepath.Join(commConsts.ExecLogDir, commConsts.ResultText) if commonUtils.IsWin() { - logPathResult = filepath.Join("winfile:///", logPathResult) + logPathResult = filepath.Join(WinFileSchema, logPathResult) zap.RegisterSink("winfile", newWinFileSink) } config.OutputPaths = []string{logPathResult} @@ -133,8 +137,8 @@ func getLogConfig() (config zap.Config) { logPathInfo := filepath.Join(CONFIG.Zap.Director, "info.log") logPathErr := filepath.Join(CONFIG.Zap.Director, "err.log") if commonUtils.IsWin() { - logPathInfo = filepath.Join("winfile:///", logPathInfo) - logPathErr = filepath.Join("winfile:///", logPathErr) + logPathInfo = filepath.Join(WinFileSchema, logPathInfo) + logPathErr = filepath.Join(WinFileSchema, logPathErr) } config = zap.Config{ diff --git a/internal/server/core/web/index.go b/internal/server/core/web/index.go index a63f794d22ac0b5a12b26144b92a3d4250ee5ad8..a9d9c4e90d9aceb3dc4ba42f9044daf3c62b42b1 100644 --- a/internal/server/core/web/index.go +++ b/internal/server/core/web/index.go @@ -81,7 +81,6 @@ func Init(port int) *WebServer { close(idleConnClosed) }) - // init grpc mvc.New(app) // init websocket diff --git a/internal/server/modules/v1/repo/interpreter.go b/internal/server/modules/v1/repo/interpreter.go index fa65b25cd4bc65a93bd13aee127e64bd55357f91..f3e1dfa7a16470fd6cb66547af4b55a04f0f8179 100644 --- a/internal/server/modules/v1/repo/interpreter.go +++ b/internal/server/modules/v1/repo/interpreter.go @@ -7,7 +7,6 @@ import ( "github.com/easysoft/zentaoatf/internal/server/modules/v1/model" "github.com/fatih/color" - "go.uber.org/zap" "gorm.io/gorm" ) @@ -33,7 +32,7 @@ func (r *InterpreterRepo) Get(id uint) (po model.Interpreter, err error) { Where("NOT deleted"). First(&po).Error if err != nil { - logUtils.Errorf(color.RedString("find interpreter by id failed, error: %s.", err.Error())) + logUtils.Info(color.RedString("find interpreter by id failed, %s.", err.Error())) return } @@ -48,7 +47,7 @@ func (r *InterpreterRepo) Create(interpreter model.Interpreter) (id uint, err er err = r.DB.Model(&model.Interpreter{}).Create(&interpreter).Error if err != nil { - logUtils.Errorf(color.RedString("create interpreter failed, error: %s.", err.Error())) + logUtils.Info(color.RedString("create interpreter failed, %s.", err.Error())) return 0, err } @@ -65,7 +64,7 @@ func (r *InterpreterRepo) Update(interpreter model.Interpreter) error { err = r.DB.Model(&model.Interpreter{}).Where("id = ?", interpreter.ID).Updates(&interpreter).Error if err != nil { - logUtils.Errorf(color.RedString("update interpreter failed, error: %s.", err.Error())) + logUtils.Info(color.RedString("update interpreter failed, %s.", err.Error())) return err } @@ -76,7 +75,7 @@ func (r *InterpreterRepo) Delete(id uint) (err error) { err = r.DB.Model(&model.Interpreter{}).Where("id = ?", id). Updates(map[string]interface{}{"deleted": true}).Error if err != nil { - logUtils.Errorf("delete interpreter by id error", zap.String("error:", err.Error())) + logUtils.Info(color.RedString("delete interpreter by id error, %s.", err.Error())) return } diff --git a/internal/server/modules/v1/repo/site.go b/internal/server/modules/v1/repo/site.go index c72d6379873ba485fb38878487ee9365bcbea136..00d1bb69ee27696097569a845d94dde610d936d5 100644 --- a/internal/server/modules/v1/repo/site.go +++ b/internal/server/modules/v1/repo/site.go @@ -36,7 +36,7 @@ func (r *SiteRepo) Paginate(req serverDomain.ReqPaginate) (data domain.PageData, err = db.Count(&count).Error if err != nil { - logUtils.Errorf("count site error", zap.String("error:", err.Error())) + logUtils.Info(color.RedString("count site error %s.", err.Error())) return } diff --git a/internal/server/modules/v1/repo/workspace.go b/internal/server/modules/v1/repo/workspace.go index 9b488f5eb84b64c34ac361936aed49bc8238d4bf..6cf89b64fe25590e6706527b89edbca20b8ffb8e 100644 --- a/internal/server/modules/v1/repo/workspace.go +++ b/internal/server/modules/v1/repo/workspace.go @@ -11,7 +11,6 @@ import ( serverDomain "github.com/easysoft/zentaoatf/internal/server/modules/v1/domain" "github.com/easysoft/zentaoatf/internal/server/modules/v1/model" "github.com/fatih/color" - "go.uber.org/zap" "gorm.io/gorm" ) @@ -40,7 +39,6 @@ func (r *WorkspaceRepo) Paginate(req serverDomain.WorkspaceReqPaginate) (data do err = db.Count(&count).Error if err != nil { - logUtils.Errorf("count site error", zap.String("error:", err.Error())) return } @@ -50,7 +48,7 @@ func (r *WorkspaceRepo) Paginate(req serverDomain.WorkspaceReqPaginate) (data do Scopes(dao.PaginateScope(req.Page, req.PageSize, req.Order, req.Field)). Find(&pos).Error if err != nil { - logUtils.Errorf("query site error", zap.String("error:", err.Error())) + logUtils.Info(color.RedString("query site error, %s.", err.Error())) return } @@ -65,7 +63,7 @@ func (r *WorkspaceRepo) Get(id uint) (po model.Workspace, err error) { Where("NOT deleted"). First(&po).Error if err != nil { - logUtils.Errorf(color.RedString("find workspace by id failed, error: %s.", err.Error())) + logUtils.Info(color.RedString("find workspace by id failed, %s.", err.Error())) return } @@ -80,7 +78,7 @@ func (r *WorkspaceRepo) Create(workspace model.Workspace) (id uint, err error) { err = r.DB.Model(&model.Workspace{}).Create(&workspace).Error if err != nil { - logUtils.Errorf(color.RedString("create site failed, error: %s.", err.Error())) + logUtils.Info(color.RedString("create site failed, %s.", err.Error())) return 0, err } @@ -132,7 +130,7 @@ func (r *WorkspaceRepo) DeleteByPath(path string, productId uint) (err error) { Error if err != nil { - logUtils.Errorf(color.RedString("by path, delete workspace failed, error: %s.", err.Error())) + logUtils.Info(color.RedString("by path, delete workspace failed, %s.", err.Error())) return } @@ -156,7 +154,7 @@ func (r *WorkspaceRepo) FindByPath(workspacePath string) (po model.Workspace, er err = db.First(&po).Error if err != nil { - logUtils.Errorf("find workspace by path error", err.Error()) + logUtils.Info(color.RedString("find workspace by path error, %s.", err.Error())) return } diff --git a/internal/server/modules/v1/service/file.go b/internal/server/modules/v1/service/file.go index 095ee93c34fd8cd1cf005c6588d3ae1ccca12b44..eb4ef0807fc5c87aa6df9ad31980026158ae252e 100644 --- a/internal/server/modules/v1/service/file.go +++ b/internal/server/modules/v1/service/file.go @@ -18,6 +18,10 @@ import ( "github.com/snowlyg/helper/str" ) +const ( + UploadFail = "file upload failed, %s." +) + var ( ErrEmpty = errors.New("请上传正确的文件") ) @@ -39,12 +43,12 @@ func (s *FileService) UploadFile(ctx iris.Context, fh *multipart.FileHeader) (ir path := filepath.Join(dir.GetCurrentAbPath(), "static", "upload", "images") err = dir.InsureDir(path) if err != nil { - logUtils.Infof(color.RedString("file upload failed, error: %s.", err.Error())) + logUtils.Infof(color.RedString(UploadFail, err.Error())) return nil, err } _, err = ctx.SaveFormFile(fh, filepath.Join(path, filename)) if err != nil { - logUtils.Infof(color.RedString("file upload failed, error: %s.", err.Error())) + logUtils.Infof(color.RedString(UploadFail, err.Error())) return nil, err } @@ -104,13 +108,13 @@ func (s *FileService) addDir(pth string, parent *serverDomain.TestAsset) (dirNod func GetFileName(name string) (string, error) { fns := strings.Split(strings.TrimLeft(name, "./"), ".") if len(fns) != 2 { - logUtils.Infof(color.RedString("file upload failed, error: wrong file name %s.", name)) + logUtils.Infof(color.RedString(UploadFail, "wrong file name "+name)) return "", ErrEmpty } ext := fns[1] md5, err := dir.MD5(name) if err != nil { - logUtils.Errorf(color.RedString("file upload failed, error: %s.", name)) + logUtils.Errorf(color.RedString(UploadFail, name)) return "", err } return str.Join(md5, ".", ext), nil diff --git a/pkg/core/mq/broker.go b/pkg/core/mq/broker.go index 29f3072720d4b75f868cf59546651486c00724f9..d0d75174a10234e52be44784664c0690f6846059 100644 --- a/pkg/core/mq/broker.go +++ b/pkg/core/mq/broker.go @@ -6,6 +6,10 @@ import ( "time" ) +const ( + BrokerClosed = "broker closed" +) + type Broker interface { publish(topic string, msg interface{}) error subscribe(topic string) (<-chan interface{}, error) @@ -50,7 +54,7 @@ func (b *BrokerImpl) close() { func (b *BrokerImpl) publish(topic string, pub interface{}) error { select { case <-b.exit: - return errors.New("broker closed") + return errors.New(BrokerClosed) default: } @@ -107,7 +111,7 @@ func (b *BrokerImpl) broadcast(msg interface{}, subscribers []chan interface{}) func (b *BrokerImpl) subscribe(topic string) (<-chan interface{}, error) { select { case <-b.exit: - return nil, errors.New("broker closed") + return nil, errors.New(BrokerClosed) default: } @@ -121,7 +125,7 @@ func (b *BrokerImpl) subscribe(topic string) (<-chan interface{}, error) { func (b *BrokerImpl) unsubscribe(topic string, sub <-chan interface{}) error { select { case <-b.exit: - return errors.New("broker closed") + return errors.New(BrokerClosed) default: } diff --git a/pkg/lib/common/utils.go b/pkg/lib/common/utils.go index dc44ecf8f8430946c145bff69859341ac0a693f5..92b9a44e821ccc238ee1550caa5a1169c121c5e5 100644 --- a/pkg/lib/common/utils.go +++ b/pkg/lib/common/utils.go @@ -52,14 +52,6 @@ func IsMac() bool { return GetOs() == "mac" } -func UpdateUrl(url string) string { - if strings.LastIndex(url, "/") < len(url)-1 { - url += "/" - } - - return url -} - func IntToStrArr(intArr []int) (strArr []string) { for _, i := range intArr { strArr = append(strArr, strconv.Itoa(i)) diff --git a/pkg/lib/shell/shell.go b/pkg/lib/shell/shell.go index e897f8d8a4919b7b16a01d8a24d607001b1472ee..261883778554725cb9e2b14f4df1817fe09355fe 100644 --- a/pkg/lib/shell/shell.go +++ b/pkg/lib/shell/shell.go @@ -4,16 +4,13 @@ import ( "bufio" "bytes" "fmt" - commonUtils "github.com/easysoft/zentaoatf/pkg/lib/common" i118Utils "github.com/easysoft/zentaoatf/pkg/lib/i118" logUtils "github.com/easysoft/zentaoatf/pkg/lib/log" stringUtils "github.com/easysoft/zentaoatf/pkg/lib/string" - "github.com/kataras/iris/v12/websocket" "io" "os" "os/exec" - "regexp" "strings" ) @@ -31,12 +28,7 @@ func ExecWinCmd(cmdStr string) (string, error) { } func ExeSysCmd(cmdStr string) (string, error) { - var cmd *exec.Cmd - if commonUtils.IsWin() { - cmd = exec.Command("cmd", "/C", cmdStr) - } else { - cmd = exec.Command("/bin/bash", "-c", cmdStr) - } + cmd := getCmd(cmdStr) var out bytes.Buffer cmd.Stdout = &out @@ -62,12 +54,7 @@ func ExeShellWithPid(cmdStr string) (string, error, int) { } func ExeShellInDirWithPid(cmdStr string, dir string) (ret string, err error, pid int) { - var cmd *exec.Cmd - if commonUtils.IsWin() { - cmd = exec.Command("cmd", "/C", cmdStr) - } else { - cmd = exec.Command("/bin/bash", "-c", cmdStr) - } + cmd := getCmd(cmdStr) if dir != "" { cmd.Dir = dir } @@ -94,12 +81,7 @@ func ExeShellWithOutputInDir(cmdStr string, dir string) ([]string, error) { } func ExeShellWithEnvVarsAndOutputInDir(cmdStr, dir string, envVars []string) ([]string, error) { - var cmd *exec.Cmd - if commonUtils.IsWin() { - cmd = exec.Command("cmd", "/C", cmdStr) - } else { - cmd = exec.Command("/bin/bash", "-c", cmdStr) - } + cmd := getCmd(cmdStr) if dir != "" { cmd.Dir = dir @@ -139,123 +121,18 @@ func ExeShellWithEnvVarsAndOutputInDir(cmdStr, dir string, envVars []string) ([] return output, nil } -func ExeShellCallback(ch chan int, cmdStr, dir string, - fun func(info string, msg websocket.Message), msg websocket.Message) (err error) { - - var cmd *exec.Cmd +func getCmd(cmdStr string) (cmd *exec.Cmd) { if commonUtils.IsWin() { - cmd = exec.Command("cmd", "/C", cmdStr) + cmd = getWinCmd(cmdStr) } else { - cmd = exec.Command("/bin/bash", "-c", cmdStr) - } - - if dir != "" { - cmd.Dir = dir - } - - stdout, err := cmd.StdoutPipe() - - if err != nil { - fmt.Println(err) - return - } - - cmd.Start() - - if err != nil { - return - } - - reader := bufio.NewReader(stdout) - for { - line, err2 := reader.ReadString('\n') - if err2 != nil || io.EOF == err2 { - break - } - - line = strings.Trim(line, "\n") - fun(line, msg) - - select { - case <-ch: - fmt.Println("exiting...") - ch <- 1 - return - default: - fmt.Println("continue...") - } + cmd = getLinuxCmd(cmdStr) } - cmd.Wait() return } - -func GetProcess(app string) (string, error) { - var cmd *exec.Cmd - - tmpl := "" - cmdStr := "" - if commonUtils.IsWin() { - tmpl = `tasklist` - cmdStr = fmt.Sprintf(tmpl) - - cmd = exec.Command("cmd", "/C", cmdStr) - } else { - tmpl = `ps -ef | grep "%s" | grep -v "grep" | awk '{print $2}'` - cmdStr = fmt.Sprintf(tmpl, app) - - cmd = exec.Command("/bin/bash", "-c", cmdStr) - } - - var out bytes.Buffer - cmd.Stdout = &out - - err := cmd.Run() - output := "" - if commonUtils.IsWin() { - arr := strings.Split(out.String(), "\n") - for _, line := range arr { - if strings.Index(line, app+".exe") > -1 { - arr2 := regexp.MustCompile(`\s+`).Split(line, -1) - output = arr2[1] - break - } - } - } else { - output = out.String() - } - - return output, err -} - -func KillProcess(app string) (string, error) { - var cmd *exec.Cmd - - tmpl := "" - cmdStr := "" - if commonUtils.IsWin() { - // tasklist | findstr ztf.exe - tmpl = `taskkill.exe /f /im %s.exe` - cmdStr = fmt.Sprintf(tmpl, app) - - cmd = exec.Command("cmd", "/C", cmdStr) - } else { - tmpl = `ps -ef | grep '%s' | grep -v "grep" | awk '{print $2}' | xargs kill -9` - cmdStr = fmt.Sprintf(tmpl, app) - - cmd = exec.Command("/bin/bash", "-c", cmdStr) - } - - var out bytes.Buffer - cmd.Stdout = &out - - err := cmd.Run() - output := out.String() - - return output, err +func getWinCmd(cmdStr string) (cmd *exec.Cmd) { + return exec.Command("cmd", "/C", cmdStr) } - -func KillProcessById(pid int) { - cmdStr := fmt.Sprintf("kill -9 %d", pid) - ExeShell(cmdStr) +func getLinuxCmd(cmdStr string) (cmd *exec.Cmd) { + return exec.Command("/bin/bash", "-c", cmdStr) } diff --git a/ui/src/components/LayoutToolbar.vue b/ui/src/components/LayoutToolbar.vue deleted file mode 100644 index 6fced96c70909b0cb94ef1e302b2b65072a73e69..0000000000000000000000000000000000000000 --- a/ui/src/components/LayoutToolbar.vue +++ /dev/null @@ -1,14 +0,0 @@ - - - diff --git a/ui/src/components/Table.vue b/ui/src/components/Table.vue index 2b9e7ec11cfab6294b1b4de1011dde19e8d4f04c..72a10d4c0fe58cad16789894886fe18e2888e001 100644 --- a/ui/src/components/Table.vue +++ b/ui/src/components/Table.vue @@ -219,12 +219,12 @@ import {computed, defineComponent, nextTick, onBeforeUpdate, onMounted, reactive, ref, watch,} from "vue"; import {useI18n} from "vue-i18n"; -interface pageOption { +interface PageOption { value: number; text: number | string; } -interface tableSetting { +interface TableSetting { isSlotMode: boolean; isCheckAll: boolean; isHidePaging: boolean; @@ -237,15 +237,15 @@ interface tableSetting { paging: Array; order: string; sort: string; - pageOptions: Array; + pageOptions: Array; } -interface column { +interface Column { isKey: string; field: string; } -interface pageMessage { +interface PageMessage { pagingInfo: string pageSizeChangeLabel: string gotoPageLabel: string @@ -334,7 +334,7 @@ export default defineComponent({ // Display text messages: { type: Object, - default: {} as pageMessage, + default: {} as PageMessage, }, // Static mode(no refresh server data) isStaticMode: { @@ -389,11 +389,11 @@ export default defineComponent({ let localTable = ref(null); // Validate dropdown values have page-size value or not - let tmpPageOptions = props.pageOptions as Array; + let tmpPageOptions = props.pageOptions as Array; let defaultPageSize = props.pageOptions.length > 0 ? ref(tmpPageOptions[0].value) : ref(props.pageSize); if (tmpPageOptions.length > 0) { - tmpPageOptions.forEach((v: pageOption) => { + tmpPageOptions.forEach((v: PageOption) => { if ( Object.prototype.hasOwnProperty.call(v, "value") && Object.prototype.hasOwnProperty.call(v, "text") && @@ -405,7 +405,7 @@ export default defineComponent({ } // Internal set value for components - const setting: tableSetting = reactive({ + const setting: TableSetting = reactive({ // Enable slot mode isSlotMode: props.isSlotMode, // Whether to select all @@ -415,7 +415,7 @@ export default defineComponent({ // KEY field name keyColumn: computed(() => { let key = ""; - Object.assign(props.columns).forEach((col: column) => { + Object.assign(props.columns).forEach((col: Column) => { if (col.isKey) { key = col.field; } @@ -466,11 +466,11 @@ export default defineComponent({ order: props.sortable.order, sort: props.sortable.sort, pageOptions: computed(() => { - const ops: pageOption[] = []; + const ops: PageOption[] = []; props.pageOptions?.forEach((o) => { ops.push({ - value: (o as pageOption).value, - text: (o as pageOption).text, + value: (o as PageOption).value, + text: (o as PageOption).text, }); }); return ops; @@ -485,7 +485,7 @@ export default defineComponent({ if (setting.sort === "desc") { sort_order = -1; } - let rows = props.rows as Array; + let rows = props.rows // eslint-disable-next-line @typescript-eslint/no-explicit-any rows.sort((a: any, b: any): number => { if (a[property] < b[property]) { @@ -642,16 +642,16 @@ export default defineComponent({ /** * Switch page number * - * @param page number New page number - * @param prevPage number Current page number + * @param pageNum number New page number + * @param prevPageNum number Current page number */ - const changePage = (page: number, prevPage: number) => { + const changePage = (pageNum: number, prevPageNum: number) => { setting.isCheckAll = false; let order = setting.order; let sort = setting.sort; - let offset = (page - 1) * setting.pageSize; + let offset = (pageNum - 1) * setting.pageSize; let limit = setting.pageSize; - if (!props.isReSearch || page > 1 || page == prevPage) { + if (!props.isReSearch || pageNum > 1 || pageNum == prevPageNum) { // Call query will only be executed if the page number is changed without re-query console.log("do-search", offset, limit) diff --git a/ui/src/components/TreeNode.vue b/ui/src/components/TreeNode.vue index 8d432940ef4b240b67507eb31216eed070854245..a807e6f24b9d9966836383a9940a0b1b58fa1b39 100644 --- a/ui/src/components/TreeNode.vue +++ b/ui/src/components/TreeNode.vue @@ -50,13 +50,6 @@ - - - - - - - - diff --git a/ui/src/views/script/index.vue b/ui/src/views/script/index.vue deleted file mode 100644 index 61d18c700feb07745179bda50e369cdeb9601bd0..0000000000000000000000000000000000000000 --- a/ui/src/views/script/index.vue +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - diff --git a/ui/src/views/script/service.ts b/ui/src/views/script/service.ts index 855a74f72e02ef549c0258660af5dd8993e36f6f..d0d07bd38a6b51907f6e1a448aa2f5f84e25ac09 100644 --- a/ui/src/views/script/service.ts +++ b/ui/src/views/script/service.ts @@ -218,27 +218,22 @@ export const getFileNodesUnderParent = (node): string[] => { getNodeMap(node, nodeMap) const arr = [] as string[] - Object.keys(nodeMap).forEach((k, v) => { - const node = nodeMap[k] - if (node.type === 'file') { - node.childrem = null - arr.push(node) + Object.keys(nodeMap).forEach((k, _v) => { + const item = nodeMap[k] + if (item.type === 'file') { + item.childrem = null + arr.push(item) } }) return arr } -export function getSyncToInfoFromMenu(key: string, node: any): any { - - return -} - export function scriptTreeAddAttr(treeData) { if(treeData == undefined){ return treeData; } - treeData = treeData.map((item, index) => { + treeData = treeData.map((item) => { item.id = item.path; item.checkable = item.workspaceType == 'ztf' ? true : false; if (item.isLeaf) { diff --git a/ui/src/views/script/store.ts b/ui/src/views/script/store.ts index 05c0ef0e2104723e477dfde7678208de96fbccbf..7fe282f8521f44c979fba5f2f1ecd7a1a030430d 100644 --- a/ui/src/views/script/store.ts +++ b/ui/src/views/script/store.ts @@ -107,7 +107,7 @@ const StoreModel: ModuleType = { commit('setQueryParams', playload); return true; }, - async loadChildren({ commit }, treeNode: any ) { + async loadChildren(_ctx, treeNode: any ) { console.log('load node children', treeNode.dataRef.workspaceType) if (treeNode.dataRef.workspaceType === 'ztf') return true @@ -118,19 +118,16 @@ const StoreModel: ModuleType = { }) }, - async getScript({ commit, dispatch }, script: any ) { + async getScript({ commit}, script: any ) { if (!script || script.type !== 'file') { commit('setItem', null); - return true; - } - - if (script.path.indexOf('zentao-') === 0) { + } else if (script.path.indexOf('zentao-') === 0) { commit('setItem', {id: script.caseId, workspaceId: script.workspaceId, code: ScriptFileNotExist}); - return true; + } else { + const response: ResponseData = await get(script.path, script.workspaceId); + commit('setItem', response.data); } - const response: ResponseData = await get(script.path, script.workspaceId); - commit('setItem', response.data); return true; }, @@ -150,7 +147,7 @@ const StoreModel: ModuleType = { return resp }, - async syncToZentao({ commit, dispatch, state }, payload: any ) { + async syncToZentao({ dispatch, state }, payload: any ) { const resp = await syncToZentao(payload) if (resp.code === 0) { @@ -170,7 +167,7 @@ const StoreModel: ModuleType = { return data.done }, - async createScript({ commit , dispatch, state}, payload: any) { + async createScript({ dispatch, state}, payload: any) { try { const jsn = await create(payload); const path = jsn.data @@ -182,7 +179,7 @@ const StoreModel: ModuleType = { return '' } }, - async updateScript({ commit }, payload: any ) { + async updateScript(_ctx, payload: any ) { try { const { id, ...params } = payload; await update(id, { ...params }); @@ -192,7 +189,7 @@ const StoreModel: ModuleType = { } }, - async updateCode({ commit, dispatch, state }, payload: any ) { + async updateCode({ dispatch, state }, payload: any ) { try { await updateCode(payload); await dispatch('listScript', state.queryParams) @@ -202,7 +199,7 @@ const StoreModel: ModuleType = { } }, - async pasteScript({ commit , dispatch, state}, data: any ) { + async pasteScript({ dispatch, state}, data: any ) { try { await paste(data); await dispatch('listScript', state.queryParams) @@ -213,7 +210,7 @@ const StoreModel: ModuleType = { } }, - async moveScript({ commit , dispatch, state}, data: any ) { + async moveScript({ dispatch, state}, data: any ) { try { await move(data); await dispatch('listScript', state.queryParams) @@ -224,7 +221,7 @@ const StoreModel: ModuleType = { } }, - async deleteScript({ commit , dispatch, state}, path: string ) { + async deleteScript({ dispatch, state}, path: string ) { try { await remove(path); await dispatch('listScript', state.queryParams) diff --git a/ui/src/views/site/store.ts b/ui/src/views/site/store.ts index c82f1b21a5a7153ebe0791a68ca4ed332f241669..fa1744a88d723bfa4382f234014adbd8aa2ee7ee 100644 --- a/ui/src/views/site/store.ts +++ b/ui/src/views/site/store.ts @@ -76,7 +76,7 @@ const StoreModel: ModuleType = { commit('setDetailResult',data); return true; }, - async save({ commit }, payload) { + async save(_ctx, payload) { try { await save(payload); return true; @@ -84,7 +84,7 @@ const StoreModel: ModuleType = { return false; } }, - async delete({ commit , dispatch, state}, id: number ) { + async delete({ dispatch}, id: number ) { try { await remove(id); dispatch('list', {}) diff --git a/ui/src/views/workspace/store.ts b/ui/src/views/workspace/store.ts index 807f92bd778f26ba418731ddb1b446a5195aeaad..bd07860cfedcb8750ead439c2f3be3393ebc3910 100644 --- a/ui/src/views/workspace/store.ts +++ b/ui/src/views/workspace/store.ts @@ -97,7 +97,7 @@ const StoreModel: ModuleType = { commit('setDetailResult',data); return true; }, - async save({ commit }, payload) { + async save(_ctx, payload) { try { await save(payload); return true; @@ -105,7 +105,7 @@ const StoreModel: ModuleType = { return false; } }, - async delete({ commit , dispatch, state}, id: number ) { + async delete({ dispatch}, id: number ) { try { await remove(id); dispatch('list', {}) diff --git a/xdoc/notes.txt b/xdoc/notes.txt index adffb4f2e58e7d946403ab873f033b2ebef5a772..3f641dd28346b9ed2a82bbaa70d232d8f42a565c 100644 --- a/xdoc/notes.txt +++ b/xdoc/notes.txt @@ -61,3 +61,9 @@ sips -z 32 32 ztf.png --out tmp.iconset/icon_32x32.png CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ GOOS=windows GOARCH=amd64 go build -ldflags "-X 'commConsts.appVersion=3.0.0' -X 'commConsts.buildTime=Mon Jul 25 09:31:39 2022 +0800' -X 'commConsts.goVersion=go version go1.17.1 darwin/amd64 ' -X 'commConsts.gitHash=d118c05ae38d76231abfb6430e52ec517e080f50'" -x -v -ldflags "-s -w" -o client/bin/win32/ztf.exe cmd/command/main.go cmd/command/main.syso + +sonar-scanner \ + -Dsonar.projectKey=ztf \ + -Dsonar.sources=. \ + -Dsonar.host.url=http://localhost:59001 \ + -Dsonar.login=sqp_94f2484e50b1cfea719eb791f4e5d544be887f87