Merge branch 'master' into issues/162-impl-manual-promotion

Conflicts:
	features/api/webhook/multipleWebhooks.feature
	src/test/groovy/deploydb/WorkFlowSpec.groovy
This commit is contained in:
Mahesh V Kelkar 2015-04-22 16:35:02 -04:00
commit 2a51a4492e
28 changed files with 2700 additions and 3123 deletions

View File

@ -61,8 +61,10 @@ dependencies {
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'cglib:cglib-nodep:2.2.+'
testCompile project(':dropwizard-integtest')
cucumberCompile 'info.cukes:cucumber-groovy:1.2.+'
cucumberCompile project(':dropwizard-integtest')
/* Include unboundid sdk for in-memory ldap test server */
cucumberCompile 'com.unboundid:unboundid-ldapsdk:2.3.8'

25
deploydb.spock.yml Normal file
View File

@ -0,0 +1,25 @@
database:
driverClass: org.h2.Driver
user: nobody
url: "jdbc:h2:mem:cucumber"
# DeployDB base configuration directory (cannonical path)
# YAML configuration files for models - services, environments, pipelines,
# webhooks and promotions - should be stored in respective sub-directories
#configDirectory: config
whoas:
queue:
type: "com.github.lookout.whoas.InMemoryQueue"
runnerType: "com.github.lookout.whoas.SequentialHookRunner"
logging:
level: INFO
loggers:
org.hibernate.SQL: ALL
appenders:
- type: file
currentLogFilename: ./logs/deploydb-spock.log
threshold: ALL
archive: false
timeZone: UTC

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
apply plugin: 'eclipse'
apply plugin: 'groovy'
version = '0.1'
group = 'com.github.lookout.dropwizard.integtest'
description = 'common deploydb test library to be used by both cukes and spock'
project.targetCompatibility = 1.7
dependencies {
compile ('org.codehaus.groovy:groovy-all:2.4.0+')
[
'dropwizard-core',
'dropwizard-assets',
'dropwizard-jersey',
'dropwizard-hibernate',
'dropwizard-views-mustache',
'dropwizard-testing',
].each {
compile ("io.dropwizard:${it}:0.8.1")
}
/* Used instead of the default HTTP connector for the Jersey client to
* allow us to make PATCH requests
*/
compile ('org.glassfish.jersey.connectors:jersey-apache-connector:2.+')
/* Used for managing migrations */
compile ('io.dropwizard.modules:dropwizard-flyway:0.7.0-1')
compile ('joda-time:joda-time:2.6+')
}
repositories {
jcenter()
mavenCentral()
maven { url 'http://dl.bintray.com/lookout/systems' }
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,9 +1,7 @@
package deploydb.cucumber
package dropwizardintegtest
import com.google.common.base.Strings
import com.google.common.collect.ImmutableMap
import deploydb.WebhookManager
import deploydb.WorkFlow
import io.dropwizard.Application
import io.dropwizard.Configuration
import io.dropwizard.cli.ServerCommand
@ -33,8 +31,6 @@ public class StubAppRunner<C extends Configuration> {
private Environment environment
private Server jettyServer
private SessionFactory sessionFactory
private WorkFlow workFlow
private WebhookManager webhookManager
public StubAppRunner(Class<? extends Application<C>> applicationClass,
@Nullable String configPath,
@ -78,30 +74,25 @@ public class StubAppRunner<C extends Configuration> {
* it's up and running
*/
sessionFactory = application.sessionFactory
webhookManager = application.webhooksManager
/**
* Save workflow object
*/
workFlow = application.workFlow
/**
* Setup config checksum for tests
*/
application.configChecksum = "0xdead"
/* We're running the DB migrations here to make sure we're running
* them in the same classloader environment as the DeployDB
* application, otherwise the Hibernate code running inside of
* DeployDB won't be able to "see" the in-memory DB
*/
Flyway flyway = configuration.flyway.build(
configuration.database.build(metricRegistry, "Flyway"))
flyway.clean()
flyway.migrate()
}
})
/**
* Setup config checksum for tests
*/
application.configChecksum = "0xdead"
/* We're running the DB migrations here to make sure we're running
* them in the same classloader environment as the DeployDB
* application, otherwise the Hibernate code running inside of
* DeployDB won't be able to "see" the in-memory DB
*/
Flyway flyway = configuration.flyway.build(
configuration.database.build(metricRegistry, "Flyway"))
flyway.clean()
flyway.migrate()
StubAppRunner.this.configuration = configuration
StubAppRunner.this.environment = environment
super.run(configuration, environment)

View File

@ -1,4 +1,4 @@
package deploydb.cucumber
package dropwizardintegtest
import com.google.common.base.Strings
import com.google.common.collect.ImmutableMap
@ -12,8 +12,6 @@ import io.dropwizard.testing.ConfigOverride
import net.sourceforge.argparse4j.inf.Namespace
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import webhookTestServer.models.RequestWebhookObject
import webhookTestServer.models.ResponseWebhookObject
import javax.annotation.Nullable

View File

@ -1,4 +1,4 @@
package webhookTestServer.health
package dropwizardintegtest
import com.codahale.metrics.health.HealthCheck

View File

@ -1,4 +1,4 @@
package webhookTestServer.models
package dropwizardintegtest
import com.google.common.collect.HashMultimap

View File

@ -1,4 +1,4 @@
package webhookTestServer.models
package dropwizardintegtest
import com.fasterxml.jackson.annotation.JsonProperty

View File

@ -1,4 +1,4 @@
package webhookTestServer.resources
package dropwizardintegtest
import com.codahale.metrics.annotation.Timed
import com.google.common.base.Charsets

View File

@ -1,10 +1,8 @@
package webhookTestServer.resources
package dropwizardintegtest
import io.dropwizard.hibernate.UnitOfWork
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import webhookTestServer.models.RequestWebhookObject
import webhookTestServer.models.ResponseWebhookObject
import javax.servlet.http.HttpServletRequest
import javax.ws.rs.POST

View File

@ -1,9 +1,6 @@
package webhookTestServer
package dropwizardintegtest
import io.dropwizard.setup.Bootstrap
import webhookTestServer.models.RequestWebhookObject
import webhookTestServer.models.ResponseWebhookObject
import webhookTestServer.health.webhookTestServerHealthCheck
import io.dropwizard.Application
import io.dropwizard.setup.Environment
@ -43,8 +40,8 @@ class webhookTestServerApp extends Application<webhookTestServerConfiguration>{
responseWebhookObject.responseCode = "201"
responseWebhookObject.delayBeforeResponseInSecs = 0
environment.jersey().register(new resources.RootResource())
environment.jersey().register(new resources.TestCallBackobjectResource(requestWebhookObject,
environment.jersey().register(new RootResource())
environment.jersey().register(new TestCallBackobjectResource(requestWebhookObject,
responseWebhookObject))
}

View File

@ -1,4 +1,4 @@
package webhookTestServer
package dropwizardintegtest
import io.dropwizard.Configuration

View File

@ -2,6 +2,6 @@ description: "Basic Environment"
webhook:
deployment:
created:
- http://jenkins.example.com/job/basicEnv-deploy-created/build
- http://localhost:10000/job/basicEnv-deploy-created/build
completed:
- http://jenkins.example.com/job/basicEnv-deploy-completed/build
- http://localhost:10000/job/basicEnv-deploy-completed/build

View File

@ -49,613 +49,4 @@ Feature: Webhook invocation when deployment is created with multiple webhooks
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: Multiple environment webhooks should be invoked when artifacts are created
Given an deployment environment webhook "created" configuration named "integ":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/job/notify-deployment-created/build
- http://localhost:10000/job/another-notify-deployment-created/build
"""
And promotions are configured
And a pipeline is configured
And a service is configured
When I POST to "/api/artifacts" with an artifact
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: Global webhook and environment webhook should be invoked when artifacts are created
Given a deployment webhook "created" configuration:
"""
deployment:
created:
- http://localhost:10000/job/notify-deployment-created/build
"""
And an deployment environment webhook "created" configuration named "integ":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/job/another-notify-deployment-created/build
"""
And promotions are configured
And a pipeline is configured
And a service is configured
When I POST to "/api/artifacts" with an artifact
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: Both global and environment webhooks should be invoked when promotion is completed with success
Given a promotion webhook "completed" configuration:
"""
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
"""
And an promotion environment webhook "completed" configuration named "pre-prod":
"""
description: "DeployDB Primary Integration"
webhook:
promotion:
completed:
- http://localhost:10000/job/another-notify-promotion-completed/build
"""
And there is a deployment in "COMPLETED" state
And promotions are configured
When I POST to "/api/deployments/1/promotions" with:
"""
{
"name" : "jenkins-smoke",
"status" : "SUCCESS",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results"
}
"""
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "VERIFIED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}",
"promotionResult":{
"id" : 1,
"createdAt" : "{{created_timestamp}}",
"promotion": "jenkins-smoke",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results",
"status" : "SUCCESS"
}
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "VERIFIED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}",
"promotionResult":{
"id" : 1,
"createdAt" : "{{created_timestamp}}",
"promotion": "jenkins-smoke",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results",
"status" : "SUCCESS"
}
}
"""
@freezetime @webhook
Scenario: Only Global webhook should be invoked when environment webhooks doesn't contain deployment created event
Given a deployment webhook "created" configuration:
"""
deployment:
created:
- http://localhost:10000/notify-deployment-created/build
started:
- http://localhost:10000/job/notify-deployment-started/build
"""
And an deployment environment webhook "created" configuration named "integ":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
completed:
- http://localhost:10000/job/notify-deployment-completed/build
"""
And promotions are configured
And a pipeline is configured
And a service is configured
When I POST to "/api/artifacts" with an artifact
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: Only environment webhooks should be invoked when global webhooks doesn't contain deployment created event
Given a deployment webhook "created" configuration:
"""
deployment:
started:
- http://localhost:10000/job/notify-deployment-started/build
completed:
- http://localhost:10000/job/notify-deployment-completed/build
"""
And an deployment environment webhook "created" configuration named "integ":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/notify-deployment-created/build
- http://localhost:10000/another-notify-deployment-created/build
completed:
- http://localhost:10000/job/notify-deployment-completed/build
"""
And promotions are configured
And a pipeline is configured
And a service is configured
When I POST to "/api/artifacts" with an artifact
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: Only global webhooks should be invoked when environment webhooks doesn't contain deployment started event
Given a deployment webhook "started" configuration:
"""
deployment:
created:
- http://localhost:10000/job/notify-deployment-created/build
started:
- http://localhost:10000/job/notify-deployment-started/build
- http://localhost:10000/job/another-notify-deployment-started/build
completed:
- http://localhost:10000/job/notify-deployment-completed/build
- http://localhost:10000/job/another-notify-deployment-completed/build
promotion:
completed:
- http://localhost:10000/job/notify-completed-completed/build
"""
And an deployment environment webhook "started" configuration named "pre-prod":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/notify-deployment-created/build
completed:
- http://localhost:10000/job/notify-deployment-completed/build
"""
And there is a deployment in "CREATED" state
When I PATCH "/api/deployments/1" with:
"""
{
"status" : "STARTED"
}
"""
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "STARTED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}"
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "STARTED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: Global webhooks should be invoked when environment webhook doesn't contain promotion event for promotion success
Given a promotion webhook "completed" configuration:
"""
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
- http://localhost:10000/job/another-notify-promotion-completed/build
"""
And an promotion environment webhook "completed" configuration named "pre-prod":
"""
description: "DeployDB Primary Integration"
"""
And there is a deployment in "COMPLETED" state
And promotions are configured
When I POST to "/api/deployments/1/promotions" with:
"""
{
"name" : "jenkins-smoke",
"status" : "SUCCESS",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results"
}
"""
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "VERIFIED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}",
"promotionResult":{
"id" : 1,
"createdAt" : "{{created_timestamp}}",
"promotion": "jenkins-smoke",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results",
"status" : "SUCCESS"
}
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "VERIFIED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}",
"promotionResult":{
"id" : 1,
"createdAt" : "{{created_timestamp}}",
"promotion": "jenkins-smoke",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results",
"status" : "SUCCESS"
}
}
"""
@freezetime @webhook
Scenario: Environment webhooks should be invoked when global webhook doesn't contain promotion event for promotion success
Given a promotion webhook "completed" configuration:
"""
deployment:
completed:
- http://localhost:10000/job/notify-deployment-completed/build
- http://localhost:10000/job/another-notify-deployment-completed/build
"""
And an promotion environment webhook "completed" configuration named "pre-prod":
"""
description: "DeployDB Primary Integration"
webhook:
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
- http://localhost:10000/job/another-notify-promotion-completed/build
"""
And there is a deployment in "COMPLETED" state
And promotions are configured
When I POST to "/api/deployments/1/promotions" with:
"""
{
"name" : "jenkins-smoke",
"status" : "SUCCESS",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results"
}
"""
Then the webhook 1 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "VERIFIED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}",
"promotionResult":{
"id" : 1,
"createdAt" : "{{created_timestamp}}",
"promotion": "jenkins-smoke",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results",
"status" : "SUCCESS"
}
}
"""
And the webhook 2 should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "VERIFIED",
"service" : "faas",
"environment" : "pre-prod",
"createdAt" : "{{created_timestamp}}",
"promotionResult":{
"id" : 1,
"createdAt" : "{{created_timestamp}}",
"promotion": "jenkins-smoke",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results",
"status" : "SUCCESS"
}
}
"""
@freezetime @webhook
Scenario: webhooks should be invoked for first environment in a pipeline
Given an deployment environment webhook "created" configuration named "integ":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/job/notify-deployment-started/build
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
"""
And an deployment environment webhook "created" configuration named "prod":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/job/prod-notify-deployment-started/build
"""
And promotions are configured
And a multi environment pipeline is configured
And a service is configured
When I POST to "/api/artifacts" with an artifact
Then the webhook should be invoked with the JSON:
"""
{
"id" : 1,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cukes",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "integ",
"createdAt" : "{{created_timestamp}}"
}
"""
@freezetime @webhook
Scenario: webhooks should be invoked for second environment in a pipeline
Given an deployment environment webhook "created" configuration named "integ":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/job/notify-deployment-started/build
"""
And an deployment environment webhook "created" configuration named "prod":
"""
description: "DeployDB Primary Integration"
webhook:
deployment:
created:
- http://localhost:10000/job/prod-notify-deployment-started/build
"""
And the first deployments is in "COMPLETED" state
And promotions are configured
When I POST to "/api/deployments/1/promotions" with:
"""
{
"name" : "status-check",
"status" : "SUCCESS",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results"
}
"""
Then the webhook should be invoked with the JSON:
"""
{
"id" : 2,
"artifact" : {
"id" : 1,
"group" : "com.example.cucumber",
"name" : "cucumber-artifact",
"version" : "1.0.1",
"sourceUrl" : "http://example.com/maven/com.example.cucumber/cucumber-artifact/1.0.1/cucumber-artifact-1.0.1.jar",
"createdAt" : "{{created_timestamp}}"
},
"status" : "CREATED",
"service" : "faas",
"environment" : "prod",
"createdAt" : "{{created_timestamp}}"
}
"""

1
settings.gradle Normal file
View File

@ -0,0 +1 @@
include "dropwizard-integtest"

View File

@ -1,24 +1,28 @@
package deploydb.cucumber
import deploydb.models.Webhook.Webhook
import deploydb.ModelLoader
import deploydb.DeployDBApp
import com.github.mustachejava.DefaultMustacheFactory
import com.github.mustachejava.Mustache
import deploydb.DeployDBApp
import deploydb.ModelLoader
import deploydb.models.Webhook.Webhook
import io.dropwizard.auth.basic.BasicCredentials
import javax.ws.rs.core.Response
import org.glassfish.jersey.client.ClientConfig
import javax.ws.rs.client.Client
import javax.ws.rs.client.ClientBuilder
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider
import org.glassfish.jersey.client.JerseyInvocation
import javax.ws.rs.core.Response
import javax.ws.rs.client.Entity
import org.hibernate.Session
import org.hibernate.SessionFactory
import org.hibernate.context.internal.ManagedSessionContext
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider
import org.glassfish.jersey.client.ClientConfig
import org.glassfish.jersey.client.JerseyInvocation
import dropwizardintegtest.StubAppRunner
import dropwizardintegtest.WebhookTestServerAppRunner
import dropwizardintegtest.webhookTestServerApp
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature
import webhookTestServer.webhookTestServerApp
class AppHelper {
private StubAppRunner runner = null
@ -53,7 +57,7 @@ class AppHelper {
* @param c (required) Closure to execute
*/
void withServiceRegistry(Closure c) {
c.call(this.runner.workFlow.serviceRegistry)
c.call(this.runner.getApplication().workFlow.serviceRegistry)
}
/**
@ -62,7 +66,7 @@ class AppHelper {
* @param c (required) Closure to execute
*/
void withEnvironmentRegistry(Closure c) {
c.call(this.runner.workFlow.environmentRegistry)
c.call(this.runner.getApplication().workFlow.environmentRegistry)
}
/**
@ -71,7 +75,7 @@ class AppHelper {
* @param c (required) Closure to execute
*/
void withPromotionRegistry(Closure c) {
c.call(this.runner.workFlow.promotionRegistry)
c.call(this.runner.getApplication().workFlow.promotionRegistry)
}
/**
@ -80,7 +84,7 @@ class AppHelper {
* @param c (required) Closure to execute
*/
void withPipelineRegistry(Closure c) {
c.call(this.runner.workFlow.pipelineRegistry)
c.call(this.runner.getApplication().workFlow.pipelineRegistry)
}
/**
@ -89,11 +93,11 @@ class AppHelper {
* @param c (required) Closure to execute
*/
void withWorkFlow(Closure c) {
c.call(this.runner.workFlow)
c.call(this.runner.getApplication().workFlow)
}
/**
* Execute the {@link Closure} with a proper WebhookManager
* Execute the {@link Closure} with a proper TestWebhookServer
*
* @param c (required) Closure to execute
*/
@ -224,14 +228,16 @@ class AppHelper {
* For a valid webhook configuration, deployment and promotion are valid objects
*/
if (webhook != null && webhook.deployment != null) {
eventUrlList = this.runner.webhookManager.getMemberOfObject(webhook.deployment, eventType)
eventUrlList = this.runner.getApplication().webhooksManager.getMemberOfObject(
webhook.deployment, eventType)
}
if (webhook != null && webhook.promotion != null) {
/*
* Only event type valid for promotion is "completed", ignore all other types
*/
if (eventType == "completed") {
eventUrlList += this.runner.webhookManager.getMemberOfObject(webhook.promotion, eventType)
eventUrlList += this.runner.getApplication().webhooksManager.getMemberOfObject(
webhook.promotion, eventType)
}
}

View File

@ -13,8 +13,8 @@ import deploydb.models.Webhook.Webhook
import deploydb.registry.ModelRegistry
import org.joda.time.DateTime
import cucumber.api.DataTable
import webhookTestServer.models.RequestWebhookObject
import dropwizardintegtest.RequestWebhookObject
Given(~/^a (.*?) webhook "(.*?)" configuration:$/) { String webhookType,
String eventType, String configBody ->

View File

@ -147,15 +147,7 @@ class DeployDBApp extends Application<DeployDBConfiguration> {
* Load configuration models
*/
this.configDirectory = configuration.configDirectory
withHibernateSession() {
try {
workFlow.loadConfigModels()
} catch (Exception e) {
logger.error("failed to read config from directory: " +
"${configDirectory} with an exception: ", e)
throw e
}
}
loadModelConfiguration()
/**
* webhooksManager
@ -211,4 +203,20 @@ class DeployDBApp extends Application<DeployDBConfiguration> {
ManagedSessionContext.unbind(this.getSessionFactory())
}
}
/**
* This function will load configuration with hibernate session.
*/
void loadModelConfiguration(){
withHibernateSession() {
try {
workFlow.loadConfigModels()
} catch (Exception e) {
logger.error("failed to read config from directory: " +
"${configDirectory} with an exception: ", e)
throw e
}
}
}
}

View File

@ -0,0 +1,214 @@
package deploydb
import spock.lang.*
class DeploymentCompletedNotificationsSpec extends Specification {
IntegrationTestAppHelper integAppHelper = new IntegrationTestAppHelper()
IntegrationModelHelper integModelHelper = new IntegrationModelHelper(integAppHelper)
private WebhooksModelConfigHelper mcfgHelper = new WebhooksModelConfigHelper()
def setup() {
mcfgHelper.setup()
integAppHelper.startAppWithConfiguration('deploydb.spock.yml')
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
integAppHelper.runner.getApplication().configDirectory = mcfgHelper.baseCfgDirName
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.deploymentcompleted.v1+json"
}
def cleanup() {
integAppHelper.stopApp()
integAppHelper.stopWebhookTestServerApp()
mcfgHelper.cleanup()
}
def "no webhook should be called when you receive deployment completed trigger if there is no webhook config" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 0
}
def "webhook should be called when you receive deployment completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createDeploymentCompletedWebhookConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-completed/build"]
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "environment webhook should be called when you receive deployment completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createDeploymentCompletedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-completed/build"]
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "both global and environment webhooks should be called when you receive deployment completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createDeploymentCompletedWebhookConfigFile()
mcfgHelper.createDeploymentCompletedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-completed/build","/job/basicEnv-deploy-completed/build"]
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple webhooks should be called when you receive deployment completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleDeploymentCompletedWebhooksConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-completed-1/build", "/job/notify-deployment-completed-2/build"]
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple environments webhook should be called when you receive deployment completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleDeploymentCompletedEnvironmentWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-completed-1/build","/job/basicEnv-deploy-completed-2/build"]
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "both multiple global and environment webhooks should be called when you receive deployment completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleDeploymentCompletedWebhooksConfigFile()
mcfgHelper.createMultipleDeploymentCompletedEnvironmentWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-completed-1/build", "/job/notify-deployment-completed-2/build",
"/job/basicEnv-deploy-completed-1/build", "/job/basicEnv-deploy-completed-2/build"]
// setup the deployment for completed trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 4
}
}

