Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(test): New UI implementation for ie test & refactor various parts of the engine #198

Merged
merged 28 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
204d9dc
[add] new test folder for the test ui rewrite and refactor the codebl…
vmarcella May 30, 2024
92dbf06
[refactor] all of the engine components and modes into separate folde…
vmarcella Jun 3, 2024
87f87fe
[update] init to execute the first codeblock and remove azure status …
vmarcella Jun 3, 2024
4f4c0a5
[add] resource group deletion into the testing again.
vmarcella Jun 3, 2024
da52d23
[add] initial set of tests for the test mode model.
vmarcella Jun 3, 2024
091c17e
[add] test to assert that the model automatically transitions to runn…
vmarcella Jun 3, 2024
4f1545f
[update] test to check the result of executing the first codeblock.
vmarcella Jun 7, 2024
17f1618
Merge branch 'main' of https://github.com/Azure/InnovationEngine into…
vmarcella Jun 14, 2024
e1154e7
fix(tests): Add local markdown tests to testing pipeline to see outpu…
vmarcella Jun 17, 2024
8381867
fix(pipeline): Specify the shell as bash explicitly.
vmarcella Jun 17, 2024
10ea029
fix(pipeline): Specify the shell as bash explicitly.
vmarcella Jun 17, 2024
99bf280
fix(pipeline): Specify the shell as bash explicitly.
vmarcella Jun 17, 2024
c69a7a6
fix(test): Update regex used to locate resource groups to correctly m…
vmarcella Jun 18, 2024
925e8a3
fix(test): Update test mode to include the Error object returned from…
vmarcella Jun 19, 2024
8240599
feat(test): Update test coverage to include all modules as part of th…
vmarcella Jun 19, 2024
aed8dc9
fix(test): Update the viewport to go to the bottom every time a comma…
vmarcella Jun 19, 2024
f4b831c
[update] ie test to take in an environment flag and only use altscree…
vmarcella Jun 21, 2024
7a2a4c2
[update] makefile to accept environment parameter and specify it in t…
vmarcella Jun 21, 2024
6d852f5
[update] stdin to be nil when the command isn't interactive.
vmarcella Jun 21, 2024
1e4a073
[remove] check.
vmarcella Jun 21, 2024
bfb82fb
[update] tea flags when the environment is CI.
vmarcella Jun 21, 2024
c5e4fb3
[remove] the renderer when in CI.
vmarcella Jun 21, 2024
2772487
[update] the failure reporting so that how the scenario failed is mad…
vmarcella Jun 21, 2024
41d5701
[fix] the codeblocks to set the error when they've failed.
vmarcella Jun 21, 2024
d0703c0
[remove] ci from being an environment in favor of github-action, as w…
vmarcella Jun 21, 2024
f22f2e3
[fix] reference.
vmarcella Jun 21, 2024
e044a66
[update] test to pass.
vmarcella Jun 24, 2024
d7ded38
[remove] bad similarity for now. Will track in a future unit test.
vmarcella Jun 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/scenario-testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ jobs:
environment: ScenarioTesting
steps:
- uses: actions/checkout@v2
- name: Build all targets.
- name: Build & test all targets.
run: |
make build-all
make test-all WITH_COVERAGE=true
make test-local-scenarios ENVIRONMENT=github-action
- name: Upload test coverage
uses: actions/upload-artifact@v2
if: github.event_name == 'pull_request'
Expand All @@ -65,6 +66,6 @@ jobs:
apk add --no-cache make git openssh openssl helm curl jq
make test-upstream-scenarios SUBSCRIPTION=${{ secrets.AZURE_SUBSCRIPTION }}
- name: Display ie.log file
if: (success() || failure()) && github.event_name != 'pull_request'
if: (success() || failure())
run: |
cat ie.log
16 changes: 13 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ install-ie:
# ------------------------------ Test targets ----------------------------------

WITH_COVERAGE := false

