From e9974374b116dc0f7de540027410b3f2350bf7a5 Mon Sep 17 00:00:00 2001 From: zhouzhou1017 <74368296+zhouzhou1017@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:36:25 +0800 Subject: [PATCH] feat: support to generator Python code from a HTTP testCase --- pkg/generator/code_generator_test.go | 29 +++++++++- pkg/generator/data/main.python.tpl | 56 +++++++++++++++++++ pkg/generator/python_generator.go | 54 ++++++++++++++++++ .../testdata/expected_python_code.txt | 33 +++++++++++ .../expected_python_cookie_request_code.txt | 37 ++++++++++++ .../expected_python_form_request_code.txt | 36 ++++++++++++ pkg/server/remote_server_test.go | 4 +- 7 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 pkg/generator/data/main.python.tpl create mode 100644 pkg/generator/python_generator.go create mode 100644 pkg/generator/testdata/expected_python_code.txt create mode 100644 pkg/generator/testdata/expected_python_cookie_request_code.txt create mode 100644 pkg/generator/testdata/expected_python_form_request_code.txt diff --git a/pkg/generator/code_generator_test.go b/pkg/generator/code_generator_test.go index e06653a..92052cf 100644 --- a/pkg/generator/code_generator_test.go +++ b/pkg/generator/code_generator_test.go @@ -1,5 +1,5 @@ /* -Copyright 2023 API Testing Authors. +Copyright 2024 API Testing Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -63,6 +63,12 @@ func TestGenerators(t *testing.T) { assert.Equal(t, expectedJavaCode, result) }) + t.Run("python", func(t *testing.T) { + result, err := generator.GetCodeGenerator("python").Generate(nil, testcase) + assert.NoError(t, err) + assert.Equal(t, expectedPythonCode, result) + }) + formRequest := &atest.TestCase{Request: testcase.Request} formRequest.Request.Form = map[string]string{ "key": "value", @@ -79,6 +85,12 @@ func TestGenerators(t *testing.T) { assert.Equal(t, expectedFormRequestJavaCode, result, result) }) + t.Run("python form HTTP request", func(t *testing.T) { + result, err := generator.GetCodeGenerator("python").Generate(nil, formRequest) + assert.NoError(t, err) + assert.Equal(t, expectedFormRequestPythonCode, result, result) + }) + cookieRequest := &atest.TestCase{Request: formRequest.Request} cookieRequest.Request.Cookie = map[string]string{ "name": "value", @@ -95,6 +107,12 @@ func TestGenerators(t *testing.T) { assert.Equal(t, expectedCookieRequestJavaCode, result, result) }) + t.Run("python cookie HTTP request", func(t *testing.T) { + result, err := generator.GetCodeGenerator("python").Generate(nil, cookieRequest) + assert.NoError(t, err) + assert.Equal(t, expectedCookieRequestPythonCode, result, result) + }) + bodyRequest := &atest.TestCase{Request: testcase.Request} bodyRequest.Request.Body.Value = `{"key": "value"}` @@ -123,5 +141,14 @@ var expectedCookieRequestGoCode string //go:embed testdata/expected_java_cookie_request_code.txt var expectedCookieRequestJavaCode string +//go:embed testdata/expected_python_code.txt +var expectedPythonCode string + +//go:embed testdata/expected_python_form_request_code.txt +var expectedFormRequestPythonCode string + +//go:embed testdata/expected_python_cookie_request_code.txt +var expectedCookieRequestPythonCode string + //go:embed testdata/expected_go_body_request_code.txt var expectedBodyRequestGoCode string diff --git a/pkg/generator/data/main.python.tpl b/pkg/generator/data/main.python.tpl new file mode 100644 index 0000000..1259f42 --- /dev/null +++ b/pkg/generator/data/main.python.tpl @@ -0,0 +1,56 @@ +/* +Copyright 2024 API Testing Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +import io +import requests +from urllib.parse import urlencode + +def main(): + {{- if gt (len .Request.Form) 0 }} + data = {} + {{- range $key, $val := .Request.Form}} + data["{{$key}}"] = "{{$val}}" + encoded_data = urlencode(data) + {{- end}} + body = io.BytesIO(encoded_data.encode("utf-8")) + {{- else}} + body = io.BytesIO(b"{{.Request.Body.String}}") + {{- end}} + {{- range $key, $val := .Request.Header}} + headers = {"{{$key}}": "{{$val}}"} + {{- end}} + {{- if gt (len .Request.Cookie) 0 }} + {{- range $key, $val := .Request.Cookie}} + cookies = {"{{$key}}": "{{$val}}"} + {{- end}} + {{- end}} + {{- if gt (len .Request.Cookie) 0 }} + try: + req = requests.Request("{{.Request.Method}}", "{{.Request.API}}", headers=headers, cookies=cookies, data=body) + except requests.RequestException as e: + raise e + {{- else}} + try: + req = requests.Request("{{.Request.Method}}", "{{.Request.API}}", headers=headers, data=body) + except requests.RequestException as e: + raise e + {{- end}} + + resp = requests.Session().send(req.prepare()) + if resp.status_code != 200: + raise Exception("status code is not 200") + + data = resp.content + print(data.decode("utf-8")) + +if __name__ == "__main__": + main() diff --git a/pkg/generator/python_generator.go b/pkg/generator/python_generator.go new file mode 100644 index 0000000..9ed3180 --- /dev/null +++ b/pkg/generator/python_generator.go @@ -0,0 +1,54 @@ +/* +Copyright 2024 API Testing Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package generator + +import ( + "bytes" + "html/template" + "net/http" + + _ "embed" + + "github.com/linuxsuren/api-testing/pkg/testing" +) + +type pythonGenerator struct { +} + +func NewPythonGenerator() CodeGenerator { + return &pythonGenerator{} +} + +func (g *pythonGenerator) Generate(testSuite *testing.TestSuite, testcase *testing.TestCase) (result string, err error) { + if testcase.Request.Method == "" { + testcase.Request.Method = http.MethodGet + } + var tpl *template.Template + if tpl, err = template.New("python template").Parse(pythonTemplate); err == nil { + buf := new(bytes.Buffer) + if err = tpl.Execute(buf, testcase); err == nil { + result = buf.String() + } + } + return +} + +func init() { + RegisterCodeGenerator("python", NewPythonGenerator()) +} + +//go:embed data/main.python.tpl +var pythonTemplate string diff --git a/pkg/generator/testdata/expected_python_code.txt b/pkg/generator/testdata/expected_python_code.txt new file mode 100644 index 0000000..0e53287 --- /dev/null +++ b/pkg/generator/testdata/expected_python_code.txt @@ -0,0 +1,33 @@ +/* +Copyright 2024 API Testing Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +import io +import requests +from urllib.parse import urlencode + +def main(): + body = io.BytesIO(b"") + headers = {"User-Agent": "atest"} + try: + req = requests.Request("GET", "https://www.baidu.com", headers=headers, data=body) + except requests.RequestException as e: + raise e + + resp = requests.Session().send(req.prepare()) + if resp.status_code != 200: + raise Exception("status code is not 200") + + data = resp.content + print(data.decode("utf-8")) + +if __name__ == "__main__": + main() diff --git a/pkg/generator/testdata/expected_python_cookie_request_code.txt b/pkg/generator/testdata/expected_python_cookie_request_code.txt new file mode 100644 index 0000000..d05f3f5 --- /dev/null +++ b/pkg/generator/testdata/expected_python_cookie_request_code.txt @@ -0,0 +1,37 @@ +/* +Copyright 2024 API Testing Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +import io +import requests +from urllib.parse import urlencode + +def main(): + data = {} + data["key"] = "value" + encoded_data = urlencode(data) + body = io.BytesIO(encoded_data.encode("utf-8")) + headers = {"User-Agent": "atest"} + cookies = {"name": "value"} + try: + req = requests.Request("GET", "https://www.baidu.com", headers=headers, cookies=cookies, data=body) + except requests.RequestException as e: + raise e + + resp = requests.Session().send(req.prepare()) + if resp.status_code != 200: + raise Exception("status code is not 200") + + data = resp.content + print(data.decode("utf-8")) + +if __name__ == "__main__": + main() diff --git a/pkg/generator/testdata/expected_python_form_request_code.txt b/pkg/generator/testdata/expected_python_form_request_code.txt new file mode 100644 index 0000000..2180c44 --- /dev/null +++ b/pkg/generator/testdata/expected_python_form_request_code.txt @@ -0,0 +1,36 @@ +/* +Copyright 2024 API Testing Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +import io +import requests +from urllib.parse import urlencode + +def main(): + data = {} + data["key"] = "value" + encoded_data = urlencode(data) + body = io.BytesIO(encoded_data.encode("utf-8")) + headers = {"User-Agent": "atest"} + try: + req = requests.Request("GET", "https://www.baidu.com", headers=headers, data=body) + except requests.RequestException as e: + raise e + + resp = requests.Session().send(req.prepare()) + if resp.status_code != 200: + raise Exception("status code is not 200") + + data = resp.content + print(data.decode("utf-8")) + +if __name__ == "__main__": + main() diff --git a/pkg/server/remote_server_test.go b/pkg/server/remote_server_test.go index 04242b7..c329dd2 100644 --- a/pkg/server/remote_server_test.go +++ b/pkg/server/remote_server_test.go @@ -1,5 +1,5 @@ /* -Copyright 2023 API Testing Authors. +Copyright 2024 API Testing Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -593,7 +593,7 @@ func TestCodeGenerator(t *testing.T) { t.Run("ListCodeGenerator", func(t *testing.T) { generators, err := server.ListCodeGenerator(ctx, &Empty{}) assert.NoError(t, err) - assert.Equal(t, 4, len(generators.Data)) + assert.Equal(t, 5, len(generators.Data)) }) t.Run("GenerateCode, no generator found", func(t *testing.T) {