View File

@ -0,0 +1,201 @@
package deploydb
import spock.lang.*
class DeploymentCreatedNotificationsSpec extends Specification {
IntegrationTestAppHelper integAppHelper = new IntegrationTestAppHelper()
IntegrationModelHelper integModelHelper = new IntegrationModelHelper(integAppHelper)
private WebhooksModelConfigHelper mcfgHelper = new WebhooksModelConfigHelper()
def setup() {
mcfgHelper.setup()
integAppHelper.startAppWithConfiguration('deploydb.spock.yml')
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.deploymentcreated.v1+json"
integAppHelper.runner.getApplication().configDirectory = mcfgHelper.baseCfgDirName
}
def cleanup() {
integAppHelper.stopApp()
integAppHelper.stopWebhookTestServerApp()
mcfgHelper.cleanup()
}
def "no webhook should be called when you create an artifact with no webhook configuration" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 0
}
def "webhook should be called when you create an artifact" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createWebhookConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-created/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "environment webhook should be called when you create an artifact" () {
given:
// create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createEnvironmentConfigFile()
// load up the config
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-created/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "both global and environment webhooks should be called when you create an artifact" () {
given:
// create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createWebhookConfigFile()
mcfgHelper.createEnvironmentConfigFile()
// load up the config
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-created/build", "/job/basicEnv-deploy-created/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple webhook should be called when you create an artifact" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleWebhooksConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-created-1/build", "/job/notify-deployment-created-2/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple environment webhook should be called when you create an artifact" () {
given:
// create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleWebhooksEnvironmentConfigFile()
// load up the config
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-created-1/build", "/job/basicEnv-deploy-created-2/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "both multiple global and multiple environment webhooks should be called when you create an artifact" () {
given:
// create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleWebhooksConfigFile()
mcfgHelper.createMultipleWebhooksEnvironmentConfigFile()
// load up the config
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-created-1/build", "/job/notify-deployment-created-2/build",
"/job/basicEnv-deploy-created-1/build", "/job/basicEnv-deploy-created-2/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 4
}
}

View File

@ -0,0 +1,212 @@
package deploydb
import spock.lang.*
class DeploymentStartedNotificationsSpec extends Specification {
IntegrationTestAppHelper integAppHelper = new IntegrationTestAppHelper()
IntegrationModelHelper integModelHelper = new IntegrationModelHelper(integAppHelper)
private WebhooksModelConfigHelper mcfgHelper = new WebhooksModelConfigHelper()
def setup() {
mcfgHelper.setup()
integAppHelper.startAppWithConfiguration('deploydb.spock.yml')
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
integAppHelper.runner.getApplication().configDirectory = mcfgHelper.baseCfgDirName
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.deploymentstarted.v1+json"
}
def cleanup() {
integAppHelper.stopApp()
integAppHelper.stopWebhookTestServerApp()
mcfgHelper.cleanup()
}
def "no webhook should be called when you receive deployment started trigger if there is no webhook config" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 0
}
def "webhook should be called when you receive deployment started trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createDeploymentStartedWebhookConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-started/build"]
// setup the deployment for started trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "environment webhook should be called when you receive deployment started trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createDeploymentStartedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-started/build"]
// setup the deployment for started trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "both global and environment webhooks should be called when you receive deployment started trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createDeploymentStartedWebhookConfigFile()
mcfgHelper.createDeploymentStartedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-started/build","/job/basicEnv-deploy-started/build"]
// setup the deployment for started trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple webhooks should be called when you receive deployment started trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleDeploymentStartedWebhooksConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-started-1/build", "/job/notify-deployment-started-2/build"]
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple environments webhook should be called when you receive deployment started trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleDeploymentStartedEnvironmentWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-started-1/build", "/job/basicEnv-deploy-started-2/build"]
// setup the deployment for started trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "both multiple global and environment webhooks should be called when you receive deployment started trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultipleDeploymentStartedWebhooksConfigFile()
mcfgHelper.createMultipleDeploymentStartedEnvironmentWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-deployment-started-1/build", "/job/notify-deployment-started-2/build",
"/job/basicEnv-deploy-started-1/build", "/job/basicEnv-deploy-started-2/build"]
// setup the deployment for started trigger
integModelHelper.sendCreateArtifact()
when:
boolean success = integModelHelper.sendDeploymentStartedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 4
}
}