test-all:
@go clean -testcache
ifeq ($(WITH_COVERAGE), true)
@echo "Running all tests with coverage..."
@go test -v -coverprofile=coverage.out ./...
@go test -v -coverpkg=./... -coverprofile=coverage.out ./...
@go tool cover -html=coverage.out -o coverage.html
else
@echo "Running all tests..."
Expand All @@ -38,16 +37,27 @@ endif
SUBSCRIPTION ?= 00000000-0000-0000-0000-000000000000
SCENARIO ?= ./README.md
WORKING_DIRECTORY ?= $(PWD)
ENVIRONMENT ?= local
test-scenario:
@echo "Running scenario $(SCENARIO)"
$(IE_BINARY) test $(SCENARIO) --subscription $(SUBSCRIPTION) --working-directory $(WORKING_DIRECTORY)
ifeq ($(SUBSCRIPTION), 00000000-0000-0000-0000-000000000000)
$(IE_BINARY) test $(SCENARIO) --working-directory $(WORKING_DIRECTORY) --environment $(ENVIRONMENT)
else
$(IE_BINARY) test $(SCENARIO) --subscription $(SUBSCRIPTION) --working-directory $(WORKING_DIRECTORY) --enviroment $(ENVIRONMENT)
endif

test-scenarios:
@echo "Testing out the scenarios"
for dir in ./scenarios/ocd/*/; do \
($(MAKE) test-scenario SCENARIO="$${dir}README.md" SUBCRIPTION="$(SUBSCRIPTION)") || exit $$?; \
done

test-local-scenarios:
@echo "Testing out the local scenarios"
for file in ./scenarios/testing/*.md; do \
($(MAKE) test-scenario SCENARIO="$${file}") || exit $$?; \
done

test-upstream-scenarios:
@echo "Pulling the upstream scenarios"
@git config --global --add safe.directory /home/runner/work/InnovationEngine/InnovationEngine
Expand Down
4 changes: 2 additions & 2 deletions cmd/ie/commands/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/engine/common"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -92,7 +93,7 @@ var executeCommand = &cobra.Command{
}

// Parse the markdown file and create a scenario
scenario, err := engine.CreateScenarioFromMarkdown(
scenario, err := common.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-interactive", "terraform"},
cliEnvironmentVariables,
Expand All @@ -112,7 +113,6 @@ var executeCommand = &cobra.Command{
WorkingDirectory: workingDirectory,
RenderValues: renderValues,
})

if err != nil {
logging.GlobalLogger.Errorf("Error creating engine: %s", err)
fmt.Printf("Error creating engine: %s", err)
Expand Down
5 changes: 2 additions & 3 deletions cmd/ie/commands/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"os"
"strings"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/engine/common"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/Azure/InnovationEngine/internal/ui"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -59,7 +59,7 @@ var inspectCommand = &cobra.Command{
cliEnvironmentVariables[keyValuePair[0]] = keyValuePair[1]
}
// Parse the markdown file and create a scenario
scenario, err := engine.CreateScenarioFromMarkdown(
scenario, err := common.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-inspect", "terraform"},
cliEnvironmentVariables,
Expand Down Expand Up @@ -104,6 +104,5 @@ var inspectCommand = &cobra.Command{
fmt.Println()
}
}

},
}
4 changes: 2 additions & 2 deletions cmd/ie/commands/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/engine/common"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -69,7 +70,7 @@ var interactiveCommand = &cobra.Command{
cliEnvironmentVariables[keyValuePair[0]] = keyValuePair[1]
}
// Parse the markdown file and create a scenario
scenario, err := engine.CreateScenarioFromMarkdown(
scenario, err := common.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-interactive", "terraform"},
cliEnvironmentVariables,
Expand All @@ -89,7 +90,6 @@ var interactiveCommand = &cobra.Command{
WorkingDirectory: workingDirectory,
RenderValues: renderValues,
})

if err != nil {
logging.GlobalLogger.Errorf("Error creating engine: %s", err)
fmt.Printf("Error creating engine: %s", err)
Expand Down
9 changes: 5 additions & 4 deletions cmd/ie/commands/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/engine/common"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/spf13/cobra"
)
Expand All @@ -23,9 +24,8 @@ func init() {
var testCommand = &cobra.Command{
Use: "test",
Args: cobra.MinimumNArgs(1),
Short: "Test document commands against it's expected outputs.",
Short: "Test document commands against their expected outputs.",
Run: func(cmd *cobra.Command, args []string) {

markdownFile := args[0]
if markdownFile == "" {
cmd.Help()
Expand All @@ -35,22 +35,23 @@ var testCommand = &cobra.Command{
verbose, _ := cmd.Flags().GetBool("verbose")
subscription, _ := cmd.Flags().GetString("subscription")
workingDirectory, _ := cmd.Flags().GetString("working-directory")
environment, _ := cmd.Flags().GetString("environment")

innovationEngine, err := engine.NewEngine(engine.EngineConfiguration{
Verbose: verbose,
DoNotDelete: false,
Subscription: subscription,
CorrelationId: "",
WorkingDirectory: workingDirectory,
Environment: environment,
})

if err != nil {
logging.GlobalLogger.Errorf("Error creating engine %s", err)
fmt.Printf("Error creating engine %s", err)
os.Exit(1)
}

scenario, err := engine.CreateScenarioFromMarkdown(
scenario, err := common.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-interactive", "terraform"},
nil,
Expand Down
7 changes: 2 additions & 5 deletions cmd/ie/commands/to-bash.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"fmt"
"strings"

"github.com/Azure/InnovationEngine/internal/engine"
"github.com/Azure/InnovationEngine/internal/engine/common"
"github.com/Azure/InnovationEngine/internal/engine/environments"
"github.com/Azure/InnovationEngine/internal/logging"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -50,11 +50,10 @@ var toBashCommand = &cobra.Command{
}

// Parse the markdown file and create a scenario
scenario, err := engine.CreateScenarioFromMarkdown(
scenario, err := common.CreateScenarioFromMarkdown(
markdownFile,
[]string{"bash", "azurecli", "azurecli-interactive", "terraform"},
cliEnvironmentVariables)

if err != nil {
logging.GlobalLogger.Errorf("Error creating scenario: %s", err)
fmt.Printf("Error creating scenario: %s", err)
Expand All @@ -66,7 +65,6 @@ var toBashCommand = &cobra.Command{
if environments.IsAzureEnvironment(environment) {
script := AzureScript{Script: scenario.ToShellScript()}
scriptJson, err := json.Marshal(script)

if err != nil {
logging.GlobalLogger.Errorf("Error converting to json: %s", err)
fmt.Printf("Error converting to json: %s", err)
Expand All @@ -79,7 +77,6 @@ var toBashCommand = &cobra.Command{
}

return nil

},
}

Expand Down
1 change: 0 additions & 1 deletion internal/az/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func FindAllDeployedResourceURIs(resourceGroup string) []string {
WriteToHistory: true,
},
)

if err != nil {
logging.GlobalLogger.Error("Failed to list deployments", err)
}
Expand Down
46 changes: 46 additions & 0 deletions internal/az/group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package az

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestFindingResourceGroups(t *testing.T) {
testCases := []struct {
resourceGroupString string
expectedResourceGroupName string
}{
// RG string that ends with a slash
{
resourceGroupString: "resourceGroups/rg1/",
expectedResourceGroupName: "rg1",
},
// RG string that ends with a space and starts new text
{
resourceGroupString: "resourceGroups/rg1 /subscriptions/",
expectedResourceGroupName: "rg1",
},

// RG string that includes nested resources and extraneous text.
{
resourceGroupString: "/subscriptions/9b70acd9-975f-44ba-bad6-255a2c8bda37/resourceGroups/myResourceGroup-rg/providers/Microsoft.ContainerRegistry/registries/mydnsrandomnamebbbhe ffc55a9e-ed2a-4b60-b034-45228dfe7db5 2024-06-11T09:41:36.631310+00:00",
expectedResourceGroupName: "myResourceGroup-rg",
},
// RG string that is surrounded by quotes.
{
resourceGroupString: `"id": "/subscriptions/0a2c89a7-a44e-4cd0-b6ec-868432ad1d13/resourceGroups/myResourceGroup"`,
expectedResourceGroupName: "myResourceGroup",
},
// RG string that has no match.
{
resourceGroupString: "NoMatch",
expectedResourceGroupName: "",
},
}

for _, tc := range testCases {
resourceGroupName := FindResourceGroupName(tc.resourceGroupString)
assert.Equal(t, tc.expectedResourceGroupName, resourceGroupName)
}
}
22 changes: 22 additions & 0 deletions internal/engine/common/codeblock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package common

import "github.com/Azure/InnovationEngine/internal/parsers"

// State for the codeblock in interactive mode. Used to keep track of the
// state of each codeblock.
type StatefulCodeBlock struct {
CodeBlock parsers.CodeBlock
CodeBlockNumber int
Error error
StdErr string
StdOut string
StepName string
StepNumber int
Success bool
}

// Checks if a codeblock was executed by looking at the
// output, errors, and if success is true.
func (s StatefulCodeBlock) WasExecuted() bool {
return s.StdOut != "" || s.StdErr != "" || s.Error != nil || s.Success
}
41 changes: 27 additions & 14 deletions internal/engine/commands.go → internal/engine/common/commands.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package engine
package common

import (
"fmt"
Expand All @@ -23,6 +23,16 @@ type FailedCommandMessage struct {
Error error
}

type ExitMessage struct {
EncounteredFailure bool
}

func Exit(encounteredFailure bool) tea.Cmd {
return func() tea.Msg {
return ExitMessage{EncounteredFailure: encounteredFailure}
}
}

// Executes a bash command and returns a tea message with the output. This function
// will be executed asycnhronously.
func ExecuteCodeBlockAsync(codeBlock parsers.CodeBlock, env map[string]string) tea.Cmd {
Expand Down Expand Up @@ -52,7 +62,7 @@ func ExecuteCodeBlockAsync(codeBlock parsers.CodeBlock, env map[string]string) t
expectedRegex := codeBlock.ExpectedOutput.ExpectedRegex
expectedOutputLanguage := codeBlock.ExpectedOutput.Language

outputComparisonError := compareCommandOutputs(
outputComparisonError := CompareCommandOutputs(
actualOutput,
expectedOutput,
expectedSimilarity,
Expand Down Expand Up @@ -86,16 +96,19 @@ func ExecuteCodeBlockAsync(codeBlock parsers.CodeBlock, env map[string]string) t
// finishes executing.
func ExecuteCodeBlockSync(codeBlock parsers.CodeBlock, env map[string]string) tea.Msg {
logging.GlobalLogger.Info("Executing command synchronously: ", codeBlock.Content)
program.ReleaseTerminal()
Program.ReleaseTerminal()

output, err := shells.ExecuteBashCommand(codeBlock.Content, shells.BashCommandConfiguration{
EnvironmentVariables: env,
InheritEnvironment: true,
InteractiveCommand: true,
WriteToHistory: true,
})
output, err := shells.ExecuteBashCommand(
codeBlock.Content,
shells.BashCommandConfiguration{
EnvironmentVariables: env,
InheritEnvironment: true,
InteractiveCommand: true,
WriteToHistory: true,
},
)

program.RestoreTerminal()
Program.RestoreTerminal()

if err != nil {
return FailedCommandMessage{
Expand All @@ -113,7 +126,7 @@ func ExecuteCodeBlockSync(codeBlock parsers.CodeBlock, env map[string]string) te
}

// clearScreen returns a command that clears the terminal screen and positions the cursor at the top-left corner
func clearScreen() tea.Cmd {
func ClearScreen() tea.Cmd {
return func() tea.Msg {
fmt.Print(
"\033[H\033[2J",
Expand All @@ -124,13 +137,13 @@ func clearScreen() tea.Cmd {

// Updates the azure status with the current state of the interactive mode
// model.
func updateAzureStatus(model InteractiveModeModel) tea.Cmd {
func UpdateAzureStatus(azureStatus environments.AzureDeploymentStatus, environment string) tea.Cmd {
return func() tea.Msg {
logging.GlobalLogger.Tracef(
"Attempting to update the azure status: %+v",
model.azureStatus,
azureStatus,
)
environments.ReportAzureStatus(model.azureStatus, model.environment)
environments.ReportAzureStatus(azureStatus, environment)
return AzureStatusUpdatedMessage{}
}
}
Expand Down
9 changes: 9 additions & 0 deletions internal/engine/common/globals.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package common

import tea "github.com/charmbracelet/bubbletea"

// TODO: Ideally we won't need a global program variable. We should
// refactor this in the future such that each tea program is localized to the
// function that creates it and ExecuteCodeBlockSync doesn't mutate the global
// program variable.
var Program *tea.Program = nil
Loading
Loading