commit 5214b6a3d6bb89c204dd76be58d394acabf76616 Author: r0n1n7an Date: Mon Jul 28 09:43:13 2025 +0800 init commit diff --git a/TesterWebSvc b/TesterWebSvc new file mode 100644 index 0000000..cce2bab Binary files /dev/null and b/TesterWebSvc differ diff --git a/TesterWebSvc.exe b/TesterWebSvc.exe new file mode 100644 index 0000000..2857f06 Binary files /dev/null and b/TesterWebSvc.exe differ diff --git a/TesterWebSvc.go b/TesterWebSvc.go new file mode 100644 index 0000000..67fd70c --- /dev/null +++ b/TesterWebSvc.go @@ -0,0 +1,288 @@ +package main + +import ( + "flag" + "fmt" + "html" + "io" + "log" + "net/http" + "os" + "sort" + "strings" + "time" + + re2 "github.com/dlclark/regexp2" + ini "gopkg.in/ini.v1" +) + +var ver string = "2.0.3" +var vsn bool = false +var cfg *ini.File + +var ( + uri string + server string + port string + plantCode string + funcName string + input string + output string + timeout int + debug bool = false +) + +func init() { + flag.BoolVar(&vsn, "v", false, "Show Program Version") + flag.BoolVar(&debug, "d", false, "Show Debug Messages") + flag.IntVar(&timeout, "t", 10, "Timeout in Seconds") + flag.StringVar(&server, "s", "127.0.0.1", "Web Service Server") + flag.StringVar(&port, "p", "80", "Web Service Listen Port") + flag.StringVar(&plantCode, "x", "", "PlantCode Suffix in Web Service URL") + flag.StringVar(&funcName, "f", "", "Function Name") + flag.StringVar(&input, "i", "./TesterWebSvc.ini", "Input Filename") + flag.StringVar(&output, "o", "./TesterWebSvcResult.ini", "Output Filename") + flag.Parse() +} + +func main() { + log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds) + log.SetOutput(os.Stdout) + + if vsn { + fmt.Printf("%s, Version: %s\r\n", os.Args[0], ver) + os.Exit(0) + } + + if funcName == "" { + log.Println("[ERR] Missing Function Name.") + os.Exit(1) + } + + if input == "" || output == "" { + log.Println("[ERR] Missing Input and/or Output Filename.") + os.Exit(1) + } + + if plantCode != "" { + plantCode = "." + plantCode + } + uri = fmt.Sprintf("http://%s:%s/Tester.WebService%s/WebService.asmx", server, port, plantCode) + + var err error + cfg, err = ini.Load(input) + if err != nil { + log.Printf("[ERR] %v\r\n", err) + os.Exit(1) + } + + keys := cfg.Section("SFC").KeyStrings() + if len(keys) == 0 { + log.Printf("[ERR] Invalid Config: %s\r\n", input) + os.Exit(1) + } + + args := make(map[string]string, 0) + for _, k := range keys { + v := cfg.Section("SFC").Key(k).MustString("") + args[k] = strings.TrimSpace(v) + } + + if debug { + log.Printf("[MSG] WebSvcUrl:\t%s\r\n", uri) + log.Printf("[MSG] Function:\t%s\r\n", funcName) + log.Printf("[MSG] Arguments:\t%#v\r\n", args) + } + + argStr := "" + for k, v := range args { + argStr = argStr + "<" + k + ">" + v + "" + } + if funcName == "Complete" { + argStr = argStr + fmt.Sprintf("%s", args["UnitSerialNumber"]) + } + + result, err := _TesterWebService(funcName, argStr) + if err != nil { + log.Printf("[ERR] %#v\r\n", err) + os.Exit(1) + } + + if debug { + log.Printf("[MSG] Result:\t%#v\r\n", result) + } + + // 对结果集按Map的Key名称排序 + resultKeys := make([]string, 0, len(result)) + for k := range result { + resultKeys = append(resultKeys, k) + } + sort.Strings(resultKeys) + + // 将排序后的结果集写入 Output File + content := fmt.Sprintf("[%s]\r\n", "SFC") + for _, rk := range resultKeys { + content = content + rk + "=" + result[rk] + "\r\n" + } + + fo, err := os.OpenFile(output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) + if err != nil { + log.Printf("[ERR] %v\r\n", err) + os.Exit(1) + } + defer fo.Close() + + _, err = fo.WriteString(content) + if err != nil { + log.Printf("[ERR] %v\r\n", err) + os.Exit(1) + } + fo.Sync() +} + +func _TesterWebService(funcName string, argStr string) (map[string]string, error) { + result := make(map[string]string, 0) + + xmlXSI := `"http://www.w3.org/2001/XMLSchema-instance"` + xmlXSD := `"http://www.w3.org/2001/XMLSchema"` + xmlSCH := `"http://schemas.xmlsoap.org/soap/envelope/"` + + reqStr := fmt.Sprintf(` + + + <%s xmlns="http://localhost/Tester.WebService/WebService"> + %s + + +`, + xmlXSI, xmlXSD, xmlSCH, funcName, argStr, funcName) + + client := http.Client{ + Timeout: time.Second * time.Duration(timeout), + } + req, err := http.NewRequest("POST", uri, strings.NewReader(reqStr)) + if err != nil { + return result, err + } + defer req.Body.Close() + + req.Header.Set("User-Agent", "TesterWebSvcClient-TE") + req.Header.Set("SOAPAction", "http://localhost/Tester.WebService/WebService/"+funcName) + req.Header.Set("Content-Type", "text/xml; charset=utf-8") + res, err := client.Do(req) + if err != nil { + return result, err + } + + resByte, err := io.ReadAll(res.Body) + if err != nil { + return result, err + } + resStr := string(resByte) + + switch funcName { + case "GetKeyInfoFromView": + result, err = _ParseInfoNameValues(resStr, funcName) + if err != nil { + result["RESULT"] = "NG, ParseInfoNameValues: " + err.Error() + return result, err + } + default: + result, err = _ParseWebServiceResult(resStr, funcName) + if err != nil { + result["RESULT"] = "NG, ParseWebServiceResult: " + err.Error() + return result, err + } + } + + if len(result) == 0 { + result["RESULT"] = fmt.Sprintf("NG, %s: Empty Response.", funcName) + } + + return result, nil +} + +// Parse SFCS Web Service Result +func _ParseWebServiceResult(src, fnc string) (map[string]string, error) { + ret := make(map[string]string, 0) + reg, err := re2.Compile(`<(\S{1,})( xmlns=.*){0,1}>([^<>]{1,})`, 0) + if err != nil { + ret["RESULT"] = "NG" + ret["ErrMsg"] = err.Error() + return ret, err + } + tch, err := reg.FindStringMatch(src) + if err != nil { + ret["RESULT"] = "NG" + ret["ErrMsg"] = err.Error() + return ret, err + } + for tch != nil { + grp := tch.Groups() + if len(grp) == 4 { + tag := html.UnescapeString(grp[1].String()) + txt := html.UnescapeString(grp[3].String()) + if tag == fnc+"Result" || tag == "Result" || tag == "result" || tag == "faultstring" { + tag = "RESULT" + } + ret[tag] = txt + } + tch, _ = reg.FindNextMatch(tch) + } + return ret, nil +} + +// Parse SFCS Web Service Result - InfoName Pairs +func _ParseInfoNameValues(src, fnc string) (map[string]string, error) { + ret := make(map[string]string, 0) + reg, err := re2.Compile(`<([^:]{1,})>([^<>]{1,})`, 0) + if err != nil { + ret["RESULT"] = "NG" + ret["ErrMsg"] = err.Error() + return ret, err + } + tch, err := reg.FindStringMatch(src) + if err != nil { + ret["RESULT"] = "NG" + ret["ErrMsg"] = err.Error() + return ret, err + } + for tch != nil { + grp := tch.Groups() + if len(grp) == 3 { + tag := grp[1].String() + txt := grp[2].String() + if tag == fnc+"Result" || tag == "Result" || tag == "result" || tag == "faultstring" { + tag = "RESULT" + ret[tag] = txt + } + } + tch, _ = reg.FindNextMatch(tch) + } + + // Parse Info Name/Values Sets + regNV, err := re2.Compile(`([^<>]{1,})\s*([^<>]{1,})`, 0) + if err != nil { + ret["RESULT"] = "NG" + ret["ErrMsg"] = err.Error() + return ret, err + } + tchNV, err := regNV.FindStringMatch(src) + if err != nil { + ret["RESULT"] = "NG" + ret["ErrMsg"] = err.Error() + return ret, err + } + for tchNV != nil { + grp := tchNV.Groups() + if len(grp) == 3 { + name := html.UnescapeString(grp[1].String()) + value := html.UnescapeString(grp[2].String()) + if strings.TrimSpace(name) != "" { + ret[name] = value + } + } + tchNV, _ = regNV.FindNextMatch(tchNV) + } + return ret, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1a5c91d --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module TesterWebSvc + +go 1.20 + +require ( + github.com/dlclark/regexp2 v1.11.5 + gopkg.in/ini.v1 v1.67.0 +) + +require github.com/stretchr/testify v1.10.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8ef4f57 --- /dev/null +++ b/go.sum @@ -0,0 +1,9 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=