View File

@ -0,0 +1,64 @@
package deploydb
import deploydb.models.Artifact
import javax.ws.rs.core.Response
class IntegrationModelHelper {
private IntegrationTestAppHelper integrationTestAppHelper = null
IntegrationModelHelper(IntegrationTestAppHelper integTestAppHelper) {
integrationTestAppHelper = integTestAppHelper
}
boolean sendCreateArtifact() {
String path = "/api/artifacts"
String messageBody = """
{
"group" : "basic.group.1",
"name" : "bg1",
"version" : "1.2.345",
"sourceUrl" : "http://example.com/cucumber.jar"
}
"""
return (integrationTestAppHelper.postJsonToPath(path, messageBody, false)).status == 201
}
boolean sendDeploymentStartedTrigger() {
String path = "/api/deployments/1"
String messageBody = """
{
"status" : "STARTED"
}
"""
Response response = integrationTestAppHelper.patchJsonToPath(path, messageBody)
response.close()
return response.status == 200
}
boolean sendDeploymentCompletedTrigger() {
String path = "/api/deployments/1"
String messageBody = """
{
"status" : "COMPLETED"
}
"""
Response response = integrationTestAppHelper.patchJsonToPath(path, messageBody)
response.close()
return response.status == 200
}
boolean sendPromotionCompletedTrigger() {
String path = "/api/deployments/1/promotions"
String messageBody = """
{
"name" : "basicPromo",
"status" : "SUCCESS",
"infoUrl" : "http://local.lookout.com/jenkins/job-id/2/results"
}
"""
Response response = integrationTestAppHelper.postJsonToPath(path, messageBody, false)
response.close()
return response.status == 201
}
}

