├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── main.yml ├── .gitignore ├── .golangci.yaml ├── .pre-commit-config.yaml ├── .resources ├── allure_go_icon.svg ├── allure_icon.svg ├── example_async_test.png ├── example_attachments.png ├── example_befores_afters.png ├── example_multiple_suites_run.png ├── example_sample_provider.png ├── example_setup_test.png ├── example_step_tree.png ├── example_table_test.png ├── example_xskip.png ├── scheme_runnerRunSuite.png └── scheme_runnerRunTest.png ├── LICENSE.md ├── Makefile ├── README.md ├── examples ├── allure_go_compare │ ├── attachments_test.go │ ├── before_after_test.go │ └── test_test.go ├── async │ ├── async_step_test.go │ ├── async_suite_test.go │ └── mixed_test.go ├── provider_demo │ ├── sample_panic_test.go │ └── sample_test.go └── suite_demo │ ├── attachments_test.go │ ├── befores_afters_test.go │ ├── fails_test.go │ ├── labels_test.go │ ├── links_test.go │ ├── new_parametrized_test.go │ ├── parameters_test.go │ ├── parametrized_test.go │ ├── running_test.go │ ├── setup_test.go │ ├── skip_test.go │ ├── step_test.go │ └── step_tree_test.go ├── go.mod ├── go.sum └── pkg ├── allure ├── .golangci.yaml ├── Makefile ├── README.md ├── attachment.go ├── attachment_test.go ├── config.go ├── config_test.go ├── container.go ├── container_test.go ├── errors.go ├── file_manager.go ├── file_manager_test.go ├── go.mod ├── go.sum ├── label.go ├── label_test.go ├── link.go ├── link_test.go ├── parameter.go ├── parameter_test.go ├── result.go ├── result_test.go ├── status.go ├── status_detail.go ├── status_test.go ├── step.go ├── step_test.go ├── time.go └── time_test.go └── framework ├── .golangci.yaml ├── Makefile ├── README.md ├── asserts_wrapper ├── asserts │ ├── asserts.go │ └── asserts_test.go ├── helper │ ├── asserts_helper.go │ ├── asserts_helper_test.go │ ├── helper.go │ ├── helper_test.go │ ├── interfaces.go │ ├── require_helper.go │ └── require_helper_test.go ├── require │ ├── require.go │ └── requires_test.go └── wrapper │ ├── helper.go │ ├── helper_test.go │ ├── interfaces.go │ ├── wrapper.go │ └── wrapper_test.go ├── core ├── allure_manager │ ├── adapter │ │ ├── suite_adapter.go │ │ ├── suite_adapter_test.go │ │ ├── test_adapter.go │ │ └── test_adapter_test.go │ ├── ctx │ │ ├── hooks.go │ │ ├── hooks_test.go │ │ ├── test_ctx.go │ │ └── test_ctx_test.go │ ├── manager │ │ ├── attachment.go │ │ ├── attachment_test.go │ │ ├── description.go │ │ ├── description_test.go │ │ ├── execution_management.go │ │ ├── execution_management_test.go │ │ ├── labels.go │ │ ├── labels_test.go │ │ ├── links.go │ │ ├── links_test.go │ │ ├── parameter.go │ │ ├── parameter_test.go │ │ ├── provider.go │ │ ├── provider_config.go │ │ ├── provider_config_test.go │ │ ├── provider_test.go │ │ ├── steps.go │ │ └── steps_test.go │ └── testplan │ │ └── testplan.go ├── assert │ ├── assertions.go │ └── assertions_test.go ├── common │ ├── common.go │ ├── common_test.go │ ├── errors_handling.go │ ├── errors_handling_test.go │ ├── hooks.go │ ├── hooks_test.go │ ├── interfaces.go │ ├── step_context.go │ ├── step_context_test.go │ ├── steps.go │ ├── steps_test.go │ └── tempdir.go └── constants │ ├── constants.go │ └── constants_test.go ├── go.mod ├── go.sum ├── provider ├── allure.go ├── provider.go └── test.go ├── runner ├── contants.go ├── interfaces.go ├── runner.go ├── runner_test.go ├── suite_runner.go └── tests.go └── suite ├── suite.go ├── suite_runner_test.go └── suite_test.go /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Used func: '...' 16 | 2. What you actually wanted to do: '...' 17 | 3. What has been expected: '...' 18 | 4. What you got actual: '....' 19 | 5. Error Log (if any): '...' 20 | 6. Allure-Report screenshot (if any): '...' 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Additional context** 29 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | golangci: 13 | name: lint 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version: "1.17.8" 20 | - name: allure-golangci-lint 21 | run: cd ./pkg/allure && make lint 22 | - name: provider-golangci-lint 23 | run: cd ./pkg/framework && make lint 24 | 25 | test: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | - name: allure-test 30 | run: cd ./pkg/allure && make test 31 | - name: provider-test 32 | run: cd ./pkg/framework && make test 33 | 34 | examples: 35 | name: examples 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - name: Run examples 40 | run: make examples 41 | - name: Archive code coverage results 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: allure-results 45 | path: ./examples/allure-results 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | testdata/ 3 | allure-results/ 4 | bin/ 5 | 6 | # MacOS 7 | .DS_Store 8 | 9 | # Binaries for programs and plugins 10 | *.exe 11 | *.exe~ 12 | *.dll 13 | *.so 14 | *.dylib 15 | 16 | # Test binary, build with `go test -c` 17 | *.test 18 | 19 | # Output of the go coverage tool, specifically when used with LiteIDE 20 | *.out 21 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | # More info on config here: https://github.com/golangci/golangci-lint#config-file 2 | run: 3 | deadline: 10s 4 | timeout: 5m 5 | issues-exit-code: 1 6 | tests: true 7 | skip-dirs: 8 | - bin 9 | - vendor 10 | - var 11 | - tmp 12 | skip-files: 13 | - \.pb\.go$ 14 | - \.pb\.goclay\.go$ 15 | - \_test.go$ 16 | 17 | output: 18 | format: colored-line-number 19 | print-issued-lines: true 20 | print-linter-name: true 21 | 22 | linters-settings: 23 | govet: 24 | check-shadowing: true 25 | golint: 26 | min-confidence: 0 27 | dupl: 28 | threshold: 100 29 | goconst: 30 | min-len: 2 31 | min-occurrences: 2 32 | 33 | linters: 34 | disable-all: true 35 | enable: 36 | - golint 37 | - govet 38 | - errcheck 39 | - deadcode 40 | - structcheck 41 | - varcheck 42 | - ineffassign 43 | - typecheck 44 | - dupl 45 | - goconst 46 | - gosec 47 | - goimports 48 | - megacheck 49 | 50 | 51 | issues: 52 | exclude-use-default: false 53 | exclude: 54 | # _ instead of err checks 55 | - G104 56 | - G306 57 | # md5 using for hash generation, not for security, so ignore this 58 | - G401 59 | - G501 60 | # for "public interface + private struct implementation" cases only! 61 | - exported func * returns unexported type *, which can be annoying to use 62 | # can be removed in the development phase 63 | # - (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form) 64 | # not for the active development - can be removed in the stable phase 65 | - should have a package comment, unless it's in another file for this package 66 | - don't use an underscore in package name 67 | # errcheck: Almost all programs ignore errors on these functions and in most cases it's ok 68 | - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv|.*Rollback). is not checked 69 | - should check returned error before deferring 70 | - should have comment or be unexported 71 | - a blank import should be only in a main or test package 72 | - Can't process result by diff processor 73 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | - repo: https://github.com/dnephin/pre-commit-golang 2 | sha: HEAD 3 | hooks: 4 | - id: go-fmt 5 | 6 | - repo: https://github.com/pre-commit/pre-commit-hooks 7 | rev: v1.4.0 8 | hooks: 9 | - id: check-yaml 10 | 11 | - repo: https://github.com/Lucas-C/pre-commit-hooks-go 12 | sha: v1.0.0 13 | hooks: 14 | - id: checkmake 15 | 16 | - repo: local 17 | hooks: 18 | - id: golangci-lint 19 | language: system 20 | name: Golangci linter 21 | entry: make lint 22 | 23 | #- repo: local 24 | # hooks: 25 | # - id: unit-tests 26 | # language: system 27 | # name: Unit tests 28 | # entry: make test -------------------------------------------------------------------------------- /.resources/allure_go_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.resources/allure_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.resources/example_async_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_async_test.png -------------------------------------------------------------------------------- /.resources/example_attachments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_attachments.png -------------------------------------------------------------------------------- /.resources/example_befores_afters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_befores_afters.png -------------------------------------------------------------------------------- /.resources/example_multiple_suites_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_multiple_suites_run.png -------------------------------------------------------------------------------- /.resources/example_sample_provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_sample_provider.png -------------------------------------------------------------------------------- /.resources/example_setup_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_setup_test.png -------------------------------------------------------------------------------- /.resources/example_step_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_step_tree.png -------------------------------------------------------------------------------- /.resources/example_table_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_table_test.png -------------------------------------------------------------------------------- /.resources/example_xskip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/example_xskip.png -------------------------------------------------------------------------------- /.resources/scheme_runnerRunSuite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/scheme_runnerRunSuite.png -------------------------------------------------------------------------------- /.resources/scheme_runnerRunTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozontech/allure-go/94107284580cfff6e668a259a9470a3021aa5ea1/.resources/scheme_runnerRunTest.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APP?=allure-go 2 | RELEASE?=0.6.0 3 | GOOS?=darwin 4 | 5 | COMMIT?=$(shell git rev-parse --short HEAD) 6 | BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S') 7 | 8 | export GO111MODULE=on 9 | export GOSUMDB=off 10 | LOCAL_BIN:=$(CURDIR)/bin 11 | EXAMPLES_TAGS:=examples_new,provider_new,allure_go_new,async 12 | 13 | ##################### GOLANG-CI RELATED CHECKS ##################### 14 | # Check global GOLANGCI-LINT 15 | GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint 16 | GOLANGCI_TAG:=1.38.0 17 | 18 | # Check local bin version 19 | ifneq ($(wildcard $(GOLANGCI_BIN)),) 20 | GOLANGCI_BIN_VERSION:=$(shell $(GOLANGCI_BIN) --version) 21 | ifneq ($(GOLANGCI_BIN_VERSION),) 22 | GOLANGCI_BIN_VERSION_SHORT:=$(shell echo "$(GOLANGCI_BIN_VERSION)" | sed -E 's/.* version (.*) built from .* on .*/\1/g') 23 | else 24 | GOLANGCI_BIN_VERSION_SHORT:=0 25 | endif 26 | ifneq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_BIN_VERSION_SHORT)))" 27 | GOLANGCI_BIN:= 28 | endif 29 | endif 30 | 31 | # Check global bin version 32 | ifneq (, $(shell which golangci-lint)) 33 | GOLANGCI_VERSION:=$(shell golangci-lint --version 2> /dev/null ) 34 | ifneq ($(GOLANGCI_VERSION),) 35 | GOLANGCI_VERSION_SHORT:=$(shell echo "$(GOLANGCI_VERSION)"|sed -E 's/.* version (.*) built from .* on .*/\1/g') 36 | else 37 | GOLANGCI_VERSION_SHORT:=0 38 | endif 39 | ifeq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_VERSION_SHORT)))" 40 | GOLANGCI_BIN:=$(shell which golangci-lint) 41 | endif 42 | endif 43 | ##################### GOLANG-CI RELATED CHECKS ##################### 44 | 45 | .PHONY: full-demo 46 | full-demo: install demo 47 | 48 | .PHONY: demo 49 | demo: examples allure-serve 50 | 51 | .PHONY: install 52 | install: .install_deps .install_allure 53 | 54 | .PHONY: .install_deps 55 | .install_deps: 56 | go mod tidy && go mod download 57 | 58 | .PHONY: .install_allure 59 | .install_allure: 60 | ifeq ($(OS),Windows_NT) 61 | $(info Run Windows run pattern...) 62 | $(info Make sure scoop installed at your system. Check for more information: https://github.com/ScoopInstaller/Scoop#installation) 63 | scoop install allure 64 | endif 65 | ifeq ($(OS),Linux) 66 | $(info Run Linux run pattern...) 67 | $(info Make sure you have sudo rights for the system.) 68 | sudo apt-add-repository ppa:qameta/allure 69 | sudo apt-get update 70 | sudo apt-get install allure 71 | endif 72 | ifeq ($(OS),Darwin) 73 | $(info Run installation for Darwin OS) 74 | $(info Make sure brew installed at your system. Check for more information: https://docs.brew.sh/Installation) 75 | brew install allure 76 | endif 77 | 78 | .PHONY: examples 79 | examples: 80 | ifeq ($(OS),Windows_NT) 81 | $(info Run windows pattern...) 82 | set ALLURE_OUTPUT_PATH=../&& go test ./examples/... --tags=$(EXAMPLES_TAGS) 83 | else 84 | $(info Run default pattern...) 85 | export ALLURE_OUTPUT_PATH=../ && go test ./examples/... --tags=$(EXAMPLES_TAGS) || true 86 | endif 87 | 88 | .PHONY: allure-serve 89 | allure-serve: 90 | allure serve ./examples/allure-results 91 | 92 | # run full lint like in pipeline 93 | .PHONY: lint 94 | lint: install-lint 95 | $(GOLANGCI_BIN) run --config=.golangci.yaml ./... --build-tags=$(EXAMPLES_TAGS) 96 | 97 | .PHONY: install-lint 98 | install-lint: 99 | ifeq ($(wildcard $(GOLANGCI_BIN)),) 100 | $(info #Downloading golangci-lint v$(GOLANGCI_TAG)) 101 | tmp=$$(mktemp -d) && cd $$tmp && pwd && go mod init temp && go get -d github.com/golangci/golangci-lint/cmd/golangci-lint@v$(GOLANGCI_TAG) && \ 102 | go build -ldflags "-X 'main.version=$(GOLANGCI_TAG)' -X 'main.commit=test' -X 'main.date=test'" -o $(LOCAL_BIN)/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint && \ 103 | rm -rf $$tmp 104 | GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint 105 | endif 106 | -------------------------------------------------------------------------------- /examples/allure_go_compare/attachments_test.go: -------------------------------------------------------------------------------- 1 | //go:build allure_go_new 2 | // +build allure_go_new 3 | 4 | package allure_go_compare 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/allure" 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | "github.com/ozontech/allure-go/pkg/framework/suite" 12 | ) 13 | 14 | type AllureGoAttachments struct { 15 | suite.Suite 16 | } 17 | 18 | /* Allure-Go style: 19 | func TestTextAttachment(t *testing.T) { 20 | allure.Test(t, allure.Description("Testing a text attachment"), allure .Action(func() { 21 | _ = allure.AddAttachments("text!", allure.TextPlain, []byte("Some text!")) 22 | })) 23 | } 24 | */ 25 | 26 | func (s *AllureGoAttachments) TestTextAttachment(t provider.T) { 27 | t.Epic("Compare with allure-go") 28 | t.Description("Testing a text attachment") 29 | t.WithAttachments(allure.NewAttachment("text!", allure.Text, []byte("Some text!"))) 30 | } 31 | 32 | /* TestTextAttachmentToStep Allure-Go style: 33 | func TestTextAttachmentToStep(t *testing.T) { 34 | allure.Test(t, allure.Description("Testing a text attachment"), allure.Action(func() { 35 | allure.Step(allure.Description("adding a text attachment"), allure.Action(func() { 36 | _ = allure.AddAttachments("text!", allure.TextPlain, []byte("Some text!")) 37 | })) 38 | })) 39 | } 40 | */ 41 | 42 | func (s *AllureGoAttachments) TestTextAttachmentToStepV1(t provider.T) { 43 | t.Epic("Compare with allure-go") 44 | t.Description("Testing a text attachment") 45 | t.WithNewStep("adding a text attachment", func(ctx provider.StepCtx) { 46 | ctx.WithAttachments(allure.NewAttachment("text!", allure.Text, []byte("Some text!"))) 47 | }) 48 | } 49 | 50 | func (s *AllureGoAttachments) TestTextAttachmentToStepV2(t provider.T) { 51 | t.Epic("Compare with allure-go") 52 | t.Description("Testing a text attachment") 53 | t.Step(allure.NewSimpleStep("adding a text attachment"). 54 | WithAttachments(allure.NewAttachment("text!", allure.Text, []byte("Some text!")))) 55 | } 56 | 57 | func (s *AllureGoAttachments) TestTextAttachmentToStepV3(t provider.T) { 58 | t.Epic("Compare with allure-go") 59 | t.Description("Testing a text attachment") 60 | step := allure.NewSimpleStep("adding a text attachment") 61 | step.WithAttachments(allure.NewAttachment("text!", allure.Text, []byte("Some text!"))) 62 | t.Step(step) 63 | } 64 | 65 | // Also we provide some complex actions with steps 66 | // In this example we initialize step, declare it like nested and add new attachment to it. 67 | 68 | func (s *AllureGoAttachments) TestTextAttachmentToStepV4(t provider.T) { 69 | t.Epic("Compare with allure-go") 70 | t.Description("Testing a text attachment") 71 | step := allure.NewSimpleStep("adding a text attachment") 72 | step.WithAttachments(allure.NewAttachment("text!", allure.Text, []byte("Some text!"))) 73 | t.WithNewStep("step", func(ctx provider.StepCtx) { 74 | ctx.WithAttachments(allure.NewAttachment("text inside step!", allure.Text, []byte("Another text!"))) 75 | }) 76 | } 77 | 78 | func TestAllureGoAttachments(t *testing.T) { 79 | suite.RunSuite(t, new(AllureGoAttachments)) 80 | } 81 | -------------------------------------------------------------------------------- /examples/allure_go_compare/before_after_test.go: -------------------------------------------------------------------------------- 1 | //go:build allure_go_new 2 | // +build allure_go_new 3 | 4 | package allure_go_compare 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/suite" 11 | ) 12 | 13 | type AllureGoBeforesAfters struct { 14 | suite.Suite 15 | } 16 | 17 | /* Allure-Go style: 18 | func TestAllureSetupTeardown(t *testing.T) { 19 | allure.BeforeTest(t, 20 | allure.Description("setup"), 21 | allure.Action(func() { 22 | allure.Step( 23 | allure.Description("Setup step 1"), 24 | allure.Action(func() {})) 25 | })) 26 | 27 | allure.Test(t, 28 | allure.Description("actual test"), 29 | allure.Action(func() { 30 | allure.Step( 31 | allure.Description("Test step 1"), 32 | allure.Action(func() {})) 33 | })) 34 | 35 | allure.AfterTest(t, 36 | allure.Description("teardown"), 37 | allure.Action(func() { 38 | allure.Step( 39 | allure.Description("teardown step 1"), 40 | allure.Action(func() {})) 41 | })) 42 | } 43 | */ 44 | 45 | // We provide even more! but without infinite breakers ({(((({(({()}))}))))}) 46 | //func (s AllureGoBeforesAfters) BeforeAll() { 47 | // s.NewStep("Setup suite step 1") 48 | //} 49 | // 50 | //func (s AllureGoBeforesAfters) AfterAll() { 51 | // s.NewStep("Teardown suite step 1") 52 | //} 53 | 54 | func (s AllureGoBeforesAfters) BeforeEach(t provider.T) { 55 | t.NewStep("Setup test step 1") 56 | } 57 | 58 | func (s AllureGoBeforesAfters) AfterEach(t provider.T) { 59 | t.NewStep("Teardown test step 1") 60 | } 61 | 62 | func (s AllureGoBeforesAfters) TestBeforesAfters(t provider.T) { 63 | t.Epic("Compare with allure-go") 64 | t.NewStep("Test step 1") 65 | } 66 | 67 | func TestAllureGoBeforesAfters(t *testing.T) { 68 | suite.RunSuite(t, new(AllureGoBeforesAfters)) 69 | } 70 | -------------------------------------------------------------------------------- /examples/allure_go_compare/test_test.go: -------------------------------------------------------------------------------- 1 | //go:build allure_go_new 2 | // +build allure_go_new 3 | 4 | package allure_go_compare 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/suite" 11 | ) 12 | 13 | type SuiteStruct struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *SuiteStruct) TestNewTest(t provider.T) { 18 | t.Epic("Compare with allure-go") 19 | t.Description("New Test Description") 20 | t.WithNewStep("Step description", func(ctx provider.StepCtx) { 21 | 22 | }) 23 | } 24 | 25 | /* Allure-Go style: 26 | func TestWithIntricateSubsteps(t *testing.T) { 27 | allure.Test(t, allure.Description("Test"), 28 | allure.Action(func() { 29 | allure.Step(allure.Description("Step 1"), allure.Action(func() { 30 | doSomething() 31 | allure.Step(allure.Description("Sub-step 1.1"), allure.Action(func() { 32 | t.Errorf("Failure") 33 | })) 34 | allure.Step(allure.Description("Sub-step 1.2"), allure.Action(func() {})) 35 | allure.SkipStep(allure.Description("Sub-step 1.3"), allure.Reason("Skip this step because of defect to be fixed"), allure.Action(func() {})) 36 | })) 37 | allure.Step(allure.Description("Step 2"), allure.Action(func() { 38 | allure.Step(allure.Description("Sub-step 2.1"), allure.Action(func() { 39 | allure.Step(allure.Description("Step 2.1.1"), allure.Action(func() { 40 | allure.Step(allure.Description("Sub-step 2.1.1.1"), allure.Action(func() { 41 | t.Errorf("Failure") 42 | })) 43 | allure.Step(allure.Description("Sub-step 2.1.1.2"), allure.Action(func() { 44 | t.Error("Failed like this") 45 | })) 46 | })) 47 | })) 48 | allure.Step(allure.Description("Sub-step 2.2"), allure.Action(func() {})) 49 | })) 50 | })) 51 | } 52 | */ 53 | 54 | func doSomething(ctx provider.StepCtx) { 55 | ctx.WithNewStep("Something", func(ctx provider.StepCtx) { 56 | ctx.WithNewStep("Because We Can!", func(ctx provider.StepCtx) { 57 | 58 | }) 59 | }) 60 | } 61 | 62 | // Works even better! each step will have his real status, but parent will be failed anyway 63 | 64 | func (s *SuiteStruct) TestWithIntricateSubsteps(t provider.T) { 65 | t.Epic("Compare with allure-go") 66 | t.Description("Test") 67 | 68 | t.WithNewStep("Step 1", func(ctx provider.StepCtx) { 69 | doSomething(ctx) 70 | ctx.WithNewStep("Sub-step 1.1", func(ctx provider.StepCtx) { 71 | ctx.Error("Failure Sub-step 1.1") 72 | }) 73 | ctx.WithNewStep("Sub-step 1.2", func(ctx provider.StepCtx) { 74 | 75 | }) 76 | ctx.WithNewStep("Sub-step 1.3", func(ctx provider.StepCtx) { 77 | 78 | }) 79 | }) 80 | t.WithNewStep("Step 2", func(ctx provider.StepCtx) { 81 | ctx.WithNewStep("Sub-Step 2.1", func(ctx provider.StepCtx) { 82 | ctx.WithNewStep("Sub-step 2.1.1", func(ctx provider.StepCtx) { 83 | ctx.WithNewStep("Sub-step 2.1.1.1", func(ctx provider.StepCtx) { 84 | ctx.Error("Failure Sub-step 2.1.1.1") 85 | }) 86 | ctx.WithNewStep("Sub-step 2.1.1.2", func(ctx provider.StepCtx) { 87 | ctx.Error("This will be in report-status. Sub-step 2.1.1.2") 88 | }) 89 | }) 90 | }) 91 | ctx.WithNewStep("Sub-Step 2.2", func(ctx provider.StepCtx) { 92 | 93 | }) 94 | }) 95 | } 96 | 97 | func TestRun(t *testing.T) { 98 | suite.RunSuite(t, new(SuiteStruct)) 99 | } 100 | -------------------------------------------------------------------------------- /examples/async/async_suite_test.go: -------------------------------------------------------------------------------- 1 | //go:build async 2 | // +build async 3 | 4 | package async 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | "time" 10 | 11 | "github.com/ozontech/allure-go/pkg/framework/provider" 12 | "github.com/ozontech/allure-go/pkg/framework/suite" 13 | ) 14 | 15 | type SuiteAsyncDemo struct { 16 | suite.Suite 17 | } 18 | 19 | func (s *SuiteAsyncDemo) BeforeEach(t provider.T) { 20 | t.Epic("Async") 21 | t.Feature("Async Suite") 22 | t.Tags("async", "suite", "steps") 23 | } 24 | 25 | func (s *SuiteAsyncDemo) TestAsyncSuiteDemo1(t provider.T) { 26 | t.Title("Async Test 1") 27 | 28 | startSign := fmt.Sprintf("%s", time.Now()) 29 | t.Parallel() 30 | t.WithNewStep("Sync Step Demo", func(ctx provider.StepCtx) { 31 | ctx.WithNewParameters("Start", startSign) 32 | ctx.Logf("Test 1 Started At: %s", startSign) 33 | time.Sleep(3 * time.Second) 34 | stopSign := fmt.Sprintf("%s", time.Now()) 35 | ctx.Logf("Test 1 Stopped At: %s", stopSign) 36 | ctx.WithNewParameters("Stop", stopSign) 37 | }) 38 | } 39 | 40 | func (s *SuiteAsyncDemo) TestAsyncSuiteDemo2(t provider.T) { 41 | t.Title("Async Test 2") 42 | 43 | startSign := fmt.Sprintf("%s", time.Now()) 44 | t.Parallel() 45 | t.WithNewStep("Sync Step Demo", func(ctx provider.StepCtx) { 46 | ctx.WithNewParameters("Start", startSign) 47 | ctx.Logf("Test 2 Started At: %s", startSign) 48 | time.Sleep(3 * time.Second) 49 | stopSign := fmt.Sprintf("%s", time.Now()) 50 | ctx.Logf("Test 2 Stopped At: %s", stopSign) 51 | ctx.WithNewParameters("Stop", stopSign) 52 | }) 53 | } 54 | 55 | func (s *SuiteAsyncDemo) TestAsyncSuiteDemo3(t provider.T) { 56 | t.Title("Async Test 3") 57 | t.Description(` 58 | This test should be failed. But all logs a correct.`) 59 | 60 | startSign := fmt.Sprintf("%s", time.Now()) 61 | t.Parallel() 62 | t.WithNewStep("Sync Step Demo", func(ctx provider.StepCtx) { 63 | ctx.WithNewParameters("Start", startSign) 64 | ctx.Logf("Test 3 Started At: %s", startSign) 65 | time.Sleep(1 * time.Second) 66 | defer func() { 67 | stopSign := fmt.Sprintf("%s", time.Now()) 68 | ctx.Logf("Test 3 Stopped At: %s", stopSign) 69 | ctx.WithNewParameters("Stop", stopSign) 70 | }() 71 | ctx.Require().False(true) 72 | }) 73 | } 74 | 75 | func (s *SuiteAsyncDemo) TestAsyncSuiteDemo4(t provider.T) { 76 | t.Title("Async Test 4") 77 | t.Description(` 78 | This test should be panic. But all logs a correct.`) 79 | 80 | startSign := fmt.Sprintf("%s", time.Now()) 81 | t.Parallel() 82 | t.WithNewStep("Sync Step Demo", func(ctx provider.StepCtx) { 83 | ctx.WithNewParameters("Start", startSign) 84 | ctx.Logf("Test 4 Started At: %s", startSign) 85 | time.Sleep(2 * time.Second) 86 | defer func() { 87 | stopSign := fmt.Sprintf("%s", time.Now()) 88 | ctx.Logf("Test 4 Stopped At: %s", stopSign) 89 | ctx.WithNewParameters("Stop", stopSign) 90 | }() 91 | panic("Whoops") 92 | }) 93 | } 94 | 95 | func TestSuiteAsyncRunner(t *testing.T) { 96 | suite.RunSuite(t, new(SuiteAsyncDemo)) 97 | } 98 | -------------------------------------------------------------------------------- /examples/async/mixed_test.go: -------------------------------------------------------------------------------- 1 | package async 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/framework/provider" 7 | "github.com/ozontech/allure-go/pkg/framework/suite" 8 | ) 9 | 10 | type MixedAsyncSuite struct { 11 | suite.Suite 12 | } 13 | 14 | func (s *MixedAsyncSuite) BeforeEach(t provider.T) { 15 | t.Epic("Async") 16 | t.Feature("Mixed Suite") 17 | t.Tags("async", "suite", "steps") 18 | } 19 | 20 | func (s *MixedAsyncSuite) TestSelectionProductsLists(t provider.T) { 21 | t.SkipOnPrint() 22 | testCases := []struct { 23 | testName string 24 | }{{"test1"}, {"test2"}, {"test3"}} 25 | 26 | for _, tc := range testCases { 27 | t.Run(tc.testName, func(t provider.T) { 28 | name := tc.testName 29 | t.Parallel() 30 | t.NewStep(name) 31 | }) 32 | } 33 | } 34 | 35 | func (s *MixedAsyncSuite) TestSelectionProductsLists2(t provider.T) { 36 | t.SkipOnPrint() 37 | t.Parallel() 38 | testCases := []struct { 39 | testName string 40 | }{{"test1"}, {"test2"}, {"test3"}} 41 | 42 | for _, tc := range testCases { 43 | t.Run(tc.testName, func(t provider.T) { 44 | name := tc.testName 45 | t.Parallel() 46 | t.NewStep(name) 47 | }) 48 | } 49 | } 50 | 51 | func (s *MixedAsyncSuite) TestSelectionProductsLists3(t provider.T) { 52 | t.SkipOnPrint() 53 | testCases := []struct { 54 | testName string 55 | }{{"test1"}, {"test2"}, {"test3"}} 56 | 57 | for _, tc := range testCases { 58 | t.Run(tc.testName, func(t provider.T) { 59 | name := tc.testName 60 | t.Parallel() 61 | t.NewStep(name) 62 | t.Fatalf("WHOOPS") 63 | }) 64 | } 65 | } 66 | 67 | func (s *MixedAsyncSuite) TestSelectionProductsLists4(t provider.T) { 68 | t.SkipOnPrint() 69 | testCases := []struct { 70 | testName string 71 | }{{"test1"}, {"test2"}, {"test3"}} 72 | 73 | for _, tc := range testCases { 74 | t.Run(tc.testName, func(t provider.T) { 75 | name := tc.testName 76 | t.Parallel() 77 | t.NewStep(name) 78 | panic("WHOOPS") 79 | }) 80 | } 81 | } 82 | 83 | func TestMixedAsyncSuite(t *testing.T) { 84 | suite.RunSuite(t, new(MixedAsyncSuite)) 85 | } 86 | -------------------------------------------------------------------------------- /examples/provider_demo/sample_panic_test.go: -------------------------------------------------------------------------------- 1 | //go:build provider_new 2 | // +build provider_new 3 | 4 | package provider_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/runner" 11 | ) 12 | 13 | func TestPanicProviderDemo(realT *testing.T) { 14 | r := runner.NewRunner(realT, realT.Name()) 15 | r.BeforeEach(func(t provider.T) { 16 | t.Epic("Only Provider Demo") 17 | t.Feature("runner.RunTest") 18 | }) 19 | r.NewTest("Test1", func(t provider.T) { 20 | t.Title("Some Panic test 1") 21 | t.Description("allure-go allows you to use allure without suites. Even if it panics or failed") 22 | panic("whoops") 23 | }) 24 | 25 | r.NewTest("Test3", func(t provider.T) { 26 | t.Title("Some Failed test 2") 27 | t.Description("allure-go allows you to use allure without suites. Even if it panics or failed") 28 | t.Require().NotNil(nil) 29 | }) 30 | 31 | r.NewTest("Test2", func(t provider.T) { 32 | t.Title("Some Normal test 2") 33 | t.Description("allure-go allows you to use allure without suites. Even if it panics or failed") 34 | }) 35 | 36 | r.RunTests() 37 | } 38 | -------------------------------------------------------------------------------- /examples/provider_demo/sample_test.go: -------------------------------------------------------------------------------- 1 | //go:build provider_new 2 | // +build provider_new 3 | 4 | package provider_demo 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/ozontech/allure-go/pkg/allure" 11 | "github.com/ozontech/allure-go/pkg/framework/provider" 12 | "github.com/ozontech/allure-go/pkg/framework/runner" 13 | ) 14 | 15 | func TestSampleDemo(t *testing.T) { 16 | runner.Run(t, "My test", func(t provider.T) { 17 | t.Epic("Only Provider Demo") 18 | t.Feature("runner.RunTest") 19 | 20 | t.Title("Some Sample test") 21 | t.Description("allure-go allows you to use allure without suites") 22 | t.WithParameters(allure.NewParameter("host", "localhost")) 23 | 24 | t.WithNewStep("Some nested step", func(ctx provider.StepCtx) { 25 | ctx.WithNewStep("Some inner step 1", func(ctx provider.StepCtx) { 26 | ctx.WithNewStep("Some inner step 1.1", func(ctx provider.StepCtx) { 27 | 28 | }) 29 | }) 30 | ctx.WithNewStep("Some inner step 2", func(ctx provider.StepCtx) { 31 | ctx.WithNewStep("Some inner step 2.1", func(ctx provider.StepCtx) { 32 | 33 | }) 34 | }) 35 | }) 36 | }, "Sample", "Provider-only", "No provider initialization") 37 | } 38 | 39 | func TestOtherSampleDemo(realT *testing.T) { 40 | r := runner.NewRunner(realT, realT.Name()) 41 | 42 | r.BeforeEach(func(t provider.T) { 43 | t.NewStep(fmt.Sprintf("This is before test step for %s", t.Name())) 44 | }) 45 | r.BeforeAll(func(t provider.T) { 46 | t.NewStep(fmt.Sprintf("This is BeforeAll test step for %s", t.Name())) 47 | }) 48 | r.AfterEach(func(t provider.T) { 49 | t.NewStep(fmt.Sprintf("This is AfterEach test step for %s", t.Name())) 50 | }) 51 | r.AfterAll(func(t provider.T) { 52 | t.NewStep(fmt.Sprintf("This is AfterAll test step for %s", t.Name())) 53 | }) 54 | 55 | r.NewTest("My test 1", func(t provider.T) { 56 | t.Epic("Only Provider Demo") 57 | t.Feature("T.Run()") 58 | 59 | t.Title("Some Other Sample test") 60 | t.Description("allure-testify allows you to use allure without suites") 61 | 62 | t.WithNewStep("Some nested step", func(ctx provider.StepCtx) { 63 | ctx.WithNewStep("Some inner step 1", func(ctx provider.StepCtx) { 64 | ctx.WithNewStep("Some inner step 1.1", func(ctx provider.StepCtx) { 65 | 66 | }) 67 | }) 68 | ctx.WithNewStep("Some inner step 2", func(ctx provider.StepCtx) { 69 | ctx.WithNewStep("Some inner step 2.1", func(ctx provider.StepCtx) { 70 | 71 | }) 72 | }) 73 | }) 74 | }, "Sample", "Provider-only", "with provider initialization") 75 | 76 | r.RunTests() 77 | } 78 | -------------------------------------------------------------------------------- /examples/suite_demo/befores_afters_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/suite" 11 | ) 12 | 13 | type BeforeAfterDemoSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *BeforeAfterDemoSuite) BeforeEach(t provider.T) { 18 | t.NewStep("Before Test Step") 19 | } 20 | 21 | func (s *BeforeAfterDemoSuite) AfterEach(t provider.T) { 22 | t.NewStep("After Test Step") 23 | } 24 | 25 | func (s *BeforeAfterDemoSuite) BeforeAll(t provider.T) { 26 | t.NewStep("Before suite Step") 27 | } 28 | 29 | func (s *BeforeAfterDemoSuite) AfterAll(t provider.T) { 30 | t.NewStep("After suite Step") 31 | t.Logf("HI") 32 | } 33 | 34 | func (s *BeforeAfterDemoSuite) TestBeforeAfterTest(t provider.T) { 35 | t.Epic("Demo") 36 | t.Feature("BeforeAfter") 37 | t.Title("Test wrapped with SetUp & TearDown") 38 | t.Description(` 39 | This test wrapped with SetUp and TearDown container.`) 40 | 41 | t.Tags("BeforeAfter") 42 | } 43 | 44 | func TestBeforesAfters(t *testing.T) { 45 | t.Parallel() 46 | suite.RunSuite(t, new(BeforeAfterDemoSuite)) 47 | } 48 | -------------------------------------------------------------------------------- /examples/suite_demo/labels_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/allure" 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | "github.com/ozontech/allure-go/pkg/framework/suite" 12 | ) 13 | 14 | type LabelsDemoSuite struct { 15 | suite.Suite 16 | } 17 | 18 | func (s *LabelsDemoSuite) BeforeEach(t provider.T) { 19 | t.Epic("Demo") 20 | t.Feature("Labels") 21 | t.Story("Story Label") 22 | 23 | t.Owner("John Doe") 24 | t.Lead("John Doe's Boss") 25 | 26 | t.Tag("EachTestTag") 27 | } 28 | 29 | func (s *LabelsDemoSuite) TestLabelsExample1(t provider.T) { 30 | t.Title("Labels Demo Example 1") 31 | t.Description(` 32 | This Test will have all labels from SetupTest function 33 | Unique labels: 34 | ID = "example1" 35 | Severity = "blocker" 36 | Unique tag = "Example1" 37 | Also this test has additional "suite" label`) 38 | 39 | t.ID("Id example1") 40 | t.Severity(allure.BLOCKER) 41 | 42 | t.AddSuiteLabel("AnotherSuite") 43 | 44 | t.Tag("Example1") 45 | } 46 | 47 | func (s *LabelsDemoSuite) TestLabelsExample2(t provider.T) { 48 | t.Title("Labels Demo Example 2") 49 | t.Description(` 50 | This Test will have all labels from SetupTest function 51 | Unique labels: 52 | ID = "example2" 53 | Severity = "critical" 54 | Unique tag = "Example2" 55 | Also this test has additional "parentSuite" label`) 56 | 57 | t.ID("example2") 58 | t.Severity(allure.CRITICAL) 59 | 60 | t.AddParentSuite("AnotherParentSuite") 61 | 62 | t.Tag("Example2") 63 | } 64 | 65 | func (s *LabelsDemoSuite) TestLabelsExample3(t provider.T) { 66 | t.Title("Labels Demo Example 3") 67 | t.Description(` 68 | This Test will have all labels from SetupTest function 69 | Unique labels: 70 | ID = "example3" 71 | Severity = "normal" 72 | Unique tag = "Example3" 73 | Also this test has additional "subSuite" label`) 74 | 75 | t.ID("example3") 76 | t.Severity(allure.NORMAL) 77 | 78 | t.AddSubSuite("SomeSubSuite") 79 | 80 | t.Tag("Example3") 81 | } 82 | 83 | func (s *LabelsDemoSuite) TestLabelsExample4(t provider.T) { 84 | t.Title("Labels Demo Example 4") 85 | t.Description(` 86 | This Test will have all labels from SetupTest function 87 | Unique labels: 88 | ID = "example4" 89 | Severity = "minor" 90 | Unique tag = "Example4"`) 91 | 92 | t.ID("example4") 93 | t.Severity(allure.MINOR) 94 | 95 | t.Tag("Example4") 96 | } 97 | 98 | func (s *LabelsDemoSuite) TestLabelsExample5(t provider.T) { 99 | t.Title("Labels Demo Example 5") 100 | t.Description(` 101 | This Test will have all labels from SetupTest function 102 | Unique labels: 103 | ID = "example5" 104 | Severity = "trivial" 105 | Unique tag = "Example5"`) 106 | 107 | t.ID("example5") 108 | t.Severity(allure.TRIVIAL) 109 | 110 | t.Tag("Example5") 111 | } 112 | 113 | func TestLabels(t *testing.T) { 114 | t.Parallel() 115 | suite.RunSuite(t, new(LabelsDemoSuite)) 116 | } 117 | -------------------------------------------------------------------------------- /examples/suite_demo/links_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "os" 8 | "testing" 9 | 10 | "github.com/ozontech/allure-go/pkg/allure" 11 | "github.com/ozontech/allure-go/pkg/framework/provider" 12 | "github.com/ozontech/allure-go/pkg/framework/suite" 13 | ) 14 | 15 | type LinkDemoSuite struct { 16 | suite.Suite 17 | } 18 | 19 | func (s *LinkDemoSuite) BeforeAll(t provider.T) { 20 | _ = os.Setenv("ALLURE_TESTCASE_PATTERN", "https://tour.golang.org/welcome/%s") 21 | _ = os.Setenv("ALLURE_ISSUE_PATTERN", "https://pkg.go.dev/%s") 22 | } 23 | 24 | func (s *LinkDemoSuite) AfterAll(t provider.T) { 25 | _ = os.Setenv("ALLURE_TESTCASE_PATTERN", "") 26 | _ = os.Setenv("ALLURE_ISSUE_PATTERN", "") 27 | } 28 | 29 | func (s *LinkDemoSuite) TestLinks(t provider.T) { 30 | t.Epic("Demo") 31 | t.Feature("Links") 32 | t.Title("Test contains links") 33 | t.Description(` 34 | This test contains link with ISSUE, TEST CASE and LINK. 35 | Test case link: https://tour.golang.org/welcome/1 36 | Issue link: https://pkg.go.dev/github.com/stretchr/testify 37 | Link link: https://www.makeuseof.com/tag/8-purrfect-cat-websites/`) 38 | 39 | t.Tags("Links") 40 | 41 | t.SetTestCase("1") 42 | t.SetIssue("github.com/stretchr/testify") 43 | 44 | link := "https://www.makeuseof.com/tag/8-purrfect-cat-websites/" 45 | t.Link(allure.LinkLink("Demo Link", link)) 46 | } 47 | 48 | func TestLinks(t *testing.T) { 49 | t.Parallel() 50 | suite.RunSuite(t, new(LinkDemoSuite)) 51 | } 52 | -------------------------------------------------------------------------------- /examples/suite_demo/new_parametrized_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/jackc/fake" 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | "github.com/ozontech/allure-go/pkg/framework/suite" 12 | ) 13 | 14 | type ParametrizedSuite struct { 15 | suite.Suite 16 | ParamCities []string 17 | } 18 | 19 | func (s *ParametrizedSuite) BeforeAll(t provider.T) { 20 | for i := 0; i < 10; i++ { 21 | s.ParamCities = append(s.ParamCities, fake.City()) 22 | } 23 | } 24 | 25 | func (s *ParametrizedSuite) TableTestCities(t provider.T, city string) { 26 | t.Parallel() 27 | t.Require().NotEmpty(city) 28 | } 29 | 30 | func TestNewParametrizedDemo(t *testing.T) { 31 | suite.RunSuite(t, new(ParametrizedSuite)) 32 | } 33 | -------------------------------------------------------------------------------- /examples/suite_demo/parameters_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/allure" 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | "github.com/ozontech/allure-go/pkg/framework/suite" 12 | ) 13 | 14 | type ParametersDemoSuite struct { 15 | suite.Suite 16 | } 17 | 18 | func (s *ParametersDemoSuite) TestAddParameterToStep(t provider.T) { 19 | t.Epic("Demo") 20 | t.Feature("Parameters") 21 | t.Title("Add Parameters to step") 22 | t.Description(` 23 | Step A will contain following parameters: 24 | Param1 = Val1 25 | Param2 = Val2 26 | Param3 = Val3 27 | Param4 = Val4 28 | Param5 = Val5 29 | Param6 = Val6 30 | Param7 = Val7`) 31 | 32 | t.Tags("Steps", "Nesting", "Parameters") 33 | 34 | step := allure.NewSimpleStep("Step A") 35 | 36 | // with step.WithParameters(s) function 37 | step.WithParameters(allure.NewParameter("Param1", "Val1")) 38 | step.WithParameters(allure.NewParameters("Param2", "Val2", "Param3", "Val3", "Param4", "Val4")...) 39 | 40 | // don't forget register your step :) 41 | t.Step(step) 42 | } 43 | 44 | func (s *ParametersDemoSuite) TestAddParameterToNestedStep(t provider.T) { 45 | t.Epic("Demo") 46 | t.Feature("Parameters") 47 | t.Title("Add parameters to Nested Steps") 48 | t.Description(` 49 | Step A is parent step for Step B 50 | Step A contains Param 1 and Param 4 51 | Step B contains Param 2 and Param 3`) 52 | 53 | t.Tags("Steps", "Nesting", "Parameters") 54 | 55 | t.WithNewStep("Step A", func(ctx provider.StepCtx) { 56 | ctx.WithNewParameters("Param 1", "Value 1") 57 | ctx.WithNewStep("Step B", func(ctx provider.StepCtx) { 58 | ctx.WithNewParameters("Param 2", "Value 2", "Param 3", "Value 3") 59 | }) 60 | ctx.WithNewParameters("Param 4", "Value 3") 61 | }) 62 | } 63 | 64 | func TestParameters(t *testing.T) { 65 | t.Parallel() 66 | suite.RunSuite(t, new(ParametersDemoSuite)) 67 | } 68 | -------------------------------------------------------------------------------- /examples/suite_demo/parametrized_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | "github.com/ozontech/allure-go/pkg/framework/suite" 12 | ) 13 | 14 | type ParametrizedTestDemo struct { 15 | suite.Suite 16 | } 17 | 18 | func (s *ParametrizedTestDemo) BeforeEach(t provider.T) { 19 | t.Epic("Demo") 20 | t.Feature("Parametrized") 21 | } 22 | 23 | func (s *ParametrizedTestDemo) TestParameterized(t provider.T) { 24 | t.Title("Parent Test") 25 | t.Description(` 26 | This test is parent for all Parametrized`) 27 | 28 | for i := 0; i < 10; i++ { 29 | newI := i 30 | t.Run(fmt.Sprintf("Parametrized #%d", newI), func(t provider.T) { 31 | t.Feature("Parametrized") 32 | t.Description(fmt.Sprintf("This test checks that 1 Equal %d", newI)) 33 | t.Tag("Parametrized") 34 | t.Parallel() 35 | t.WithNewStep(fmt.Sprintf("Step %d", i), func(ctx provider.StepCtx) { 36 | ctx.Require().Equal(1, newI) 37 | }) 38 | }) 39 | } 40 | 41 | for i := 0; i < 10; i++ { 42 | newI := i 43 | t.Run(fmt.Sprintf("Parametrized 2#%d", newI), func(t provider.T) { 44 | t.Feature("Parametrized") 45 | t.Description(fmt.Sprintf("This test checks that 1 Equal %d", newI)) 46 | t.Tag("Parametrized") 47 | t.Parallel() 48 | t.WithNewStep(fmt.Sprintf("Step %d", newI), func(ctx provider.StepCtx) { 49 | ctx.Require().Less(1, newI) 50 | }) 51 | }) 52 | } 53 | } 54 | 55 | func TestParametrizedDemo(t *testing.T) { 56 | suite.RunSuite(t, new(ParametrizedTestDemo)) 57 | } 58 | 59 | type ParametrizedTestDemo2 struct { 60 | suite.Suite 61 | } 62 | 63 | func (s *ParametrizedTestDemo2) BeforeEach(t provider.T) { 64 | t.Epic("Demo") 65 | t.Feature("Parametrized") 66 | } 67 | 68 | func (s *ParametrizedTestDemo2) TestParameterized2(t provider.T) { 69 | t.Title("Parent Test") 70 | t.Description(` 71 | This test is parent for all Parametrized`) 72 | 73 | for i := 0; i < 10; i++ { 74 | newI := i 75 | t.Run(fmt.Sprintf("Parametrized #%d", newI), func(t provider.T) { 76 | t.Feature("Parametrized") 77 | t.Description(fmt.Sprintf("This test checks that 1 Equal %d", newI)) 78 | t.Tag("Parametrized") 79 | t.WithNewStep(fmt.Sprintf("Step %d", newI), func(ctx provider.StepCtx) { 80 | ctx.Require().Equal(1, newI) 81 | }) 82 | }) 83 | } 84 | 85 | for i := 0; i < 10; i++ { 86 | newI := i 87 | t.Run(fmt.Sprintf("Parametrized 2#%d", newI), func(t provider.T) { 88 | t.Feature("Parametrized") 89 | t.Description(fmt.Sprintf("This test checks that 1 Equal %d", newI)) 90 | t.Tag("Parametrized") 91 | t.WithNewStep(fmt.Sprintf("Step %d", newI), func(ctx provider.StepCtx) { 92 | if newI == 4 { 93 | panic("WHOOPS") 94 | } 95 | ctx.Require().Less(1, newI) 96 | }) 97 | }) 98 | } 99 | } 100 | 101 | func TestParametrizedDemo2(t *testing.T) { 102 | suite.RunSuite(t, new(ParametrizedTestDemo2)) 103 | } 104 | -------------------------------------------------------------------------------- /examples/suite_demo/running_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "github.com/ozontech/allure-go/pkg/framework/provider" 8 | "testing" 9 | 10 | "github.com/ozontech/allure-go/pkg/framework/suite" 11 | ) 12 | 13 | // TestRunningDemoSuite demonstrate parallel running 14 | type TestRunningDemoSuite struct { 15 | suite.Suite 16 | } 17 | 18 | func (s *TestRunningDemoSuite) TestBeforesAfters(t provider.T) { 19 | t.Parallel() 20 | s.RunSuite(t, new(BeforeAfterDemoSuite)) 21 | } 22 | 23 | func (s *TestRunningDemoSuite) TestFails(t provider.T) { 24 | t.Parallel() 25 | s.RunSuite(t, new(FailsDemoSuite)) 26 | } 27 | 28 | func (s *TestRunningDemoSuite) TestLabels(t provider.T) { 29 | t.Parallel() 30 | s.RunSuite(t, new(LabelsDemoSuite)) 31 | } 32 | 33 | func (s *TestRunningDemoSuite) TestParametrized(t provider.T) { 34 | t.Parallel() 35 | s.RunSuite(t, new(ParametrizedSuite)) 36 | } 37 | 38 | func TestRunDemo(t *testing.T) { 39 | // use RunSuite to run suite of suites 40 | t.Parallel() 41 | suite.RunSuite(t, new(TestRunningDemoSuite)) 42 | } 43 | -------------------------------------------------------------------------------- /examples/suite_demo/setup_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/jackc/fake" 12 | "github.com/ozontech/allure-go/pkg/allure" 13 | "github.com/ozontech/allure-go/pkg/framework/provider" 14 | "github.com/ozontech/allure-go/pkg/framework/suite" 15 | ) 16 | 17 | type Example struct { 18 | country string 19 | number int 20 | } 21 | 22 | func (e *Example) String() string { 23 | return fmt.Sprintf("%s#%d", e.country, e.number) 24 | } 25 | 26 | type SetupSuite struct { 27 | suite.Suite 28 | ParamMyTest []*Example 29 | } 30 | 31 | func (s *SetupSuite) BeforeAll(t provider.T) { 32 | var params []*allure.Parameter 33 | for i := 0; i < 10; i++ { 34 | param := &Example{ 35 | country: fake.Country(), 36 | number: fake.Year(1900, 2000), 37 | } 38 | params = append(params, allure.NewParameter(fmt.Sprintf("Ex %d", i), param)) 39 | s.ParamMyTest = append(s.ParamMyTest, param) 40 | } 41 | t.NewStep("BeforeAllStep", params...) 42 | } 43 | 44 | func (s *SetupSuite) BeforeEach(t provider.T) { 45 | t.Epic("Demo") 46 | t.Feature("BeforeAfter") 47 | t.NewStep("This Step will be before Each") 48 | } 49 | 50 | func (s *SetupSuite) AfterEach(t provider.T) { 51 | t.NewStep("AfterEach Step") 52 | } 53 | 54 | func (s *SetupSuite) AfterAll(t provider.T) { 55 | t.NewStep("AfterAll Step") 56 | } 57 | 58 | func (s *SetupSuite) TableTestMyTest(t provider.T, example *Example) { 59 | t.Titlef("TableTest With Setup - %s", example) 60 | t.Descriptionf(` 61 | Test will unpack all data from passed parameter to the variables in WithTestSetup func. 62 | After test finish, it will do ctx.Done() in TestTearDown. 63 | All Setup and TearDown tests will be add as Befores and Afters to test's container. 64 | Used Data: %s`, example) 65 | t.Tags("Parametrized", "Parallel", "Setup", "BeforeAfter") 66 | 67 | t.Parallel() 68 | var ( 69 | country string 70 | year int 71 | ctx context.Context 72 | ) 73 | 74 | defer t.WithTestTeardown(func(t provider.T) { 75 | t.WithNewStep("Close ctx", func(sCtx provider.StepCtx) { 76 | ctx.Done() 77 | sCtx.WithNewParameters("ctx", ctx) 78 | }) 79 | }) 80 | 81 | t.WithTestSetup(func(t provider.T) { 82 | t.WithNewStep("init country", func(sCtx provider.StepCtx) { 83 | country = example.country 84 | sCtx.WithNewParameters("country", country) 85 | }) 86 | t.WithNewStep("init year", func(sCtx provider.StepCtx) { 87 | year = example.number 88 | sCtx.WithNewParameters("year", year) 89 | }) 90 | t.WithNewStep("init ctx", func(sCtx provider.StepCtx) { 91 | ctx = context.Background() 92 | sCtx.WithNewParameters("ctx", ctx) 93 | }) 94 | }) 95 | 96 | t.Require().NotEqual("PonyCountry", country, "No magic countries in the list") 97 | t.Require().NotEqual(2007, year, "No one returned to 2007") 98 | t.Require().NotNil(ctx, "Not empty context") 99 | } 100 | 101 | func (s *SetupSuite) TestMyOtherTest(t provider.T) { 102 | t.Title("Just Test WithSetup") 103 | t.Description(` 104 | Test will prepare some data at TestSetup.`) 105 | t.Tags("Parallel", "Setup", "BeforeAfter") 106 | 107 | t.Parallel() 108 | var ( 109 | name string 110 | age int 111 | ) 112 | 113 | t.WithTestSetup(func(t provider.T) { 114 | t.WithNewStep("init args", func(sCtx provider.StepCtx) { 115 | name = fake.FullName() 116 | age = fake.Day() 117 | sCtx.WithNewParameters("name", name, "age", age) 118 | }) 119 | }) 120 | } 121 | 122 | func TestRunner(t *testing.T) { 123 | suite.RunSuite(t, new(SetupSuite)) 124 | } 125 | -------------------------------------------------------------------------------- /examples/suite_demo/skip_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/suite" 11 | ) 12 | 13 | type SkipDemoSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *SkipDemoSuite) TestSkip(t provider.T) { 18 | t.Epic("Demo") 19 | t.Feature("Skip Test") 20 | t.Title("Skip test") 21 | t.Description(` 22 | This test will be skipped`) 23 | 24 | t.Tags("Test", "Skip") 25 | t.Skip("Skip Reason") 26 | } 27 | 28 | func TestSkipDemo(t *testing.T) { 29 | t.Parallel() 30 | suite.RunSuite(t, new(SkipDemoSuite)) 31 | } 32 | -------------------------------------------------------------------------------- /examples/suite_demo/step_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | "time" 9 | 10 | "github.com/ozontech/allure-go/pkg/allure" 11 | "github.com/ozontech/allure-go/pkg/framework/provider" 12 | "github.com/ozontech/allure-go/pkg/framework/suite" 13 | ) 14 | 15 | type StepDemoSuite struct { 16 | suite.Suite 17 | } 18 | 19 | func (s *StepDemoSuite) TestAddSteps(t provider.T) { 20 | t.Epic("Demo") 21 | t.Feature("Steps") 22 | t.Title("Base. Add steps to allure result") 23 | t.Description(` 24 | Step A, Step B and Step C will be add to Allure Result`) 25 | 26 | t.Tags("Steps") 27 | 28 | stepA := allure.NewSimpleStep("Step A") 29 | t.Step(stepA) 30 | 31 | stepB := allure.NewStep("Step B", // Step's Name 32 | allure.Passed, // Step Status 33 | allure.GetNow(), // Step Start 34 | allure.GetNow(), // Step Finish 35 | allure.NewParameters("paramB", "value")) // Step Parameters 36 | 37 | t.Step(stepB) 38 | 39 | stepC := allure.NewSimpleStep("Step C") 40 | stepC.Start = allure.GetNow() 41 | stepC.WithNewParameters("paramC", "value") 42 | stepC.Stop = allure.GetNow() 43 | t.Step(stepC) 44 | } 45 | 46 | func (s *StepDemoSuite) TestQuickWorkWithSteps(t provider.T) { 47 | t.Epic("Demo") 48 | t.Feature("Steps") 49 | t.Title("Base. Add steps to allure result") 50 | t.Description(` 51 | Step A, Step B, Step C and Step D will be add to Allure Result`) 52 | 53 | t.Tags("Steps") 54 | 55 | t.Step(allure.NewSimpleStep("Step A").Passed()) // This step will be passed 56 | t.Step(allure.NewSimpleStep("Step B").Failed()) // This step will be failed 57 | t.Step(allure.NewSimpleStep("Step C").Skipped()) // This step will be skipped 58 | 59 | stepD := allure.NewSimpleStep("Step D").Begin() 60 | time.Sleep(1 * time.Second) // Do some 61 | stepD = stepD.Finish().Passed() 62 | t.Step(stepD) 63 | } 64 | 65 | func (s *StepDemoSuite) TestInnerStep(t provider.T) { 66 | t.Epic("Demo") 67 | t.Layer("Layer") 68 | t.Feature("Steps") 69 | t.Title("Add child steps to existed step.") 70 | t.Description(` 71 | Step A is parent step for Step B and Step C 72 | Step D is parent step for Step E and Step F 73 | Call order will be saved in allure report 74 | A -> (B, C), D -> (E, F)`) 75 | 76 | t.Tags("Steps", "Nesting") 77 | 78 | // use allure.NewSimpleStep constructor 79 | stepA := allure.NewSimpleStep("Step A") 80 | stepB := allure.NewSimpleStep("Step B") 81 | stepC := allure.NewSimpleStep("Step C") 82 | stepA.WithChild(stepB) 83 | stepA.WithChild(stepC) 84 | t.Step(stepA) 85 | 86 | // use InnerStep function 87 | stepD := allure.NewSimpleStep("Step D") 88 | t.Step(stepD) 89 | stepD.WithChild(allure.NewSimpleStep("Step E")) 90 | stepF := allure.NewStep("Step F", // Step's Name 91 | allure.Passed, // Step Status 92 | allure.GetNow(), // Step Start 93 | allure.GetNow(), // Step Finish 94 | allure.NewParameters("paramF", "value")) // Step Parameters 95 | stepF.WithParent(stepD) 96 | 97 | // forward way 98 | stepG := allure.NewSimpleStep("Step G") 99 | stepH := allure.NewSimpleStep("Step H") 100 | stepI := allure.NewSimpleStep("Step I") 101 | stepG.WithChild(stepH) 102 | stepG.WithChild(stepI) 103 | } 104 | 105 | func TestStepDemo(t *testing.T) { 106 | t.Parallel() 107 | suite.RunSuite(t, new(StepDemoSuite)) 108 | } 109 | -------------------------------------------------------------------------------- /examples/suite_demo/step_tree_test.go: -------------------------------------------------------------------------------- 1 | //go:build examples_new 2 | // +build examples_new 3 | 4 | package suite_demo 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/suite" 11 | ) 12 | 13 | type StepTreeDemoSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *StepTreeDemoSuite) TestInnerSteps(t provider.T) { 18 | t.Epic("Demo") 19 | t.Feature("Inner Steps") 20 | t.Title("Simple Nesting") 21 | t.Description(` 22 | Step A is parent step for Step B and Step C 23 | Call order will be saved in allure report 24 | A -> (B, C)`) 25 | 26 | t.Tags("Steps", "Nesting") 27 | 28 | t.WithNewStep("Step A", func(ctx provider.StepCtx) { 29 | ctx.NewStep("Step B") 30 | ctx.NewStep("Step C") 31 | }) 32 | } 33 | 34 | func (s *StepTreeDemoSuite) TestComplexStepTree(t provider.T) { 35 | t.Epic("Demo") 36 | t.Feature("Inner Steps") 37 | t.Title("Complex Nesting") 38 | t.Description(` 39 | Step A is parent for Step B, Step C and Step F 40 | Step C is parent for Step D and Step E 41 | Step F is parent for Step G and Step H 42 | Call order will be saved in allure report 43 | A -> (B, C -> (D, E), F -> (G, H), I)`) 44 | 45 | t.Tags("Steps", "Nesting") 46 | 47 | t.WithNewStep("Step A", func(ctx provider.StepCtx) { 48 | ctx.NewStep("Step B") 49 | ctx.WithNewStep("Step C", func(ctx provider.StepCtx) { 50 | ctx.NewStep("Step D") 51 | ctx.NewStep("Step E") 52 | }) 53 | ctx.WithNewStep("Step F", func(ctx provider.StepCtx) { 54 | ctx.NewStep("Step G") 55 | ctx.NewStep("Step H") 56 | }) 57 | ctx.NewStep("Step I") 58 | }) 59 | } 60 | 61 | func TestStepTree(t *testing.T) { 62 | t.Parallel() 63 | suite.RunSuite(t, new(StepTreeDemoSuite)) 64 | } 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ozontech/allure-go 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/ozontech/allure-go/pkg/allure => ./pkg/allure 7 | github.com/ozontech/allure-go/pkg/framework => ./pkg/framework 8 | ) 9 | 10 | require ( 11 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 12 | github.com/ozontech/allure-go/pkg/allure v0.6.14 13 | github.com/ozontech/allure-go/pkg/framework v0.6.33 14 | ) 15 | 16 | require ( 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/google/uuid v1.3.0 // indirect 19 | github.com/pkg/errors v0.9.1 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | github.com/stretchr/testify v1.7.1 // indirect 22 | gopkg.in/yaml.v3 v3.0.0 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 5 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 6 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= 7 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= 8 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 9 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 10 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 11 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 12 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 13 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 14 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 15 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 16 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 17 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 18 | gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= 19 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 20 | -------------------------------------------------------------------------------- /pkg/allure/.golangci.yaml: -------------------------------------------------------------------------------- 1 | # More info on config here: https://github.com/golangci/golangci-lint#config-file 2 | run: 3 | deadline: 10s 4 | timeout: 5m 5 | issues-exit-code: 1 6 | tests: true 7 | skip-dirs: 8 | - bin 9 | - vendor 10 | - var 11 | - tmp 12 | skip-files: 13 | - \.pb\.go$ 14 | - \.pb\.goclay\.go$ 15 | - \_test.go$ 16 | 17 | output: 18 | format: colored-line-number 19 | print-issued-lines: true 20 | print-linter-name: true 21 | 22 | linters-settings: 23 | govet: 24 | check-shadowing: true 25 | golint: 26 | min-confidence: 0 27 | dupl: 28 | threshold: 100 29 | goconst: 30 | min-len: 2 31 | min-occurrences: 2 32 | 33 | linters: 34 | disable-all: true 35 | enable: 36 | - golint 37 | - govet 38 | - errcheck 39 | - deadcode 40 | - structcheck 41 | - varcheck 42 | - ineffassign 43 | - typecheck 44 | - dupl 45 | - goconst 46 | - gosec 47 | - goimports 48 | - megacheck 49 | 50 | 51 | issues: 52 | exclude-use-default: false 53 | exclude: 54 | # _ instead of err checks 55 | - G104 56 | - G306 57 | # md5 using for hash generation, not for security, so ignore this 58 | - G401 59 | - G501 60 | # for "public interface + private struct implementation" cases only! 61 | - exported func * returns unexported type *, which can be annoying to use 62 | # can be removed in the development phase 63 | # - (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form) 64 | # not for the active development - can be removed in the stable phase 65 | - should have a package comment, unless it's in another file for this package 66 | - don't use an underscore in package name 67 | # errcheck: Almost all programs ignore errors on these functions and in most cases it's ok 68 | - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv|.*Rollback). is not checked 69 | - should check returned error before deferring 70 | - should have comment or be unexported 71 | - a blank import should be only in a main or test package 72 | - Can't process result by diff processor 73 | -------------------------------------------------------------------------------- /pkg/allure/Makefile: -------------------------------------------------------------------------------- 1 | APP?=allure-testify 2 | RELEASE?=0.5.0 3 | GOOS?=darwin 4 | 5 | COMMIT?=$(shell git rev-parse --short HEAD) 6 | BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S') 7 | 8 | export GO111MODULE=on 9 | export GOSUMDB=off 10 | LOCAL_BIN:=$(CURDIR)/bin 11 | 12 | ##################### GOLANG-CI RELATED CHECKS ##################### 13 | # Check global GOLANGCI-LINT 14 | GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint 15 | GOLANGCI_TAG:=1.38.0 16 | 17 | # Check local bin version 18 | ifneq ($(wildcard $(GOLANGCI_BIN)),) 19 | GOLANGCI_BIN_VERSION:=$(shell $(GOLANGCI_BIN) --version) 20 | ifneq ($(GOLANGCI_BIN_VERSION),) 21 | GOLANGCI_BIN_VERSION_SHORT:=$(shell echo "$(GOLANGCI_BIN_VERSION)" | sed -E 's/.* version (.*) built from .* on .*/\1/g') 22 | else 23 | GOLANGCI_BIN_VERSION_SHORT:=0 24 | endif 25 | ifneq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_BIN_VERSION_SHORT)))" 26 | GOLANGCI_BIN:= 27 | endif 28 | endif 29 | 30 | # Check global bin version 31 | ifneq (, $(shell which golangci-lint)) 32 | GOLANGCI_VERSION:=$(shell golangci-lint --version 2> /dev/null ) 33 | ifneq ($(GOLANGCI_VERSION),) 34 | GOLANGCI_VERSION_SHORT:=$(shell echo "$(GOLANGCI_VERSION)"|sed -E 's/.* version (.*) built from .* on .*/\1/g') 35 | else 36 | GOLANGCI_VERSION_SHORT:=0 37 | endif 38 | ifeq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_VERSION_SHORT)))" 39 | GOLANGCI_BIN:=$(shell which golangci-lint) 40 | endif 41 | endif 42 | ##################### GOLANG-CI RELATED CHECKS ##################### 43 | 44 | # run full lint like in pipeline 45 | .PHONY: lint 46 | lint: install-lint 47 | $(GOLANGCI_BIN) run --config=.golangci.yaml ./... 48 | 49 | 50 | .PHONY: install-lint 51 | install-lint: 52 | ifeq ($(wildcard $(GOLANGCI_BIN)),) 53 | $(info #Downloading golangci-lint v$(GOLANGCI_TAG)) 54 | tmp=$$(mktemp -d) && cd $$tmp && pwd && go mod init temp && go get -d github.com/golangci/golangci-lint/cmd/golangci-lint@v$(GOLANGCI_TAG) && \ 55 | go build -ldflags "-X 'main.version=$(GOLANGCI_TAG)' -X 'main.commit=test' -X 'main.date=test'" -o $(LOCAL_BIN)/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint && \ 56 | rm -rf $$tmp 57 | GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint 58 | endif 59 | 60 | .PHONY: test 61 | test: 62 | go test ./... -cover -------------------------------------------------------------------------------- /pkg/allure/attachment.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "github.com/google/uuid" 5 | ) 6 | 7 | // Attachment - is an implementation of the attachments to the report in allure. It is most often used to contain 8 | // screenshots, responses, files and other data obtained during the test. 9 | type Attachment struct { 10 | Name string `json:"name,omitempty"` // Attachment name 11 | Source string `json:"source,omitempty"` // Path to the Attachment file (name) 12 | Type MimeType `json:"type,omitempty"` // Mime-type of the Attachment 13 | uuid string // Unique identifier of the Attachment 14 | content []byte // Attachment's content as bytes array 15 | } 16 | 17 | // MimeType is Attachment's mime type. 18 | // See more: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types 19 | type MimeType string 20 | 21 | // Attachment's MimeType constants 22 | const ( 23 | Text MimeType = "text/plain" 24 | Csv MimeType = "text/csv" 25 | Tsv MimeType = "text/tab-separated-values" 26 | URIList MimeType = "text/uri-list" 27 | 28 | HTML MimeType = "text/html" 29 | XML MimeType = "application/xml" 30 | JSON MimeType = "application/json" 31 | Yaml MimeType = "application/yaml" 32 | Pcap MimeType = "application/vnd.tcpdump.pcap" 33 | 34 | Png MimeType = "image/png" 35 | Jpg MimeType = "image/jpg" 36 | Svg MimeType = "image/svg-xml" 37 | Gif MimeType = "image/gif" 38 | Bmp MimeType = "image/bmp" 39 | Tiff MimeType = "image/tiff" 40 | 41 | Mp4 MimeType = "video/mp4" 42 | Ogg MimeType = "video/ogg" 43 | Webm MimeType = "video/webm" 44 | Mpeg MimeType = "video/mpeg" 45 | 46 | Pdf MimeType = "application/pdf" 47 | Xlsx MimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" 48 | ) 49 | 50 | // Ext returns file extension for this mime-type 51 | func (mt MimeType) Ext() string { 52 | switch mt { 53 | case Text: 54 | return ".txt" 55 | case Csv: 56 | return ".csv" 57 | case Tsv: 58 | return ".tsv" 59 | case URIList: 60 | return ".uri" 61 | case HTML: 62 | return ".html" 63 | case XML: 64 | return ".xml" 65 | case JSON: 66 | return ".json" 67 | case Yaml: 68 | return ".yaml" 69 | case Pcap: 70 | return ".pcap" 71 | case Png: 72 | return ".png" 73 | case Jpg: 74 | return ".jpg" 75 | case Svg: 76 | return ".svg" 77 | case Gif: 78 | return ".gif" 79 | case Bmp: 80 | return ".bmp" 81 | case Tiff: 82 | return ".tiff" 83 | case Mp4: 84 | return ".mp4" 85 | case Ogg: 86 | return ".ogg" 87 | case Webm: 88 | return ".webm" 89 | case Mpeg: 90 | return ".mpeg" 91 | case Pdf: 92 | return ".pdf" 93 | case Xlsx: 94 | return ".xlsx" 95 | default: 96 | return "" 97 | } 98 | } 99 | 100 | // NewAttachment - Constructor. Returns pointer to new attachment object. 101 | func NewAttachment(name string, mimeType MimeType, content []byte) *Attachment { 102 | id := uuid.New().String() 103 | 104 | return &Attachment{ 105 | uuid: id, 106 | content: content, 107 | Name: name, 108 | Type: mimeType, 109 | Source: id + "-attachment" + mimeType.Ext(), 110 | } 111 | } 112 | 113 | func (a *Attachment) GetUUID() string { 114 | return a.uuid 115 | } 116 | 117 | func (a *Attachment) GetContent() []byte { 118 | return a.content 119 | } 120 | 121 | // Print - Creates a file from `Attachment.content`. The file type is determined by its `Attachment.mimeType`. 122 | func (a *Attachment) Print() error { 123 | return NewFileManager().CreateFile(a.Source, a.content) 124 | } 125 | -------------------------------------------------------------------------------- /pkg/allure/attachment_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | var mimeTypes = []MimeType{ 12 | Text, 13 | Csv, 14 | Tsv, 15 | URIList, 16 | HTML, 17 | XML, 18 | JSON, 19 | Yaml, 20 | Pcap, 21 | Png, 22 | Jpg, 23 | Svg, 24 | Gif, 25 | Bmp, 26 | Tiff, 27 | Mp4, 28 | Ogg, 29 | Webm, 30 | Mpeg, 31 | Pdf, 32 | Xlsx, 33 | } 34 | 35 | func TestNewAttachment(t *testing.T) { 36 | for _, mt := range mimeTypes { 37 | testAttachName := fmt.Sprintf("Test init fileType: %s", mt) 38 | t.Run(testAttachName, func(t *testing.T) { 39 | content := []byte("some content") 40 | attachment := NewAttachment(testAttachName, mt, content) 41 | require.NotNil(t, attachment.uuid) 42 | require.Equal(t, mt, attachment.Type, "mime type should be same") 43 | require.Equal(t, testAttachName, attachment.Name) 44 | require.Equal(t, content, attachment.content) 45 | require.Contains(t, attachment.Source, mt.Ext()) 46 | }) 47 | } 48 | } 49 | 50 | func TestAttachment_Print(t *testing.T) { 51 | const testFolder = "allure-results" 52 | 53 | err := os.MkdirAll(testFolder, os.ModePerm) 54 | require.NoError(t, err) 55 | 56 | defer os.RemoveAll(testFolder) 57 | 58 | for _, mt := range mimeTypes { 59 | testAttachName := fmt.Sprintf("Test init fileType: %s", mt) 60 | t.Run(testAttachName, func(t *testing.T) { 61 | content := []byte("some content") 62 | attachment := NewAttachment(testAttachName, mt, content) 63 | err := attachment.Print() 64 | require.Nil(t, err, "No errors expected") 65 | require.FileExists(t, fmt.Sprintf("./allure-results/%s", attachment.Source)) 66 | }) 67 | } 68 | } 69 | 70 | func TestAttachment_GetUUID(t *testing.T) { 71 | content := []byte("some content") 72 | testAttachName := fmt.Sprintf("Test init fileType: %s", Text) 73 | 74 | attachment := NewAttachment(testAttachName, Text, content) 75 | require.NotNil(t, attachment.GetUUID()) 76 | } 77 | 78 | func TestAttachment_GetContent(t *testing.T) { 79 | content := []byte("some content") 80 | testAttachName := fmt.Sprintf("Test init fileType: %s", Text) 81 | 82 | attachment := NewAttachment(testAttachName, Text, content) 83 | require.Equal(t, content, attachment.GetContent()) 84 | } 85 | -------------------------------------------------------------------------------- /pkg/allure/config.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | // DefaultVersion - allure-go current Version 4 | const DefaultVersion = "Allure-Go@v0.6.0" 5 | 6 | const ( 7 | resultsPathEnvKey = "ALLURE_OUTPUT_PATH" // Indicates the path to the results print folder 8 | outputFolderEnvKey = "ALLURE_OUTPUT_FOLDER" // Indicates the name of the folder to print the results. 9 | issuePatternEnvKey = "ALLURE_ISSUE_PATTERN" // Indicates the URL pattern for Issue. It must contain exactly one `%s` 10 | testCasePatternEnvKey = "ALLURE_TESTCASE_PATTERN" // Indicates the URL pattern for TestCase. It must contain exactly one `%s` 11 | tmsLinkPatternEnvKey = "ALLURE_LINK_TMS_PATTERN" // Indicates the URL pattern for TmsLink. It must contain exactly one `%s` 12 | defaultTagsEnvKey = "ALLURE_LAUNCH_TAGS" // Indicates the default tags that will mark all tests in the run. The tags must be specified separated by commas. 13 | ) 14 | 15 | // Attachment permission 16 | const fileSystemPermissionCode = 0o644 17 | -------------------------------------------------------------------------------- /pkg/allure/config_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestConfig(t *testing.T) { 10 | require.Equal(t, "ALLURE_OUTPUT_PATH", resultsPathEnvKey) 11 | require.Equal(t, "ALLURE_OUTPUT_FOLDER", outputFolderEnvKey) 12 | require.Equal(t, "ALLURE_ISSUE_PATTERN", issuePatternEnvKey) 13 | require.Equal(t, "ALLURE_TESTCASE_PATTERN", testCasePatternEnvKey) 14 | require.Equal(t, "ALLURE_LAUNCH_TAGS", defaultTagsEnvKey) 15 | require.Equal(t, "ALLURE_LINK_TMS_PATTERN", tmsLinkPatternEnvKey) 16 | require.Equal(t, 0o644, fileSystemPermissionCode) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/allure/container.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/google/uuid" 7 | "github.com/pkg/errors" 8 | ) 9 | 10 | // Container This is an implementation of the `Container` entity used by Allure to handle TestSetup and TestTeardown hooks. 11 | // The list of container-dependent tests is contained in the `Container.Children` array. 12 | // Note: For Before/After Test hooks, the Container.Children array will contain one element (one container per test). 13 | // For Before/After Suite hooks the Container.Children array will contain UUIDs of all tests for which the hook was executed. 14 | type Container struct { 15 | UUID uuid.UUID `json:"uuid,omitempty"` // Unique identifier of the container 16 | Children []uuid.UUID `json:"children,omitempty"` // UUID array containing all reports referring to the container 17 | Befores []*Step `json:"befores,omitempty"` // Array of pointers to allure.Step in Test Setup 18 | Afters []*Step `json:"afters,omitempty"` // Array of pointers to allure.Step in Test TearDown 19 | Start int64 `json:"start,omitempty"` // Start time of the container 20 | Stop int64 `json:"stop,omitempty"` // Stop time of the container 21 | } 22 | 23 | // NewContainer - Constructor. Builds and returns a new `allure.Container` object. 24 | func NewContainer() *Container { 25 | return &Container{ 26 | UUID: uuid.New(), 27 | } 28 | } 29 | 30 | // AddChild Adds a new child to the Container.Children array. 31 | func (container *Container) AddChild(child uuid.UUID) { 32 | container.Children = append(container.Children, child) 33 | } 34 | 35 | // IsEmpty Returns `true` if arrays Container.Befores and Container.Afters are empty. 36 | func (container *Container) IsEmpty() bool { 37 | return len(container.Befores) == 0 && len(container.Afters) == 0 38 | } 39 | 40 | // Print Checks the file with the function Container.IsEmpty: 41 | // 42 | // 1. If the container is empty, execution of the function completes without error. 43 | // 44 | // 2. If the container contains steps 45 | // 2.1. Call Container.PrintAttachments() 46 | // 2.2. Serializes the file into `uuid4-container.json`. 47 | // 2.3. Creates a file in the file system in the output folder (`$ALLURE_OUTPUT_PATH`/`$ALLURE_OUTPUT_FOLDER`). If there is an error during 48 | // 49 | // If error occurs during execution - returns it 50 | func (container *Container) Print() error { 51 | if !container.IsEmpty() { 52 | container.PrintAttachments() 53 | 54 | return container.printContainer() 55 | } 56 | 57 | return nil 58 | } 59 | 60 | // PrintAttachments It goes through all Container.Befores and Container.Afters 61 | // of the Container and calls the Container.PrintAttachments() method at each allure.Step. 62 | func (container *Container) PrintAttachments() { 63 | for _, step := range container.Befores { 64 | step.PrintAttachments() 65 | } 66 | 67 | for _, step := range container.Afters { 68 | step.PrintAttachments() 69 | } 70 | } 71 | 72 | // Begin Sets `Container.Start` = allure.GetNow() 73 | func (container *Container) Begin() { 74 | container.Start = GetNow() 75 | } 76 | 77 | // Finish Sets Container.Stop = allure.GetNow() 78 | func (container *Container) Finish() { 79 | container.Stop = GetNow() 80 | } 81 | 82 | // Done calls Finish and Print 83 | func (container *Container) Done() error { 84 | container.Finish() 85 | 86 | return container.Print() 87 | } 88 | 89 | // ToJSON marshal allure.Result to json file 90 | // 91 | // Deprecated: use [json.Marshal] instead 92 | func (container *Container) ToJSON() ([]byte, error) { 93 | return json.Marshal(container) 94 | } 95 | 96 | // Print prints all attachments of [Container.Befores] and [Container.Afters] 97 | // after that marshals [Container] and [os.WriteFile] 98 | func (container *Container) printContainer() error { 99 | bResult, err := json.Marshal(container) 100 | if err != nil { 101 | return errors.Wrap(err, "Failed marshal Result") 102 | } 103 | 104 | err = NewFileManager().CreateFile(container.UUID.String()+"-container.json", bResult) 105 | if err != nil { 106 | return errors.Wrap(err, "Error write Result") 107 | } 108 | 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /pkg/allure/container_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "os" 8 | "testing" 9 | "time" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | const ( 16 | allureDir = "allure-results" 17 | ) 18 | 19 | func TestNewContainer(t *testing.T) { 20 | container := NewContainer() 21 | require.NotNil(t, container) 22 | require.Zero(t, container.Start) 23 | require.Zero(t, container.Stop) 24 | require.NotNil(t, container.UUID) 25 | } 26 | 27 | func TestContainer_AddChild(t *testing.T) { 28 | container := NewContainer() 29 | result := NewResult("Mock Name", "Full Mock Name") 30 | container.AddChild(result.UUID) 31 | require.NotEmpty(t, container.Children) 32 | require.Len(t, container.Children, 1) 33 | require.Equal(t, result.UUID, container.Children[0]) 34 | } 35 | 36 | func TestContainer_Begin(t *testing.T) { 37 | container := NewContainer() 38 | begin := GetNow() 39 | container.Begin() 40 | assert.Equal(t, container.Start, begin) 41 | } 42 | 43 | func TestContainer_Finish(t *testing.T) { 44 | container := NewContainer() 45 | finish := GetNow() 46 | container.Finish() 47 | assert.Equal(t, container.Stop, finish) 48 | } 49 | 50 | func TestContainer_Print(t *testing.T) { 51 | container := NewContainer() 52 | containerBefore := NewSimpleStep("Before") 53 | containerAfter := NewSimpleStep("After") 54 | container.Befores = append(container.Befores, containerBefore) 55 | container.Afters = append(container.Afters, containerAfter) 56 | 57 | _ = container.Print() 58 | defer os.RemoveAll(allureDir) 59 | require.DirExists(t, allureDir) 60 | files, _ := os.ReadDir(allureDir) 61 | require.Len(t, files, 1) 62 | var jsonFile *os.File 63 | defer jsonFile.Close() 64 | 65 | f := files[0] 66 | emptyContainer := &Container{} 67 | jsonFile, _ = os.Open(fmt.Sprintf("%s/%s", allureDir, f.Name())) 68 | bytes, readErr := io.ReadAll(jsonFile) 69 | require.NoError(t, readErr) 70 | unMarshallErr := json.Unmarshal(bytes, emptyContainer) 71 | require.NoError(t, unMarshallErr) 72 | require.Equal(t, container.UUID, emptyContainer.UUID) 73 | 74 | require.NotEmpty(t, emptyContainer.Befores) 75 | require.NotEmpty(t, emptyContainer.Afters) 76 | require.Len(t, emptyContainer.Befores, 1) 77 | require.Len(t, emptyContainer.Afters, 1) 78 | 79 | before := emptyContainer.Befores[0] 80 | after := emptyContainer.Afters[0] 81 | 82 | require.Equal(t, containerBefore, before) 83 | require.Equal(t, containerAfter, after) 84 | } 85 | 86 | func TestMarshallingContainer(t *testing.T) { 87 | container := NewContainer() 88 | b := `grpc_cli call --json_input --json_output myendpoint.com:82 bla.bla/GetBla '{"bla":"blabla"}' -metadata 'x-bla::x-app-bla:bla-qa/bla-tests:x-bla-version::x-nocache:true:x-pf-nocache:true:x-s2s:*****'` 89 | container.Befores = append(container.Befores, &Step{ 90 | Name: "name", 91 | Status: Passed, 92 | Attachments: nil, 93 | Start: time.Now().UnixNano(), 94 | Stop: time.Now().UnixNano(), 95 | Steps: nil, 96 | Parameters: []*Parameter{NewParameter("p", b)}, 97 | }) 98 | 99 | _, err := container.ToJSON() 100 | require.NoError(t, err) 101 | } 102 | -------------------------------------------------------------------------------- /pkg/allure/errors.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // Copied from https://cs.opensource.google/go/go/+/refs/tags/go1.24.3:src/errors/join.go;l=40 8 | // Since this go version does not have errors.Join 9 | // 10 | // TODO: delete this in v2 11 | type joinError struct { 12 | errs []error 13 | } 14 | 15 | func (e *joinError) Error() string { 16 | b := make([]string, 0, len(e.errs)) 17 | 18 | for _, err := range e.errs { 19 | b = append(b, err.Error()) 20 | } 21 | 22 | return strings.Join(b, "\n") 23 | } 24 | 25 | func (e *joinError) Unwrap() []error { 26 | return e.errs 27 | } 28 | -------------------------------------------------------------------------------- /pkg/allure/file_manager.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | type FileManager interface { 9 | CreateFile(name string, content []byte) error 10 | } 11 | 12 | type fileManager struct { 13 | resultsPath string 14 | } 15 | 16 | func NewFileManager() FileManager { 17 | resultsPath := getResultPath() 18 | 19 | fm := &fileManager{resultsPath: resultsPath} 20 | fm.createOutputDir() 21 | 22 | return fm 23 | } 24 | 25 | func (m *fileManager) CreateFile(name string, content []byte) error { 26 | file := filepath.Join(m.resultsPath, name) 27 | 28 | return os.WriteFile(file, content, fileSystemPermissionCode) 29 | } 30 | 31 | func (m *fileManager) createOutputDir() { 32 | isExists, err := exists(m.resultsPath) 33 | if err != nil { 34 | panic(err) 35 | } 36 | 37 | if !isExists { 38 | _ = os.MkdirAll(m.resultsPath, os.ModePerm) 39 | } 40 | } 41 | 42 | func getOutputFolderName() string { 43 | outputFolderName := os.Getenv(outputFolderEnvKey) 44 | if outputFolderName != "" { 45 | return outputFolderName 46 | } 47 | 48 | return "allure-results" 49 | } 50 | 51 | func getResultPath() string { 52 | resultsPathToOutput := os.Getenv(resultsPathEnvKey) 53 | outputFolderName := getOutputFolderName() 54 | 55 | if resultsPathToOutput != "" { 56 | return filepath.Join(resultsPathToOutput, outputFolderName) 57 | } 58 | 59 | return outputFolderName 60 | } 61 | 62 | // exists returns whether the given file or directory exists 63 | func exists(path string) (bool, error) { 64 | _, err := os.Stat(path) 65 | if err == nil { 66 | return true, nil 67 | } 68 | 69 | if os.IsNotExist(err) { 70 | return false, nil 71 | } 72 | 73 | return false, err 74 | } 75 | -------------------------------------------------------------------------------- /pkg/allure/file_manager_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestNewFileManager(t *testing.T) { 13 | fm := NewFileManager() 14 | require.NotNil(t, fm) 15 | } 16 | 17 | func TestCreateOutputDir(t *testing.T) { 18 | fm := &fileManager{allureDir} 19 | fm.createOutputDir() 20 | defer os.RemoveAll(allureDir) 21 | require.DirExists(t, allureDir) 22 | } 23 | 24 | func TestGetOutputFolderName_noEnv(t *testing.T) { 25 | require.Equal(t, "allure-results", getOutputFolderName()) 26 | } 27 | 28 | func TestGetOutputFolderName_Env(t *testing.T) { 29 | os.Setenv(outputFolderEnvKey, "not_allure_results") 30 | defer os.Setenv(outputFolderEnvKey, "") 31 | require.Equal(t, "not_allure_results", getOutputFolderName()) 32 | } 33 | 34 | func TestGetResultPath_noEnv(t *testing.T) { 35 | require.Equal(t, allureDir, getResultPath()) 36 | } 37 | 38 | func TestGetResultPath_Env(t *testing.T) { 39 | os.Setenv(resultsPathEnvKey, "not_allure_results") 40 | defer os.Setenv(resultsPathEnvKey, "") 41 | require.Equal(t, "not_allure_results/allure-results", getResultPath()) 42 | } 43 | 44 | func TestFileManager_CreateFile(t *testing.T) { 45 | fileContent := `SOME TEXT` 46 | fm := NewFileManager() 47 | fm.CreateFile("test.txt", []byte(fileContent)) 48 | require.DirExists(t, allureDir) 49 | defer os.RemoveAll(allureDir) 50 | 51 | files, _ := os.ReadDir(allureDir) 52 | require.Len(t, files, 1) 53 | var file *os.File 54 | defer file.Close() 55 | 56 | f := files[0] 57 | file, _ = os.Open(fmt.Sprintf("%s/%s", allureDir, f.Name())) 58 | bytes, readErr := io.ReadAll(file) 59 | require.NoError(t, readErr) 60 | require.Equal(t, fileContent, string(bytes)) 61 | } 62 | -------------------------------------------------------------------------------- /pkg/allure/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ozontech/allure-go/pkg/allure 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/google/uuid v1.3.0 7 | github.com/pkg/errors v0.9.1 8 | github.com/stretchr/testify v1.7.1 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.0 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /pkg/allure/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 5 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 6 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 7 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 9 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 10 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 11 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 12 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 14 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 15 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 16 | gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= 17 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 18 | -------------------------------------------------------------------------------- /pkg/allure/link.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | // Link is an implementation of the Link entity used by Allure to specify the links needed for test reports. 10 | // Such as: 11 | // - A link to a task in Issue tracker. 12 | // - A link to a test case in the TMS 13 | // - Any other link (e.g. a link to an environment pod) 14 | type Link struct { 15 | Name string `json:"name"` // Link name 16 | Type string `json:"type"` // Link's Type (issue, test case or any other) 17 | URL string `json:"url"` // Link URL 18 | } 19 | 20 | // LinkTypes ... 21 | type LinkTypes string 22 | 23 | // LinkTypes constants 24 | const ( 25 | LINK LinkTypes = "link" 26 | ISSUE LinkTypes = "issue" 27 | TESTCASE LinkTypes = "test_case" 28 | TMS LinkTypes = "tms" 29 | ) 30 | 31 | // NewLink Constructor. Builds and returns a new `allure.Link` object. 32 | func NewLink(name string, linkType LinkTypes, url string) *Link { 33 | return &Link{name, string(linkType), url} 34 | } 35 | 36 | // TestCaseLink returns TESTCASE type link 37 | func TestCaseLink(testCase string) *Link { 38 | linkName := fmt.Sprintf("TestCase[%s]", testCase) 39 | return NewLink(linkName, TESTCASE, fmt.Sprintf(getTestCasePattern(), testCase)) 40 | } 41 | 42 | // IssueLink returns ISSUE type link 43 | func IssueLink(issue string) *Link { 44 | linkName := fmt.Sprintf("Issue[%s]", issue) 45 | return NewLink(linkName, ISSUE, fmt.Sprintf(getIssuePattern(), issue)) 46 | } 47 | 48 | // LinkLink returns LINK type link 49 | func LinkLink(linkname, link string) *Link { 50 | return NewLink(linkname, LINK, link) 51 | } 52 | 53 | // TmsLink returns TMS type link 54 | func TmsLink(testCase string) *Link { 55 | return NewLink(testCase, TMS, fmt.Sprintf(getTmsPattern(), testCase)) 56 | } 57 | 58 | // TmsLinks returns multiple TmsLink type link 59 | func TmsLinks(testCases ...string) []*Link { 60 | result := make([]*Link, 0, len(testCases)) 61 | 62 | for _, testCase := range testCases { 63 | url := fmt.Sprintf(getTmsPattern(), testCase) 64 | 65 | result = append(result, NewLink(testCase, TMS, url)) 66 | } 67 | 68 | return result 69 | } 70 | 71 | func getIssuePattern() string { 72 | return getPattern(issuePatternEnvKey, "%s") 73 | } 74 | 75 | func getTestCasePattern() string { 76 | return getPattern(testCasePatternEnvKey, "%s") 77 | } 78 | 79 | func getTmsPattern() string { 80 | return getPattern(tmsLinkPatternEnvKey, "%s") 81 | } 82 | 83 | func getPattern(envKey string, defaultPattern string) string { 84 | pattern := os.Getenv(envKey) 85 | 86 | if !strings.Contains(pattern, "%s") { 87 | fmt.Printf("Provided pattern (%s) is either missing '%%s' or empty.\n", pattern) 88 | fmt.Printf("Use %s environment variable to supply correct one.\n", envKey) 89 | fmt.Printf("Default pattern will be used (%s).\n", defaultPattern) 90 | 91 | return defaultPattern 92 | } 93 | 94 | return pattern 95 | } 96 | -------------------------------------------------------------------------------- /pkg/allure/link_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestLinkTypes(t *testing.T) { 11 | link := "link" 12 | issue := "issue" 13 | testCase := "test_case" 14 | tms := "tms" 15 | 16 | require.Equal(t, link, string(LINK)) 17 | require.Equal(t, issue, string(ISSUE)) 18 | require.Equal(t, testCase, string(TESTCASE)) 19 | require.Equal(t, tms, string(TMS)) 20 | } 21 | 22 | func TestNewLink(t *testing.T) { 23 | link := NewLink("testLink", LINK, "https://www.testLink.com") 24 | issue := NewLink("issueLink", ISSUE, "https://www.testIssue.com") 25 | testCase := NewLink("testCaseLink", TESTCASE, "https://www.testCase.com") 26 | tms := NewLink("tmsLink", TMS, "https://www.tmslink.com") 27 | 28 | require.NotNil(t, link) 29 | require.Equal(t, "testLink", link.Name) 30 | require.Equal(t, string(LINK), link.Type) 31 | require.Equal(t, "https://www.testLink.com", link.URL) 32 | 33 | require.NotNil(t, issue) 34 | require.Equal(t, "issueLink", issue.Name) 35 | require.Equal(t, string(ISSUE), issue.Type) 36 | require.Equal(t, "https://www.testIssue.com", issue.URL) 37 | 38 | require.NotNil(t, testCase) 39 | require.Equal(t, "testCaseLink", testCase.Name) 40 | require.Equal(t, string(TESTCASE), testCase.Type) 41 | require.Equal(t, "https://www.testCase.com", testCase.URL) 42 | 43 | require.NotNil(t, tms) 44 | require.Equal(t, "tmsLink", tms.Name) 45 | require.Equal(t, string(TMS), tms.Type) 46 | require.Equal(t, "https://www.tmslink.com", tms.URL) 47 | } 48 | 49 | func TestTestCaseLink_noEnv(t *testing.T) { 50 | testCase := TestCaseLink("TEST-112") 51 | require.NotNil(t, testCase) 52 | require.Equal(t, "TestCase[TEST-112]", testCase.Name) 53 | require.Equal(t, string(TESTCASE), testCase.Type) 54 | require.Equal(t, "TEST-112", testCase.URL) 55 | } 56 | 57 | func TestTestCaseLink_Env(t *testing.T) { 58 | os.Setenv(testCasePatternEnvKey, "https://jira-mock.com/%s") 59 | defer os.Setenv(testCasePatternEnvKey, "") 60 | testCase := TestCaseLink("TEST-112") 61 | require.NotNil(t, testCase) 62 | require.Equal(t, "TestCase[TEST-112]", testCase.Name) 63 | require.Equal(t, string(TESTCASE), testCase.Type) 64 | require.Equal(t, "https://jira-mock.com/TEST-112", testCase.URL) 65 | } 66 | 67 | func TestIssueLink_noEnv(t *testing.T) { 68 | testCase := IssueLink("TEST-112") 69 | require.NotNil(t, testCase) 70 | require.Equal(t, "Issue[TEST-112]", testCase.Name) 71 | require.Equal(t, string(ISSUE), testCase.Type) 72 | require.Equal(t, "TEST-112", testCase.URL) 73 | } 74 | 75 | func TestIssueLink_Env(t *testing.T) { 76 | os.Setenv(issuePatternEnvKey, "https://jira-mock.com/%s") 77 | defer os.Setenv(issuePatternEnvKey, "") 78 | testCase := IssueLink("TEST-112") 79 | require.NotNil(t, testCase) 80 | require.Equal(t, "Issue[TEST-112]", testCase.Name) 81 | require.Equal(t, string(ISSUE), testCase.Type) 82 | require.Equal(t, "https://jira-mock.com/TEST-112", testCase.URL) 83 | } 84 | 85 | func TestTmsLink_noEnv(t *testing.T) { 86 | testCase := TmsLink("TMS-112") 87 | require.NotNil(t, testCase) 88 | require.Equal(t, "TMS-112", testCase.Name) 89 | require.Equal(t, string(TMS), testCase.Type) 90 | require.Equal(t, "TMS-112", testCase.URL) 91 | } 92 | 93 | func TestTmsLink_Env(t *testing.T) { 94 | os.Setenv(tmsLinkPatternEnvKey, "https://tms-mock.com/%s") 95 | defer os.Setenv(tmsLinkPatternEnvKey, "") 96 | testCase := TmsLink("TMS-112") 97 | require.NotNil(t, testCase) 98 | require.Equal(t, "TMS-112", testCase.Name) 99 | require.Equal(t, string(TMS), testCase.Type) 100 | require.Equal(t, "https://tms-mock.com/TMS-112", testCase.URL) 101 | } 102 | 103 | func TestTmsLinks_noEnv(t *testing.T) { 104 | testCase := TmsLinks("TMS-110", "TMS-112") 105 | require.NotNil(t, testCase) 106 | require.Len(t, testCase, 2) 107 | require.Equal(t, "TMS-110", testCase[0].Name) 108 | require.Equal(t, "TMS-112", testCase[1].Name) 109 | require.Equal(t, string(TMS), testCase[0].Type) 110 | require.Equal(t, string(TMS), testCase[1].Type) 111 | require.Equal(t, "TMS-110", testCase[0].URL) 112 | require.Equal(t, "TMS-112", testCase[1].URL) 113 | } 114 | 115 | func TestTmsLinks_Env(t *testing.T) { 116 | os.Setenv(tmsLinkPatternEnvKey, "https://tms-mock.com/%s") 117 | defer os.Setenv(tmsLinkPatternEnvKey, "") 118 | testCase := TmsLinks("TEST-110", "TEST-112") 119 | require.NotNil(t, testCase) 120 | require.Len(t, testCase, 2) 121 | require.Equal(t, "TEST-110", testCase[0].Name) 122 | require.Equal(t, "TEST-112", testCase[1].Name) 123 | require.Equal(t, string(TMS), testCase[0].Type) 124 | require.Equal(t, string(TMS), testCase[1].Type) 125 | require.Equal(t, "https://tms-mock.com/TEST-110", testCase[0].URL) 126 | require.Equal(t, "https://tms-mock.com/TEST-112", testCase[1].URL) 127 | } 128 | -------------------------------------------------------------------------------- /pkg/allure/parameter_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestNewParameter(t *testing.T) { 11 | const paramName = "paramName" 12 | paramValue := "paramValue" 13 | param := NewParameter(paramName, paramValue) 14 | require.NotNil(t, param) 15 | require.Equal(t, paramName, param.Name) 16 | require.Equal(t, string(paramValue), param.GetValue()) 17 | } 18 | 19 | func TestNewParameters_even(t *testing.T) { 20 | params := NewParameters("p1", "v1", "p2", "v2", "p3", "v3") 21 | require.NotNil(t, params) 22 | require.Len(t, params, 3) 23 | 24 | require.Equal(t, "p1", params[0].Name) 25 | require.Equal(t, "v1", params[0].GetValue()) 26 | require.Equal(t, "p2", params[1].Name) 27 | require.Equal(t, "v2", params[1].GetValue()) 28 | require.Equal(t, "p3", params[2].Name) 29 | require.Equal(t, "v3", params[2].GetValue()) 30 | } 31 | 32 | func TestNewParameters_odd(t *testing.T) { 33 | params := NewParameters("p1", "v1", "p2", "v2", "p3", 24) 34 | require.NotNil(t, params) 35 | require.Len(t, params, 3) 36 | 37 | require.Equal(t, "p1", params[0].Name) 38 | require.Equal(t, "v1", params[0].GetValue()) 39 | 40 | require.Equal(t, "p2", params[1].Name) 41 | require.Equal(t, "v2", params[1].GetValue()) 42 | 43 | require.Equal(t, "p3", params[2].Name) 44 | require.Equal(t, "24", params[2].GetValue()) 45 | } 46 | 47 | func TestParameterUnmarshal(t *testing.T) { 48 | t.Run("string", func(t *testing.T) { 49 | const data = `{"name": "epic", "value": "\"very epic indeed\""}` 50 | 51 | var param Parameter 52 | 53 | require.NoError(t, json.Unmarshal([]byte(data), ¶m)) 54 | 55 | require.Equal(t, Parameter{ 56 | Name: "epic", 57 | Value: "\"very epic indeed\"", 58 | }, param) 59 | 60 | require.Equal(t, "very epic indeed", param.GetValue()) 61 | }) 62 | 63 | t.Run("int", func(t *testing.T) { 64 | const data = `{"name": "epic", "value": 83294782375982}` 65 | 66 | var param Parameter 67 | 68 | require.NoError(t, json.Unmarshal([]byte(data), ¶m)) 69 | 70 | require.Equal(t, Parameter{ 71 | Name: "epic", 72 | Value: int64(83294782375982), 73 | }, param) 74 | 75 | require.Equal(t, "83294782375982", param.GetValue()) 76 | }) 77 | 78 | t.Run("float", func(t *testing.T) { 79 | const data = `{"name": "epic", "value": 3.14159}` 80 | 81 | var param Parameter 82 | 83 | require.NoError(t, json.Unmarshal([]byte(data), ¶m)) 84 | 85 | require.Equal(t, Parameter{ 86 | Name: "epic", 87 | Value: 3.14159, 88 | }, param) 89 | 90 | require.Equal(t, "3.14159", param.GetValue()) 91 | }) 92 | 93 | t.Run("slice", func(t *testing.T) { 94 | const data = `{"name": "epic", "value": [1, 2, 3]}` 95 | 96 | var param Parameter 97 | 98 | require.NoError(t, json.Unmarshal([]byte(data), ¶m)) 99 | 100 | require.Equal(t, Parameter{ 101 | Name: "epic", 102 | Value: []interface{}{int64(1), int64(2), int64(3)}, 103 | }, param) 104 | 105 | require.Equal(t, "[1 2 3]", param.GetValue()) 106 | }) 107 | 108 | t.Run("map", func(t *testing.T) { 109 | const data = `{"name": "epic", "value": {"a": [1, true, 3.14]}}` 110 | 111 | var param Parameter 112 | 113 | require.NoError(t, json.Unmarshal([]byte(data), ¶m)) 114 | 115 | require.Equal(t, Parameter{ 116 | Name: "epic", 117 | Value: map[string]interface{}{ 118 | "a": []interface{}{int64(1), true, 3.14}, 119 | }, 120 | }, param) 121 | 122 | require.Equal(t, "map[a:[1 true 3.14]]", param.GetValue()) 123 | }) 124 | } 125 | -------------------------------------------------------------------------------- /pkg/allure/status.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | // Status is Step's Status info 4 | type Status string 5 | 6 | // Status constants 7 | const ( 8 | Passed Status = "passed" 9 | Failed Status = "failed" 10 | Skipped Status = "skipped" 11 | Broken Status = "broken" 12 | Unknown Status = "unknown" 13 | ) 14 | 15 | func (s Status) String() string { 16 | return string(s) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/allure/status_detail.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | // StatusDetail ... 4 | type StatusDetail struct { 5 | Message string `json:"message"` // Abridged version of the message 6 | Trace string `json:"trace"` // Full message 7 | } 8 | -------------------------------------------------------------------------------- /pkg/allure/status_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestStatus(t *testing.T) { 10 | require.Equal(t, "passed", string(Passed)) 11 | require.Equal(t, "failed", string(Failed)) 12 | require.Equal(t, "skipped", string(Skipped)) 13 | require.Equal(t, "broken", string(Broken)) 14 | require.Equal(t, "unknown", string(Unknown)) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/allure/time.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import "time" 4 | 5 | // GetNow returns [time.Now] as UNIX milliseconds 6 | func GetNow() int64 { 7 | return time.Now().UnixMilli() 8 | } 9 | -------------------------------------------------------------------------------- /pkg/allure/time_test.go: -------------------------------------------------------------------------------- 1 | package allure 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestGetNow(t *testing.T) { 10 | require.NotZero(t, GetNow()) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/framework/.golangci.yaml: -------------------------------------------------------------------------------- 1 | # More info on config here: https://github.com/golangci/golangci-lint#config-file 2 | run: 3 | deadline: 10s 4 | timeout: 5m 5 | issues-exit-code: 1 6 | tests: true 7 | skip-dirs: 8 | - bin 9 | - vendor 10 | - var 11 | - tmp 12 | skip-files: 13 | - \.pb\.go$ 14 | - \.pb\.goclay\.go$ 15 | - \_test.go$ 16 | 17 | output: 18 | format: colored-line-number 19 | print-issued-lines: true 20 | print-linter-name: true 21 | 22 | linters-settings: 23 | govet: 24 | check-shadowing: true 25 | golint: 26 | min-confidence: 0 27 | dupl: 28 | threshold: 100 29 | goconst: 30 | min-len: 2 31 | min-occurrences: 2 32 | 33 | linters: 34 | disable-all: true 35 | enable: 36 | - golint 37 | - govet 38 | - errcheck 39 | - deadcode 40 | - structcheck 41 | - varcheck 42 | - ineffassign 43 | - typecheck 44 | - dupl 45 | - goconst 46 | - gosec 47 | - goimports 48 | - megacheck 49 | 50 | 51 | issues: 52 | exclude-use-default: false 53 | exclude: 54 | # _ instead of err checks 55 | - G103 56 | - G104 57 | - G306 58 | # md5 using for hash generation, not for security, so ignore this 59 | - G401 60 | - G501 61 | # for "public interface + private struct implementation" cases only! 62 | - exported func * returns unexported type *, which can be annoying to use 63 | # can be removed in the development phase 64 | # - (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form) 65 | # not for the active development - can be removed in the stable phase 66 | - should have a package comment, unless it's in another file for this package 67 | - don't use an underscore in package name 68 | # errcheck: Almost all programs ignore errors on these functions and in most cases it's ok 69 | - Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv|.*Rollback). is not checked 70 | - should check returned error before deferring 71 | - should have comment or be unexported 72 | - a blank import should be only in a main or test package 73 | - Can't process result by diff processor 74 | -------------------------------------------------------------------------------- /pkg/framework/Makefile: -------------------------------------------------------------------------------- 1 | APP?=allure-testify 2 | RELEASE?=0.5.0 3 | GOOS?=darwin 4 | 5 | COMMIT?=$(shell git rev-parse --short HEAD) 6 | BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S') 7 | 8 | export GO111MODULE=on 9 | export GOSUMDB=off 10 | LOCAL_BIN:=$(CURDIR)/bin 11 | 12 | ##################### GOLANG-CI RELATED CHECKS ##################### 13 | # Check global GOLANGCI-LINT 14 | GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint 15 | GOLANGCI_TAG:=1.38.0 16 | 17 | # Check local bin version 18 | ifneq ($(wildcard $(GOLANGCI_BIN)),) 19 | GOLANGCI_BIN_VERSION:=$(shell $(GOLANGCI_BIN) --version) 20 | ifneq ($(GOLANGCI_BIN_VERSION),) 21 | GOLANGCI_BIN_VERSION_SHORT:=$(shell echo "$(GOLANGCI_BIN_VERSION)" | sed -E 's/.* version (.*) built from .* on .*/\1/g') 22 | else 23 | GOLANGCI_BIN_VERSION_SHORT:=0 24 | endif 25 | ifneq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_BIN_VERSION_SHORT)))" 26 | GOLANGCI_BIN:= 27 | endif 28 | endif 29 | 30 | # Check global bin version 31 | ifneq (, $(shell which golangci-lint)) 32 | GOLANGCI_VERSION:=$(shell golangci-lint --version 2> /dev/null ) 33 | ifneq ($(GOLANGCI_VERSION),) 34 | GOLANGCI_VERSION_SHORT:=$(shell echo "$(GOLANGCI_VERSION)"|sed -E 's/.* version (.*) built from .* on .*/\1/g') 35 | else 36 | GOLANGCI_VERSION_SHORT:=0 37 | endif 38 | ifeq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_VERSION_SHORT)))" 39 | GOLANGCI_BIN:=$(shell which golangci-lint) 40 | endif 41 | endif 42 | ##################### GOLANG-CI RELATED CHECKS ##################### 43 | 44 | # run full lint like in pipeline 45 | .PHONY: lint 46 | lint: install-lint 47 | $(GOLANGCI_BIN) run --config=.golangci.yaml ./... 48 | 49 | 50 | .PHONY: install-lint 51 | install-lint: 52 | ifeq ($(wildcard $(GOLANGCI_BIN)),) 53 | $(info #Downloading golangci-lint v$(GOLANGCI_TAG)) 54 | tmp=$$(mktemp -d) && cd $$tmp && pwd && go mod init temp && go get -d github.com/golangci/golangci-lint/cmd/golangci-lint@v$(GOLANGCI_TAG) && \ 55 | go build -ldflags "-X 'main.version=$(GOLANGCI_TAG)' -X 'main.commit=test' -X 'main.date=test'" -o $(LOCAL_BIN)/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint && \ 56 | rm -rf $$tmp 57 | GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint 58 | endif 59 | 60 | .PHONY: test 61 | test: 62 | go test ./... -cover -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/helper/asserts_helper.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import "github.com/ozontech/allure-go/pkg/framework/asserts_wrapper/wrapper" 4 | 5 | // NewAssertsHelper inits new Assert interface 6 | func NewAssertsHelper(t ProviderT) AssertsHelper { 7 | return &a{ 8 | t: t, 9 | asserts: wrapper.NewAsserts(t), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/helper/asserts_helper_test.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/ozontech/allure-go/pkg/allure" 9 | ) 10 | 11 | type tAssertMock struct { 12 | } 13 | 14 | func (p *tAssertMock) Step(step *allure.Step) { 15 | } 16 | 17 | func (p *tAssertMock) Errorf(format string, msgAndArgs ...interface{}) { 18 | } 19 | 20 | func (p *tAssertMock) FailNow() { 21 | } 22 | 23 | func TestNewAssertsHelper(t *testing.T) { 24 | h := NewAssertsHelper(&tAssertMock{}) 25 | require.NotNil(t, h) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/helper/interfaces.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | type ProviderT interface { 11 | Step(step *allure.Step) 12 | Errorf(format string, args ...interface{}) 13 | FailNow() 14 | } 15 | 16 | // AssertsHelper ... 17 | type AssertsHelper interface { 18 | Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 19 | Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 20 | NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 21 | Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 22 | NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 23 | EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 24 | NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) 25 | Error(err error, msgAndArgs ...interface{}) 26 | NoError(err error, msgAndArgs ...interface{}) 27 | EqualError(theError error, errString string, msgAndArgs ...interface{}) 28 | ErrorIs(err error, target error, msgAndArgs ...interface{}) 29 | ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) 30 | NotNil(object interface{}, msgAndArgs ...interface{}) 31 | Nil(object interface{}, msgAndArgs ...interface{}) 32 | Len(object interface{}, length int, msgAndArgs ...interface{}) 33 | NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) 34 | Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) 35 | Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 36 | GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 37 | Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 38 | LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 39 | Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) 40 | Empty(object interface{}, msgAndArgs ...interface{}) 41 | NotEmpty(object interface{}, msgAndArgs ...interface{}) 42 | WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) 43 | JSONEq(expected, actual string, msgAndArgs ...interface{}) 44 | JSONContains(expected, actual string, msgAndArgs ...interface{}) 45 | Subset(list, subset interface{}, msgAndArgs ...interface{}) 46 | NotSubset(list, subset interface{}, msgAndArgs ...interface{}) 47 | IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) 48 | True(value bool, msgAndArgs ...interface{}) 49 | False(value bool, msgAndArgs ...interface{}) 50 | Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) 51 | ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) 52 | DirExists(path string, msgAndArgs ...interface{}) 53 | Condition(condition assert.Comparison, msgAndArgs ...interface{}) 54 | Zero(i interface{}, msgAndArgs ...interface{}) 55 | NotZero(i interface{}, msgAndArgs ...interface{}) 56 | InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) 57 | Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) 58 | } 59 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/helper/require_helper.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/framework/asserts_wrapper/wrapper" 5 | ) 6 | 7 | // NewRequireHelper inits new Require interface 8 | func NewRequireHelper(t ProviderT) AssertsHelper { 9 | return &a{ 10 | t: t, 11 | asserts: wrapper.NewRequire(t), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/helper/require_helper_test.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/ozontech/allure-go/pkg/allure" 9 | ) 10 | 11 | type tRequireMock struct { 12 | } 13 | 14 | func (p *tRequireMock) Step(step *allure.Step) { 15 | } 16 | 17 | func (p *tRequireMock) Errorf(format string, msgAndArgs ...interface{}) { 18 | } 19 | 20 | func (p *tRequireMock) FailNow() { 21 | } 22 | 23 | func TestNewRequireHelper(t *testing.T) { 24 | h := NewAssertsHelper(&tRequireMock{}) 25 | require.NotNil(t, h) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/wrapper/helper.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | ) 8 | 9 | type Provider interface { 10 | Step(step *allure.Step) 11 | } 12 | 13 | type assertHelper struct { 14 | prefix string 15 | } 16 | 17 | func (h *assertHelper) getStepName(assertName string, msgAndArgs ...interface{}) string { 18 | if len(msgAndArgs) == 0 { 19 | return fmt.Sprintf("%s: %s", h.prefix, assertName) 20 | } 21 | return fmt.Sprintf("%s: %s", h.prefix, messageFromMsgAndArgs(msgAndArgs...)) 22 | } 23 | 24 | func (h *assertHelper) WithNewStep(t TestingT, provider Provider, assertName string, assert func(t TestingT) bool, params []*allure.Parameter, msgAndArgs ...interface{}) bool { 25 | var ( 26 | step = allure.NewSimpleStep(h.getStepName(assertName, msgAndArgs...), params...) 27 | result = assert(t) 28 | ) 29 | 30 | provider.Step(step) 31 | if !result { 32 | step.Failed() 33 | } 34 | 35 | return result 36 | } 37 | 38 | func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { 39 | if len(msgAndArgs) == 0 || msgAndArgs == nil { 40 | return "" 41 | } 42 | if len(msgAndArgs) == 1 { 43 | msg := msgAndArgs[0] 44 | if msgAsStr, ok := msg.(string); ok { 45 | return msgAsStr 46 | } 47 | return fmt.Sprintf("%+v", msg) 48 | } 49 | if len(msgAndArgs) > 1 { 50 | return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) 51 | } 52 | return "" 53 | } 54 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/wrapper/helper_test.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/ozontech/allure-go/pkg/allure" 9 | ) 10 | 11 | type tMock struct { 12 | steps []*allure.Step 13 | errorF bool 14 | errorFString string 15 | failNow bool 16 | } 17 | 18 | func newTMock() *tMock { 19 | return &tMock{steps: make([]*allure.Step, 0)} 20 | } 21 | 22 | func (p *tMock) Step(step *allure.Step) { 23 | p.steps = append(p.steps, step) 24 | } 25 | 26 | func (p *tMock) Errorf(format string, msgAndArgs ...interface{}) { 27 | p.errorFString = format 28 | p.errorF = true 29 | } 30 | 31 | func (p *tMock) FailNow() { 32 | p.failNow = true 33 | } 34 | 35 | func TestAssertHelper_getStepName(t *testing.T) { 36 | a := &assertHelper{prefix: "ASSERT"} 37 | require.Equal(t, "ASSERT: Test", a.getStepName("Test")) 38 | 39 | b := &assertHelper{prefix: "REQUIRE"} 40 | require.Equal(t, "REQUIRE: Test", b.getStepName("Test")) 41 | } 42 | 43 | func TestAssertHelper_withNewStep_requireFalse(t *testing.T) { 44 | a := &assertHelper{prefix: "ASSERT"} 45 | mock := newTMock() 46 | param := allure.NewParameters("pName", "pValue") 47 | result := a.WithNewStep(mock, mock, "Test", func(t TestingT) bool { return true }, param) 48 | require.True(t, result) 49 | require.NotEmpty(t, mock.steps) 50 | require.Len(t, mock.steps, 1) 51 | require.Equal(t, "ASSERT: Test", mock.steps[0].Name) 52 | require.Equal(t, allure.Passed, mock.steps[0].Status) 53 | require.NotEmpty(t, mock.steps[0].Parameters) 54 | require.Len(t, mock.steps[0].Parameters, 1) 55 | require.Equal(t, param[0].Name, mock.steps[0].Parameters[0].Name) 56 | require.Equal(t, param[0].GetValue(), mock.steps[0].Parameters[0].GetValue()) 57 | 58 | mock2 := newTMock() 59 | param2 := allure.NewParameter("pName", "pValue") 60 | result2 := a.WithNewStep(mock2, mock2, "Test", func(t TestingT) bool { return false }, param) 61 | require.False(t, result2) 62 | require.NotEmpty(t, mock2.steps) 63 | require.Len(t, mock2.steps, 1) 64 | require.Equal(t, "ASSERT: Test", mock2.steps[0].Name) 65 | require.Equal(t, allure.Failed, mock2.steps[0].Status) 66 | require.NotEmpty(t, mock2.steps[0].Parameters) 67 | require.Len(t, mock2.steps[0].Parameters, 1) 68 | require.Equal(t, param2.Name, mock2.steps[0].Parameters[0].Name) 69 | require.Equal(t, param2.GetValue(), mock2.steps[0].Parameters[0].GetValue()) 70 | } 71 | 72 | func TestAssertHelper_withNewStep_requireTrue(t *testing.T) { 73 | a := &assertHelper{prefix: "REQUIRE"} 74 | mock := newTMock() 75 | param := allure.NewParameters("pName", "pValue") 76 | result := a.WithNewStep(mock, mock, "Test", func(t TestingT) bool { return true }, param) 77 | require.True(t, result) 78 | require.NotEmpty(t, mock.steps) 79 | require.Len(t, mock.steps, 1) 80 | require.Equal(t, "REQUIRE: Test", mock.steps[0].Name) 81 | require.Equal(t, allure.Passed, mock.steps[0].Status) 82 | require.NotEmpty(t, mock.steps[0].Parameters) 83 | require.Len(t, mock.steps[0].Parameters, 1) 84 | require.Equal(t, param[0].Name, mock.steps[0].Parameters[0].Name) 85 | require.Equal(t, param[0].GetValue(), mock.steps[0].Parameters[0].GetValue()) 86 | 87 | mock2 := newTMock() 88 | param2 := allure.NewParameter("pName", "pValue") 89 | result2 := a.WithNewStep(mock2, mock2, "Test", func(t TestingT) bool { return false }, param) 90 | require.False(t, result2) 91 | require.NotEmpty(t, mock2.steps) 92 | require.Len(t, mock2.steps, 1) 93 | require.Equal(t, "REQUIRE: Test", mock2.steps[0].Name) 94 | require.Equal(t, allure.Failed, mock2.steps[0].Status) 95 | require.NotEmpty(t, mock2.steps[0].Parameters) 96 | require.Len(t, mock2.steps[0].Parameters, 1) 97 | require.Equal(t, param2.Name, mock2.steps[0].Parameters[0].Name) 98 | require.Equal(t, param2.GetValue(), mock2.steps[0].Parameters[0].GetValue()) 99 | } 100 | -------------------------------------------------------------------------------- /pkg/framework/asserts_wrapper/wrapper/interfaces.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | // AssertsWrapper ... 10 | type AssertsWrapper interface { 11 | Exactly(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 12 | Same(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 13 | NotSame(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 14 | Equal(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 15 | NotEqual(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 16 | EqualValues(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 17 | NotEqualValues(provider Provider, expected interface{}, actual interface{}, msgAndArgs ...interface{}) 18 | Error(provider Provider, err error, msgAndArgs ...interface{}) 19 | NoError(provider Provider, err error, msgAndArgs ...interface{}) 20 | EqualError(provider Provider, theError error, errString string, msgAndArgs ...interface{}) 21 | ErrorIs(provider Provider, err error, target error, msgAndArgs ...interface{}) 22 | ErrorAs(provider Provider, err error, target interface{}, msgAndArgs ...interface{}) 23 | NotNil(provider Provider, object interface{}, msgAndArgs ...interface{}) 24 | Nil(provider Provider, object interface{}, msgAndArgs ...interface{}) 25 | Len(provider Provider, object interface{}, length int, msgAndArgs ...interface{}) 26 | NotContains(provider Provider, s interface{}, contains interface{}, msgAndArgs ...interface{}) 27 | Contains(provider Provider, s interface{}, contains interface{}, msgAndArgs ...interface{}) 28 | Greater(provider Provider, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 29 | GreaterOrEqual(provider Provider, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 30 | Less(provider Provider, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 31 | LessOrEqual(provider Provider, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) 32 | Implements(provider Provider, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) 33 | Empty(provider Provider, object interface{}, msgAndArgs ...interface{}) 34 | NotEmpty(provider Provider, object interface{}, msgAndArgs ...interface{}) 35 | WithinDuration(provider Provider, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) 36 | JSONEq(provider Provider, expected, actual string, msgAndArgs ...interface{}) 37 | JSONContains(provider Provider, expected, actual string, msgAndArgs ...interface{}) 38 | Subset(provider Provider, list, subset interface{}, msgAndArgs ...interface{}) 39 | NotSubset(provider Provider, list, subset interface{}, msgAndArgs ...interface{}) 40 | IsType(provider Provider, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) 41 | True(provider Provider, value bool, msgAndArgs ...interface{}) 42 | False(provider Provider, value bool, msgAndArgs ...interface{}) 43 | Regexp(provider Provider, rx interface{}, str interface{}, msgAndArgs ...interface{}) 44 | ElementsMatch(provider Provider, listA interface{}, listB interface{}, msgAndArgs ...interface{}) 45 | DirExists(provider Provider, path string, msgAndArgs ...interface{}) 46 | Condition(provider Provider, condition assert.Comparison, msgAndArgs ...interface{}) 47 | Zero(provider Provider, i interface{}, msgAndArgs ...interface{}) 48 | NotZero(provider Provider, i interface{}, msgAndArgs ...interface{}) 49 | InDelta(provider Provider, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) 50 | Eventually(provider Provider, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) 51 | } 52 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/adapter/suite_adapter.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | "github.com/ozontech/allure-go/pkg/framework/provider" 6 | ) 7 | 8 | // SuiteAdapter describes behavior of the suite 9 | // such as before/after all functions, package name, runner name, suite path and suite name 10 | type SuiteAdapter struct { 11 | packageName string 12 | runner string 13 | fullSuiteName string 14 | suiteName string 15 | parentSuite string 16 | 17 | beforeAll func(provider.T) 18 | afterAll func(provider.T) 19 | 20 | container *allure.Container 21 | } 22 | 23 | // NewSuiteMeta returns SuiteAdapter pointer 24 | func NewSuiteMeta(packageName, runner, fullSuiteName, suiteName string) *SuiteAdapter { 25 | return &SuiteAdapter{ 26 | packageName: packageName, 27 | runner: runner, 28 | fullSuiteName: fullSuiteName, 29 | suiteName: suiteName, 30 | container: allure.NewContainer(), 31 | } 32 | } 33 | 34 | func NewSuiteMetaWithParent(packageName, runner, fullSuiteName, suiteName, parentSuite string) *SuiteAdapter { 35 | return &SuiteAdapter{ 36 | packageName: packageName, 37 | runner: runner, 38 | fullSuiteName: fullSuiteName, 39 | suiteName: suiteName, 40 | parentSuite: parentSuite, 41 | container: allure.NewContainer(), 42 | } 43 | } 44 | 45 | // GetPackageName returns package name 46 | func (ctx *SuiteAdapter) GetPackageName() string { 47 | return ctx.packageName 48 | } 49 | 50 | // GetRunner returns runner name 51 | func (ctx *SuiteAdapter) GetRunner() string { 52 | return ctx.runner 53 | } 54 | 55 | // GetSuiteName returns suite name 56 | func (ctx *SuiteAdapter) GetSuiteName() string { 57 | return ctx.suiteName 58 | } 59 | 60 | // GetParentSuite returns suite name 61 | func (ctx *SuiteAdapter) GetParentSuite() string { 62 | return ctx.parentSuite 63 | } 64 | 65 | // GetSuiteFullName returns full name 66 | func (ctx *SuiteAdapter) GetSuiteFullName() string { 67 | return ctx.fullSuiteName 68 | } 69 | 70 | // GetContainer returns container 71 | func (ctx *SuiteAdapter) GetContainer() *allure.Container { 72 | return ctx.container 73 | } 74 | 75 | // SetBeforeAll sets before all func 76 | func (ctx *SuiteAdapter) SetBeforeAll(hook func(provider.T)) { 77 | ctx.beforeAll = hook 78 | } 79 | 80 | // SetAfterAll sets after all func 81 | func (ctx *SuiteAdapter) SetAfterAll(hook func(provider.T)) { 82 | ctx.afterAll = hook 83 | } 84 | 85 | // GetBeforeAll returns before all func 86 | func (ctx *SuiteAdapter) GetBeforeAll() func(provider.T) { 87 | return ctx.beforeAll 88 | } 89 | 90 | // GetAfterAll returns after all func 91 | func (ctx *SuiteAdapter) GetAfterAll() func(provider.T) { 92 | return ctx.afterAll 93 | } 94 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/adapter/suite_adapter_test.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/ozontech/allure-go/pkg/allure" 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | ) 11 | 12 | func TestNewSuiteMeta(t *testing.T) { 13 | adapter := NewSuiteMeta("packageName", "runner", "fullName", "suiteName") 14 | require.NotNil(t, adapter) 15 | require.Equal(t, "packageName", adapter.GetPackageName()) 16 | require.Equal(t, "suiteName", adapter.GetSuiteName()) 17 | require.Equal(t, "runner", adapter.GetRunner()) 18 | require.Equal(t, "fullName", adapter.GetSuiteFullName()) 19 | require.NotNil(t, adapter.GetContainer()) 20 | } 21 | 22 | func TestSuiteAdapter_GetPackageName(t *testing.T) { 23 | adapter := &SuiteAdapter{packageName: "packageName"} 24 | require.Equal(t, "packageName", adapter.GetPackageName()) 25 | } 26 | 27 | func TestSuiteAdapter_GetSuiteName(t *testing.T) { 28 | adapter := &SuiteAdapter{suiteName: "suiteName"} 29 | require.Equal(t, "suiteName", adapter.GetSuiteName()) 30 | } 31 | 32 | func TestSuiteAdapter_GetRunner(t *testing.T) { 33 | adapter := &SuiteAdapter{runner: "runner"} 34 | require.Equal(t, "runner", adapter.GetRunner()) 35 | } 36 | 37 | func TestSuiteAdapter_GetSuiteFullName(t *testing.T) { 38 | adapter := &SuiteAdapter{fullSuiteName: "fullName"} 39 | require.Equal(t, "fullName", adapter.GetSuiteFullName()) 40 | } 41 | 42 | func TestSuiteAdapter_GetBeforeAll(t *testing.T) { 43 | adapter := &SuiteAdapter{beforeAll: func(t provider.T) {}} 44 | require.NotNil(t, adapter.GetBeforeAll()) 45 | } 46 | 47 | func TestSuiteAdapter_GetAfterAll(t *testing.T) { 48 | adapter := &SuiteAdapter{afterAll: func(t provider.T) {}} 49 | require.NotNil(t, adapter.GetAfterAll()) 50 | } 51 | 52 | func TestSuiteAdapter_SetBeforeAll(t *testing.T) { 53 | adapter := &SuiteAdapter{} 54 | adapter.SetBeforeAll(func(t provider.T) {}) 55 | require.NotNil(t, adapter.GetBeforeAll()) 56 | } 57 | 58 | func TestSuiteAdapter_SetAfterAll(t *testing.T) { 59 | adapter := &SuiteAdapter{} 60 | adapter.SetAfterAll(func(t provider.T) {}) 61 | require.NotNil(t, adapter.GetAfterAll()) 62 | } 63 | 64 | func TestSuiteAdapter_GetContainer(t *testing.T) { 65 | c := allure.NewContainer() 66 | adapter := &SuiteAdapter{container: c} 67 | require.NotNil(t, adapter.GetContainer()) 68 | require.Equal(t, c, adapter.GetContainer()) 69 | } 70 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/adapter/test_adapter.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "os" 5 | "runtime" 6 | "strings" 7 | 8 | "github.com/ozontech/allure-go/pkg/allure" 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | ) 11 | 12 | // TestAdapter describes behavior of the test 13 | // such as before/after each function, container, test result object, and container object 14 | type TestAdapter struct { 15 | beforeEach func(provider.T) 16 | afterEach func(provider.T) 17 | 18 | result *allure.Result 19 | container *allure.Container 20 | } 21 | 22 | // NewTestMeta returns pointer to instance of TestAdapter 23 | func NewTestMeta(suiteFullName, suiteName, testName, packageName string, tags ...string) *TestAdapter { 24 | // TODO: handle error 25 | host, _ := os.Hostname() 26 | fullName := suiteFullName 27 | 28 | // ex: suiteFullName=TestRunner/My_Test, testName=My Test => after split and replace: My_test == My_test 29 | // why? to avoid TestRunner/My_Test/My Test 30 | if callers := strings.Split(suiteFullName, "/"); callers[len(callers)-1] != strings.ReplaceAll(testName, " ", "_") { 31 | fullName = fullName + "/" + testName 32 | } 33 | 34 | newTags := make([]*allure.Label, 0, len(tags)) 35 | for _, tag := range tags { 36 | newTags = append(newTags, allure.NewLabel(allure.Tag, tag)) 37 | } 38 | 39 | result := allure.NewResult(testName, fullName). 40 | WithFrameWork(allure.DefaultVersion). 41 | WithHost(host). 42 | WithThread(fullName). 43 | WithLanguage(runtime.Version()). 44 | WithLaunchTags(). 45 | WithSuite(suiteName). 46 | WithPackage(packageName). 47 | WithLabels(newTags...) 48 | 49 | container := allure.NewContainer() 50 | container.AddChild(result.UUID) 51 | 52 | return &TestAdapter{result: result, container: container} 53 | } 54 | 55 | // GetResult returns allure.Result pointer 56 | func (ctx *TestAdapter) GetResult() *allure.Result { 57 | return ctx.result 58 | } 59 | 60 | // SetResult sets allure.Result 61 | func (ctx *TestAdapter) SetResult(result *allure.Result) { 62 | ctx.result = result 63 | } 64 | 65 | // GetContainer returns allure.Container pointer 66 | func (ctx *TestAdapter) GetContainer() *allure.Container { 67 | return ctx.container 68 | } 69 | 70 | // SetBeforeEach sets before each function 71 | func (ctx *TestAdapter) SetBeforeEach(hook func(provider.T)) { 72 | ctx.beforeEach = hook 73 | } 74 | 75 | // GetBeforeEach returns before each function 76 | func (ctx *TestAdapter) GetBeforeEach() func(provider.T) { 77 | return ctx.beforeEach 78 | } 79 | 80 | // SetAfterEach sets after each function 81 | func (ctx *TestAdapter) SetAfterEach(hook func(provider.T)) { 82 | ctx.afterEach = hook 83 | } 84 | 85 | // GetAfterEach returns after each function 86 | func (ctx *TestAdapter) GetAfterEach() func(provider.T) { 87 | return ctx.afterEach 88 | } 89 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/adapter/test_adapter_test.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | 9 | "github.com/ozontech/allure-go/pkg/allure" 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | ) 12 | 13 | func TestNewTestMeta(t *testing.T) { 14 | host, _ := os.Hostname() 15 | 16 | adapter := NewTestMeta("fullName", "suiteName", "testName", "packageName", "tag1", "tag2") 17 | require.Equal(t, "testName", adapter.GetResult().Name) 18 | require.Equal(t, "fullName/testName", adapter.GetResult().FullName) 19 | 20 | require.Len(t, adapter.GetResult().GetLabels(allure.Host), 1) 21 | require.Equal(t, adapter.GetResult().GetLabels(allure.Host)[0].GetValue(), host) 22 | 23 | require.Len(t, adapter.GetResult().GetLabels(allure.Framework), 1) 24 | require.Equal(t, adapter.GetResult().GetLabels(allure.Framework)[0].GetValue(), allure.DefaultVersion) 25 | 26 | require.Len(t, adapter.GetResult().GetLabels(allure.Thread), 1) 27 | require.Equal(t, "fullName/testName", adapter.GetResult().GetLabels(allure.Thread)[0].GetValue()) 28 | 29 | require.Len(t, adapter.GetResult().GetLabels(allure.Suite), 1) 30 | require.Equal(t, "suiteName", adapter.GetResult().GetLabels(allure.Suite)[0].GetValue()) 31 | 32 | require.Len(t, adapter.GetResult().GetLabels(allure.Package), 1) 33 | require.Equal(t, "packageName", adapter.GetResult().GetLabels(allure.Package)[0].GetValue()) 34 | 35 | require.Len(t, adapter.GetResult().GetLabels(allure.Tag), 2) 36 | require.Equal(t, "tag1", adapter.GetResult().GetLabels(allure.Tag)[0].GetValue()) 37 | require.Equal(t, "tag2", adapter.GetResult().GetLabels(allure.Tag)[1].GetValue()) 38 | 39 | } 40 | 41 | func TestTestAdapter_GetResult(t *testing.T) { 42 | test := &allure.Result{} 43 | adapter := TestAdapter{result: test} 44 | require.Equal(t, test, adapter.GetResult()) 45 | } 46 | 47 | func TestTestAdapter_SetResult(t *testing.T) { 48 | test := &allure.Result{} 49 | adapter := TestAdapter{} 50 | adapter.SetResult(test) 51 | require.Equal(t, test, adapter.GetResult()) 52 | } 53 | 54 | func TestTestAdapter_SetBeforeEach(t *testing.T) { 55 | adapter := TestAdapter{} 56 | adapter.SetBeforeEach(func(t provider.T) {}) 57 | require.NotNil(t, adapter.GetBeforeEach()) 58 | } 59 | 60 | func TestTestAdapter_SetAfterEach(t *testing.T) { 61 | adapter := TestAdapter{} 62 | adapter.SetAfterEach(func(t provider.T) {}) 63 | require.NotNil(t, adapter.GetAfterEach()) 64 | } 65 | 66 | func TestTestAdapter_GetBeforeEach(t *testing.T) { 67 | adapter := TestAdapter{beforeEach: func(t provider.T) {}} 68 | require.NotNil(t, adapter.GetBeforeEach()) 69 | } 70 | 71 | func TestTestAdapter_GetAfterEach(t *testing.T) { 72 | adapter := TestAdapter{afterEach: func(t provider.T) {}} 73 | require.NotNil(t, adapter.GetAfterEach()) 74 | } 75 | 76 | func TestTestAdapter_GetContainer(t *testing.T) { 77 | container := allure.NewContainer() 78 | adapter := TestAdapter{container: container} 79 | require.Equal(t, container, adapter.container) 80 | } 81 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/ctx/hooks.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 8 | "github.com/ozontech/allure-go/pkg/framework/provider" 9 | ) 10 | 11 | type hooksCtx struct { 12 | name string 13 | container *allure.Container 14 | } 15 | 16 | // NewAfterAllCtx returns after all context 17 | func NewAfterAllCtx(container *allure.Container) provider.ExecutionContext { 18 | return &hooksCtx{container: container, name: constants.AfterAllContextName} 19 | } 20 | 21 | // NewAfterEachCtx returns after each context 22 | func NewAfterEachCtx(container *allure.Container) provider.ExecutionContext { 23 | return &hooksCtx{container: container, name: constants.AfterEachContextName} 24 | } 25 | 26 | // NewBeforeAllCtx returns before all context 27 | func NewBeforeAllCtx(container *allure.Container) provider.ExecutionContext { 28 | return &hooksCtx{container: container, name: constants.BeforeAllContextName} 29 | } 30 | 31 | // NewBeforeEachCtx returns before each context 32 | func NewBeforeEachCtx(result *allure.Container) provider.ExecutionContext { 33 | return &hooksCtx{container: result, name: constants.BeforeEachContextName} 34 | } 35 | 36 | // AddStep adds step to current execution container 37 | func (ctx *hooksCtx) AddStep(newStep *allure.Step) { 38 | switch ctx.name { 39 | case constants.BeforeAllContextName, constants.BeforeEachContextName: 40 | ctx.container.Befores = append(ctx.container.Befores, newStep) 41 | 42 | case constants.AfterAllContextName, constants.AfterEachContextName: 43 | ctx.container.Afters = append(ctx.container.Afters, newStep) 44 | } 45 | } 46 | 47 | // GetName returns context name 48 | func (ctx *hooksCtx) GetName() string { 49 | return ctx.name 50 | } 51 | 52 | // AddAttachments adds attachment to the execution context 53 | func (ctx *hooksCtx) AddAttachments(attachments ...*allure.Attachment) { 54 | if len(attachments) == 0 { 55 | return 56 | } 57 | 58 | first := attachments[0] 59 | 60 | newStep := allure.NewSimpleStep( 61 | fmt.Sprintf("Attachment %s", first.Name), 62 | allure.NewParameter("name", first.Name), 63 | allure.NewParameter("type", string(first.Type)), 64 | allure.NewParameter("source", first.Source), 65 | ).WithAttachments(attachments...) 66 | 67 | ctx.AddStep(newStep) 68 | } 69 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/ctx/hooks_test.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/ozontech/allure-go/pkg/allure" 9 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 10 | ) 11 | 12 | func TestNewAfterAllCtx(t *testing.T) { 13 | ctx := NewAfterAllCtx(allure.NewContainer()) 14 | require.NotNil(t, ctx) 15 | } 16 | 17 | func TestNewAfterEachCtx(t *testing.T) { 18 | ctx := NewAfterEachCtx(allure.NewContainer()) 19 | require.NotNil(t, ctx) 20 | } 21 | 22 | func TestNewBeforeEachCtx(t *testing.T) { 23 | ctx := NewBeforeEachCtx(allure.NewContainer()) 24 | require.NotNil(t, ctx) 25 | } 26 | 27 | func TestNewBeforeAllCtx(t *testing.T) { 28 | ctx := NewBeforeAllCtx(allure.NewContainer()) 29 | require.NotNil(t, ctx) 30 | } 31 | 32 | func TestHooksCtx_GetName(t *testing.T) { 33 | th := hooksCtx{name: "test"} 34 | require.Equal(t, "test", th.GetName()) 35 | } 36 | 37 | func TestHooksCtx_AddStep(t *testing.T) { 38 | testStep := allure.NewSimpleStep("test") 39 | beforeEach := hooksCtx{name: constants.BeforeEachContextName, container: &allure.Container{}} 40 | beforeEach.AddStep(testStep) 41 | require.NotEmpty(t, beforeEach.container.Befores) 42 | require.Len(t, beforeEach.container.Befores, 1) 43 | require.Equal(t, testStep, beforeEach.container.Befores[0]) 44 | 45 | beforeAll := hooksCtx{name: constants.BeforeAllContextName, container: &allure.Container{}} 46 | beforeAll.AddStep(testStep) 47 | require.NotEmpty(t, beforeAll.container.Befores) 48 | require.Len(t, beforeAll.container.Befores, 1) 49 | require.Equal(t, testStep, beforeAll.container.Befores[0]) 50 | 51 | afterEach := hooksCtx{name: constants.AfterEachContextName, container: &allure.Container{}} 52 | afterEach.AddStep(testStep) 53 | require.NotEmpty(t, afterEach.container.Afters) 54 | require.Len(t, afterEach.container.Afters, 1) 55 | require.Equal(t, testStep, afterEach.container.Afters[0]) 56 | 57 | afterAll := hooksCtx{name: constants.AfterAllContextName, container: &allure.Container{}} 58 | afterAll.AddStep(testStep) 59 | require.NotEmpty(t, afterAll.container.Afters) 60 | require.Len(t, afterAll.container.Afters, 1) 61 | require.Equal(t, testStep, afterAll.container.Afters[0]) 62 | } 63 | 64 | func TestHooksCtx_AddAttachment(t *testing.T) { 65 | attach := allure.NewAttachment("testAttach", allure.Text, []byte("test")) 66 | beforeAll := hooksCtx{name: constants.BeforeAllContextName, container: &allure.Container{}} 67 | beforeAll.AddAttachments(attach) 68 | require.NotEmpty(t, beforeAll.container.Befores) 69 | require.Len(t, beforeAll.container.Befores, 1) 70 | require.NotEmpty(t, beforeAll.container.Befores[0].Attachments) 71 | require.Len(t, beforeAll.container.Befores[0].Attachments, 1) 72 | require.Equal(t, attach, beforeAll.container.Befores[0].Attachments[0]) 73 | 74 | beforeEach := hooksCtx{name: constants.BeforeEachContextName, container: &allure.Container{}} 75 | beforeEach.AddAttachments(attach) 76 | require.NotEmpty(t, beforeEach.container.Befores) 77 | require.Len(t, beforeEach.container.Befores, 1) 78 | require.NotEmpty(t, beforeEach.container.Befores[0].Attachments) 79 | require.Len(t, beforeEach.container.Befores[0].Attachments, 1) 80 | require.Equal(t, attach, beforeEach.container.Befores[0].Attachments[0]) 81 | 82 | afterAll := hooksCtx{name: constants.AfterAllContextName, container: &allure.Container{}} 83 | afterAll.AddAttachments(attach) 84 | require.NotEmpty(t, afterAll.container.Afters) 85 | require.Len(t, afterAll.container.Afters, 1) 86 | require.NotEmpty(t, afterAll.container.Afters[0].Attachments) 87 | require.Len(t, afterAll.container.Afters[0].Attachments, 1) 88 | require.Equal(t, attach, afterAll.container.Afters[0].Attachments[0]) 89 | 90 | afterEach := hooksCtx{name: constants.AfterEachContextName, container: &allure.Container{}} 91 | afterEach.AddAttachments(attach) 92 | require.NotEmpty(t, afterEach.container.Afters) 93 | require.Len(t, afterEach.container.Afters, 1) 94 | require.NotEmpty(t, afterEach.container.Afters[0].Attachments) 95 | require.Len(t, afterEach.container.Afters[0].Attachments, 1) 96 | require.Equal(t, attach, afterEach.container.Afters[0].Attachments[0]) 97 | } 98 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/ctx/test_ctx.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 6 | "github.com/ozontech/allure-go/pkg/framework/provider" 7 | ) 8 | 9 | type testCtx struct { 10 | name string 11 | 12 | result *allure.Result 13 | } 14 | 15 | func NewTestCtx(result *allure.Result) provider.ExecutionContext { 16 | return &testCtx{result: result, name: constants.TestContextName} 17 | } 18 | 19 | func (ctx *testCtx) AddStep(newStep *allure.Step) { 20 | ctx.result.Steps = append(ctx.result.Steps, newStep) 21 | } 22 | 23 | func (ctx *testCtx) GetName() string { 24 | return ctx.name 25 | } 26 | 27 | func (ctx *testCtx) AddAttachments(attachments ...*allure.Attachment) { 28 | ctx.result.Attachments = append(ctx.result.Attachments, attachments...) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/ctx/test_ctx_test.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestNewTestCtx(t *testing.T) { 12 | ctx := NewTestCtx(&allure.Result{}) 13 | require.NotNil(t, ctx) 14 | } 15 | 16 | func TestTestCtx_GetName(t *testing.T) { 17 | th := testCtx{name: "test"} 18 | require.Equal(t, "test", th.GetName()) 19 | } 20 | 21 | func TestTestCtx_AddStep(t *testing.T) { 22 | testStep := allure.NewSimpleStep("test") 23 | test := testCtx{name: constants.TestContextName, result: &allure.Result{}} 24 | test.AddStep(testStep) 25 | require.NotEmpty(t, test.result.Steps) 26 | require.Len(t, test.result.Steps, 1) 27 | require.Equal(t, testStep, test.result.Steps[0]) 28 | } 29 | 30 | func TestTestCtx_AddAttachment(t *testing.T) { 31 | attach := allure.NewAttachment("testAttach", allure.Text, []byte("test")) 32 | test := testCtx{name: constants.TestContextName, result: &allure.Result{}} 33 | test.AddAttachments(attach) 34 | require.NotEmpty(t, test.result.Attachments) 35 | require.Len(t, test.result.Attachments, 1) 36 | require.Equal(t, attach, test.result.Attachments[0]) 37 | } 38 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/attachment.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import "github.com/ozontech/allure-go/pkg/allure" 4 | 5 | // WithAttachments adds attachment to report in case of current execution context 6 | func (a *allureManager) WithAttachments(attachments ...*allure.Attachment) { 7 | a.ExecutionContext().AddAttachments(attachments...) 8 | } 9 | 10 | // WithNewAttachment creates and adds attachment to report in case of current execution context 11 | func (a *allureManager) WithNewAttachment(name string, mimeType allure.MimeType, content []byte) { 12 | a.ExecutionContext().AddAttachments(allure.NewAttachment(name, mimeType, content)) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/attachment_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | type execMockAttach struct { 12 | name string 13 | steps []*allure.Step 14 | attach []*allure.Attachment 15 | } 16 | 17 | func newExecMockAttach(name string) *execMockAttach { 18 | return &execMockAttach{ 19 | name: name, 20 | steps: make([]*allure.Step, 0), 21 | attach: make([]*allure.Attachment, 0), 22 | } 23 | } 24 | 25 | func (m *execMockAttach) AddStep(step *allure.Step) { 26 | m.steps = append(m.steps, step) 27 | } 28 | 29 | func (m *execMockAttach) AddAttachments(attachments ...*allure.Attachment) { 30 | m.attach = append(m.attach, attachments...) 31 | } 32 | 33 | func (m *execMockAttach) GetName() string { 34 | return m.name 35 | } 36 | 37 | func TestAllureManager_Attachment(t *testing.T) { 38 | mock := newExecMockAttach(constants.TestContextName) 39 | attach := allure.NewAttachment("testAttach", allure.Text, []byte("test")) 40 | manager := allureManager{executionContext: mock} 41 | 42 | manager.WithAttachments(attach) 43 | require.NotEmpty(t, mock.attach) 44 | require.Len(t, mock.attach, 1) 45 | require.Equal(t, mock.attach[0], attach) 46 | } 47 | 48 | func TestAllureManager_NewAttachment(t *testing.T) { 49 | mock := newExecMockAttach(constants.TestContextName) 50 | manager := allureManager{executionContext: mock} 51 | manager.WithNewAttachment("testAttach", allure.Text, []byte("test")) 52 | require.NotEmpty(t, mock.attach) 53 | require.Len(t, mock.attach, 1) 54 | require.Equal(t, "testAttach", mock.attach[0].Name) 55 | require.Equal(t, allure.Text, mock.attach[0].Type) 56 | require.Equal(t, []byte("test"), mock.attach[0].GetContent()) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/description.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | ) 8 | 9 | // Title changes default test name to title(using fmt.Sprint) 10 | func (a *allureManager) Title(args ...interface{}) { 11 | a.withResult(func(r *allure.Result) { 12 | r.Name = fmt.Sprint(args...) 13 | }) 14 | } 15 | 16 | // Titlef changes default test name to title(using fmt.Sprintf) 17 | func (a *allureManager) Titlef(format string, args ...interface{}) { 18 | a.withResult(func(r *allure.Result) { 19 | r.Name = fmt.Sprintf(format, args...) 20 | }) 21 | } 22 | 23 | // Description provides description to test result(using fmt.Sprint) 24 | func (a *allureManager) Description(args ...interface{}) { 25 | a.withResult(func(r *allure.Result) { 26 | r.Description = fmt.Sprint(args...) 27 | }) 28 | } 29 | 30 | // Descriptionf provides description to test result(using fmt.Sprintf) 31 | func (a *allureManager) Descriptionf(format string, args ...interface{}) { 32 | a.withResult(func(r *allure.Result) { 33 | r.Description = fmt.Sprintf(format, args...) 34 | }) 35 | } 36 | 37 | // Stage provides staqe to test result(using fmt.Sprint) 38 | func (a *allureManager) Stage(args ...interface{}) { 39 | a.withResult(func(r *allure.Result) { 40 | r.Stage = fmt.Sprint(args...) 41 | }) 42 | } 43 | 44 | // Stagef provides staqe to test result(using fmt.Sprintf) 45 | func (a *allureManager) Stagef(format string, args ...interface{}) { 46 | a.withResult(func(r *allure.Result) { 47 | r.Stage = fmt.Sprintf(format, args...) 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/description_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/provider" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | type testMetaMockDescription struct { 12 | result *allure.Result 13 | container *allure.Container 14 | be func(t provider.T) 15 | ae func(t provider.T) 16 | } 17 | 18 | func (m *testMetaMockDescription) GetResult() *allure.Result { 19 | return m.result 20 | } 21 | 22 | func (m *testMetaMockDescription) SetResult(result *allure.Result) { 23 | m.result = result 24 | } 25 | 26 | func (m *testMetaMockDescription) GetContainer() *allure.Container { 27 | return m.container 28 | } 29 | 30 | func (m *testMetaMockDescription) SetBeforeEach(hook func(t provider.T)) { 31 | m.be = hook 32 | } 33 | 34 | func (m *testMetaMockDescription) GetBeforeEach() func(t provider.T) { 35 | return m.be 36 | } 37 | 38 | func (m *testMetaMockDescription) SetAfterEach(hook func(t provider.T)) { 39 | m.ae = hook 40 | } 41 | 42 | func (m *testMetaMockDescription) GetAfterEach() func(t provider.T) { 43 | return m.ae 44 | } 45 | 46 | func TestAllureManager_Title(t *testing.T) { 47 | manager := allureManager{testMeta: &testMetaMockDescription{result: &allure.Result{}}} 48 | manager.Title("Test") 49 | require.Equal(t, "Test", manager.testMeta.GetResult().Name) 50 | } 51 | 52 | func TestAllureManager_Description(t *testing.T) { 53 | manager := allureManager{testMeta: &testMetaMockDescription{result: &allure.Result{}}} 54 | manager.Description("Test") 55 | require.Equal(t, "Test", manager.testMeta.GetResult().Description) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/execution_management.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import "github.com/ozontech/allure-go/pkg/framework/core/allure_manager/ctx" 4 | 5 | // TestContext initiate test context 6 | func (a *allureManager) TestContext() { 7 | a.executionContext = ctx.NewTestCtx(a.testMeta.GetResult()) 8 | } 9 | 10 | // BeforeEachContext initiate before each context 11 | func (a *allureManager) BeforeEachContext() { 12 | a.executionContext = ctx.NewBeforeEachCtx(a.testMeta.GetContainer()) 13 | } 14 | 15 | // AfterEachContext initiate after each context 16 | func (a *allureManager) AfterEachContext() { 17 | a.executionContext = ctx.NewAfterEachCtx(a.testMeta.GetContainer()) 18 | } 19 | 20 | // BeforeAllContext initiate before all context 21 | func (a *allureManager) BeforeAllContext() { 22 | a.executionContext = ctx.NewBeforeAllCtx(a.suiteMeta.GetContainer()) 23 | } 24 | 25 | // AfterAllContext initiate after all context 26 | func (a *allureManager) AfterAllContext() { 27 | a.executionContext = ctx.NewAfterAllCtx(a.suiteMeta.GetContainer()) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/execution_management_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 8 | "github.com/ozontech/allure-go/pkg/framework/provider" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | type testMetaMockExecM struct { 13 | result *allure.Result 14 | container *allure.Container 15 | be func(t provider.T) 16 | ae func(t provider.T) 17 | } 18 | 19 | func (m *testMetaMockExecM) GetResult() *allure.Result { 20 | return m.result 21 | } 22 | 23 | func (m *testMetaMockExecM) SetResult(result *allure.Result) { 24 | m.result = result 25 | } 26 | 27 | func (m *testMetaMockExecM) GetContainer() *allure.Container { 28 | return m.container 29 | } 30 | 31 | func (m *testMetaMockExecM) SetBeforeEach(hook func(t provider.T)) { 32 | m.be = hook 33 | } 34 | 35 | func (m *testMetaMockExecM) GetBeforeEach() func(t provider.T) { 36 | return m.be 37 | } 38 | 39 | func (m *testMetaMockExecM) SetAfterEach(hook func(t provider.T)) { 40 | m.ae = hook 41 | } 42 | 43 | func (m *testMetaMockExecM) GetAfterEach() func(t provider.T) { 44 | return m.ae 45 | } 46 | 47 | type suiteMetaMockExecM struct { 48 | name string 49 | container *allure.Container 50 | hook func(t provider.T) 51 | } 52 | 53 | func (m *suiteMetaMockExecM) GetPackageName() string { 54 | return m.name 55 | } 56 | 57 | func (m *suiteMetaMockExecM) GetRunner() string { 58 | return m.name 59 | } 60 | 61 | func (m *suiteMetaMockExecM) GetSuiteName() string { 62 | return m.name 63 | } 64 | 65 | func (m *suiteMetaMockExecM) GetParentSuite() string { 66 | return "" 67 | } 68 | 69 | func (m *suiteMetaMockExecM) GetSuiteFullName() string { 70 | return m.name 71 | } 72 | 73 | func (m *suiteMetaMockExecM) GetContainer() *allure.Container { 74 | return m.container 75 | } 76 | 77 | func (m *suiteMetaMockExecM) SetBeforeAll(hook func(provider.T)) { 78 | m.hook = hook 79 | } 80 | 81 | func (m *suiteMetaMockExecM) SetAfterAll(hook func(provider.T)) { 82 | m.hook = hook 83 | } 84 | 85 | func (m *suiteMetaMockExecM) GetBeforeAll() func(provider.T) { 86 | return m.hook 87 | } 88 | 89 | func (m *suiteMetaMockExecM) GetAfterAll() func(provider.T) { 90 | return m.hook 91 | } 92 | 93 | func TestAllureManager_AfterAllContext(t *testing.T) { 94 | manager := allureManager{suiteMeta: &suiteMetaMockExecM{container: allure.NewContainer()}} 95 | manager.AfterAllContext() 96 | require.NotNil(t, manager.executionContext) 97 | require.Equal(t, constants.AfterAllContextName, manager.executionContext.GetName()) 98 | } 99 | 100 | func TestAllureManager_BeforeAllContext(t *testing.T) { 101 | manager := allureManager{suiteMeta: &suiteMetaMockExecM{container: allure.NewContainer()}} 102 | manager.BeforeAllContext() 103 | require.NotNil(t, manager.executionContext) 104 | require.Equal(t, constants.BeforeAllContextName, manager.executionContext.GetName()) 105 | } 106 | 107 | func TestAllureManager_BeforeEachContext(t *testing.T) { 108 | manager := allureManager{testMeta: &testMetaMockExecM{container: allure.NewContainer()}} 109 | manager.BeforeEachContext() 110 | require.NotNil(t, manager.executionContext) 111 | require.Equal(t, constants.BeforeEachContextName, manager.executionContext.GetName()) 112 | } 113 | 114 | func TestAllureManager_AfterEachContext(t *testing.T) { 115 | manager := allureManager{testMeta: &testMetaMockExecM{container: allure.NewContainer()}} 116 | manager.AfterEachContext() 117 | require.NotNil(t, manager.executionContext) 118 | require.Equal(t, constants.AfterEachContextName, manager.executionContext.GetName()) 119 | } 120 | 121 | func TestAllureManager_TestContext(t *testing.T) { 122 | manager := allureManager{testMeta: &testMetaMockExecM{result: &allure.Result{}}} 123 | manager.TestContext() 124 | require.NotNil(t, manager.executionContext) 125 | require.Equal(t, constants.TestContextName, manager.executionContext.GetName()) 126 | } 127 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/labels.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | ) 6 | 7 | /* 8 | Labels 9 | */ 10 | 11 | // Label provides possibility to add any Label to test result 12 | func (a *allureManager) Label(label *allure.Label) { 13 | a.withResult(func(r *allure.Result) { 14 | r.Labels = append(r.Labels, label) 15 | }) 16 | } 17 | 18 | // Labels provides possibility to add few Labels to test result 19 | func (a *allureManager) Labels(labels ...*allure.Label) { 20 | a.withResult(func(r *allure.Result) { 21 | r.Labels = append(r.Labels, labels...) 22 | }) 23 | } 24 | 25 | func (a *allureManager) ReplaceLabel(label *allure.Label) { 26 | a.withResult(func(r *allure.Result) { 27 | for _, l := range r.Labels { 28 | if l.Name == label.Name { 29 | l.Value = label.Value 30 | 31 | return 32 | } 33 | } 34 | 35 | a.Label(label) 36 | }) 37 | } 38 | 39 | // Epic adds Epic label to test result 40 | func (a *allureManager) Epic(value string) { 41 | a.Label(allure.EpicLabel(value)) 42 | } 43 | 44 | // Layer adds Layer label to test result 45 | func (a *allureManager) Layer(value string) { 46 | a.Label(allure.LayerLabel(value)) 47 | } 48 | 49 | // Feature adds Feature label to test result 50 | func (a *allureManager) Feature(value string) { 51 | a.Label(allure.FeatureLabel(value)) 52 | } 53 | 54 | // Story adds Story label to test result 55 | func (a *allureManager) Story(value string) { 56 | a.Label(allure.StoryLabel(value)) 57 | } 58 | 59 | // FrameWork adds FrameWork label to test result 60 | func (a *allureManager) FrameWork(value string) { 61 | a.ReplaceLabel(allure.FrameWorkLabel(value)) 62 | } 63 | 64 | // Host adds Host label to test result 65 | func (a *allureManager) Host(value string) { 66 | a.ReplaceLabel(allure.HostLabel(value)) 67 | } 68 | 69 | // Thread adds Thread label to test result 70 | // Seems like there is no way to access an identifier for the current goroutine in Go. 71 | func (a *allureManager) Thread(value string) { 72 | a.ReplaceLabel(allure.ThreadLabel(value)) 73 | } 74 | 75 | // ID adds ID label to test result 76 | func (a *allureManager) ID(value string) { 77 | a.ReplaceLabel(allure.IDLabel(value)) 78 | } 79 | 80 | // Language adds Language label to test result 81 | func (a *allureManager) Language(value string) { 82 | a.ReplaceLabel(allure.LanguageLabel(value)) 83 | } 84 | 85 | // AddSuiteLabel adds suite label to test result 86 | func (a *allureManager) AddSuiteLabel(value string) { 87 | a.Label(allure.SuiteLabel(value)) 88 | } 89 | 90 | // AddSubSuite adds AddSubSuite label to test result 91 | func (a *allureManager) AddSubSuite(value string) { 92 | a.Label(allure.SubSuiteLabel(value)) 93 | } 94 | 95 | // AddParentSuite adds AddParentSuite label to test result 96 | func (a *allureManager) AddParentSuite(value string) { 97 | a.Label(allure.ParentSuiteLabel(value)) 98 | } 99 | 100 | // Severity adds Severity label to test result 101 | func (a *allureManager) Severity(value allure.SeverityType) { 102 | a.ReplaceLabel(allure.SeverityLabel(value)) 103 | } 104 | 105 | // Tag adds Tag label to test result 106 | func (a *allureManager) Tag(value string) { 107 | a.Label(allure.TagLabel(value)) 108 | } 109 | 110 | // Tags adds a multiple Tag label to test result 111 | func (a *allureManager) Tags(values ...string) { 112 | a.Labels(allure.TagLabels(values...)...) 113 | } 114 | 115 | // Package adds Package label to test result 116 | func (a *allureManager) Package(value string) { 117 | a.ReplaceLabel(allure.PackageLabel(value)) 118 | } 119 | 120 | // Owner adds Owner label to test result 121 | func (a *allureManager) Owner(value string) { 122 | a.Label(allure.OwnerLabel(value)) 123 | } 124 | 125 | // Lead adds Lead label to test result 126 | func (a *allureManager) Lead(value string) { 127 | a.Label(allure.LeadLabel(value)) 128 | } 129 | 130 | func (a *allureManager) AllureID(value string) { 131 | a.ReplaceLabel(allure.IDAllureLabel(value)) 132 | } 133 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/links.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | ) 6 | 7 | // SetIssue adds issue link due environment variable ALLURE_ISSUE_PATTERN 8 | func (a *allureManager) SetIssue(issue string) { 9 | a.Link(allure.IssueLink(issue)) 10 | } 11 | 12 | // SetTestCase adds test case link due environment variable ALLURE_TESTCASE_PATTERN 13 | func (a *allureManager) SetTestCase(testCase string) { 14 | a.Link(allure.TestCaseLink(testCase)) 15 | } 16 | 17 | // TmsLink adds allure external test case link due environment variable ALLURE_TMS_LINK_PATTERN 18 | func (a *allureManager) TmsLink(testCase string) { 19 | a.Link(allure.TmsLink(testCase)) 20 | } 21 | 22 | // TmsLinks adds multiple external test case links due environment variable ALLURE_TMS_LINK_PATTERN 23 | func (a *allureManager) TmsLinks(testCase ...string) { 24 | a.Links(allure.TmsLinks(testCase...)) 25 | } 26 | 27 | // Link adds Link to struct.AllureResult 28 | func (a *allureManager) Link(link *allure.Link) { 29 | a.withResult(func(r *allure.Result) { 30 | r.Links = append(r.Links, link) 31 | }) 32 | } 33 | 34 | // Links adds multiple Link to struct.AllureResult 35 | func (a *allureManager) Links(links []*allure.Link) { 36 | a.withResult(func(r *allure.Result) { 37 | r.Links = append(r.Links, links...) 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/links_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/provider" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | type testMetaMockLinks struct { 12 | result *allure.Result 13 | container *allure.Container 14 | be func(t provider.T) 15 | ae func(t provider.T) 16 | } 17 | 18 | func (m *testMetaMockLinks) GetResult() *allure.Result { 19 | return m.result 20 | } 21 | 22 | func (m *testMetaMockLinks) SetResult(result *allure.Result) { 23 | m.result = result 24 | } 25 | 26 | func (m *testMetaMockLinks) GetContainer() *allure.Container { 27 | return m.container 28 | } 29 | 30 | func (m *testMetaMockLinks) SetBeforeEach(hook func(t provider.T)) { 31 | m.be = hook 32 | } 33 | 34 | func (m *testMetaMockLinks) GetBeforeEach() func(t provider.T) { 35 | return m.be 36 | } 37 | 38 | func (m *testMetaMockLinks) SetAfterEach(hook func(t provider.T)) { 39 | m.ae = hook 40 | } 41 | 42 | func (m *testMetaMockLinks) GetAfterEach() func(t provider.T) { 43 | return m.ae 44 | } 45 | 46 | func TestAllureManager_Link(t *testing.T) { 47 | manager := allureManager{testMeta: &testMetaMockLinks{result: &allure.Result{}}} 48 | manager.Link(allure.NewLink("Name", allure.LINK, "http://test.com")) 49 | require.Len(t, manager.GetResult().Links, 1) 50 | require.Equal(t, "Name", manager.GetResult().Links[0].Name) 51 | require.Equal(t, string(allure.LINK), manager.GetResult().Links[0].Type) 52 | require.Equal(t, "http://test.com", manager.GetResult().Links[0].URL) 53 | 54 | } 55 | 56 | func TestAllureManager_SetTestCase(t *testing.T) { 57 | manager := allureManager{testMeta: &testMetaMockLinks{result: &allure.Result{}}} 58 | manager.SetTestCase("TestCase") 59 | require.Len(t, manager.GetResult().Links, 1) 60 | require.Equal(t, "TestCase[TestCase]", manager.GetResult().Links[0].Name) 61 | require.Equal(t, string(allure.TESTCASE), manager.GetResult().Links[0].Type) 62 | } 63 | 64 | func TestAllureManager_SetIssue(t *testing.T) { 65 | manager := allureManager{testMeta: &testMetaMockLinks{result: &allure.Result{}}} 66 | manager.SetIssue("Issue") 67 | require.NotEmpty(t, manager.GetResult().Links) 68 | require.Len(t, manager.GetResult().Links, 1) 69 | require.Equal(t, "Issue[Issue]", manager.GetResult().Links[0].Name) 70 | require.Equal(t, string(allure.ISSUE), manager.GetResult().Links[0].Type) 71 | } 72 | 73 | func TestAllureManager_TmsLink(t *testing.T) { 74 | manager := allureManager{testMeta: &testMetaMockLinks{result: &allure.Result{}}} 75 | manager.TmsLink("TmsLink") 76 | require.NotEmpty(t, manager.GetResult().Links) 77 | require.Len(t, manager.GetResult().Links, 1) 78 | require.Equal(t, "TmsLink", manager.GetResult().Links[0].Name) 79 | require.Equal(t, string(allure.TMS), manager.GetResult().Links[0].Type) 80 | } 81 | 82 | func TestAllureManager_TmsLinks(t *testing.T) { 83 | manager := allureManager{testMeta: &testMetaMockLinks{result: &allure.Result{}}} 84 | manager.TmsLinks("TmsLink1", "TmsLink2") 85 | require.NotEmpty(t, manager.GetResult().Links) 86 | require.Len(t, manager.GetResult().Links, 2) 87 | require.Equal(t, "TmsLink1", manager.GetResult().Links[0].Name) 88 | require.Equal(t, "TmsLink2", manager.GetResult().Links[1].Name) 89 | require.Equal(t, string(allure.TMS), manager.GetResult().Links[0].Type) 90 | require.Equal(t, string(allure.TMS), manager.GetResult().Links[1].Type) 91 | } 92 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/parameter.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import "github.com/ozontech/allure-go/pkg/allure" 4 | 5 | // WithParameters adds parameters to report in case of current execution context 6 | func (a *allureManager) WithParameters(params ...*allure.Parameter) { 7 | a.withResult(func(r *allure.Result) { 8 | r.Parameters = append(r.Parameters, params...) 9 | }) 10 | } 11 | 12 | // WithNewParameters adds parameters to report in case of current execution context 13 | func (a *allureManager) WithNewParameters(kv ...interface{}) { 14 | a.withResult(func(r *allure.Result) { 15 | r.Parameters = append(r.Parameters, allure.NewParameters(kv...)...) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/parameter_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/provider" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | type testMetaMockParameter struct { 12 | result *allure.Result 13 | container *allure.Container 14 | be func(t provider.T) 15 | ae func(t provider.T) 16 | } 17 | 18 | func (m *testMetaMockParameter) GetResult() *allure.Result { 19 | return m.result 20 | } 21 | 22 | func (m *testMetaMockParameter) SetResult(result *allure.Result) { 23 | m.result = result 24 | } 25 | 26 | func (m *testMetaMockParameter) GetContainer() *allure.Container { 27 | return m.container 28 | } 29 | 30 | func (m *testMetaMockParameter) SetBeforeEach(hook func(t provider.T)) { 31 | m.be = hook 32 | } 33 | 34 | func (m *testMetaMockParameter) GetBeforeEach() func(t provider.T) { 35 | return m.be 36 | } 37 | 38 | func (m *testMetaMockParameter) SetAfterEach(hook func(t provider.T)) { 39 | m.ae = hook 40 | } 41 | 42 | func (m *testMetaMockParameter) GetAfterEach() func(t provider.T) { 43 | return m.ae 44 | } 45 | 46 | func TestAllureManager_Parameter(t *testing.T) { 47 | manager := allureManager{testMeta: &testMetaMockParameter{result: &allure.Result{}}} 48 | manager.WithParameters(allure.NewParameter("host", "localhost")) 49 | require.Len(t, manager.GetResult().Parameters, 1) 50 | require.Equal(t, "host", manager.GetResult().Parameters[0].Name) 51 | require.Equal(t, "localhost", manager.GetResult().Parameters[0].GetValue()) 52 | } 53 | 54 | func TestAllureManager_NewParameter(t *testing.T) { 55 | manager := allureManager{testMeta: &testMetaMockParameter{result: &allure.Result{}}} 56 | manager.WithNewParameters("host", "localhost", "os", "linux") 57 | require.Len(t, manager.GetResult().Parameters, 2) 58 | require.Equal(t, "host", manager.GetResult().Parameters[0].Name) 59 | require.Equal(t, "localhost", manager.GetResult().Parameters[0].GetValue()) 60 | require.Equal(t, "os", manager.GetResult().Parameters[1].Name) 61 | require.Equal(t, "linux", manager.GetResult().Parameters[1].GetValue()) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/provider.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | "github.com/ozontech/allure-go/pkg/framework/core/allure_manager/adapter" 6 | "github.com/ozontech/allure-go/pkg/framework/provider" 7 | ) 8 | 9 | type allureManager struct { 10 | testMeta provider.TestMeta 11 | suiteMeta provider.SuiteMeta 12 | 13 | executionContext provider.ExecutionContext 14 | } 15 | 16 | func NewProvider(cfg ProviderConfig) provider.Provider { 17 | suiteMeta := adapter.NewSuiteMetaWithParent( 18 | cfg.PackageName(), 19 | cfg.Runner(), 20 | cfg.FullName(), 21 | cfg.SuiteName(), 22 | cfg.ParentSuite(), 23 | ) 24 | 25 | return &allureManager{ 26 | suiteMeta: suiteMeta, 27 | testMeta: &adapter.TestAdapter{}, 28 | } 29 | } 30 | 31 | func (a *allureManager) withResult(f func(r *allure.Result)) { 32 | if r := a.GetResult(); r != nil { 33 | f(r) 34 | } 35 | } 36 | 37 | func (a *allureManager) UpdateResultStatus(msg string, trace string) { 38 | a.GetResult().SetStatusMessage(msg) 39 | a.GetResult().SetStatusTrace(trace) 40 | } 41 | 42 | func (a *allureManager) StopResult(status allure.Status) { 43 | a.withResult(func(r *allure.Result) { 44 | r.Status = status 45 | r.Stop = allure.GetNow() 46 | }) 47 | } 48 | 49 | func (a *allureManager) GetResult() *allure.Result { 50 | return a.testMeta.GetResult() 51 | } 52 | 53 | func (a *allureManager) SetTestMeta(meta provider.TestMeta) { 54 | a.testMeta = meta 55 | } 56 | 57 | func (a *allureManager) GetTestMeta() provider.TestMeta { 58 | return a.testMeta 59 | } 60 | 61 | func (a *allureManager) GetSuiteMeta() provider.SuiteMeta { 62 | return a.suiteMeta 63 | } 64 | 65 | func (a *allureManager) ExecutionContext() provider.ExecutionContext { 66 | return a.executionContext 67 | } 68 | 69 | func (a *allureManager) NewTest(testName, packageName string, tags ...string) { 70 | a.testMeta = adapter.NewTestMeta( 71 | a.suiteMeta.GetSuiteFullName(), 72 | a.suiteMeta.GetSuiteName(), 73 | testName, 74 | packageName, 75 | tags..., 76 | ) 77 | 78 | if parentSuite := a.suiteMeta.GetParentSuite(); parentSuite != "" { 79 | a.testMeta.GetResult().WithParentSuite(parentSuite) 80 | } 81 | 82 | a.suiteMeta.GetContainer().AddChild(a.testMeta.GetResult().UUID) 83 | } 84 | 85 | func (a *allureManager) FinishTest() error { 86 | container := a.testMeta.GetContainer() 87 | if container != nil { 88 | if err := container.Done(); err != nil { 89 | return err 90 | } 91 | } 92 | 93 | return a.testMeta.GetResult().Done() 94 | } 95 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/provider_config.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | type ConfigKey string 4 | 5 | // describes base provider configs 6 | const ( 7 | SuiteName ConfigKey = "suite" 8 | PackageName ConfigKey = "package" 9 | FullName ConfigKey = "fullName" 10 | SuitePath ConfigKey = "suitePath" 11 | Runner ConfigKey = "runner" 12 | ParentSuite ConfigKey = "parentSuite" 13 | ) 14 | 15 | func (c ConfigKey) String() string { 16 | return string(c) 17 | } 18 | 19 | // ProviderConfig describes configuration interface 20 | type ProviderConfig interface { 21 | SuitePath() string 22 | SuiteName() string 23 | FullName() string 24 | PackageName() string 25 | ParentSuite() string 26 | Runner() string 27 | 28 | WithSuitePath(suitePath string) ProviderConfig 29 | WithSuiteName(suiteName string) ProviderConfig 30 | WithFullName(fullName string) ProviderConfig 31 | WithPackageName(packageName string) ProviderConfig 32 | WithParentSuite(parentSuite string) ProviderConfig 33 | WithRunner(runner string) ProviderConfig 34 | } 35 | 36 | type providerConfig struct { 37 | cfg map[ConfigKey]string 38 | } 39 | 40 | // NewProviderConfig ... 41 | func NewProviderConfig() ProviderConfig { 42 | return &providerConfig{make(map[ConfigKey]string)} 43 | } 44 | 45 | // SuitePath ... 46 | func (cfg *providerConfig) SuitePath() string { 47 | return cfg.cfg[SuitePath] 48 | } 49 | 50 | // SuiteName ... 51 | func (cfg *providerConfig) SuiteName() string { 52 | return cfg.cfg[SuiteName] 53 | } 54 | 55 | // PackageName ... 56 | func (cfg *providerConfig) PackageName() string { 57 | return cfg.cfg[PackageName] 58 | } 59 | 60 | // FullName ... 61 | func (cfg *providerConfig) FullName() string { 62 | return cfg.cfg[FullName] 63 | } 64 | 65 | // Runner ... 66 | func (cfg *providerConfig) Runner() string { 67 | return cfg.cfg[Runner] 68 | } 69 | 70 | // ParentSuite ... 71 | func (cfg *providerConfig) ParentSuite() string { 72 | return cfg.cfg[ParentSuite] 73 | } 74 | 75 | // WithSuitePath ... 76 | func (cfg *providerConfig) WithSuitePath(suitePath string) ProviderConfig { 77 | cfg.cfg[SuitePath] = suitePath 78 | return cfg 79 | } 80 | 81 | // WithSuiteName ... 82 | func (cfg *providerConfig) WithSuiteName(suiteName string) ProviderConfig { 83 | cfg.cfg[SuiteName] = suiteName 84 | return cfg 85 | } 86 | 87 | // WithPackageName ... 88 | func (cfg *providerConfig) WithPackageName(packageName string) ProviderConfig { 89 | cfg.cfg[PackageName] = packageName 90 | return cfg 91 | } 92 | 93 | // WithFullName ... 94 | func (cfg *providerConfig) WithFullName(fullName string) ProviderConfig { 95 | cfg.cfg[FullName] = fullName 96 | return cfg 97 | } 98 | 99 | // WithRunner ... 100 | func (cfg *providerConfig) WithRunner(runner string) ProviderConfig { 101 | cfg.cfg[Runner] = runner 102 | return cfg 103 | } 104 | 105 | // WithParentSuite ... 106 | func (cfg *providerConfig) WithParentSuite(parentSuite string) ProviderConfig { 107 | cfg.cfg[ParentSuite] = parentSuite 108 | return cfg 109 | } 110 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/provider_config_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestProviderConfigConstants(t *testing.T) { 10 | require.Equal(t, "suite", string(SuiteName)) 11 | require.Equal(t, "package", string(PackageName)) 12 | require.Equal(t, "fullName", string(FullName)) 13 | require.Equal(t, "suitePath", string(SuitePath)) 14 | require.Equal(t, "runner", string(Runner)) 15 | } 16 | 17 | func TestNewProviderConfig(t *testing.T) { 18 | cfg := NewProviderConfig() 19 | require.NotNil(t, cfg) 20 | } 21 | 22 | func TestProviderConfig_values(t *testing.T) { 23 | cfg := providerConfig{map[ConfigKey]string{}} 24 | 25 | cfg.WithRunner("runner") 26 | require.NotEmpty(t, cfg.cfg[Runner]) 27 | require.Equal(t, "runner", cfg.cfg[Runner]) 28 | require.NotEmpty(t, cfg.Runner()) 29 | require.Equal(t, "runner", cfg.Runner()) 30 | 31 | cfg.WithSuiteName("suiteName") 32 | require.NotEmpty(t, cfg.cfg[SuiteName]) 33 | require.Equal(t, "suiteName", cfg.cfg[SuiteName]) 34 | require.NotEmpty(t, cfg.SuiteName()) 35 | require.Equal(t, "suiteName", cfg.SuiteName()) 36 | 37 | cfg.WithFullName("fullName") 38 | require.NotEmpty(t, cfg.cfg[FullName]) 39 | require.Equal(t, "fullName", cfg.cfg[FullName]) 40 | require.NotEmpty(t, cfg.FullName()) 41 | require.Equal(t, "fullName", cfg.FullName()) 42 | 43 | cfg.WithPackageName("packageName") 44 | require.NotEmpty(t, cfg.cfg[PackageName]) 45 | require.Equal(t, "packageName", cfg.cfg[PackageName]) 46 | require.NotEmpty(t, cfg.PackageName()) 47 | require.Equal(t, "packageName", cfg.PackageName()) 48 | 49 | cfg.WithSuitePath("suitePath") 50 | require.NotEmpty(t, cfg.cfg[SuitePath]) 51 | require.Equal(t, "suitePath", cfg.cfg[SuitePath]) 52 | require.NotEmpty(t, cfg.SuitePath()) 53 | require.Equal(t, "suitePath", cfg.SuitePath()) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/manager/steps.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | ) 6 | 7 | // Step adds step to test result 8 | func (a *allureManager) Step(step *allure.Step) { 9 | a.ExecutionContext().AddStep(step) 10 | } 11 | 12 | // NewStep creates new step and adds it to test result 13 | func (a *allureManager) NewStep(stepName string, params ...*allure.Parameter) { 14 | a.ExecutionContext().AddStep(allure.NewSimpleStep(stepName, params...)) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/framework/core/allure_manager/testplan/testplan.go: -------------------------------------------------------------------------------- 1 | package testplan 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | var ( 13 | once = sync.Once{} 14 | testPlan = initTestPlan() 15 | ) 16 | 17 | // Path to testplan.json 18 | const testPlanPath = "ALLURE_TESTPLAN_PATH" 19 | 20 | type TestCase struct { 21 | ID int `json:"id"` 22 | Selector string `json:"selector"` 23 | } 24 | 25 | type TestPlan struct { 26 | Version string `json:"version"` 27 | Tests []*TestCase `json:"tests"` 28 | } 29 | 30 | func newTestPlan() (*TestPlan, error) { 31 | filePath := os.Getenv(testPlanPath) 32 | if filePath == "" { 33 | return nil, fmt.Errorf("{%s} environment variable not set", testPlanPath) 34 | } 35 | 36 | if filepath.Ext(filePath) != ".json" { 37 | return nil, fmt.Errorf("%s environment variable has a wrong format. Please, set path to .json file. Current path:%s", testPlanPath, filePath) 38 | } 39 | 40 | testPlanRaw, err := findTestPlan(filePath) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | var plan TestPlan 46 | 47 | err = json.Unmarshal(testPlanRaw, &plan) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | if len(plan.Tests) == 0 { 53 | return nil, fmt.Errorf("no any tests found in %s", filePath) 54 | } 55 | 56 | return &plan, nil 57 | } 58 | 59 | // IsSelected returns true if selector matches with testplan selector 60 | // TODO: ID parsing from TestOps 61 | func (p *TestPlan) IsSelected(id, selector string) bool { 62 | for _, t := range p.Tests { 63 | if t.Selector == selector { 64 | return true 65 | } 66 | } 67 | 68 | return false 69 | } 70 | 71 | func initTestPlan() *TestPlan { 72 | var ( 73 | err error 74 | tPlan *TestPlan 75 | ) 76 | 77 | testPlanOnce := func() { 78 | tPlan, err = newTestPlan() 79 | if err == nil { 80 | fmt.Printf("TestPlan found!") 81 | } 82 | } 83 | once.Do(testPlanOnce) 84 | 85 | return tPlan 86 | } 87 | 88 | // GetTestPlan ... 89 | func GetTestPlan() *TestPlan { 90 | return testPlan 91 | } 92 | 93 | func findTestPlan(path string) (testPlanRaw []byte, readFileErr error) { 94 | // TODO: refactor this function to use filepath pkg properly 95 | 96 | testPlanRaw, readFileErr = os.ReadFile(filepath.Clean(path)) 97 | if readFileErr == nil && testPlanRaw != nil { 98 | return testPlanRaw, nil 99 | } 100 | 101 | dir, getWdErr := os.Getwd() 102 | if getWdErr != nil { 103 | return nil, getWdErr 104 | } 105 | 106 | pathParts := strings.Split(dir, string(os.PathSeparator)) 107 | 108 | // windows absolute path workaround 109 | // issue describing: https://github.com/golang/go/issues/26953#issuecomment-412447719 110 | if strings.HasSuffix(pathParts[0], ":") { 111 | pathParts[0] = pathParts[0] + "/" 112 | } 113 | 114 | // os.Getwd() returns current test folder. 115 | // trying to walk up the absolute path to find testplan.json 116 | tmpPathParts := pathParts 117 | for range pathParts { 118 | basicPath := filepath.Join(tmpPathParts...) 119 | absolutePath := filepath.Join(basicPath, filepath.Clean(path)) 120 | if pathParts[0] == "" && len(pathParts) > 1 { 121 | absolutePath = "/" + absolutePath 122 | } 123 | 124 | //nolint:gosec // already cleared 125 | testPlanRaw, readFileErr = os.ReadFile(absolutePath) 126 | if readFileErr != nil { 127 | // stop looking if project root found 128 | //nolint:gosec // already cleared 129 | _, gErr := os.ReadFile(filepath.Join(basicPath, "go.mod")) 130 | if gErr == nil { 131 | return 132 | } 133 | tmpPathParts = tmpPathParts[:len(tmpPathParts)-1] 134 | continue 135 | } 136 | break 137 | } 138 | return 139 | } 140 | -------------------------------------------------------------------------------- /pkg/framework/core/assert/assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | // TestingT is an interface wrapper around *testing.T 11 | type TestingT interface { 12 | Errorf(format string, args ...interface{}) 13 | } 14 | 15 | type tHelper interface { 16 | Helper() 17 | } 18 | 19 | // JSONContains asserts that expected JSON contains fields and values of actual JSON which can be bigger. 20 | // 21 | // assert.JSONContains(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world", "foobar": 1}`) 22 | func JSONContains(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { 23 | if h, ok := t.(tHelper); ok { 24 | h.Helper() 25 | } 26 | var expectedJSONAsInterface, actualJSONAsInterface interface{} 27 | 28 | if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { 29 | return assert.Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) 30 | } 31 | 32 | if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { 33 | return assert.Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...) 34 | } 35 | 36 | return assert.Equal(t, expectedJSONAsInterface, extractActualJSON(t, expectedJSONAsInterface, actualJSONAsInterface), msgAndArgs...) 37 | } 38 | 39 | func extractActualJSON(t TestingT, expected interface{}, actual interface{}) interface{} { 40 | switch expected.(type) { 41 | case []interface{}: 42 | exp := expected.([]interface{}) 43 | act, ok := actual.([]interface{}) 44 | if !ok { 45 | assert.Fail(t, "Unexpected type of actual JSON element") 46 | return nil 47 | } 48 | if len(exp) > len(act) { 49 | assert.Fail(t, "Expected slice bigger than actual JSON element") 50 | return nil 51 | } 52 | result := make([]interface{}, 0, len(exp)) 53 | 54 | for i, ev := range exp { 55 | result = append(result, extractActualJSON(t, ev, act[i])) 56 | } 57 | return result 58 | 59 | case map[string]interface{}: 60 | result := make(map[string]interface{}, len(expected.(map[string]interface{}))) 61 | act, ok := actual.(map[string]interface{}) 62 | if !ok { 63 | assert.Fail(t, "Unexpected type of actual JSON element") 64 | return nil 65 | } 66 | 67 | for k, ev := range expected.(map[string]interface{}) { // use type assertion to loop over map[string]interface{} 68 | result[k] = extractActualJSON(t, ev, act[k]) 69 | } 70 | return result 71 | } 72 | return actual 73 | } 74 | -------------------------------------------------------------------------------- /pkg/framework/core/assert/assertions_test.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestJSONContains_EqualSONString(t *testing.T) { 10 | mockT := new(testing.T) 11 | assert.True(t, JSONContains(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) 12 | } 13 | 14 | func TestJSONContains_EquivalentButNotEqual(t *testing.T) { 15 | mockT := new(testing.T) 16 | assert.True(t, JSONContains(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) 17 | } 18 | 19 | func TestJSONContains_HashOfArraysAndHashes(t *testing.T) { 20 | mockT := new(testing.T) 21 | assert.True(t, JSONContains(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", 22 | "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")) 23 | } 24 | 25 | func TestJSONContains_Array(t *testing.T) { 26 | mockT := new(testing.T) 27 | assert.True(t, JSONContains(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) 28 | } 29 | 30 | func TestJSONContains_ExpectedArrayLessThanActual(t *testing.T) { 31 | mockT := new(testing.T) 32 | assert.False(t, JSONContains(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{"foobar": 1}, "foo", {"nested": "hash", "hello": "world"}]`)) 33 | } 34 | 35 | func TestJSONContains_ExpectedArrayBiggerThanActual(t *testing.T) { 36 | mockT := new(testing.T) 37 | assert.False(t, JSONContains(mockT, `[{"foobar": 1}, "foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) 38 | } 39 | 40 | func TestJSONContains_ExpectedLessThanActual(t *testing.T) { 41 | mockT := new(testing.T) 42 | assert.True(t, JSONContains(mockT, `{"hello": {"world": 1}, "foo": [{"bar": "baz"}]}`, 43 | `{"hello": {"world": 1, "missing": "key"}, "foo": [{"bar": "baz", "waldo": "fred"}], "foobar": 2}`)) 44 | } 45 | 46 | func TestJSONContains_ExpectedBiggerThanActual(t *testing.T) { 47 | mockT := new(testing.T) 48 | assert.False(t, JSONContains(mockT, `{"hello": {"world": 1}, "foo": [{"bar": "baz", "waldo": "fred"}], "foobar": 2}`, 49 | `{"hello": {"world": 1, "missing": "key"}, "foo": [{"bar": "baz"}]}`)) 50 | } 51 | 52 | func TestJSONContains_HashAndArrayNotEquivalent(t *testing.T) { 53 | mockT := new(testing.T) 54 | assert.False(t, JSONContains(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)) 55 | } 56 | 57 | func TestJSONContains_ActualIsNotJSON(t *testing.T) { 58 | mockT := new(testing.T) 59 | assert.False(t, JSONContains(mockT, `{"foo": "bar"}`, "Not JSON")) 60 | } 61 | 62 | func TestJSONContains_ExpectedIsNotJSON(t *testing.T) { 63 | mockT := new(testing.T) 64 | assert.False(t, JSONContains(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)) 65 | } 66 | 67 | func TestJSONContains_ExpectedAndActualNotJSON(t *testing.T) { 68 | mockT := new(testing.T) 69 | assert.False(t, JSONContains(mockT, "Not JSON", "Not JSON")) 70 | } 71 | 72 | func TestJSONContains_ArraysOfDifferentOrder(t *testing.T) { 73 | mockT := new(testing.T) 74 | assert.False(t, JSONContains(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)) 75 | } 76 | -------------------------------------------------------------------------------- /pkg/framework/core/common/errors_handling.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 6 | ) 7 | 8 | type ErrorT interface { 9 | Errorf(format string, args ...interface{}) 10 | Logf(format string, args ...interface{}) 11 | FailNow() 12 | } 13 | 14 | type ErrorProvider interface { 15 | StopResult(status allure.Status) 16 | UpdateResultStatus(msg string, trace string) 17 | } 18 | 19 | func TestError(t ErrorT, provider ErrorProvider, contextName, errMsg string) { 20 | short := errMsg 21 | if len(errMsg) > 100 { 22 | // TODO: trim properly to avoid invalid UTF-8 23 | short = errMsg[:100] 24 | } 25 | 26 | switch contextName { 27 | case constants.TestContextName, constants.BeforeEachContextName: 28 | provider.StopResult(allure.Broken) 29 | provider.UpdateResultStatus(short, errMsg) 30 | t.Errorf(errMsg) 31 | t.FailNow() 32 | 33 | case constants.AfterEachContextName, constants.AfterAllContextName: 34 | t.Logf(errMsg) 35 | provider.UpdateResultStatus(short, errMsg) 36 | 37 | case constants.BeforeAllContextName: 38 | t.Logf(errMsg) 39 | provider.UpdateResultStatus(short, errMsg) 40 | t.FailNow() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/framework/core/common/errors_handling_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | "github.com/ozontech/allure-go/pkg/framework/core/constants" 6 | "github.com/stretchr/testify/require" 7 | "testing" 8 | ) 9 | 10 | type errorTMock struct { 11 | logF bool 12 | errorF bool 13 | failNow bool 14 | } 15 | 16 | func (e *errorTMock) Errorf(format string, args ...interface{}) { 17 | e.errorF = true 18 | } 19 | 20 | func (e *errorTMock) Logf(format string, args ...interface{}) { 21 | e.logF = true 22 | } 23 | 24 | func (e *errorTMock) FailNow() { 25 | e.failNow = true 26 | } 27 | 28 | type errorProviderMock struct { 29 | status allure.Status 30 | msg string 31 | trace string 32 | } 33 | 34 | func (m *errorProviderMock) StopResult(status allure.Status) { 35 | m.status = status 36 | } 37 | 38 | func (m *errorProviderMock) UpdateResultStatus(msg string, trace string) { 39 | m.msg = msg 40 | m.trace = trace 41 | } 42 | 43 | func TestTestError_less100(t *testing.T) { 44 | errTMock := &errorTMock{} 45 | errProviderMock := &errorProviderMock{} 46 | 47 | TestError(errTMock, errProviderMock, constants.TestContextName, "errMsg") 48 | require.Equal(t, "errMsg", errProviderMock.msg) 49 | require.Equal(t, "errMsg", errProviderMock.trace) 50 | require.Equal(t, allure.Broken, errProviderMock.status) 51 | require.True(t, errTMock.errorF) 52 | require.True(t, errTMock.failNow) 53 | 54 | errTMock = &errorTMock{} 55 | errProviderMock = &errorProviderMock{} 56 | 57 | TestError(errTMock, errProviderMock, constants.BeforeEachContextName, "errMsg") 58 | require.Equal(t, "errMsg", errProviderMock.msg) 59 | require.Equal(t, "errMsg", errProviderMock.trace) 60 | require.Equal(t, allure.Broken, errProviderMock.status) 61 | require.True(t, errTMock.errorF) 62 | require.True(t, errTMock.failNow) 63 | 64 | errTMock = &errorTMock{} 65 | errProviderMock = &errorProviderMock{} 66 | 67 | TestError(errTMock, errProviderMock, constants.BeforeAllContextName, "errMsg") 68 | require.Equal(t, "errMsg", errProviderMock.msg) 69 | require.Equal(t, "errMsg", errProviderMock.trace) 70 | require.Empty(t, errProviderMock.status) 71 | require.True(t, errTMock.logF) 72 | require.True(t, errTMock.failNow) 73 | 74 | errTMock = &errorTMock{} 75 | errProviderMock = &errorProviderMock{} 76 | 77 | TestError(errTMock, errProviderMock, constants.AfterEachContextName, "errMsg") 78 | require.Equal(t, "errMsg", errProviderMock.msg) 79 | require.Equal(t, "errMsg", errProviderMock.trace) 80 | require.Empty(t, errProviderMock.status) 81 | require.True(t, errTMock.logF) 82 | 83 | errTMock = &errorTMock{} 84 | errProviderMock = &errorProviderMock{} 85 | 86 | TestError(errTMock, errProviderMock, constants.AfterAllContextName, "errMsg") 87 | require.Equal(t, "errMsg", errProviderMock.msg) 88 | require.Equal(t, "errMsg", errProviderMock.trace) 89 | require.Empty(t, errProviderMock.status) 90 | require.True(t, errTMock.logF) 91 | } 92 | 93 | func TestTestError_more100(t *testing.T) { 94 | errTMock := &errorTMock{} 95 | errProviderMock := &errorProviderMock{} 96 | errMsg := `errMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMserrMs` 97 | TestError(errTMock, errProviderMock, constants.TestContextName, errMsg) 98 | require.Equal(t, errMsg[:100], errProviderMock.msg) 99 | require.Equal(t, errMsg, errProviderMock.trace) 100 | require.Equal(t, allure.Broken, errProviderMock.status) 101 | require.True(t, errTMock.errorF) 102 | require.True(t, errTMock.failNow) 103 | 104 | errTMock = &errorTMock{} 105 | errProviderMock = &errorProviderMock{} 106 | TestError(errTMock, errProviderMock, constants.BeforeAllContextName, errMsg) 107 | require.Equal(t, errMsg[:100], errProviderMock.msg) 108 | require.Equal(t, errMsg, errProviderMock.trace) 109 | require.Empty(t, errProviderMock.status) 110 | require.True(t, errTMock.logF) 111 | require.True(t, errTMock.failNow) 112 | 113 | errTMock = &errorTMock{} 114 | errProviderMock = &errorProviderMock{} 115 | TestError(errTMock, errProviderMock, constants.BeforeEachContextName, errMsg) 116 | require.Equal(t, errMsg[:100], errProviderMock.msg) 117 | require.Equal(t, errMsg, errProviderMock.trace) 118 | require.Equal(t, allure.Broken, errProviderMock.status) 119 | require.True(t, errTMock.errorF) 120 | require.True(t, errTMock.failNow) 121 | 122 | errTMock = &errorTMock{} 123 | errProviderMock = &errorProviderMock{} 124 | TestError(errTMock, errProviderMock, constants.AfterEachContextName, errMsg) 125 | require.Equal(t, errMsg[:100], errProviderMock.msg) 126 | require.Equal(t, errMsg, errProviderMock.trace) 127 | require.Empty(t, errProviderMock.status) 128 | require.True(t, errTMock.logF) 129 | 130 | errTMock = &errorTMock{} 131 | errProviderMock = &errorProviderMock{} 132 | TestError(errTMock, errProviderMock, constants.AfterAllContextName, errMsg) 133 | require.Equal(t, errMsg[:100], errProviderMock.msg) 134 | require.Equal(t, errMsg, errProviderMock.trace) 135 | require.Empty(t, errProviderMock.status) 136 | require.True(t, errTMock.logF) 137 | } 138 | -------------------------------------------------------------------------------- /pkg/framework/core/common/hooks.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "runtime/debug" 6 | "testing" 7 | 8 | "github.com/ozontech/allure-go/pkg/framework/provider" 9 | ) 10 | 11 | type HookFunc func(t InternalT, provider HookProvider) (bool, error) 12 | 13 | type HookType string 14 | 15 | // HookType constants 16 | const ( 17 | BeforeAll HookType = "BeforeAll" 18 | AfterAll HookType = "AfterAll" 19 | BeforeEach HookType = "BeforeEach" 20 | AfterEach HookType = "AfterEach" 21 | ) 22 | 23 | func (h HookType) String() string { 24 | return string(h) 25 | } 26 | 27 | func CarriedHook(hook HookType, getHookBody func() func(t provider.T)) HookFunc { 28 | return func(t InternalT, provider HookProvider) (result bool, err error) { 29 | result = true 30 | if hookBody := getHookBody(); hookBody != nil { 31 | t.WG().Add(1) 32 | defer t.WG().Wait() 33 | 34 | // for correct logs 35 | oldT := t.RealT() 36 | defer t.SetRealT(oldT) 37 | 38 | // HACK: allows testing library control routines to avoid deadlocks and appropriate waiting 39 | result = t.RealT().Run(string(hook), func(realT *testing.T) { 40 | defer t.WG().Done() 41 | switch hook { 42 | case BeforeAll: 43 | provider.BeforeAllContext() 44 | 45 | case AfterAll: 46 | provider.AfterAllContext() 47 | 48 | case BeforeEach: 49 | provider.BeforeEachContext() 50 | 51 | case AfterEach: 52 | provider.AfterEachContext() 53 | } 54 | 55 | defer func() { 56 | r := recover() 57 | if r != nil { 58 | err = fmt.Errorf("%s hook panicked:%v\n%s", hook, r, debug.Stack()) 59 | t.Errorf("%s hook panicked:%v\n%s", hook, r, debug.Stack()) 60 | t.FailNow() 61 | } 62 | }() 63 | 64 | t.SetRealT(realT) 65 | hookBody(t) 66 | }) 67 | } 68 | return 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pkg/framework/core/common/interfaces.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/ozontech/allure-go/pkg/allure" 7 | "github.com/ozontech/allure-go/pkg/framework/provider" 8 | ) 9 | 10 | type ParentT interface { 11 | GetProvider() provider.Provider 12 | GetResult() *allure.Result 13 | } 14 | 15 | type HookProvider interface { 16 | BeforeEachContext() 17 | AfterEachContext() 18 | BeforeAllContext() 19 | AfterAllContext() 20 | 21 | GetSuiteMeta() provider.SuiteMeta 22 | GetTestMeta() provider.TestMeta 23 | } 24 | 25 | type InternalT interface { 26 | provider.T 27 | 28 | SetRealT(realT provider.TestingT) 29 | WG() *sync.WaitGroup 30 | } 31 | -------------------------------------------------------------------------------- /pkg/framework/core/common/steps.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "runtime/debug" 6 | 7 | "github.com/ozontech/allure-go/pkg/allure" 8 | "github.com/ozontech/allure-go/pkg/framework/provider" 9 | ) 10 | 11 | // WithNewStep opens nesting for struct.Step 12 | // Any other struct.Step that will be added to struct.AllureResult object will be added as child step 13 | func (c *Common) WithNewStep(stepName string, step func(ctx provider.StepCtx), params ...*allure.Parameter) { 14 | stCtx := NewStepCtx(c, c.Provider, stepName, params...) 15 | defer c.Step(stCtx.CurrentStep()) 16 | defer func() { 17 | r := recover() 18 | stCtx.WG().Wait() 19 | stCtx.CurrentStep().Finish() 20 | if r != nil { 21 | ctxName := c.ExecutionContext().GetName() 22 | errMsg := fmt.Sprintf("%s panicked: %v\n%s", ctxName, r, debug.Stack()) 23 | stCtx.Broken() 24 | TestError(c.TestingT, c.Provider, c.Provider.ExecutionContext().GetName(), errMsg) 25 | } 26 | }() 27 | step(stCtx) 28 | } 29 | 30 | // WithNewAsyncStep opens nesting for struct.Step 31 | // Any other struct.Step that will be added to struct.AllureResult object will be added as child step 32 | func (c *Common) WithNewAsyncStep(stepName string, step func(ctx provider.StepCtx), params ...*allure.Parameter) { 33 | c.wg.Add(1) 34 | go func() { 35 | defer c.wg.Done() 36 | c.WithNewStep(stepName, step, params...) 37 | }() 38 | } 39 | -------------------------------------------------------------------------------- /pkg/framework/core/common/tempdir.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | "unicode" 8 | "unicode/utf8" 9 | ) 10 | 11 | func (c *Common) TempDir() string { 12 | // HACK: Temp solution for the go stdlib bug. 13 | // 14 | // Copied from https://github.com/golang/go/blob/master/src/testing/testing.go#L1307 15 | // 16 | // testing.T.TempDir() will fail if test name is too long. 17 | // 18 | // See this issue https://github.com/golang/go/issues/71742 19 | // 20 | // It was fixed recently (as of 14.05.2025) by the go team https://go.dev/cl/671577 21 | // but it will require some time until it reaches the stable version. 22 | 23 | // Use a single parent directory for all the temporary directories 24 | // created by a test, each numbered sequentially. 25 | c.tempDirMu.Lock() 26 | 27 | var nonExistent bool 28 | 29 | if c.tempDir == "" { // Usually the case with js/wasm 30 | nonExistent = true 31 | } else { 32 | _, err := os.Stat(c.tempDir) 33 | nonExistent = os.IsNotExist(err) 34 | 35 | if err != nil && !nonExistent { 36 | c.Fatalf("TempDir: %v", err) 37 | } 38 | } 39 | 40 | if nonExistent { 41 | c.Helper() 42 | pattern := c.Name() 43 | 44 | // Limit length of file names on disk. 45 | // Invalid runes from slicing are dropped by strings.Map below. 46 | if len(pattern) > 64 { 47 | pattern = pattern[:64] 48 | } 49 | 50 | // Drop unusual characters (such as path separators or 51 | // characters interacting with globs) from the directory name to 52 | // avoid surprising os.MkdirTemp behavior. 53 | mapper := func(r rune) rune { 54 | if r < utf8.RuneSelf { 55 | const allowed = "!#$%&()+,-.=@^_{}~ " 56 | 57 | if '0' <= r && r <= '9' || 58 | 'a' <= r && r <= 'z' || 59 | 'A' <= r && r <= 'Z' { 60 | return r 61 | } 62 | 63 | if strings.ContainsRune(allowed, r) { 64 | return r 65 | } 66 | } else if unicode.IsLetter(r) || unicode.IsNumber(r) { 67 | return r 68 | } 69 | 70 | return -1 71 | } 72 | 73 | pattern = strings.Map(mapper, pattern) 74 | c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern) 75 | 76 | if c.tempDirErr == nil { 77 | c.Cleanup(func() { 78 | if err := os.RemoveAll(c.tempDir); err != nil { 79 | c.Errorf("TempDir RemoveAll cleanup: %v", err) 80 | } 81 | }) 82 | } 83 | } 84 | 85 | if c.tempDirErr == nil { 86 | c.tempDirSeq++ 87 | } 88 | 89 | seq := c.tempDirSeq 90 | 91 | c.tempDirMu.Unlock() 92 | 93 | if c.tempDirErr != nil { 94 | c.Fatalf("TempDir: %v", c.tempDirErr) 95 | } 96 | 97 | dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq) 98 | 99 | //nolint:gosec // copied from the stdlib 100 | if err := os.Mkdir(dir, 0o777); err != nil { 101 | c.Fatalf("TempDir: %v", err) 102 | } 103 | 104 | return dir 105 | } 106 | -------------------------------------------------------------------------------- /pkg/framework/core/constants/constants.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | // Context names constants 4 | const ( 5 | TestContextName = "test" 6 | BeforeEachContextName = "beforeEach" 7 | AfterEachContextName = "afterEach" 8 | BeforeAllContextName = "beforeAll" 9 | AfterAllContextName = "afterAll" 10 | ) 11 | -------------------------------------------------------------------------------- /pkg/framework/core/constants/constants_test.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestConstants(t *testing.T) { 10 | require.Equal(t, "test", TestContextName) 11 | require.Equal(t, "beforeEach", BeforeEachContextName) 12 | require.Equal(t, "afterEach", AfterEachContextName) 13 | require.Equal(t, "beforeAll", BeforeAllContextName) 14 | require.Equal(t, "afterAll", AfterAllContextName) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/framework/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ozontech/allure-go/pkg/framework 2 | 3 | go 1.17 4 | 5 | replace github.com/ozontech/allure-go/pkg/allure => ../allure 6 | 7 | require ( 8 | github.com/ozontech/allure-go/pkg/allure v0.6.14 9 | github.com/pkg/errors v0.9.1 10 | github.com/stretchr/testify v1.7.1 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/google/uuid v1.3.0 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | gopkg.in/yaml.v3 v3.0.0 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /pkg/framework/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 5 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 6 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 7 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 9 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 10 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 11 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 12 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 14 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 15 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 16 | gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= 17 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 18 | -------------------------------------------------------------------------------- /pkg/framework/provider/allure.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | ) 6 | 7 | type SystemLabels interface { 8 | Package(value string) 9 | FrameWork(value string) 10 | Host(value string) 11 | Thread(value string) 12 | Language(value string) 13 | } 14 | 15 | type SuiteLabels interface { 16 | AddSuiteLabel(value string) 17 | AddSubSuite(value string) 18 | AddParentSuite(value string) 19 | } 20 | 21 | type DescriptionLabels interface { 22 | ID(value string) 23 | AllureID(value string) 24 | Epic(value string) 25 | Layer(value string) 26 | Feature(value string) 27 | Story(value string) 28 | Severity(severityType allure.SeverityType) 29 | Tag(value string) 30 | Tags(values ...string) 31 | Owner(value string) 32 | Lead(value string) 33 | Label(label *allure.Label) 34 | Labels(labels ...*allure.Label) 35 | ReplaceLabel(label *allure.Label) 36 | } 37 | 38 | type Links interface { 39 | SetIssue(issue string) 40 | SetTestCase(testCase string) 41 | Link(link *allure.Link) 42 | TmsLink(tmsCase string) 43 | TmsLinks(tmsCases ...string) 44 | } 45 | 46 | type DescriptionFields interface { 47 | Title(args ...interface{}) 48 | Titlef(format string, args ...interface{}) 49 | Description(args ...interface{}) 50 | Descriptionf(format string, args ...interface{}) 51 | Stage(args ...interface{}) 52 | Stagef(format string, args ...interface{}) 53 | } 54 | 55 | type AllureSteps interface { 56 | Step(step *allure.Step) 57 | NewStep(stepName string, params ...*allure.Parameter) 58 | } 59 | 60 | type Attachments interface { 61 | WithAttachments(attachment ...*allure.Attachment) 62 | WithNewAttachment(name string, mimeType allure.MimeType, content []byte) 63 | } 64 | 65 | type Parameters interface { 66 | WithParameters(params ...*allure.Parameter) 67 | WithNewParameters(kv ...interface{}) 68 | } 69 | 70 | type AllureForward interface { 71 | DescriptionLabels 72 | SuiteLabels 73 | Links 74 | DescriptionFields 75 | AllureSteps 76 | Attachments 77 | Parameters 78 | } 79 | 80 | type AllureForwardFull interface { 81 | AllureForward 82 | SystemLabels 83 | } 84 | -------------------------------------------------------------------------------- /pkg/framework/provider/provider.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "github.com/ozontech/allure-go/pkg/allure" 5 | ) 6 | 7 | type Provider interface { 8 | AllureForwardFull 9 | 10 | GetResult() *allure.Result 11 | UpdateResultStatus(msg string, trace string) 12 | StopResult(status allure.Status) 13 | 14 | SetTestMeta(meta TestMeta) 15 | GetTestMeta() TestMeta 16 | GetSuiteMeta() SuiteMeta 17 | ExecutionContext() ExecutionContext 18 | 19 | TestContext() 20 | BeforeEachContext() 21 | AfterEachContext() 22 | BeforeAllContext() 23 | AfterAllContext() 24 | 25 | NewTest(testName, packageName string, tags ...string) 26 | FinishTest() error 27 | } 28 | 29 | type TestMeta interface { 30 | GetResult() *allure.Result 31 | SetResult(result *allure.Result) 32 | 33 | GetContainer() *allure.Container 34 | 35 | SetBeforeEach(hook func(T)) 36 | GetBeforeEach() func(T) 37 | SetAfterEach(hook func(T)) 38 | GetAfterEach() func(T) 39 | } 40 | 41 | type SuiteMeta interface { 42 | GetPackageName() string 43 | GetRunner() string 44 | GetSuiteName() string 45 | GetParentSuite() string 46 | GetSuiteFullName() string 47 | GetContainer() *allure.Container 48 | 49 | SetBeforeAll(func(T)) 50 | SetAfterAll(func(T)) 51 | GetBeforeAll() func(T) 52 | GetAfterAll() func(T) 53 | } 54 | 55 | type ExecutionContext interface { 56 | AddStep(step *allure.Step) 57 | AddAttachments(attachment ...*allure.Attachment) 58 | GetName() string 59 | } 60 | -------------------------------------------------------------------------------- /pkg/framework/provider/test.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/ozontech/allure-go/pkg/allure" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | type TestingT interface { 12 | testing.TB 13 | 14 | Parallel() 15 | Run(testName string, testBody func(t *testing.T)) bool 16 | } 17 | 18 | type T interface { 19 | testing.TB 20 | 21 | AllureForward 22 | 23 | Parallel() 24 | 25 | RealT() TestingT 26 | XSkip() 27 | Break(args ...interface{}) 28 | Breakf(format string, args ...interface{}) 29 | Broken() 30 | BrokenNow() 31 | SkipOnPrint() 32 | Assert() Asserts 33 | Require() Asserts 34 | Run(testName string, testBody func(T), tags ...string) *allure.Result 35 | 36 | LogStep(args ...interface{}) 37 | LogfStep(format string, args ...interface{}) 38 | WithNewStep(stepName string, step func(sCtx StepCtx), params ...*allure.Parameter) 39 | WithNewAsyncStep(stepName string, step func(sCtx StepCtx), params ...*allure.Parameter) 40 | WithTestSetup(setup func(T)) 41 | WithTestTeardown(teardown func(T)) 42 | } 43 | 44 | type StepCtx interface { 45 | Step(step *allure.Step) 46 | NewStep(stepName string, parameters ...*allure.Parameter) 47 | WithNewStep(stepName string, step func(sCtx StepCtx), params ...*allure.Parameter) 48 | WithNewAsyncStep(stepName string, step func(sCtx StepCtx), params ...*allure.Parameter) 49 | 50 | WithParameters(parameters ...*allure.Parameter) 51 | WithNewParameters(kv ...interface{}) 52 | 53 | WithAttachments(attachment ...*allure.Attachment) 54 | WithNewAttachment(name string, mimeType allure.MimeType, content []byte) 55 | 56 | Assert() Asserts 57 | Require() Asserts 58 | 59 | LogStep(args ...interface{}) 60 | LogfStep(format string, args ...interface{}) 61 | WithStatusDetails(message, trace string) 62 | CurrentStep() *allure.Step 63 | 64 | Broken() 65 | BrokenNow() 66 | 67 | Fail() 68 | FailNow() 69 | Log(args ...interface{}) 70 | Logf(format string, args ...interface{}) 71 | Error(args ...interface{}) 72 | Errorf(format string, args ...interface{}) 73 | Break(args ...interface{}) 74 | Breakf(format string, args ...interface{}) 75 | Name() string 76 | } 77 | 78 | // Asserts ... 79 | type Asserts interface { 80 | Exactly(expected, actual interface{}, msgAndArgs ...interface{}) 81 | Same(expected, actual interface{}, msgAndArgs ...interface{}) 82 | NotSame(expected, actual interface{}, msgAndArgs ...interface{}) 83 | Equal(expected, actual interface{}, msgAndArgs ...interface{}) 84 | NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) 85 | EqualValues(expected, actual interface{}, msgAndArgs ...interface{}) 86 | NotEqualValues(expected, actual interface{}, msgAndArgs ...interface{}) 87 | Error(err error, msgAndArgs ...interface{}) 88 | NoError(err error, msgAndArgs ...interface{}) 89 | EqualError(theError error, errString string, msgAndArgs ...interface{}) 90 | ErrorIs(err, target error, msgAndArgs ...interface{}) 91 | ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) 92 | NotNil(object interface{}, msgAndArgs ...interface{}) 93 | Nil(object interface{}, msgAndArgs ...interface{}) 94 | Len(object interface{}, length int, msgAndArgs ...interface{}) 95 | NotContains(s, contains interface{}, msgAndArgs ...interface{}) 96 | Contains(s, contains interface{}, msgAndArgs ...interface{}) 97 | Greater(e1, e2 interface{}, msgAndArgs ...interface{}) 98 | GreaterOrEqual(e1, e2 interface{}, msgAndArgs ...interface{}) 99 | Less(e1, e2 interface{}, msgAndArgs ...interface{}) 100 | LessOrEqual(e1, e2 interface{}, msgAndArgs ...interface{}) 101 | Implements(interfaceObject, object interface{}, msgAndArgs ...interface{}) 102 | Empty(object interface{}, msgAndArgs ...interface{}) 103 | NotEmpty(object interface{}, msgAndArgs ...interface{}) 104 | WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) 105 | JSONEq(expected, actual string, msgAndArgs ...interface{}) 106 | JSONContains(expected, actual string, msgAndArgs ...interface{}) 107 | Subset(list, subset interface{}, msgAndArgs ...interface{}) 108 | NotSubset(list, subset interface{}, msgAndArgs ...interface{}) 109 | IsType(expectedType, object interface{}, msgAndArgs ...interface{}) 110 | True(value bool, msgAndArgs ...interface{}) 111 | False(value bool, msgAndArgs ...interface{}) 112 | Regexp(rx, str interface{}, msgAndArgs ...interface{}) 113 | ElementsMatch(listA, listB interface{}, msgAndArgs ...interface{}) 114 | DirExists(path string, msgAndArgs ...interface{}) 115 | Condition(condition assert.Comparison, msgAndArgs ...interface{}) 116 | Zero(i interface{}, msgAndArgs ...interface{}) 117 | NotZero(i interface{}, msgAndArgs ...interface{}) 118 | InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) 119 | Eventually(condition func() bool, waitFor, tick time.Duration, msgAndArgs ...interface{}) 120 | } 121 | -------------------------------------------------------------------------------- /pkg/framework/runner/contants.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | const ( 4 | tableParamPrefix = "Param" 5 | tableTestPrefix = "TableTest" 6 | testPrefix = "Test" 7 | ) 8 | 9 | // magic number of depth caller to find test's caller package 10 | const defaultPackageDepth = 2 11 | -------------------------------------------------------------------------------- /pkg/framework/runner/interfaces.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | 7 | "github.com/ozontech/allure-go/pkg/allure" 8 | "github.com/ozontech/allure-go/pkg/framework/provider" 9 | ) 10 | 11 | // AllureBeforeTest has a BeforeEach method, which will run before each 12 | // test in the suite. 13 | type AllureBeforeTest interface { 14 | BeforeEach(t provider.T) 15 | } 16 | 17 | // AllureAfterTest has a AfterEach method, which will run after 18 | // each test in the suite. 19 | type AllureAfterTest interface { 20 | AfterEach(t provider.T) 21 | } 22 | 23 | // AllureBeforeSuite has a BeforeAll method, which will run before the 24 | // tests in the suite are run. 25 | type AllureBeforeSuite interface { 26 | BeforeAll(t provider.T) 27 | } 28 | 29 | // AllureAfterSuite has a AfterAll method, which will run after 30 | // all the tests in the suite have been run. 31 | type AllureAfterSuite interface { 32 | AfterAll(t provider.T) 33 | } 34 | 35 | // AllureIDSuite has a GetAllureID method, 36 | // which will produce allureIDs for the test by its name 37 | type AllureIDSuite interface { 38 | GetAllureID(testName string) string 39 | } 40 | 41 | // ParametrizedSuite suit can initialize parameters for 42 | // parametrized test before running hooks 43 | type ParametrizedSuite interface { 44 | InitializeTestsParams() 45 | } 46 | 47 | // ParametrizedTestParam parameter for parametrized test 48 | // with custom AllureId and Title 49 | type ParametrizedTestParam interface { 50 | GetAllureID() string 51 | GetAllureTitle() string 52 | } 53 | 54 | type TestSuite interface { 55 | GetRunner() TestRunner 56 | SetRunner(runner TestRunner) 57 | } 58 | 59 | type TestingT interface { 60 | testing.TB 61 | 62 | Parallel() 63 | Run(testName string, testBody func(t *testing.T)) bool 64 | } 65 | 66 | type TestRunner interface { 67 | NewTest(testName string, testBody func(provider.T), tags ...string) 68 | BeforeEach(hookBody func(provider.T)) 69 | AfterEach(hookBody func(provider.T)) 70 | BeforeAll(hookBody func(provider.T)) 71 | AfterAll(hookBody func(provider.T)) 72 | RunTests() SuiteResult 73 | } 74 | 75 | type Test interface { 76 | GetBody() TestBody 77 | GetMeta() provider.TestMeta 78 | } 79 | 80 | type SuiteResult interface { 81 | NewResult(result TestResult) 82 | GetContainer() *allure.Container 83 | GetAllTestResults() []TestResult 84 | GetResultByName(name string) TestResult 85 | GetResultByUUID(uuid string) TestResult 86 | ToJSON() ([]byte, error) 87 | } 88 | 89 | type TestResult interface { 90 | GetResult() *allure.Result 91 | GetContainer() *allure.Container 92 | Print() error 93 | ToJSON() ([]byte, error) 94 | } 95 | 96 | type internalT interface { 97 | provider.T 98 | 99 | SetRealT(t provider.TestingT) 100 | GetProvider() provider.Provider 101 | WG() *sync.WaitGroup 102 | GetResult() *allure.Result 103 | } 104 | -------------------------------------------------------------------------------- /pkg/framework/runner/tests.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "reflect" 7 | "sync" 8 | 9 | "github.com/ozontech/allure-go/pkg/allure" 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | ) 12 | 13 | type suiteResult struct { 14 | Container *allure.Container `json:"container,omitempty"` 15 | TestResults []TestResult `json:"test_results,omitempty"` 16 | 17 | mu sync.Mutex 18 | } 19 | 20 | // NewSuiteResult Returns new SuiteResult 21 | func NewSuiteResult(container *allure.Container) SuiteResult { 22 | return &suiteResult{Container: container} 23 | } 24 | 25 | // NewResult appends test result to suite result 26 | func (sr *suiteResult) NewResult(result TestResult) { 27 | sr.mu.Lock() 28 | defer sr.mu.Unlock() 29 | 30 | sr.TestResults = append(sr.TestResults, result) 31 | } 32 | 33 | // GetContainer returns parent Container 34 | func (sr *suiteResult) GetContainer() *allure.Container { 35 | return sr.Container 36 | } 37 | 38 | // GetAllTestResults returns all test results of suite 39 | func (sr *suiteResult) GetAllTestResults() []TestResult { 40 | return sr.TestResults 41 | } 42 | 43 | // GetResultByName searches result by name and returns it 44 | func (sr *suiteResult) GetResultByName(name string) TestResult { 45 | for _, tr := range sr.TestResults { 46 | if r := tr.GetResult(); r != nil { 47 | if r.Name == name { 48 | return tr 49 | } 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | // GetResultByUUID searches result by UUID and returns it 57 | func (sr *suiteResult) GetResultByUUID(uuid string) TestResult { 58 | for _, tr := range sr.TestResults { 59 | if r := tr.GetResult(); r != nil { 60 | if r.UUID.String() == uuid { 61 | return tr 62 | } 63 | } 64 | } 65 | return nil 66 | } 67 | 68 | // ToJSON marshall result to Json object 69 | // 70 | // Deprecated: use [json.Marshal] instead. 71 | func (sr *suiteResult) ToJSON() ([]byte, error) { 72 | return json.Marshal(sr) 73 | } 74 | 75 | type testResult struct { 76 | Result *allure.Result `json:"result,omitempty"` 77 | Container *allure.Container `json:"container,omitempty"` 78 | } 79 | 80 | // NewTestResult returns new test result 81 | func NewTestResult(result *allure.Result, container *allure.Container) TestResult { 82 | return &testResult{ 83 | Result: result, 84 | Container: container, 85 | } 86 | } 87 | 88 | // GetResult returns result 89 | func (tr *testResult) GetResult() *allure.Result { 90 | return tr.Result 91 | } 92 | 93 | // GetContainer returns Container 94 | func (tr *testResult) GetContainer() *allure.Container { 95 | return tr.Container 96 | } 97 | 98 | // Print returns print 99 | func (tr *testResult) Print() error { 100 | var ( 101 | resultErr error 102 | containerErr error 103 | ) 104 | 105 | result := tr.GetResult() 106 | 107 | if result != nil { 108 | resultErr = result.Done() 109 | } else { 110 | resultErr = fmt.Errorf("failed to print Result. Reason: *allure.Result is nil") 111 | } 112 | 113 | container := tr.GetContainer() 114 | if container != nil { 115 | containerErr = container.Done() 116 | } else { 117 | containerErr = fmt.Errorf("failed to print Container. Reason: *allure.Container is nil") 118 | } 119 | 120 | if resultErr != nil && containerErr != nil { 121 | return fmt.Errorf("failed to print Result. Reason: %s\nAlso failed to print Container. Reason: %s", resultErr, containerErr) 122 | } 123 | 124 | if resultErr != nil { 125 | return resultErr 126 | } 127 | 128 | if containerErr != nil { 129 | return containerErr 130 | } 131 | 132 | return nil 133 | } 134 | 135 | // ToJSON marshall TestResult to the JSON 136 | // 137 | // Deprecated: use [json.Marshal] instead 138 | func (tr *testResult) ToJSON() ([]byte, error) { 139 | return json.Marshal(tr) 140 | } 141 | 142 | type TestBody func(t provider.T) 143 | 144 | type testMethod struct { 145 | testMeta provider.TestMeta 146 | testBody reflect.Method 147 | callArgs []reflect.Value 148 | } 149 | 150 | // GetArgs returns call args of the test 151 | func (t *testMethod) GetArgs() []reflect.Value { 152 | return t.callArgs 153 | } 154 | 155 | // GetRawBody returns reflect.Method of the test 156 | func (t *testMethod) GetRawBody() reflect.Method { 157 | return t.testBody 158 | } 159 | 160 | // GetBody returns wrapped function at the test 161 | func (t *testMethod) GetBody() TestBody { 162 | return func(pT provider.T) { 163 | t.testBody.Func.Call(insert(t.callArgs, 1, reflect.ValueOf(pT))) 164 | } 165 | } 166 | 167 | // GetMeta returns provider.TestMeta of the test 168 | func (t *testMethod) GetMeta() provider.TestMeta { 169 | return t.testMeta 170 | } 171 | 172 | type testFunc struct { 173 | testBody TestBody 174 | testMeta provider.TestMeta 175 | } 176 | 177 | // GetBody returns test function 178 | func (t *testFunc) GetBody() TestBody { 179 | return t.testBody 180 | } 181 | 182 | // GetMeta returns provider.TestMeta of the test 183 | func (t *testFunc) GetMeta() provider.TestMeta { 184 | return t.testMeta 185 | } 186 | 187 | func newTestFunc(body TestBody, testMeta provider.TestMeta) *testFunc { 188 | return &testFunc{ 189 | testBody: body, 190 | testMeta: testMeta, 191 | } 192 | } 193 | 194 | func insert(a []reflect.Value, index int, value reflect.Value) []reflect.Value { 195 | if len(a) == index { // nil or empty slice or after last element 196 | return append(a, value) 197 | } 198 | 199 | a = append(a[:index+1], a[index:]...) // index < len(a) 200 | a[index] = value 201 | 202 | return a 203 | } 204 | -------------------------------------------------------------------------------- /pkg/framework/suite/suite.go: -------------------------------------------------------------------------------- 1 | package suite 2 | 3 | import ( 4 | "reflect" 5 | "runtime" 6 | "strings" 7 | 8 | "github.com/ozontech/allure-go/pkg/framework/provider" 9 | "github.com/ozontech/allure-go/pkg/framework/runner" 10 | ) 11 | 12 | type Suite struct { 13 | runner runner.TestRunner 14 | } 15 | 16 | func (s *Suite) GetRunner() runner.TestRunner { 17 | return s.runner 18 | } 19 | 20 | func (s *Suite) SetRunner(runner runner.TestRunner) { 21 | s.runner = runner 22 | } 23 | 24 | func (s *Suite) RunSuite(t provider.T, suite runner.TestSuite) runner.SuiteResult { 25 | t.SkipOnPrint() 26 | parts := strings.Split(t.RealT().Name(), "/") 27 | parentName := parts[len(parts)-3] 28 | 29 | return runner.NewSuiteRunnerWithParent(t.RealT(), getPackage(2), cleanName(getSuiteName(suite)), parentName, suite).RunTests() 30 | } 31 | 32 | func (s *Suite) RunNamedSuite(t provider.T, suiteName string, suite runner.TestSuite) runner.SuiteResult { 33 | t.SkipOnPrint() 34 | parts := strings.Split(t.RealT().Name(), "/") 35 | parentName := parts[len(parts)-3] 36 | 37 | return runner.NewSuiteRunnerWithParent(t.RealT(), getPackage(2), suiteName, parentName, suite).RunTests() 38 | } 39 | 40 | func RunSuite(t provider.TestingT, suite runner.TestSuite) runner.SuiteResult { 41 | return runner.NewSuiteRunner(t, getPackage(2), getSuiteName(suite), suite).RunTests() 42 | } 43 | 44 | func RunNamedSuite(t provider.TestingT, suiteName string, suite runner.TestSuite) runner.SuiteResult { 45 | return runner.NewSuiteRunner(t, getPackage(2), suiteName, suite).RunTests() 46 | } 47 | 48 | func getSuiteName(suite interface{}) string { 49 | s := reflect.TypeOf(suite) 50 | if s.Kind() == reflect.Ptr { 51 | return s.Elem().Name() 52 | } 53 | 54 | return s.Name() 55 | } 56 | 57 | func cleanName(fullName string) string { 58 | nameParts := strings.Split(fullName, "/") 59 | 60 | removeIDs := make([]int, 0, len(nameParts)) 61 | 62 | for idx, namePart := range nameParts { 63 | if strings.HasSuffix(namePart, "_Tests") { 64 | removeIDs = append(removeIDs, idx) 65 | } 66 | } 67 | 68 | for _, idx := range removeIDs { 69 | nameParts = remove(nameParts, idx) 70 | } 71 | 72 | return strings.Join(nameParts, "/") 73 | } 74 | 75 | func remove(slice []string, s int) []string { 76 | return append(slice[:s], slice[s+1:]...) 77 | } 78 | 79 | func getPackage(depth int) string { 80 | pc, _, _, _ := runtime.Caller(depth) 81 | funcName := runtime.FuncForPC(pc).Name() 82 | lastSlash := strings.LastIndexByte(funcName, '/') 83 | if lastSlash < 0 { 84 | lastSlash = 0 85 | } 86 | 87 | lastDot := strings.LastIndexByte(funcName[lastSlash:], '.') + lastSlash 88 | 89 | return funcName[:lastDot] 90 | } 91 | -------------------------------------------------------------------------------- /pkg/framework/suite/suite_runner_test.go: -------------------------------------------------------------------------------- 1 | package suite 2 | 3 | import ( 4 | "os" 5 | "sync" 6 | "testing" 7 | "time" 8 | 9 | "github.com/ozontech/allure-go/pkg/framework/provider" 10 | "github.com/ozontech/allure-go/pkg/framework/runner" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | type suiteRunnerTMock struct { 15 | testing.TB 16 | 17 | t *testing.T 18 | failNow bool 19 | parallel bool 20 | } 21 | 22 | func (m *suiteRunnerTMock) Name() string { 23 | return "testSuite" 24 | } 25 | 26 | func (m *suiteRunnerTMock) Parallel() { 27 | m.parallel = true 28 | } 29 | 30 | func (m *suiteRunnerTMock) FailNow() { 31 | m.failNow = true 32 | } 33 | 34 | func (m *suiteRunnerTMock) Run(testName string, testBody func(t *testing.T)) bool { 35 | testBody(m.t) 36 | return true 37 | } 38 | 39 | type TestSuiteRunner struct { 40 | Suite 41 | testSome1 bool 42 | testSome2 bool 43 | } 44 | 45 | func (s *TestSuiteRunner) TestSome1(t provider.T) { 46 | s.testSome1 = true 47 | } 48 | 49 | func (s *TestSuiteRunner) TestSome2(t provider.T) { 50 | s.testSome2 = true 51 | } 52 | 53 | func TestSuiteRunner_RunTests(t *testing.T) { 54 | allureDir := "./allure-results" 55 | defer os.RemoveAll(allureDir) 56 | 57 | suite := new(TestSuiteRunner) 58 | 59 | r := runner.NewSuiteRunner(t, "packageName", "suiteName", suite) 60 | r.RunTests() 61 | 62 | require.True(t, suite.testSome1) 63 | require.True(t, suite.testSome2) 64 | } 65 | 66 | type TestSuiteRunnerPanic struct { 67 | Suite 68 | wg sync.WaitGroup 69 | testSome1 bool 70 | } 71 | 72 | func (s *TestSuiteRunnerPanic) TestSome1(t provider.T) { 73 | defer s.wg.Done() 74 | s.testSome1 = true 75 | panic("whoops") 76 | } 77 | 78 | func TestRunner_RunTests_panic(t *testing.T) { 79 | t.Skipf("This test need to be reworked") 80 | allureDir := "./allure-results" 81 | defer os.RemoveAll(allureDir) 82 | 83 | suite := new(TestSuiteRunnerPanic) 84 | suite.wg = sync.WaitGroup{} 85 | mockT := &suiteRunnerTMock{t: new(testing.T)} 86 | r := runner.NewSuiteRunner(mockT, "packageName", "suiteName", suite) 87 | suite.wg.Add(1) 88 | go require.NotPanics(t, func() { 89 | r.RunTests() 90 | }) 91 | suite.wg.Wait() 92 | require.True(t, suite.testSome1) 93 | } 94 | 95 | type TestSuiteRunnerHooks struct { 96 | Suite 97 | wg sync.WaitGroup 98 | testSome1 bool 99 | 100 | beforeAll bool 101 | beforeEach bool 102 | afterEach bool 103 | afterAll bool 104 | } 105 | 106 | func (s *TestSuiteRunnerHooks) BeforeAll(t provider.T) { 107 | s.beforeAll = true 108 | } 109 | 110 | func (s *TestSuiteRunnerHooks) BeforeEach(t provider.T) { 111 | s.beforeEach = true 112 | } 113 | 114 | func (s *TestSuiteRunnerHooks) AfterEach(t provider.T) { 115 | s.afterEach = true 116 | } 117 | 118 | func (s *TestSuiteRunnerHooks) AfterAll(t provider.T) { 119 | s.afterAll = true 120 | } 121 | 122 | func (s *TestSuiteRunnerHooks) TestSome(t provider.T) { 123 | s.testSome1 = true 124 | } 125 | 126 | func TestRunner_hooks(t *testing.T) { 127 | t.Skipf("This test need to be reworked") 128 | allureDir := "./allure-results" 129 | defer os.RemoveAll(allureDir) 130 | 131 | suite := new(TestSuiteRunnerHooks) 132 | mockT := &suiteRunnerTMock{t: new(testing.T)} 133 | r := runner.NewSuiteRunner(mockT, "packageName", "suiteName", suite) 134 | r.RunTests() 135 | 136 | require.True(t, suite.beforeAll) 137 | require.True(t, suite.beforeEach) 138 | require.True(t, suite.afterEach) 139 | require.True(t, suite.afterAll) 140 | require.True(t, suite.testSome1) 141 | } 142 | 143 | type TestSuiteStartTimeOfConsistentTests struct { 144 | Suite 145 | } 146 | 147 | func (s *TestSuiteStartTimeOfConsistentTests) TestSome1(t provider.T) { 148 | t.WithNewStep("step 1", func(sCtx provider.StepCtx) { 149 | time.Sleep(1 * time.Second) 150 | }) 151 | } 152 | 153 | func (s *TestSuiteStartTimeOfConsistentTests) TestSome2(t provider.T) { 154 | t.WithNewStep("step 2", func(sCtx provider.StepCtx) { 155 | time.Sleep(1 * time.Second) 156 | }) 157 | } 158 | 159 | func TestSuiteRunner_StartTimeAndDurationOfConsistentTests(t *testing.T) { 160 | allureDir := "./allure-results" 161 | defer os.RemoveAll(allureDir) 162 | 163 | suite := new(TestSuiteStartTimeOfConsistentTests) 164 | r := runner.NewSuiteRunner(t, "packageName", "suiteName", suite) 165 | results := r.RunTests().GetAllTestResults() 166 | 167 | require.True(t, results[1].GetResult().Start-results[0].GetResult().Stop <= 15) 168 | require.Equal(t, time.UnixMilli(results[0].GetResult().Stop-results[0].GetResult().Start).Second(), 1) 169 | require.Equal(t, time.UnixMilli(results[1].GetResult().Stop-results[1].GetResult().Start).Second(), 1) 170 | } 171 | -------------------------------------------------------------------------------- /pkg/framework/suite/suite_test.go: -------------------------------------------------------------------------------- 1 | package suite 2 | 3 | import ( 4 | "os" 5 | "sync" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/ozontech/allure-go/pkg/framework/provider" 11 | "github.com/ozontech/allure-go/pkg/framework/runner" 12 | ) 13 | 14 | func TestSuite_SetRunner(t *testing.T) { 15 | suite := Suite{} 16 | r := runner.NewRunner(new(testing.T), "suiteName") 17 | suite.SetRunner(r) 18 | require.Equal(t, r, suite.runner) 19 | } 20 | 21 | func TestSuite_GetRunner(t *testing.T) { 22 | r := runner.NewRunner(new(testing.T), "suiteName") 23 | suite := Suite{runner: r} 24 | require.Equal(t, r, suite.GetRunner()) 25 | } 26 | 27 | type TestSuiteRunSuite struct { 28 | Suite 29 | s2 *TestSuiteRunSuite2 30 | } 31 | 32 | func (s *TestSuiteRunSuite) TestSome(t provider.T) { 33 | s.s2 = new(TestSuiteRunSuite2) 34 | s.RunSuite(t, s.s2) 35 | } 36 | 37 | type TestSuiteRunSuite2 struct { 38 | Suite 39 | 40 | wg sync.WaitGroup 41 | testSome1 bool 42 | 43 | beforeAll bool 44 | beforeEach bool 45 | afterEach bool 46 | afterAll bool 47 | } 48 | 49 | func (s *TestSuiteRunSuite2) BeforeAll(t provider.T) { 50 | s.beforeAll = true 51 | } 52 | 53 | func (s *TestSuiteRunSuite2) BeforeEach(t provider.T) { 54 | s.beforeEach = true 55 | } 56 | 57 | func (s *TestSuiteRunSuite2) AfterEach(t provider.T) { 58 | s.afterEach = true 59 | } 60 | 61 | func (s *TestSuiteRunSuite2) AfterAll(t provider.T) { 62 | s.afterAll = true 63 | } 64 | 65 | func (s *TestSuiteRunSuite2) TestSome(t provider.T) { 66 | s.testSome1 = true 67 | } 68 | 69 | func TestSuite_RunSuite(t *testing.T) { 70 | allureDir := "./allure-results" 71 | defer os.RemoveAll(allureDir) 72 | 73 | suite := new(TestSuiteRunSuite) 74 | mockT := &suiteRunnerTMock{t: t} 75 | r := runner.NewSuiteRunner(mockT, "packageName", "suiteName", suite) 76 | r.RunTests() 77 | 78 | // subtests have been run 79 | require.True(t, suite.s2.testSome1) 80 | require.True(t, suite.s2.beforeEach) 81 | require.True(t, suite.s2.beforeAll) 82 | require.True(t, suite.s2.afterEach) 83 | require.True(t, suite.s2.afterAll) 84 | } 85 | --------------------------------------------------------------------------------