Skip to content

Commit

Permalink
Merge pull request #604 from ystia/feature/godog-ci
Browse files Browse the repository at this point in the history
Feature/godog ci
  • Loading branch information
loicalbertin committed Feb 28, 2020
2 parents c5cae6f + 5202316 commit 59977fd
Show file tree
Hide file tree
Showing 27 changed files with 1,881 additions and 0 deletions.
4 changes: 4 additions & 0 deletions testdata/ci/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.vscode
.idea
components/*
ci
53 changes: 53 additions & 0 deletions testdata/ci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Yorc CI BDD

This project contains Behavior Driven Development integration tests.
We use [GoDog](https://github.com/DATA-DOG/godog) as BDD framework.

## How to use this

### Installation prerequisites

First godog binary should be installed using `go get github.com/DATA-DOG/godog/cmd/godog`.

Then you need to have Yorc and Alien4Cloud installed. We recommend using [Yorc bootstrap](https://yorc.readthedocs.io/en/latest/bootstrap.html) to do it.

### Configuration

This project comes with several configuration options that could be given using environment variables or a config file.
We use [Viper](https://github.com/spf13/viper) to manage configuration so the config file format may be JSON, TOML, YAML, HCL, envfile or Java properties.
A dot `.` in configuration keys name represent a nested key separator.

Here are supported config options:

| Config Key Name | Environment Variable Name | Default Value | Description |
| ----------------------------- | ----------------------------- | ----------------------- | ----------------------------------------------------------------------- |
| keep_failed_applications | KEEP_FAILED_APPLICATIONS | `false` | Do not undeploy the application if test fails |
| alien4cloud.url | ALIEN4CLOUD_URL | `http://127.0.0.1:8088` | Alien4Cloud URL |
| alien4cloud.user | ALIEN4CLOUD_USER | `admin` | Alien4Cloud user name |
| alien4cloud.password | ALIEN4CLOUD_PASSWORD | `admin` | Alien4Cloud user password |
| alien4cloud.ca | ALIEN4CLOUD_CA | no default | Path or content of a SSL CA used to connect to a secured Alien4Cloud |
| alien4cloud.orchestrator_name | ALIEN4CLOUD_ORCHESTRATOR_NAME | `yorc` | Name of the configured orchestrator in A4C to use to interact with Yorc |
| chromedp.no_headless | CHROMEDP_NO_HEADLESS | `false` | Specify if chromedp should run in headless mode |
| chromedp.timeout | CHROMEDP_TIMEOUT | `1m` | Timeout of chromedp execution should be expressed in Go duration format |

### Running

To run all tests without distinction simply run godog in the current folder:

```bash
ALIEN4CLOUD_URL="https://127.0.0.1:8088" godog
```

You can also specify a feature file:

```bash
godog features/TestDev.feature
```

For a better control you can also use tags:

```bash
godog -t "@premium && ~@slow,~@Monitoring"
```

This will run scenarios that are tagged `@premium` but not `~@slow` or `~@Monitoring`.
75 changes: 75 additions & 0 deletions testdata/ci/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"fmt"
"time"

"github.com/spf13/viper"
)

type Config struct {
KeepFailedApplications bool `mapstructure:"keep_failed_applications"`
Alien4Cloud Alien `mapstructure:"alien4cloud"`
Yorc Yorc `mapstructure:"yorc"`
ChromeDP ChromeDP `mapstructure:"chromedp"`
Infrastructure Infrastructure `mapstructure:"infrastructure"`
}

type Infrastructure struct {
Name string `mapstructure:"name"`
}

type Alien struct {
URL string `mapstructure:"url"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
CA string `mapstructure:"ca"`
OrchestratorName string `mapstructure:"orchestrator_name"`
}

type Yorc struct {
ResourcesPrefix string `mapstructure:"resources_prefix"`
}

type ChromeDP struct {
NoHeadless bool `mapstructure:"no_headless"`
Timeout time.Duration `mapstructure:"timeout"`
}

func initConfig() {
viper.SetConfigName("godog_config")
viper.AddConfigPath(".")

viper.AutomaticEnv()

viper.BindEnv("keep_failed_applications", "KEEP_FAILED_APPLICATIONS")
viper.BindEnv("alien4cloud.url", "ALIEN4CLOUD_URL")
viper.BindEnv("alien4cloud.user", "ALIEN4CLOUD_USER")
viper.BindEnv("alien4cloud.password", "ALIEN4CLOUD_PASSWORD")
viper.BindEnv("alien4cloud.ca", "ALIEN4CLOUD_CA")
viper.BindEnv("alien4cloud.orchestrator_name", "ALIEN4CLOUD_ORCHESTRATOR_NAME")
viper.BindEnv("yorc.resources_prefix", "YORC_RESOURCES_PREFIX")
viper.BindEnv("chromedp.no_headless", "CHROMEDP_NO_HEADLESS")
viper.BindEnv("chromedp.timeout", "CHROMEDP_TIMEOUT")
viper.BindEnv("infrastructure.name", "INFRASTRUCTURE_NAME")

viper.SetDefault("keep_failed_applications", false)
viper.SetDefault("alien4cloud.url", "http://127.0.0.1:8088")
viper.SetDefault("alien4cloud.user", "admin")
viper.SetDefault("alien4cloud.password", "admin")
viper.SetDefault("alien4cloud.orchestrator_name", "yorc")
viper.SetDefault("yorc.resources_prefix", "testci-")
viper.SetDefault("chromedp.no_headless", false)
viper.SetDefault("chromedp.timeout", time.Minute)
}

func getConfig() (Config, error) {
c := Config{}

err := viper.Unmarshal(&c)
if err != nil {
return c, fmt.Errorf("failed to unmarshal configuration file: %w", err)
}

return c, nil
}
109 changes: 109 additions & 0 deletions testdata/ci/context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"context"
"fmt"
"time"

"github.com/DATA-DOG/godog"
"github.com/DATA-DOG/godog/gherkin"
"github.com/alien4cloud/alien4cloud-go-client/v2/alien4cloud"
)

type suiteContext struct {
config Config
a4cClient alien4cloud.Client
applicationID string
environmentID string
ctx context.Context
cancel context.CancelFunc
}

func (c *suiteContext) reset(s interface{}) {
c.ctx, c.cancel = context.WithTimeout(context.Background(), 120*time.Minute)
err := c.a4cClient.Login(context.Background())
if err != nil {
panic(fmt.Errorf("failed to login into Alien4CLoud: %w", err))
}
c.applicationID = ""
c.environmentID = ""
}

func FeatureContext(s *godog.Suite) {
c := &suiteContext{}

s.BeforeSuite(func() {
initConfig()
var err error
c.config, err = getConfig()
if err != nil {
panic(fmt.Sprintf("Failed to get config: %+v", err))
}

var secure bool
if c.config.Alien4Cloud.CA != "" {
secure = true
}
c.a4cClient, err = alien4cloud.NewClient(c.config.Alien4Cloud.URL, c.config.Alien4Cloud.User, c.config.Alien4Cloud.Password, c.config.Alien4Cloud.CA, secure)
if err != nil {
panic(fmt.Sprintf("Failed to create alien4cloud client: %+v", err))
}
})

s.Step(`^I have uploaded the artifact named "([^"]*)" to Alien$`, c.iHaveUploadedTheArtifactNamedToAlien)
s.Step(`^I have created an application named "([^"]*)" based on template named "([^"]*)"$`, c.iHaveCreatedAnApplicationNamedBasedOnTemplateNamed)
s.Step(`^I deploy the application named "([^"]*)"$`, c.iDeployTheApplicationNamed)
s.Step(`^I wait for "([^"]*)" seconds$`, c.iWaitForSeconds)
s.Step(`^Kibana contains a dashboard named "([^"]*)"$`, c.kibanaContainsADashboardNamed)
s.Step(`^There is data in Kibana$`, c.thereIsDataInKibana)
s.Step(`^I have deployed the application named "([^"]*)"$`, c.iDeployTheApplicationNamed)
s.Step(`^I have deleted the policy named "([^"]*)" in the application "([^"]*)"$`, c.iHaveDeletedThePolicyNamedInTheApplication)
s.Step(`^I update the deployment with application "([^"]*)"$`, c.iUpdateTheDeploymentWithApplication)
s.Step(`^The web page with base url stored in attribute "([^"]*)" on node "([^"]*)" with path "([^"]*)" contains a title named "([^"]*)"$`, c.theWebPageWithBaseURLStoredInAttributeOnNodeWithPathContainsATitleNamed)
s.Step(`^I have deleted the workflow named "([^"]*)" in the application "([^"]*)"$`, c.iHaveDeletedTheWorkflowNamedInTheApplication)
s.Step(`^The workflow with name "([^"]*)" is no longer executable$`, c.theWorkflowWithNameIsNoLongerExecutable)
s.Step(`^I create the workflow with name "([^"]*)" in the application "([^"]*)"$`, c.iCreateTheWorkflowWithNameInTheApplication)
s.Step(`^I add a call-operation activity with operation "([^"]*)" on target "([^"]*)" to the workflow with name "([^"]*)" in the application "([^"]*)"$`, c.iAddACalloperationActivityWithOperationOnTargetToTheWorkflowWithNameInTheApplication)
s.Step(`^The workflow with name "([^"]*)" is again executable$`, c.theWorkflowWithNameIsAgainExecutable)
s.Step(`^I have deployed an application named "([^"]*)" on environment named "([^"]*)"$`, c.iHaveDeployedAnApplicationNamedOnEnvironmentNamed)
s.Step(`^I run the workflow named "([^"]*)"$`, c.iRunTheWorkflowNamed)
s.Step(`^The status of the instance "([^"]*)" of the node named "([^"]*)" is "([^"]*)"$`, c.theStatusOfTheInstanceOfTheNodeNamedIs)

s.Step(`^I have built the artifact named "([^"]*)" from templates named "([^"]*)" to Alien$`, c.iHaveBuiltTheArtifactNamedFromTemplatesNamedToAlien)
s.Step(`^The attribute "([^"]*)" of the instance "([^"]*)" of the node named "([^"]*)" is equal to the attribute "([^"]*)" of the instance "([^"]*)" of the node named "([^"]*)"$`, c.theAttributeOfTheInstanceOfTheNodeNamedIsEqualToTheAttributeOfTheInstanceOfTheNodeNamed)
s.Step(`^I have added a policy named "([^"]*)" of type "([^"]*)" on targets "([^"]*)"$`, c.iHaveAddedAPolicyNamedOfTypeOnTargets)
s.Step(`^The attribute "([^"]*)" of the instance "([^"]*)" of the node named "([^"]*)" is different than the attribute "([^"]*)" of the instance "([^"]*)" of the node named "([^"]*)"$`, c.theAttributeOfTheInstanceOfTheNodeNamedIsDifferentThanTheAttributeOfTheInstanceOfTheNodeNamed)
s.Step(`^The attribute "([^"]*)" of the instance "([^"]*)" of the node named "([^"]*)" is equal to "([^"]*)"$`, c.theAttributeOfTheInstanceOfTheNodeNamedIsEqualTo)

s.BeforeScenario(c.reset)

s.BeforeFeature(func(f *gherkin.Feature) {
if c.config.Infrastructure.Name != "" {
f.Name = fmt.Sprintf("[%s] %s", c.config.Infrastructure.Name, f.Name)
}
})

s.AfterScenario(func(s interface{}, scErr error) {
if c.cancel != nil {
defer c.cancel()
}
var tags []*gherkin.Tag
switch v := s.(type) {
case *gherkin.ScenarioOutline:
tags = v.Tags
case *gherkin.Scenario:
tags = v.Tags
}
if tagsContains(tags, "@cleanupAlien") && (scErr == nil || !c.config.KeepFailedApplications) && c.applicationID != "" && c.environmentID != "" {
ctx, cancel := context.WithTimeout(c.ctx, 30*time.Minute)
defer cancel()
c.a4cClient.DeploymentService().UndeployApplication(ctx, c.applicationID, c.environmentID)
c.a4cClient.DeploymentService().WaitUntilStateIs(ctx, c.applicationID, c.environmentID, alien4cloud.ApplicationUndeployed)
// Seems we need to wait a little time to avoid the terrible A4C delete deployed element error !!!
time.Sleep(2 * time.Second)
c.a4cClient.ApplicationService().DeleteApplication(ctx, c.applicationID)
}

c.a4cClient.Logout(c.ctx)
})
}
39 changes: 39 additions & 0 deletions testdata/ci/features/ELK_basic.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#
# 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France.
#

@slow
@selenium
@ELK_basic
Feature: Deploy a basic ELK application to Yorc using Alien4Cloud, both set-up using Yorc bootstrap

Background: Deploying required artifacts
Given I have uploaded the artifact named "org-ystia-common" to Alien
And I have uploaded the artifact named "org-ystia-consul-pub" to Alien
And I have uploaded the artifact named "org-ystia-consul-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-java-pub" to Alien
And I have uploaded the artifact named "org-ystia-java-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-elasticsearch-pub" to Alien
And I have uploaded the artifact named "org-ystia-elasticsearch-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-kafka-pub" to Alien
And I have uploaded the artifact named "org-ystia-kafka-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-logstash-pub" to Alien
And I have uploaded the artifact named "org-ystia-logstash-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-kibana-pub" to Alien
And I have uploaded the artifact named "org-ystia-kibana-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-beats-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-samples-dummylogs-linux-bash" to Alien
And I have uploaded the artifact named "org-ystia-samples-topologies-elk_dummylogs" to Alien

@CI
@openstack
@gcp
@cleanupAlien
Scenario: Deploy ELK
Given I have created an application named "TestElkDummyLogs" based on template named "org.ystia.samples.topologies.elk_dummylogs"

When I deploy the application named "TestElkDummyLogs"
And I wait for "20" seconds

Then Kibana contains a dashboard named "DummyLogs"
And There is data in Kibana
25 changes: 25 additions & 0 deletions testdata/ci/features/GenericResource.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France.
#

@GenericResource
Feature: Deploy a TestResourceApp application using Alien4Cloud with host generic resources requirements

Background: Deploying required artifacts
Given I have built the artifact named "testResource" from templates named "testResource" to Alien
And I have uploaded the artifact named "testResource" to Alien

@CI
@hp
@cleanupAlien
Scenario: Deploy a TestResourceApp application using Alien4Cloud with host generic resources requirements
Given I have created an application named "TestResourceApp" based on template named "org.ystia.ci.tests.test_resource"

When I deploy the application named "TestResourceApp"

Then The attribute "gpu" of the instance "0" of the node named "ComputeA" is equal to "gpu2"
Then The attribute "hostname" of the instance "0" of the node named "ComputeA" is equal to "hostspool-ci-0"

Then The attribute "gpu" of the instance "0" of the node named "ComputeB" is equal to "gpu0,gpu1"
Then The attribute "hostname" of the instance "0" of the node named "ComputeB" is equal to "hostspool-ci-1"

47 changes: 47 additions & 0 deletions testdata/ci/features/Monitoring.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#
# 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France.
#

@Monitoring
Feature: Deploy a Welcome application with monitoring to Yorc using Alien4Cloud, both set-up using Yorc bootstrap

Background: Deploying required artifacts
Given I have uploaded the artifact named "common" to Alien
And I have uploaded the artifact named "welcome-linux-bash" to Alien
And I have uploaded the artifact named "samples-tcp-echo-ansible" to Alien
And I have uploaded the artifact named "welcome_monitoring" to Alien

@CI
@openstack
@gcp
@cleanupAlien
Scenario: Deploy WelcomeMonitoringTest and check TCP and HTTP monitoring
Given I have created an application named "WelcomeMonitoringTest" based on template named "org.ystia.samples.topologies.welcome_monitoring"

When I deploy the application named "WelcomeMonitoringTest"
And I run the workflow named "killTCPEchoServer"
And I run the workflow named "killWebServer"
And I wait for "5" seconds

Then The status of the instance "0" of the node named "MntTCPEcho" is "error"
And The status of the instance "0" of the node named "MntWelcome" is "error"

@premium
@CI
@openstack
@gcp
@cleanupAlien
Scenario: Update WelcomeMonitoringTest and check TCP and HTTP Monitoring are no longer working
Given I have created an application named "WelcomeMonitoringTest" based on template named "org.ystia.samples.topologies.welcome_monitoring"
And I have deployed the application named "WelcomeMonitoringTest"
And I have deleted the policy named "TCPMonitoring" in the application "WelcomeMonitoringTest"
And I have deleted the policy named "HTTPMonitoring" in the application "WelcomeMonitoringTest"

When I update the deployment with application "WelcomeMonitoringTest"
And I run the workflow named "killTCPEchoServer"
And I run the workflow named "killWebServer"
And I wait for "5" seconds

Then The status of the instance "0" of the node named "MntTCPEcho" is "started"
And The status of the instance "0" of the node named "MntWelcome" is "started"

0 comments on commit 59977fd

Please sign in to comment.