View File

@ -0,0 +1,162 @@
package deploydb
import deploydb.models.Webhook.Webhook
import com.github.mustachejava.DefaultMustacheFactory
import com.github.mustachejava.Mustache
import org.glassfish.jersey.client.ClientConfig
import javax.ws.rs.client.Client
import javax.ws.rs.client.ClientBuilder
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider
import org.glassfish.jersey.client.JerseyInvocation
import javax.ws.rs.core.Response
import javax.ws.rs.client.Entity
import org.hibernate.Session
import org.hibernate.SessionFactory
import org.hibernate.context.internal.ManagedSessionContext
import dropwizardintegtest.StubAppRunner
import dropwizardintegtest.WebhookTestServerAppRunner
import dropwizardintegtest.webhookTestServerApp
class IntegrationTestAppHelper {
private StubAppRunner runner = null
private Client jerseyClient = null
private WebhookTestServerAppRunner webhookRunner = null
SessionFactory getSessionFactory() {
return this.runner.sessionFactory
}
/**
* Execute the {@link Closure} with a properly set up
* {@link org.hibernate.Session}
*
* @param c (required) Closure to execute with a session
*/
void withSession(Closure c) {
final Session session = sessionFactory.openSession()
try {
ManagedSessionContext.bind(session)
c.call()
}
finally {
session.close()
}
}
String processTemplate(String buffer, Map scope) {
DefaultMustacheFactory mf = new DefaultMustacheFactory()
StringWriter writer = new StringWriter()
Mustache m = mf.compile(new StringReader(buffer),
'cuke-stash-compiler')
m.execute(writer, scope)
return writer.toString()
}
Client getClient() {
if (this.jerseyClient == null) {
ClientConfig clientConfig = new ClientConfig()
clientConfig.connectorProvider(new ApacheConnectorProvider())
this.jerseyClient = ClientBuilder.newClient(clientConfig)
}
return this.jerseyClient
}
/**
* Create the proper full URL for our running app with the given path.
*
* If this is an admin request, we'll hit the admin port correctly
*/
String urlWithPort(String path, Boolean isAdmin) {
int port = isAdmin ? runner.adminPort : runner.localPort
return String.format("http://localhost:%d${path}", port)
}
JerseyInvocation makeRequestToPath(String path, String method, Entity entity) {
return this.makeRequestToPath(path, method, entity, false)
}
JerseyInvocation makeRequestToPath(String path, String method, Entity entity, Boolean isAdmin) {
return client.target(urlWithPort(path, isAdmin))
.request()
.build(method, entity)
}
/**
* Execute a POST to the test server for step definitions
*/
Response postJsonToPath(String path, String requestBody, Boolean isAdmin) {
return this.makeRequestToPath(path, 'POST', Entity.json(requestBody), isAdmin).invoke()
}
/**
* Execute a PATCH to the test server for step definitions
*/
Response patchJsonToPath(String path, String requestBody) {
return this.makeRequestToPath(path, 'PATCH', Entity.json(requestBody)).invoke()
}
Response deleteFromPath(String path) {
return this.makeRequestToPath(path, 'DELETE', null).invoke()
}
/*
* Get url path from webhook config body
*/
List<String> getUrlPathFromWebhookConfigBody(String configBody, String eventType) {
ModelLoader<Webhook> webhookLoader = new
ModelLoader<Webhook>(Webhook.class)
Webhook webhook = webhookLoader.loadFromString(configBody)
return getUrlPathFromWebhook(webhook, configBody, eventType)
}
/**
* Minor convenience method to make sure we're dispatching GET requests to the
* right port in our test application
*/
Response getFromPath(String path, boolean isAdmin) {
return this.makeRequestToPath(path, 'GET', null , isAdmin).invoke()
}
/** Set config directory */
void setConfigDirectory(String configDirectory) {
this.runner.setConfigDirectory(configDirectory)
}
void startAppWithConfiguration(String config) {
if (this.runner != null) {
return
}
println("start application with config ${config}")
this.runner = new StubAppRunner(DeployDBApp.class, config)
this.runner.start()
}
void stopApp() {
if (this.runner != null) {
this.runner.stop()
}
}
void startWebhookTestServerWithConfiguration(String config) {
if (this.webhookRunner != null) {
return
}
println("start webhook test server with config ${config}")
this.webhookRunner = new WebhookTestServerAppRunner(webhookTestServerApp.class, config)
this.webhookRunner.start()
}
void stopWebhookTestServerApp() {
if (this.webhookRunner != null) {
this.webhookRunner.stop()
}
}
}

