diff --git a/api/transactions.yaml b/api/transactions.yaml index 37eb87451f..800df100e1 100644 --- a/api/transactions.yaml +++ b/api/transactions.yaml @@ -29,7 +29,6 @@ components: properties: id: type: string - readOnly: true name: type: string description: diff --git a/cli/openapi/model_transaction.go b/cli/openapi/model_transaction.go index 898bf08637..cafb423e75 100644 --- a/cli/openapi/model_transaction.go +++ b/cli/openapi/model_transaction.go @@ -316,7 +316,9 @@ func (o Transaction) MarshalJSON() ([]byte, error) { func (o Transaction) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - // skip: id is readOnly + if !isNil(o.Id) { + toSerialize["id"] = o.Id + } if !isNil(o.Name) { toSerialize["name"] = o.Name } diff --git a/testing/cli-e2etest/Makefile b/testing/cli-e2etest/Makefile index dbb99c630f..900c522f54 100644 --- a/testing/cli-e2etest/Makefile +++ b/testing/cli-e2etest/Makefile @@ -9,9 +9,13 @@ help: Makefile ## show list of commands @awk 'BEGIN {FS = ":.*?## "} /[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-40s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort test: # run tests for this application - go clean -testcache - go test -timeout 300s -p 1 ./... + export TRACETEST_CLI=$(TRACETEST_CLI); \ + export TEST_ENVIRONMENT=$(TEST_ENVIRONMENT); \ + export TAG=$(TAG); \ + export ENABLE_CLI_DEBUG=$(ENABLE_CLI_DEBUG); \ + go clean -testcache; \ + go test -timeout 300s -p 1 ./...; test/debug: # run tests for this application with debug mode enabled - ENABLE_CLI_DEBUG="true" - make test + export ENABLE_CLI_DEBUG="true"; \ + make test; diff --git a/testing/cli-e2etest/README.md b/testing/cli-e2etest/README.md index cc999721b6..ba4a8890c6 100644 --- a/testing/cli-e2etest/README.md +++ b/testing/cli-e2etest/README.md @@ -31,10 +31,10 @@ The main idea is to test every CLI command against the Tracetest server with dif | CLI Command | Test scenarios | | ------------------------------------------------------------------ | -------------- | | `test list` | | -| `test run -d [test-definition]` | [TestRunTestWithGrpcTrigger](./testscenarios/test/run_test_with_grpc_trigger_test.go) | -| `test run -d [test-definition] -e [environment-id]` | [TestRunTestWithHttpTriggerAndEnvironmentFile](./testscenarios/test/run_test_with_http_trigger_and_environment_file_test.go) | -| `test run -d [test-definition] -e [environment-definition]` | [TestRunTestWithHttpTriggerAndEnvironmentFile](./testscenarios/test/run_test_with_http_trigger_and_environment_file_test.go) | -| `test run -d [transaction-definition]` | | +| `test run -d [test-definition]` | [RunTestWithGrpcTrigger](./testscenarios/test/run_test_with_grpc_trigger_test.go) | +| `test run -d [test-definition] -e [environment-id]` | [RunTestWithHttpTriggerAndEnvironmentFile](./testscenarios/test/run_test_with_http_trigger_and_environment_file_test.go) | +| `test run -d [test-definition] -e [environment-definition]` | [RunTestWithHttpTriggerAndEnvironmentFile](./testscenarios/test/run_test_with_http_trigger_and_environment_file_test.go) | +| `test run -d [transaction-definition]` | [RunTransaction](./testscenarios/transaction//run_transaction_test.go) | | `test run -d [transaction-definition] -e [environment-id]` | | | `test run -d [transaction-definition] -e [environment-definition]` | | @@ -117,19 +117,19 @@ The main idea is to test every CLI command against the Tracetest server with dif | CLI Command | Test scenarios | | ----------------------------------------------------------- | -------------- | -| `apply transaction -f [new-transaction-file]` | | -| `apply transaction -f [existing-transaction-file]` | | -| `delete transaction --id [existing-id]` | | -| `delete transaction --id [non-existing-id]` | | -| `get transaction --id [non-existing-id]` | | -| `get transaction --id [existing-id] --output pretty` | | -| `get transaction --id [existing-id] --output json` | | -| `get transaction --id [existing-id] --output yaml` | | -| `list transaction --output pretty` | | -| `list transaction --output json` | | -| `list transaction --output yaml` | | -| `list transaction --skip 1 --take 2` | | -| `list transaction --sortBy name --sortDirection asc` | | +| `apply transaction -f [new-transaction-file]` | [ApplyTransaction](./testscenarios/transaction/apply_transaction_test.go) | +| `apply transaction -f [existing-transaction-file]` | [ApplyTransaction](./testscenarios/transaction/apply_transaction_test.go) | +| `delete transaction --id [existing-id]` | [DeleteTransaction](./testscenarios/transaction/delete_transaction_test.go) | +| `delete transaction --id [non-existing-id]` | [DeleteTransaction](./testscenarios/transaction/delete_transaction_test.go) | +| `get transaction --id [non-existing-id]` | [GetTransaction](./testscenarios/transaction/get_transaction_test.go), [DeleteTransaction](./testscenarios/transaction/delete_transaction_test.go) | +| `get transaction --id [existing-id] --output pretty` | [GetTransaction](./testscenarios/transaction/get_transaction_test.go) | +| `get transaction --id [existing-id] --output json` | [GetTransaction](./testscenarios/transaction/get_transaction_test.go) | +| `get transaction --id [existing-id] --output yaml` | [GetTransaction](./testscenarios/transaction/get_transaction_test.go) | +| `list transaction --output pretty` | [ListTransaction](./testscenarios/transaction/list_transactions_test.go) | +| `list transaction --output json` | [ListTransaction](./testscenarios/transaction/list_transactions_test.go) | +| `list transaction --output yaml` | [ListTransaction](./testscenarios/transaction/list_transactions_test.go) | +| `list transaction --skip 1 --take 2` | [ListTransaction](./testscenarios/transaction/list_transactions_test.go) | +| `list transaction --sortBy name --sortDirection asc` | [ListTransaction](./testscenarios/transaction/list_transactions_test.go) | ### Resources: Tests diff --git a/testing/cli-e2etest/testscenarios/transaction/apply_transaction_test.go b/testing/cli-e2etest/testscenarios/transaction/apply_transaction_test.go new file mode 100644 index 0000000000..e94c61f346 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/apply_transaction_test.go @@ -0,0 +1,88 @@ +package transaction + +import ( + "fmt" + "testing" + + "github.com/kubeshop/tracetest/cli-e2etest/environment" + "github.com/kubeshop/tracetest/cli-e2etest/helpers" + "github.com/kubeshop/tracetest/cli-e2etest/testscenarios/types" + "github.com/kubeshop/tracetest/cli-e2etest/tracetestcli" + "github.com/stretchr/testify/require" +) + +func TestApplyTransaction(t *testing.T) { + // instantiate require with testing helper + require := require.New(t) + + // setup isolated e2e environment + env := environment.CreateAndStart(t) + defer env.Close(t) + + cliConfig := env.GetCLIConfigPath(t) + + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to set up a new transaction + // Then it should be applied with success + newTransactionPath := env.GetTestResourcePath(t, "new-transaction") + + result := tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", newTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transaction := helpers.UnmarshalYAML[types.TransactionResource](t, result.StdOut) + + require.Equal("Transaction", transaction.Type) + require.Equal("Qti5R3_VR", transaction.Spec.ID) + require.Equal("New Transaction", transaction.Spec.Name) + require.Equal("a transaction", transaction.Spec.Description) + require.Len(transaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", transaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", transaction.Spec.Steps[1]) + + // When I try to get the transaction applied on the last step + // Then it should return it + result = tracetestcli.Exec(t, "get transaction --id Qti5R3_VR --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + require.Equal("Transaction", transaction.Type) + require.Equal("Qti5R3_VR", transaction.Spec.ID) + require.Equal("New Transaction", transaction.Spec.Name) + require.Equal("a transaction", transaction.Spec.Description) + require.Len(transaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", transaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", transaction.Spec.Steps[1]) + + // When I try to update the last transaction + // Then it should be applied with success + updatedNewTransactionPath := env.GetTestResourcePath(t, "updated-new-transaction") + + result = tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", updatedNewTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + updatedTransaction := helpers.UnmarshalYAML[types.TransactionResource](t, result.StdOut) + require.Equal("Transaction", updatedTransaction.Type) + require.Equal("Qti5R3_VR", updatedTransaction.Spec.ID) + require.Equal("Updated Transaction", updatedTransaction.Spec.Name) + require.Equal("an updated transaction", updatedTransaction.Spec.Description) + require.Len(updatedTransaction.Spec.Steps, 3) + require.Equal("9wtAH2_Vg", updatedTransaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", updatedTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", updatedTransaction.Spec.Steps[2]) + + // When I try to get the transaction applied on the last step + // Then it should return it + result = tracetestcli.Exec(t, "get transaction --id Qti5R3_VR --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + updatedTransaction = helpers.UnmarshalYAML[types.TransactionResource](t, result.StdOut) + require.Equal("Transaction", updatedTransaction.Type) + require.Equal("Qti5R3_VR", updatedTransaction.Spec.ID) + require.Equal("Updated Transaction", updatedTransaction.Spec.Name) + require.Equal("an updated transaction", updatedTransaction.Spec.Description) + require.Len(updatedTransaction.Spec.Steps, 3) + require.Equal("9wtAH2_Vg", updatedTransaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", updatedTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", updatedTransaction.Spec.Steps[2]) +} diff --git a/testing/cli-e2etest/testscenarios/transaction/delete_transaction_test.go b/testing/cli-e2etest/testscenarios/transaction/delete_transaction_test.go new file mode 100644 index 0000000000..a185a7a9d6 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/delete_transaction_test.go @@ -0,0 +1,50 @@ +package transaction + +import ( + "fmt" + "testing" + + "github.com/kubeshop/tracetest/cli-e2etest/environment" + "github.com/kubeshop/tracetest/cli-e2etest/helpers" + "github.com/kubeshop/tracetest/cli-e2etest/tracetestcli" + "github.com/stretchr/testify/require" +) + +func TestDeleteTransaction(t *testing.T) { + // instantiate require with testing helper + require := require.New(t) + + // setup isolated e2e environment + env := environment.CreateAndStart(t) + defer env.Close(t) + + cliConfig := env.GetCLIConfigPath(t) + + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to delete a transaction that don't exist + // Then it should return an error and say that this resource does not exist + result := tracetestcli.Exec(t, "delete transaction --id dont-exist", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 1) + require.Contains(result.StdErr, "Resource transactions with ID dont-exist not found") // TODO: update this message to singular + + // When I try to set up a new transaction + // Then it should be applied with success + newTransactionPath := env.GetTestResourcePath(t, "new-transaction") + + result = tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", newTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + // When I try to delete the transaction + // Then it should delete with success + result = tracetestcli.Exec(t, "delete transaction --id Qti5R3_VR", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + require.Contains(result.StdOut, "✔ Transaction successfully deleted") + + // When I try to get a transaction again + // Then it should return a message saying that the transaction was not found + result = tracetestcli.Exec(t, "delete transaction --id Qti5R3_VR", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 1) + require.Contains(result.StdErr, "Resource transactions with ID Qti5R3_VR not found") +} diff --git a/testing/cli-e2etest/testscenarios/transaction/get_transaction_test.go b/testing/cli-e2etest/testscenarios/transaction/get_transaction_test.go new file mode 100644 index 0000000000..3358524dd9 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/get_transaction_test.go @@ -0,0 +1,108 @@ +package transaction + +import ( + "fmt" + "strings" + "testing" + + "github.com/kubeshop/tracetest/cli-e2etest/environment" + "github.com/kubeshop/tracetest/cli-e2etest/helpers" + "github.com/kubeshop/tracetest/cli-e2etest/testscenarios/types" + "github.com/kubeshop/tracetest/cli-e2etest/tracetestcli" + "github.com/stretchr/testify/require" +) + +func addGetTransactionPreReqs(t *testing.T, env environment.Manager) { + cliConfig := env.GetCLIConfigPath(t) + + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to set up a new transaction + // Then it should be applied with success + newTransactionPath := env.GetTestResourcePath(t, "new-transaction") + + result := tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", newTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) +} + +func TestGetTransaction(t *testing.T) { + // instantiate require with testing helper + require := require.New(t) + + env := environment.CreateAndStart(t) + defer env.Close(t) + + cliConfig := env.GetCLIConfigPath(t) + + t.Run("get with no transaction initialized", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + // And no transaction registered + + // When I try to get a transaction on yaml mode + // Then it should return a error message + result := tracetestcli.Exec(t, "get transaction --id no-id --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + require.Contains(result.StdOut, "Resource transaction with ID no-id not found") + }) + + addGetTransactionPreReqs(t, env) + + t.Run("get with YAML format", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + // And I have a transaction already set + + // When I try to get a transaction on yaml mode + // Then it should print a YAML + result := tracetestcli.Exec(t, "get transaction --id Qti5R3_VR --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transaction := helpers.UnmarshalYAML[types.TransactionResource](t, result.StdOut) + + require.Equal("Transaction", transaction.Type) + require.Equal("Qti5R3_VR", transaction.Spec.ID) + require.Equal("New Transaction", transaction.Spec.Name) + require.Equal("a transaction", transaction.Spec.Description) + require.Len(transaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", transaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", transaction.Spec.Steps[1]) + }) + + t.Run("get with JSON format", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + // And I have a transaction already set + + // When I try to get a transaction on json mode + // Then it should print a json + result := tracetestcli.Exec(t, "get transaction --id Qti5R3_VR --output json", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transaction := helpers.UnmarshalJSON[types.TransactionResource](t, result.StdOut) + + require.Equal("Transaction", transaction.Type) + require.Equal("Qti5R3_VR", transaction.Spec.ID) + require.Equal("New Transaction", transaction.Spec.Name) + require.Equal("a transaction", transaction.Spec.Description) + require.Len(transaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", transaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", transaction.Spec.Steps[1]) + }) + + t.Run("get with pretty format", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + // And I have a transaction already set + + // When I try to get a transaction on pretty mode + // Then it should print a table with 4 lines printed: header, separator, transaction item and empty line + result := tracetestcli.Exec(t, "get transaction --id Qti5R3_VR --output pretty", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + require.Contains(result.StdOut, "New Transaction") + + lines := strings.Split(result.StdOut, "\n") + require.Len(lines, 4) + }) +} diff --git a/testing/cli-e2etest/testscenarios/transaction/list_transactions_test.go b/testing/cli-e2etest/testscenarios/transaction/list_transactions_test.go new file mode 100644 index 0000000000..23750d3255 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/list_transactions_test.go @@ -0,0 +1,235 @@ +package transaction + +import ( + "fmt" + "strings" + "testing" + + "github.com/kubeshop/tracetest/cli-e2etest/environment" + "github.com/kubeshop/tracetest/cli-e2etest/helpers" + "github.com/kubeshop/tracetest/cli-e2etest/testscenarios/types" + "github.com/kubeshop/tracetest/cli-e2etest/tracetestcli" + "github.com/stretchr/testify/require" +) + +func addListTransactionPreReqs(t *testing.T, env environment.Manager) { + cliConfig := env.GetCLIConfigPath(t) + + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to set up a new environment + // Then it should be applied with success + newTransactionPath := env.GetTestResourcePath(t, "new-transaction") + + result := tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", newTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + // When I try to set up a another environment + // Then it should be applied with success + anotherTransactionPath := env.GetTestResourcePath(t, "another-transaction") + + result = tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", anotherTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + // When I try to set up a third environment + // Then it should be applied with success + oneMoreTransactionPath := env.GetTestResourcePath(t, "one-more-transaction") + + result = tracetestcli.Exec(t, fmt.Sprintf("apply transaction --file %s", oneMoreTransactionPath), tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) +} + +func TestListTransactions(t *testing.T) { + // instantiate require with testing helper + require := require.New(t) + + // setup isolated e2e environment + env := environment.CreateAndStart(t) + defer env.Close(t) + + cliConfig := env.GetCLIConfigPath(t) + + t.Run("list no transactions", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + // And there is no envs + result := tracetestcli.Exec(t, "list transaction --sortBy name --sortDirection asc --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transactions := helpers.UnmarshalYAMLSequence[types.AugmentedTransactionResource](t, result.StdOut) + require.Len(transactions, 0) + }) + + addListTransactionPreReqs(t, env) + + t.Run("list with invalid sortBy field", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to list these transactions by an invalid field + // Then I should receive an error + result := tracetestcli.Exec(t, "list transaction --sortBy id --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 1) + require.Contains(result.StdErr, "invalid sort field: id") // TODO: think on how to improve this error handling + }) + + t.Run("list with YAML format", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to list these transactions by a valid field and in YAML format + // Then I should receive three transactions + result := tracetestcli.Exec(t, "list transaction --sortBy name --sortDirection asc --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transactions := helpers.UnmarshalYAMLSequence[types.AugmentedTransactionResource](t, result.StdOut) + require.Len(transactions, 3) + + anotherTransaction := transactions[0] + require.Equal("Transaction", anotherTransaction.Type) + require.Equal("asuhfdkj", anotherTransaction.Spec.ID) + require.Equal("Another Transaction", anotherTransaction.Spec.Name) + require.Equal("another transaction", anotherTransaction.Spec.Description) + require.Equal(0, anotherTransaction.Spec.Summary.Runs) + require.Equal(0, anotherTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, anotherTransaction.Spec.Summary.LastRun.Passes) + require.Len(anotherTransaction.Spec.Steps, 4) + require.Equal("9wtAH2_Vg", anotherTransaction.Spec.Steps[0]) + require.Equal("9wtAH2_Vg", anotherTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", anotherTransaction.Spec.Steps[2]) + require.Equal("ajksdkasjbd", anotherTransaction.Spec.Steps[3]) + + newTransaction := transactions[1] + require.Equal("Transaction", newTransaction.Type) + require.Equal("Qti5R3_VR", newTransaction.Spec.ID) + require.Equal("New Transaction", newTransaction.Spec.Name) + require.Equal("a transaction", newTransaction.Spec.Description) + require.Equal(0, newTransaction.Spec.Summary.Runs) + require.Equal(0, newTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, newTransaction.Spec.Summary.LastRun.Passes) + require.Len(newTransaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", newTransaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", newTransaction.Spec.Steps[1]) + + oneMoreTransaction := transactions[2] + require.Equal("Transaction", oneMoreTransaction.Type) + require.Equal("i2ug34j", oneMoreTransaction.Spec.ID) + require.Equal("One More Transaction", oneMoreTransaction.Spec.Name) + require.Equal("one more transaction", oneMoreTransaction.Spec.Description) + require.Equal(0, oneMoreTransaction.Spec.Summary.Runs) + require.Equal(0, oneMoreTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, oneMoreTransaction.Spec.Summary.LastRun.Passes) + require.Len(oneMoreTransaction.Spec.Steps, 3) + require.Equal("9wtAH2_Vg", oneMoreTransaction.Spec.Steps[0]) + require.Equal("9wtAH2_Vg", oneMoreTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", oneMoreTransaction.Spec.Steps[2]) + }) + + t.Run("list with JSON format", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to list these transactions by a valid field and in JSON format + // Then I should receive three transactions + result := tracetestcli.Exec(t, "list transaction --sortBy name --sortDirection asc --output json", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transactions := helpers.UnmarshalJSON[[]types.AugmentedTransactionResource](t, result.StdOut) + require.Len(transactions, 3) + + anotherTransaction := transactions[0] + require.Equal("Transaction", anotherTransaction.Type) + require.Equal("asuhfdkj", anotherTransaction.Spec.ID) + require.Equal("Another Transaction", anotherTransaction.Spec.Name) + require.Equal("another transaction", anotherTransaction.Spec.Description) + require.Equal(0, anotherTransaction.Spec.Summary.Runs) + require.Equal(0, anotherTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, anotherTransaction.Spec.Summary.LastRun.Passes) + require.Len(anotherTransaction.Spec.Steps, 4) + require.Equal("9wtAH2_Vg", anotherTransaction.Spec.Steps[0]) + require.Equal("9wtAH2_Vg", anotherTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", anotherTransaction.Spec.Steps[2]) + require.Equal("ajksdkasjbd", anotherTransaction.Spec.Steps[3]) + + newTransaction := transactions[1] + require.Equal("Transaction", newTransaction.Type) + require.Equal("Qti5R3_VR", newTransaction.Spec.ID) + require.Equal("New Transaction", newTransaction.Spec.Name) + require.Equal("a transaction", newTransaction.Spec.Description) + require.Equal(0, newTransaction.Spec.Summary.Runs) + require.Equal(0, newTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, newTransaction.Spec.Summary.LastRun.Passes) + require.Len(newTransaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", newTransaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", newTransaction.Spec.Steps[1]) + + oneMoreTransaction := transactions[2] + require.Equal("Transaction", oneMoreTransaction.Type) + require.Equal("i2ug34j", oneMoreTransaction.Spec.ID) + require.Equal("One More Transaction", oneMoreTransaction.Spec.Name) + require.Equal("one more transaction", oneMoreTransaction.Spec.Description) + require.Equal(0, oneMoreTransaction.Spec.Summary.Runs) + require.Equal(0, oneMoreTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, oneMoreTransaction.Spec.Summary.LastRun.Passes) + require.Len(oneMoreTransaction.Spec.Steps, 3) + require.Equal("9wtAH2_Vg", oneMoreTransaction.Spec.Steps[0]) + require.Equal("9wtAH2_Vg", oneMoreTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", oneMoreTransaction.Spec.Steps[2]) + }) + + t.Run("list with pretty format", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to list these transactions by a valid field and in pretty format + // Then it should print a table with 6 lines printed: header, separator, three transactions and empty line + result := tracetestcli.Exec(t, "list transaction --sortBy name --sortDirection asc --output pretty", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + lines := strings.Split(result.StdOut, "\n") + require.Len(lines, 6) + + require.Contains(lines[2], "Another Transaction") + require.Contains(lines[3], "New Transaction") + require.Contains(lines[4], "One More Transaction") + }) + + t.Run("list with YAML format skipping the first and taking two items", func(t *testing.T) { + // Given I am a Tracetest CLI user + // And I have my server recently created + + // When I try to list these transactions by a valid field, paging options and in YAML format + // Then I should receive two transactions + result := tracetestcli.Exec(t, "list transaction --sortBy name --sortDirection asc --skip 1 --take 2 --output yaml", tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + + transactions := helpers.UnmarshalYAMLSequence[types.AugmentedTransactionResource](t, result.StdOut) + require.Len(transactions, 2) + + newTransaction := transactions[0] + require.Equal("Transaction", newTransaction.Type) + require.Equal("Qti5R3_VR", newTransaction.Spec.ID) + require.Equal("New Transaction", newTransaction.Spec.Name) + require.Equal("a transaction", newTransaction.Spec.Description) + require.Equal(0, newTransaction.Spec.Summary.Runs) + require.Equal(0, newTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, newTransaction.Spec.Summary.LastRun.Passes) + require.Len(newTransaction.Spec.Steps, 2) + require.Equal("9wtAH2_Vg", newTransaction.Spec.Steps[0]) + require.Equal("ajksdkasjbd", newTransaction.Spec.Steps[1]) + + oneMoreTransaction := transactions[1] + require.Equal("Transaction", oneMoreTransaction.Type) + require.Equal("i2ug34j", oneMoreTransaction.Spec.ID) + require.Equal("One More Transaction", oneMoreTransaction.Spec.Name) + require.Equal("one more transaction", oneMoreTransaction.Spec.Description) + require.Equal(0, oneMoreTransaction.Spec.Summary.Runs) + require.Equal(0, oneMoreTransaction.Spec.Summary.LastRun.Fails) + require.Equal(0, oneMoreTransaction.Spec.Summary.LastRun.Passes) + require.Len(oneMoreTransaction.Spec.Steps, 3) + require.Equal("9wtAH2_Vg", oneMoreTransaction.Spec.Steps[0]) + require.Equal("9wtAH2_Vg", oneMoreTransaction.Spec.Steps[1]) + require.Equal("ajksdkasjbd", oneMoreTransaction.Spec.Steps[2]) + }) +} diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/another-transaction.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/another-transaction.yaml new file mode 100644 index 0000000000..3eb80bbbc9 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/another-transaction.yaml @@ -0,0 +1,10 @@ +type: Transaction +spec: + id: asuhfdkj + name: Another Transaction + description: another transaction + steps: + - 9wtAH2_Vg + - 9wtAH2_Vg + - ajksdkasjbd + - ajksdkasjbd diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/new-transaction.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/new-transaction.yaml new file mode 100644 index 0000000000..3caab5009f --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/new-transaction.yaml @@ -0,0 +1,8 @@ +type: Transaction +spec: + id: Qti5R3_VR + name: New Transaction + description: a transaction + steps: + - 9wtAH2_Vg + - ajksdkasjbd diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/one-more-transaction.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/one-more-transaction.yaml new file mode 100644 index 0000000000..2efd96f648 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/one-more-transaction.yaml @@ -0,0 +1,9 @@ +type: Transaction +spec: + id: i2ug34j + name: One More Transaction + description: one more transaction + steps: + - 9wtAH2_Vg + - 9wtAH2_Vg + - ajksdkasjbd diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/transaction-step-1.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/transaction-step-1.yaml new file mode 100644 index 0000000000..b14284dab3 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/transaction-step-1.yaml @@ -0,0 +1,24 @@ +type: Test +spec: + id: 9wtAH2_Vg + name: Pokeshop - Add + description: Add a Pokemon + trigger: + type: http + httpRequest: + url: http://demo-api:8081/pokemon/ + method: POST + headers: + - key: Content-Type + value: application/json + body: '{"name":"snorlax","type":"normal","imageUrl":"https://assets.pokemon.com/assets/cms2/img/pokedex/full/143.png","isFeatured":true}' + specs: + - name: It should add a Pokemon correctly + selector: span[tracetest.span.type="http" name="POST /pokemon/" http.method="POST"] + assertions: + - attr:http.status_code = 201 + - name: It should save the correct data + selector: span[tracetest.span.type="database" name="create postgres.pokemon" db.system="postgres" db.name="postgres" db.user="postgres" db.operation="create" db.sql.table="pokemon"] + assertions: + - attr:db.result contains '"imageUrl":"https://assets.pokemon.com/assets/cms2/img/pokedex/full/143.png"' + - attr:db.result contains '"name":"snorlax"' diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/transaction-step-2.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/transaction-step-2.yaml new file mode 100644 index 0000000000..3e27ad0d93 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/transaction-step-2.yaml @@ -0,0 +1,18 @@ +type: Test +spec: + id: ajksdkasjbd + name: Pokeshop - Get + description: Get a Pokemon + trigger: + type: http + httpRequest: + url: http://demo-api:8081/pokemon + method: GET + headers: + - key: Content-Type + value: application/json + specs: + - name: It should Get Pokemons correctly + selector: span[tracetest.span.type="http" name="GET /pokemon" http.method="GET"] + assertions: + - attr:http.status_code = 200 diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/transaction-to-run.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/transaction-to-run.yaml new file mode 100644 index 0000000000..c3d886882c --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/transaction-to-run.yaml @@ -0,0 +1,8 @@ +type: Transaction +spec: + id: k1ug23k + name: Transaction To Run + description: a transaction to run + steps: + - ./transaction-step-1.yaml + - ./transaction-step-2.yaml diff --git a/testing/cli-e2etest/testscenarios/transaction/resources/updated-new-transaction.yaml b/testing/cli-e2etest/testscenarios/transaction/resources/updated-new-transaction.yaml new file mode 100644 index 0000000000..ffdad1491f --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/resources/updated-new-transaction.yaml @@ -0,0 +1,9 @@ +type: Transaction +spec: + id: Qti5R3_VR + name: Updated Transaction + description: an updated transaction + steps: + - 9wtAH2_Vg + - ajksdkasjbd + - ajksdkasjbd diff --git a/testing/cli-e2etest/testscenarios/transaction/run_transaction_test.go b/testing/cli-e2etest/testscenarios/transaction/run_transaction_test.go new file mode 100644 index 0000000000..5900f802cc --- /dev/null +++ b/testing/cli-e2etest/testscenarios/transaction/run_transaction_test.go @@ -0,0 +1,42 @@ +package transaction + +import ( + "fmt" + "testing" + + "github.com/kubeshop/tracetest/cli-e2etest/environment" + "github.com/kubeshop/tracetest/cli-e2etest/helpers" + "github.com/kubeshop/tracetest/cli-e2etest/tracetestcli" + "github.com/stretchr/testify/require" +) + +func TestRunTransaction(t *testing.T) { + // setup isolated e2e environment + env := environment.CreateAndStart(t, environment.WithDataStoreEnabled(), environment.WithPokeshop()) + defer env.Close(t) + + cliConfig := env.GetCLIConfigPath(t) + + t.Run("should pass", func(t *testing.T) { + // instantiate require with testing helper + require := require.New(t) + + // Given I am a Tracetest CLI user + // And I have my server recently created + // And the datasource is already set + + // When I try to run a transaction + // Then it should pass + transactionFile := env.GetTestResourcePath(t, "transaction-to-run") + + command := fmt.Sprintf("test run -w -d %s", transactionFile) + result := tracetestcli.Exec(t, command, tracetestcli.WithCLIConfig(cliConfig)) + helpers.RequireExitCodeEqual(t, result, 0) + require.Contains(result.StdOut, "Transaction To Run") // transaction name + require.Contains(result.StdOut, "Pokeshop - Add") // first test + require.Contains(result.StdOut, "✔ It should add a Pokemon correctly") + require.Contains(result.StdOut, "✔ It should save the correct data") + require.Contains(result.StdOut, "Pokeshop - Get") // second test + require.Contains(result.StdOut, "✔ It should Get Pokemons correctly") + }) +} diff --git a/testing/cli-e2etest/testscenarios/types/analyzer.go b/testing/cli-e2etest/testscenarios/types/analyzer.go new file mode 100644 index 0000000000..32274fa26d --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/analyzer.go @@ -0,0 +1,23 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type AnalyzerResource struct { + Type string `json:"type"` + Spec Analyzer `json:"spec"` +} + +type Analyzer struct { + Id string `json:"id"` + Name string `json:"name"` + Enabled bool `json:"enabled"` + MinimumScore int `json:"minimumScore"` + Plugins []AnalyzerPlugin `json:"plugins"` +} + +type AnalyzerPlugin struct { + Name string `json:"name"` + Enabled bool `json:"enabled"` + Required bool `json:"required"` +} diff --git a/testing/cli-e2etest/testscenarios/types/config.go b/testing/cli-e2etest/testscenarios/types/config.go new file mode 100644 index 0000000000..5f7cca7b2e --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/config.go @@ -0,0 +1,16 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type Config struct { + ID string `json:"id"` + Name string `json:"name"` + + AnalyticsEnabled bool `json:"analyticsEnabled"` +} + +type ConfigResource struct { + Type string `json:"type"` + Spec Config `json:"spec"` +} diff --git a/testing/cli-e2etest/testscenarios/types/datastore.go b/testing/cli-e2etest/testscenarios/types/datastore.go new file mode 100644 index 0000000000..344f9dad6c --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/datastore.go @@ -0,0 +1,15 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type DataStore struct { + ID string `json:"id"` + Name string `json:"name"` + Default bool `json:"default"` +} + +type DataStoreResource struct { + Type string `json:"type"` + Spec DataStore `json:"spec"` +} diff --git a/testing/cli-e2etest/testscenarios/types/demo.go b/testing/cli-e2etest/testscenarios/types/demo.go new file mode 100644 index 0000000000..fbc0109cba --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/demo.go @@ -0,0 +1,30 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type DemoPokeshop struct { + HttpEndpoint string `json:"httpEndpoint"` + GrpcEndpoint string `json:"grpcEndpoint"` +} + +type DemoOTelStore struct { + FrontendEndpoint string `json:"frontendEndpoint"` + ProductCatalogEndpoint string `json:"productCatalogEndpoint"` + CartEndpoint string `json:"cartEndpoint"` + CheckoutEndpoint string `json:"checkoutEndpoint"` +} + +type Demo struct { + Id string `json:"id"` + Name string `json:"name"` + Enabled bool `json:"enabled"` + Type string `json:"type"` + OTelStore DemoOTelStore `json:"opentelemetryStore"` + Pokeshop DemoPokeshop `json:"pokeshop"` +} + +type DemoResource struct { + Type string `json:"type"` + Spec Demo `json:"spec"` +} diff --git a/testing/cli-e2etest/testscenarios/types/environment.go b/testing/cli-e2etest/testscenarios/types/environment.go new file mode 100644 index 0000000000..2a9bc88a40 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/environment.go @@ -0,0 +1,20 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type EnvironmentKeyValue struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type Environment struct { + ID string `json:"id"` + Name string `json:"name"` + Values []EnvironmentKeyValue `json:"values"` +} + +type EnvironmentResource struct { + Type string `json:"type"` + Spec Environment `json:"spec"` +} diff --git a/testing/cli-e2etest/testscenarios/types/pollingprofile.go b/testing/cli-e2etest/testscenarios/types/pollingprofile.go new file mode 100644 index 0000000000..09a77ac6c2 --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/pollingprofile.go @@ -0,0 +1,24 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type PollingProfilePeriodicStrategy struct { + Timeout string `json:"timeout"` + RetryDelay string `json:"retryDelay"` + SelectorMatchRetries string `json:"selectorMatchRetries"` +} + +type PollingProfile struct { + ID string `json:"id"` + Name string `json:"name"` + Default bool `json:"default"` + + Strategy string `json:"strategy"` + Periodic PollingProfilePeriodicStrategy `json:"periodic"` +} + +type PollingProfileResource struct { + Type string `json:"type"` + Spec PollingProfile `json:"spec"` +} diff --git a/testing/cli-e2etest/testscenarios/types/transaction.go b/testing/cli-e2etest/testscenarios/types/transaction.go new file mode 100644 index 0000000000..8eb566897f --- /dev/null +++ b/testing/cli-e2etest/testscenarios/types/transaction.go @@ -0,0 +1,39 @@ +package types + +// Note: these types are very similar to the types on the server folder +// however they are defined here to avoid bias with the current implementation + +type Transaction struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Steps []string `json:"steps"` +} + +type TransactionResource struct { + Type string `json:"type"` + Spec Transaction `json:"spec"` +} + +type AugmentedTransactionLastRun struct { + Passes int `json:"passes"` + Fails int `json:"fails"` +} + +type AugmentedTransactionSummary struct { + Runs int `json:"runs"` + LastRun AugmentedTransactionLastRun `json:"lastRun"` +} + +type AugmentedTransaction struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Steps []string `json:"steps"` + Summary AugmentedTransactionSummary `json:"summary"` +} + +type AugmentedTransactionResource struct { + Type string `json:"type"` + Spec AugmentedTransaction `json:"spec"` +} diff --git a/testing/cli-e2etest/testscenarios/types/types.go b/testing/cli-e2etest/testscenarios/types/types.go deleted file mode 100644 index c05a1812f2..0000000000 --- a/testing/cli-e2etest/testscenarios/types/types.go +++ /dev/null @@ -1,117 +0,0 @@ -package types - -// Note: these types are very similar to the types on the server folder -// however they are defined here to avoid bias with the current implementation - -// DataStore -type DataStore struct { - ID string `json:"id"` - Name string `json:"name"` - Default bool `json:"default"` -} - -type DataStoreResource struct { - Type string `json:"type"` - Spec DataStore `json:"spec"` -} - -// Environment - -type EnvironmentKeyValue struct { - Key string `json:"key"` - Value string `json:"value"` -} - -type Environment struct { - ID string `json:"id"` - Name string `json:"name"` - Values []EnvironmentKeyValue `json:"values"` -} - -type EnvironmentResource struct { - Type string `json:"type"` - Spec Environment `json:"spec"` -} - -// Config - -type Config struct { - ID string `json:"id"` - Name string `json:"name"` - - AnalyticsEnabled bool `json:"analyticsEnabled"` -} - -type ConfigResource struct { - Type string `json:"type"` - Spec Config `json:"spec"` -} - -// PollingProfile - -type PollingProfilePeriodicStrategy struct { - Timeout string `json:"timeout"` - RetryDelay string `json:"retryDelay"` - SelectorMatchRetries string `json:"selectorMatchRetries"` -} - -type PollingProfile struct { - ID string `json:"id"` - Name string `json:"name"` - Default bool `json:"default"` - - Strategy string `json:"strategy"` - Periodic PollingProfilePeriodicStrategy `json:"periodic"` -} - -type PollingProfileResource struct { - Type string `json:"type"` - Spec PollingProfile `json:"spec"` -} - -// Demo - -type DemoPokeshop struct { - HttpEndpoint string `json:"httpEndpoint"` - GrpcEndpoint string `json:"grpcEndpoint"` -} - -type DemoOTelStore struct { - FrontendEndpoint string `json:"frontendEndpoint"` - ProductCatalogEndpoint string `json:"productCatalogEndpoint"` - CartEndpoint string `json:"cartEndpoint"` - CheckoutEndpoint string `json:"checkoutEndpoint"` -} - -type Demo struct { - Id string `json:"id"` - Name string `json:"name"` - Enabled bool `json:"enabled"` - Type string `json:"type"` - OTelStore DemoOTelStore `json:"opentelemetryStore"` - Pokeshop DemoPokeshop `json:"pokeshop"` -} - -type DemoResource struct { - Type string `json:"type"` - Spec Demo `json:"spec"` -} - -type AnalyzerResource struct { - Type string `json:"type"` - Spec Analyzer `json:"spec"` -} - -type Analyzer struct { - Id string `json:"id"` - Name string `json:"name"` - Enabled bool `json:"enabled"` - MinimumScore int `json:"minimumScore"` - Plugins []AnalyzerPlugin `json:"plugins"` -} - -type AnalyzerPlugin struct { - Name string `json:"name"` - Enabled bool `json:"enabled"` - Required bool `json:"required"` -}