View File

@ -0,0 +1,361 @@
package deploydb
class ModelConfigHelper {
String baseCfgDirName = "./build/tmp/config"
def setup() {
File baseCfgDir = new File(baseCfgDirName)
if (baseCfgDir.exists()) {
baseCfgDir.deleteDir()
}
}
def cleanup() {
File baseCfgDir = new File(baseCfgDirName)
if (baseCfgDir.exists()) {
baseCfgDir.deleteDir()
}
}
def createEnvironmentWebhookConfigFile(String fileContents, String name) {
/* Create temp file */
File environmentsDir = new File("${baseCfgDirName}/environments")
if (!environmentsDir.exists()) {
environmentsDir.mkdirs()
}
File environmentFile = new File(environmentsDir, "${name}.yml")
environmentFile.write(fileContents)
}
def createBasicWebhookConfigFile(String fileContents) {
/* Create temp file */
File webhookDir = new File("${baseCfgDirName}/webhook")
if (!webhookDir.exists()) {
webhookDir.mkdirs()
}
File webhookFile = new File(webhookDir, "basicWebhook.yml")
webhookFile.write(fileContents)
}
def createPromotionConfigFile() {
String fileContents = """
type: deploydb.models.promotion.BasicPromotionImpl
description: "Basic Smoke test for the Basic Service"
"""
/* Create temp file */
File promotionsDir = new File("${baseCfgDirName}/promotions")
if (!promotionsDir.exists()) {
promotionsDir.mkdirs()
}
File promotionFile = new File(promotionsDir, "basicPromo.yml")
promotionFile.write(fileContents)
}
def createAnotherPromotionConfigFile() {
String fileContents = """
type: deploydb.models.promotion.ManualLDAPPromotionImpl
description: "Advanced Smoke test for the Basic Service"
"""
/* Create temp file */
File promotionsDir = new File("${baseCfgDirName}/promotions")
if (!promotionsDir.exists()) {
promotionsDir.mkdirs()
}
File promotionFile = new File(promotionsDir, "advancedPromo.yml")
promotionFile.write(fileContents)
}
def createEnvironmentConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
created:
- http://localhost:10000/job/basicEnv-deploy-created/build
completed:
- http://localhost:10000/job/basicEnv-deploy-completed/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createEnvironmentNoWebhooksConfigFile() {
String fileContents = """
description: "Basic Environment"
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createPipelineConfigFile() {
String fileContents = """
description: "Basic pipeline"
environments:
basicEnv:
promotions:
- basicPromo
"""
/* Create temp file */
File pipelinesDir = new File("${baseCfgDirName}/pipelines")
if (!pipelinesDir.exists()) {
pipelinesDir.mkdirs()
}
File pipelineFile = new File(pipelinesDir, "basicPipe.yml")
pipelineFile.write(fileContents)
}
def createWebhookConfigFile() {
String fileContents = """
deployment:
created:
- http://localhost:10000/job/notify-deployment-created/build
started:
- http://localhost:10000/job/notify-deployment-started/build
completed:
- http://localhost:10000/job/notify-deployment-completed/build
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createServiceConfigFile() {
String fileContents = """
description: "Basic Service"
artifacts:
- basic.group.1:bg1
- basic.group.2:bg2
pipelines:
- basicPipe
promotions:
- basicPromo
"""
/* Create temp file */
File servicesDir = new File("${baseCfgDirName}/services")
if (!servicesDir.exists()) {
servicesDir.mkdirs()
}
File serviceFile = new File(servicesDir, "basicServ.yml")
serviceFile.write(fileContents)
}
def createProdEnvironmentConfigFile() {
String fileContents = """
description: "Production Environment"
webhook:
deployment:
created:
- http://localhost:10000/job/prodEnv-deploy-created/build
completed:
- http://localhost:10000/job/prodEnv-deploy-completed/build
"""
createEnvironmentWebhookConfigFile(fileContents, "prodEnv")
}
def createBasicProdPipelineConfigFile() {
String fileContents = """
description: "Basic pipeline"
environments:
basicEnv:
promotions:
- basicPromo
prodEnv:
promotions:
- basicPromo
"""
/* Create temp file */
File pipelinesDir = new File("${baseCfgDirName}/pipelines")
if (!pipelinesDir.exists()) {
pipelinesDir.mkdirs()
}
File pipelineFile = new File(pipelinesDir, "basicPipe.yml")
pipelineFile.write(fileContents)
}
}
class WebhooksModelConfigHelper extends deploydb.ModelConfigHelper {
def createMultipleWebhooksConfigFile() {
String fileContents = """
deployment:
created:
- http://localhost:10000/job/notify-deployment-created-1/build
- http://localhost:10000/job/notify-deployment-created-2/build
started:
- http://localhost:10000/job/notify-deployment-started-1/build
- http://localhost:10000/job/notify-deployment-started-2/build
completed:
- http://localhost:10000/job/notify-deployment-completed-1/build
- http://localhost:10000/job/notify-deployment-completed-2/build
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed-1/build
- http://localhost:10000/job/notify-promotion-completed-2/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createMultipleWebhooksEnvironmentConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
created:
- http://localhost:10000/job/basicEnv-deploy-created-1/build
- http://localhost:10000/job/basicEnv-deploy-created-2/build
completed:
- http://localhost:10000/job/basicEnv-deploy-completed/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createDeploymentStartedWebhookConfigFile() {
String fileContents = """
deployment:
started:
- http://localhost:10000/job/notify-deployment-started/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createDeploymentStartedEnvironmentWebhookConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
started:
- http://localhost:10000/job/basicEnv-deploy-started/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createMultipleDeploymentStartedWebhooksConfigFile() {
String fileContents = """
deployment:
started:
- http://localhost:10000/job/notify-deployment-started-1/build
- http://localhost:10000/job/notify-deployment-started-2/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createMultipleDeploymentStartedEnvironmentWebhooksConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
started:
- http://localhost:10000/job/basicEnv-deploy-started-1/build
- http://localhost:10000/job/basicEnv-deploy-started-2/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createDeploymentCompletedWebhookConfigFile() {
String fileContents = """
deployment:
completed:
- http://localhost:10000/job/notify-deployment-completed/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createDeploymentCompletedEnvironmentWebhookConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
completed:
- http://localhost:10000/job/basicEnv-deploy-completed/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createMultipleDeploymentCompletedWebhooksConfigFile() {
String fileContents = """
deployment:
completed:
- http://localhost:10000/job/notify-deployment-completed-1/build
- http://localhost:10000/job/notify-deployment-completed-2/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createMultipleDeploymentCompletedEnvironmentWebhooksConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
completed:
- http://localhost:10000/job/basicEnv-deploy-completed-1/build
- http://localhost:10000/job/basicEnv-deploy-completed-2/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createPromotionCompletedWebhookConfigFile() {
String fileContents = """
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createPromotionCompletedEnvironmentWebhookConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
promotion:
completed:
- http://localhost:10000/job/basicEnv-promotion-completed/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createMultiplePromotionCompletedWebhookConfigFile() {
String fileContents = """
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed-1/build
- http://localhost:10000/job/notify-promotion-completed-2/build
"""
createBasicWebhookConfigFile(fileContents)
}
def createMultiplePromotionCompletedEnvironmentWebhookConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
promotion:
completed:
- http://localhost:10000/job/basicEnv-promotion-completed-1/build
- http://localhost:10000/job/basicEnv-promotion-completed-2/build
"""
createEnvironmentWebhookConfigFile(fileContents, "basicEnv")
}
def createServicePromoitionPipelineModelsConfigFiles() {
createPromotionConfigFile()
createPipelineConfigFile()
createServiceConfigFile()
}
def createBasicProdServicePromoitionPipelineModelsConfigFiles() {
createEnvironmentConfigFile()
createProdEnvironmentConfigFile()
createPromotionConfigFile()
createBasicProdPipelineConfigFile()
createServiceConfigFile()
}
}

View File

@ -0,0 +1,87 @@
package deploydb
import spock.lang.*
class MultipleEnvironmentsNotificationsSpec extends Specification {
IntegrationTestAppHelper integAppHelper = new IntegrationTestAppHelper()
IntegrationModelHelper integModelHelper = new IntegrationModelHelper(integAppHelper)
private WebhooksModelConfigHelper mcfgHelper = new WebhooksModelConfigHelper()
def setup() {
mcfgHelper.setup()
integAppHelper.startAppWithConfiguration('deploydb.spock.yml')
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
integAppHelper.runner.getApplication().configDirectory = mcfgHelper.baseCfgDirName
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.deploymentcreated.v1+json"
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
}
def cleanup() {
integAppHelper.stopApp()
integAppHelper.stopWebhookTestServerApp()
mcfgHelper.cleanup()
}
/**
* This integration tests end-to-end scenario when multiple environment are configured in
* pipeline. In this scenario multiple deployments are created and once a given deployment
* is verified with promotion result, then we transition to next deployment.
*
*/
def "multiple notifications should be called when configured with multiple environment pipeline" () {
given:
// Create the required config
mcfgHelper.createBasicProdServicePromoitionPipelineModelsConfigFiles()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-created/build"]
when:
boolean success = integModelHelper.sendCreateArtifact()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
when:
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.deploymentcompleted.v1+json"
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-created/build", "/job/basicEnv-deploy-completed/build"]
success = integModelHelper.sendDeploymentCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
when:
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.deploymentcreated.v1+json"
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-deploy-created/build", "/job/basicEnv-deploy-completed/build",
"/job/prodEnv-deploy-created/build"]
success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 3
}
}

View File

@ -0,0 +1,218 @@
package deploydb
import spock.lang.*
class PromotionCompletedNotificationsSpec extends Specification {
IntegrationTestAppHelper integAppHelper = new IntegrationTestAppHelper()
IntegrationModelHelper integModelHelper = new IntegrationModelHelper(integAppHelper)
private WebhooksModelConfigHelper mcfgHelper = new WebhooksModelConfigHelper()
def setup() {
mcfgHelper.setup()
integAppHelper.startAppWithConfiguration('deploydb.spock.yml')
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
// load up the configuration
integAppHelper.runner.getApplication().configDirectory = mcfgHelper.baseCfgDirName
integAppHelper.webhookRunner.requestWebhookObject.contentTypeParam =
"application/vnd.deploydb.promotioncompleted.v1+json"
integAppHelper.startWebhookTestServerWithConfiguration('webhookTestServer.example.yml')
}
def cleanup() {
integAppHelper.stopApp()
integAppHelper.stopWebhookTestServerApp()
mcfgHelper.cleanup()
}
def setupDeploymentForPromotionTrigger(){
integModelHelper.sendCreateArtifact()
integModelHelper.sendDeploymentStartedTrigger()
integModelHelper.sendDeploymentCompletedTrigger()
}
def "no webhook should be called when you receive promotion completed trigger if there is no webhook config" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
// setup the deployment for promotion trigger
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 0
}
def "webhook should be called when you receive promotion completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createPromotionCompletedWebhookConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-promotion-completed/build"]
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "environment webhook should be called when you receive promotion completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createPromotionCompletedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-promotion-completed/build"]
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 1
}
def "both global and environment webhooks should be called when you receive promotion completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createPromotionCompletedWebhookConfigFile()
mcfgHelper.createPromotionCompletedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-promotion-completed/build","/job/basicEnv-promotion-completed/build"]
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple webhooks should be called when you receive promotion completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultiplePromotionCompletedWebhookConfigFile()
mcfgHelper.createEnvironmentNoWebhooksConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-promotion-completed-1/build", "/job/notify-promotion-completed-2/build"]
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "multiple environment webhooks should be called when you receive promotion completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultiplePromotionCompletedEnvironmentWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/basicEnv-promotion-completed-1/build", "/job/basicEnv-promotion-completed-2/build"]
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 2
}
def "both multiple global and environment webhooks should be called when you receive promotion completed trigger" () {
given:
// Create the required config
mcfgHelper.createServicePromoitionPipelineModelsConfigFiles()
mcfgHelper.createMultiplePromotionCompletedEnvironmentWebhookConfigFile()
mcfgHelper.createMultiplePromotionCompletedWebhookConfigFile()
// load up the configuration
integAppHelper.runner.getApplication().loadModelConfiguration()
/* set the webhookTestServer's requestWebhookObject. This data will be compare once deploydb
* sends the webhook to the webhookTestServer
*/
integAppHelper.webhookRunner.requestWebhookObject.configuredUriPaths =
["/job/notify-promotion-completed-1/build", "/job/notify-promotion-completed-2/build",
"/job/basicEnv-promotion-completed-1/build", "/job/basicEnv-promotion-completed-2/build"]
setupDeploymentForPromotionTrigger()
when:
boolean success = integModelHelper.sendPromotionCompletedTrigger()
then:
success == true
sleep(1000)
integAppHelper.webhookRunner.requestWebhookObject.requestMessageBodies.size() == 4
}
}

View File

@ -18,14 +18,15 @@ class WorkFlowSpec extends Specification {
}
class workFlowWithArgsSpec extends Specification {
private String baseCfgDirName = "./build/tmp/config"
private ModelConfigHelper modelConfigHelper = new ModelConfigHelper()
private DeployDBApp app = new DeployDBApp()
private WorkFlow workFlow
private FlowDAO fdao = Mock(FlowDAO)
private ModelConfigDAO mdao = Mock(ModelConfigDAO)
def setup() {
app.configDirectory = baseCfgDirName
modelConfigHelper.setup()
app.configDirectory = modelConfigHelper.baseCfgDirName
app.configChecksum = null
workFlow = new WorkFlow(app)
workFlow.initializeRegistry()
@ -34,132 +35,16 @@ class workFlowWithArgsSpec extends Specification {
}
def cleanup() {
File baseCfgDir = new File(baseCfgDirName)
if (baseCfgDir.exists()) {
baseCfgDir.deleteDir()
}
}
def createPromotionConfigFile() {
String fileContents = """
type: deploydb.models.promotion.BasicPromotionImpl
description: "Basic Smoke test for the Basic Service"
"""
/* Create temp file */
File promotionsDir = new File("${baseCfgDirName}/promotions")
if (!promotionsDir.exists()) {
promotionsDir.mkdirs()
}
File promotionFile = new File(promotionsDir, "basicPromo.yml")
promotionFile.write(fileContents)
}
def createAnotherPromotionConfigFile() {
String fileContents = """
type: deploydb.models.promotion.ManualLDAPPromotionImpl
description: "Manual LDAP Promotion"
"""
/* Create temp file */
File promotionsDir = new File("${baseCfgDirName}/promotions")
if (!promotionsDir.exists()) {
promotionsDir.mkdirs()
}
File promotionFile = new File(promotionsDir, "advancedPromo.yml")
promotionFile.write(fileContents)
}
def createEnvironmentConfigFile() {
String fileContents = """
description: "Basic Environment"
webhook:
deployment:
created:
- http://jenkins.example.com/job/basicEnv-deploy-created/build
completed:
- http://jenkins.example.com/job/basicEnv-deploy-completed/build
"""
/* Create temp file */
File environmentsDir = new File("${baseCfgDirName}/environments")
if (!environmentsDir.exists()) {
environmentsDir.mkdirs()
}
File environmentFile = new File(environmentsDir, "basicEnv.yml")
environmentFile.write(fileContents)
}
def createPipelineConfigFile() {
String fileContents = """
description: "Basic pipeline"
environments:
basicEnv:
promotions:
- basicPromo
"""
/* Create temp file */
File pipelinesDir = new File("${baseCfgDirName}/pipelines")
if (!pipelinesDir.exists()) {
pipelinesDir.mkdirs()
}
File pipelineFile = new File(pipelinesDir, "basicPipe.yml")
pipelineFile.write(fileContents)
}
def createServiceConfigFile() {
String fileContents = """
description: "Basic Service"
artifacts:
- basic.group.1:bg1
- basic.group.2:bg2
pipelines:
- basicPipe
promotions:
- basicPromo
"""
/* Create temp file */
File servicesDir = new File("${baseCfgDirName}/services")
if (!servicesDir.exists()) {
servicesDir.mkdirs()
}
File serviceFile = new File(servicesDir, "basicServ.yml")
serviceFile.write(fileContents)
}
def createWebhookConfigFile() {
String fileContents = """
deployment:
created:
- http://localhost:10000/job/notify-deployment-created/build
started:
- http://localhost:10000/job/notify-deployment-started/build
completed:
- http://localhost:10000/job/notify-deployment-completed1/build
- http://localhost:10000/job/notify-deployment-completed2/build
promotion:
completed:
- http://localhost:10000/job/notify-promotion-completed/build
"""
/* Create temp file */
File webhookDir = new File("${baseCfgDirName}/webhook")
if (!webhookDir.exists()) {
webhookDir.mkdirs()
}
File webhookFile = new File(webhookDir, "basicWebhook.yml")
webhookFile.write(fileContents)
modelConfigHelper.cleanup()
}
def "Load entire config from a directory and make sure it passes"() {
given:
createPromotionConfigFile()
createEnvironmentConfigFile()
createPipelineConfigFile()
createServiceConfigFile()
createWebhookConfigFile()
modelConfigHelper.createPromotionConfigFile()
modelConfigHelper.createEnvironmentConfigFile()
modelConfigHelper.createPipelineConfigFile()
modelConfigHelper.createServiceConfigFile()
modelConfigHelper.createWebhookConfigFile()
workFlow.loadConfigModels()
mdao.persist(_) >> _
@ -177,8 +62,8 @@ promotion:
def "If promotion is missing, then loading pipeline in loadConfigModels throws an exception"() {
when:
createEnvironmentConfigFile()
createPipelineConfigFile()
modelConfigHelper.createEnvironmentConfigFile()
modelConfigHelper.createPipelineConfigFile()
workFlow.loadConfigModels()
mdao.persist(_) >> _
@ -188,8 +73,8 @@ promotion:
def "If environment is missing, then loading pipeline in loadConfigModels throws an exception"() {
when:
createPromotionConfigFile()
createPipelineConfigFile()
modelConfigHelper.createPromotionConfigFile()
modelConfigHelper.createPipelineConfigFile()
workFlow.loadConfigModels()
mdao.persist(_) >> _
@ -199,9 +84,9 @@ promotion:
def "If pipeline is missing, then loading service in loadConfigModels throws an exception"() {
when:
createPromotionConfigFile()
createEnvironmentConfigFile()
createServiceConfigFile()
modelConfigHelper.createPromotionConfigFile()
modelConfigHelper.createEnvironmentConfigFile()
modelConfigHelper.createServiceConfigFile()
workFlow.loadConfigModels()
mdao.persist(_) >> _
@ -212,11 +97,11 @@ promotion:
def "Reload unchanged config from a directory and make sure its ignored"() {
given:
createPromotionConfigFile()
createEnvironmentConfigFile()
createPipelineConfigFile()
createServiceConfigFile()
createWebhookConfigFile()
modelConfigHelper.createPromotionConfigFile()
modelConfigHelper.createEnvironmentConfigFile()
modelConfigHelper.createPipelineConfigFile()
modelConfigHelper.createServiceConfigFile()
modelConfigHelper.createWebhookConfigFile()
workFlow.loadConfigModels()
String oldChecksum = app.configChecksum
mdao.persist(_) >> _
@ -231,14 +116,14 @@ promotion:
def "Reload changed config from a directory and make sure it passes"() {
given:
createPromotionConfigFile()
createEnvironmentConfigFile()
createPipelineConfigFile()
createServiceConfigFile()
createWebhookConfigFile()
modelConfigHelper.createPromotionConfigFile()
modelConfigHelper.createEnvironmentConfigFile()
modelConfigHelper.createPipelineConfigFile()
modelConfigHelper.createServiceConfigFile()
modelConfigHelper.createWebhookConfigFile()
workFlow.loadConfigModels()
String oldChecksum = app.configChecksum
createAnotherPromotionConfigFile()
modelConfigHelper.createAnotherPromotionConfigFile()
mdao.persist(_) >> _
when: