nifi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bbe...@apache.org
Subject nifi-registry git commit: NIFIREG-37: Add integration tests for web API to build
Date Mon, 23 Oct 2017 12:49:49 GMT
Repository: nifi-registry
Updated Branches:
  refs/heads/master 93863f5b0 -> 74e254941


NIFIREG-37: Add integration tests for web API to build

This closes #24.

Signed-off-by: Bryan Bende <bbende@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi-registry/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-registry/commit/74e25494
Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/74e25494
Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/74e25494

Branch: refs/heads/master
Commit: 74e25494127f3a3cb4f1ed4735919a9b5e36abeb
Parents: 93863f5
Author: Kevin Doran <kdoran.apache@gmail.com>
Authored: Wed Oct 18 15:53:46 2017 -0400
Committer: Bryan Bende <bbende@apache.org>
Committed: Mon Oct 23 08:49:28 2017 -0400

----------------------------------------------------------------------
 .travis.yml                                     |   2 +-
 nifi-registry-client/pom.xml                    |   6 +
 .../org/apache/nifi/registry/flow/Position.java |  24 +
 .../nifi/registry/flow/VersionedComponent.java  |  28 ++
 nifi-registry-framework/pom.xml                 |   6 -
 .../registry/db/DatabaseMetadataService.java    |   4 +-
 .../db/migration/V999999.1__test-setup.sql      |  24 +-
 nifi-registry-web-api/pom.xml                   |  28 +-
 .../web/NiFiRegistrySecurityConfig.java         |   6 +-
 .../registry/web/api/BucketFlowResource.java    |  17 +-
 .../nifi/registry/web/api/BucketResource.java   |   2 +
 .../NiFiRegistryApiTestApplication.java         |  59 +++
 .../apache/nifi/registry/web/api/BucketsIT.java | 250 ++++++++++
 .../apache/nifi/registry/web/api/FlowsIT.java   | 457 +++++++++++++++++++
 .../registry/web/api/IntegrationTestBase.java   |  78 ++++
 .../web/api/UnsecuredIntegrationTestBase.java   |  50 ++
 .../src/test/resources/application.properties   |  29 ++
 .../src/test/resources/conf/providers.xml       |  25 +
 .../conf/unsecured/nifi-registry.properties     |  25 +
 .../src/test/resources/db/BucketsIT.sql         |  26 ++
 .../src/test/resources/db/FlowsIT.sql           |  50 ++
 .../src/test/resources/db/clearDB.sql           |  19 +
 pom.xml                                         |  47 +-
 23 files changed, 1220 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 6811415..4f8da18 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,4 +51,4 @@ before_install:
     - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
 
 install: true
-script:  mvn -T 2C clean install -PjsUnitTests
\ No newline at end of file
+script:  mvn -T 2C clean install -PjsUnitTests,integration-tests,contrib-check
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-client/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-client/pom.xml b/nifi-registry-client/pom.xml
index daf8ddd..129e2ff 100644
--- a/nifi-registry-client/pom.xml
+++ b/nifi-registry-client/pom.xml
@@ -40,5 +40,11 @@
             <groupId>org.glassfish.jersey.media</groupId>
             <artifactId>jersey-media-json-jackson</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>${org.slf4j.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/Position.java
----------------------------------------------------------------------
diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/Position.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/Position.java
index 0cbb12c..e12cddd 100644
--- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/Position.java
+++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/Position.java
@@ -19,6 +19,8 @@ package org.apache.nifi.registry.flow;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
 
 @ApiModel("The position of a component on the graph")
 public class Position {
@@ -55,4 +57,26 @@ public class Position {
     public String toString() {
         return "[x=" + x + ", y=" + y + "]";
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Position position = (Position) o;
+
+        return new EqualsBuilder()
+                .append(x, position.x)
+                .append(y, position.y)
+                .isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37)
+                .append(x)
+                .append(y)
+                .toHashCode();
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedComponent.java
----------------------------------------------------------------------
diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedComponent.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedComponent.java
index af9b3d7..9c7dcb5 100644
--- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedComponent.java
+++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedComponent.java
@@ -18,6 +18,8 @@
 package org.apache.nifi.registry.flow;
 
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
 
 
 public abstract class VersionedComponent {
@@ -68,4 +70,30 @@ public abstract class VersionedComponent {
     public void setComponentType(ComponentType type) {
         // purposely do nothing here, this just to allow unmarshalling
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        VersionedComponent that = (VersionedComponent) o;
+
+        return new EqualsBuilder()
+                .append(identifier, that.identifier)
+                .append(name, that.name)
+                .append(comments, that.comments)
+                .append(position, that.position)
+                .isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37)
+                .append(identifier)
+                .append(name)
+                .append(comments)
+                .append(position)
+                .toHashCode();
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-framework/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/pom.xml b/nifi-registry-framework/pom.xml
index 002d460..faf6c48 100644
--- a/nifi-registry-framework/pom.xml
+++ b/nifi-registry-framework/pom.xml
@@ -177,12 +177,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>4.12</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
index 0710ef3..02be445 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/db/DatabaseMetadataService.java
@@ -353,7 +353,9 @@ public class DatabaseMetadataService implements MetadataService {
 
     @Override
     public FlowSnapshotEntity createFlowSnapshot(final FlowSnapshotEntity flowSnapshot) {
-        flowSnapshot.setCreated(new Date());
+        if (flowSnapshot.getCreated() == null) {
+            flowSnapshot.setCreated(new Date());
+        }
         return flowSnapshotRepository.save(flowSnapshot);
     }
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql b/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
index 4352e50..26fe647 100644
--- a/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
+++ b/nifi-registry-framework/src/test/resources/db/migration/V999999.1__test-setup.sql
@@ -16,38 +16,38 @@
 -- test data for buckets
 
 insert into bucket (id, name, description, created)
-  values ('1', 'Bucket 1', 'This is test bucket 1', parsedatetime('2017-09-11 12:51:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+  values ('1', 'Bucket 1', 'This is test bucket 1', parsedatetime('2017-09-11 12:51:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
 
 insert into bucket (id, name, description, created)
-  values ('2', 'Bucket 2', 'This is test bucket 2', parsedatetime('2017-09-11 12:52:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+  values ('2', 'Bucket 2', 'This is test bucket 2', parsedatetime('2017-09-11 12:52:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
 
 insert into bucket (id, name, description, created)
-  values ('3', 'Bucket 3', 'This is test bucket 3', parsedatetime('2017-09-11 12:53:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+  values ('3', 'Bucket 3', 'This is test bucket 3', parsedatetime('2017-09-11 12:53:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
 
 insert into bucket (id, name, description, created)
-  values ('4', 'Bucket 4', 'This is test bucket 4', parsedatetime('2017-09-11 12:54:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+  values ('4', 'Bucket 4', 'This is test bucket 4', parsedatetime('2017-09-11 12:54:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
 
 insert into bucket (id, name, description, created)
-  values ('5', 'Bucket 5', 'This is test bucket 5', parsedatetime('2017-09-11 12:55:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+  values ('5', 'Bucket 5', 'This is test bucket 5', parsedatetime('2017-09-11 12:55:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
 
 insert into bucket (id, name, description, created)
-  values ('6', 'Bucket 6', 'This is test bucket 6', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'));
+  values ('6', 'Bucket 6', 'This is test bucket 6', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
 
 
 -- test data for flows
 
 insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
-  values ('1', 'Flow 1', 'This is flow 1', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'FLOW', '1');
+  values ('1', 'Flow 1', 'This is flow 1', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'FLOW', '1');
 
 insert into flow (id) values ('1');
 
 insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
-  values ('2', 'Flow 2', 'This is flow 2', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'FLOW', '1');
+  values ('2', 'Flow 2', 'This is flow 2', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'FLOW', '1');
 
 insert into flow (id) values ('2');
 
 insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
-  values ('3', 'Flow 3', 'This is flow 3', parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), parsedatetime('2017-09-11 12:56:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'FLOW', '2');
+  values ('3', 'Flow 3', 'This is flow 3', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'FLOW', '2');
 
 insert into flow (id) values ('3');
 
@@ -55,10 +55,10 @@ insert into flow (id) values ('3');
 -- test data for flow snapshots
 
 insert into flow_snapshot (flow_id, version, created, comments)
-  values ('1', 1, parsedatetime('2017-09-11 12:57:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'This is flow 1 snapshot 1');
+  values ('1', 1, parsedatetime('2017-09-11 12:57:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'This is flow 1 snapshot 1');
 
 insert into flow_snapshot (flow_id, version, created, comments)
-  values ('1', 2, parsedatetime('2017-09-11 12:58:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'This is flow 1 snapshot 2');
+  values ('1', 2, parsedatetime('2017-09-11 12:58:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'This is flow 1 snapshot 2');
 
 insert into flow_snapshot (flow_id, version, created, comments)
-  values ('1', 3, parsedatetime('2017-09-11 12:59:00.000', 'yyyy-MM-dd hh:mm:ss.SSS'), 'This is flow 1 snapshot 3');
\ No newline at end of file
+  values ('1', 3, parsedatetime('2017-09-11 12:59:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'This is flow 1 snapshot 3');
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/pom.xml b/nifi-registry-web-api/pom.xml
index 3e1308a..caa74b6 100644
--- a/nifi-registry-web-api/pom.xml
+++ b/nifi-registry-web-api/pom.xml
@@ -137,11 +137,17 @@
             <version>0.0.1-SNAPSHOT</version>
             <scope>provided</scope> <!-- This will be in lib directory -->
         </dependency>
-	<dependency>
-	    <groupId>org.apache.nifi.registry</groupId>
-            <artifactId>nifi-registry-security-utils</artifactId>
+        <dependency>
+            <groupId>org.apache.nifi.registry</groupId>
+            <artifactId>nifi-registry-provider-api</artifactId>
             <version>0.0.1-SNAPSHOT</version>
-	</dependency>
+            <scope>provided</scope> <!-- This will be in lib directory -->
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi.registry</groupId>
+                <artifactId>nifi-registry-security-utils</artifactId>
+                <version>0.0.1-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
@@ -185,5 +191,19 @@
             <artifactId>guava</artifactId>
             <version>18.0</version>
         </dependency>
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <version>${spring.boot.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <!-- Integration tests run using embedded Jetty server -->
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jetty</artifactId>
+            <version>${spring.boot.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/NiFiRegistrySecurityConfig.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/NiFiRegistrySecurityConfig.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/NiFiRegistrySecurityConfig.java
index e9431d0..3c5c62f 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/NiFiRegistrySecurityConfig.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/NiFiRegistrySecurityConfig.java
@@ -72,12 +72,12 @@ public class NiFiRegistrySecurityConfig extends WebSecurityConfigurerAdapter {
 
     @Override
     public void configure(WebSecurity webSecurity) throws Exception {
-        // ignore the access endpoints for obtaining the access config, the access token
+        // ignore the access endpoints for obtaining the access config, access token
         // granting, and access status for a given user (note: we are not ignoring the
-        // the /access/download-token and /access/ui-extension-token endpoints
+        // the /access/download-token endpoints)
         webSecurity
                 .ignoring()
-                    .antMatchers("/access", "/access/config", "/access/token", "/access/kerberos", "/access/oidc/**");
+                    .antMatchers("/access", "/access/config", "/access/token");
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
index de602a6..f626b3d 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
@@ -101,6 +101,7 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.WRITE, bucketId);
         verifyPathParamsMatchBody(bucketId, flow);
         final VersionedFlow createdFlow = registryService.createFlow(bucketId, flow);
+        linkService.populateFlowLinks(createdFlow);
         return Response.status(Response.Status.OK).entity(createdFlow).build();
     }
 
@@ -166,7 +167,6 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
         final VersionedFlow flow = registryService.getFlow(bucketId, flowId, false);
 
         linkService.populateFlowLinks(flow);
-
         if (flow.getSnapshotMetadata() != null) {
             linkService.populateSnapshotLinks(flow.getSnapshotMetadata());
         }
@@ -203,6 +203,11 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.WRITE, bucketId);
 
         final VersionedFlow updatedFlow = registryService.updateFlow(flow);
+        linkService.populateFlowLinks(updatedFlow);
+        if (updatedFlow.getSnapshotMetadata() != null) {
+            linkService.populateSnapshotLinks(updatedFlow.getSnapshotMetadata());
+        }
+
         return Response.status(Response.Status.OK).entity(updatedFlow).build();
     }
 
@@ -261,6 +266,9 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
 
         setSnaphotMetadataIfMissing(bucketId, flowId, snapshot);
         final VersionedFlowSnapshot createdSnapshot = registryService.createFlowSnapshot(snapshot);
+        if (createdSnapshot.getSnapshotMetadata() != null) {
+            linkService.populateSnapshotLinks(createdSnapshot.getSnapshotMetadata());
+        }
         return Response.status(Response.Status.OK).entity(createdSnapshot).build();
     }
 
@@ -328,6 +336,10 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
         final VersionedFlowSnapshotMetadata lastSnapshotMetadata = snapshots.last();
         final VersionedFlowSnapshot lastSnapshot = registryService.getFlowSnapshot(bucketId, flowId, lastSnapshotMetadata.getVersion());
 
+        if (lastSnapshot.getSnapshotMetadata() != null) {
+            linkService.populateSnapshotLinks(lastSnapshot.getSnapshotMetadata());
+        }
+
         return Response.status(Response.Status.OK).entity(lastSnapshot).build();
     }
 
@@ -357,6 +369,9 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
                 final Integer versionNumber) {
         authorizeBucketAccess(RequestAction.READ, bucketId);
         final VersionedFlowSnapshot snapshot = registryService.getFlowSnapshot(bucketId, flowId, versionNumber);
+        if (snapshot.getSnapshotMetadata() != null) {
+            linkService.populateSnapshotLinks(snapshot.getSnapshotMetadata());
+        }
         return Response.status(Response.Status.OK).entity(snapshot).build();
     }
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
index 4614ae4..a83286e 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
@@ -100,6 +100,7 @@ public class BucketResource extends AuthorizableApplicationResource {
     public Response createBucket(final Bucket bucket) {
         authorizeAccess(RequestAction.WRITE);
         final Bucket createdBucket = registryService.createBucket(bucket);
+        linkService.populateBucketLinks(createdBucket);
         return Response.status(Response.Status.OK).entity(createdBucket).build();
     }
 
@@ -204,6 +205,7 @@ public class BucketResource extends AuthorizableApplicationResource {
         authorizeBucketAccess(RequestAction.WRITE, bucketId);
 
         final Bucket updatedBucket = registryService.updateBucket(bucket);
+        linkService.populateBucketLinks(updatedBucket);
         return Response.status(Response.Status.OK).entity(updatedBucket).build();
     }
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/NiFiRegistryApiTestApplication.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/NiFiRegistryApiTestApplication.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/NiFiRegistryApiTestApplication.java
new file mode 100644
index 0000000..01b0269
--- /dev/null
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/NiFiRegistryApiTestApplication.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry;
+
+import org.apache.nifi.registry.db.DataSourceFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
+
+import java.util.Properties;
+
+@SpringBootApplication
+@ComponentScan(
+        excludeFilters = {
+                @ComponentScan.Filter(
+                        type = FilterType.ASSIGNABLE_TYPE,
+                        value = SpringBootServletInitializer.class), // Avoid loading NiFiRegistryApiApplication
+                @ComponentScan.Filter(
+                        type = FilterType.ASSIGNABLE_TYPE,
+                        value = DataSourceFactory.class), // Avoid loading DataSourceFactory
+                @ComponentScan.Filter(
+                        type = FilterType.REGEX,
+                        pattern = "org\\.apache\\.nifi\\.registry\\.NiFiRegistryPropertiesFactory"), // Avoid loading NiFiRegistryPropertiesFactory
+        })
+public class NiFiRegistryApiTestApplication extends SpringBootServletInitializer {
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        final Properties fixedProps = new Properties();
+        fixedProps.setProperty("spring.jpa.hibernate.ddl-auto", "none");
+        fixedProps.setProperty("spring.jpa.hibernate.naming.physical-strategy", "org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl");
+
+        return application
+                .sources(NiFiRegistryApiTestApplication.class)
+                .properties(fixedProps);
+    }
+
+    public static void main(String[] args) {
+        SpringApplication.run(NiFiRegistryApiTestApplication.class, args);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
new file mode 100644
index 0000000..88ce2da
--- /dev/null
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.web.api;
+
+import org.apache.nifi.registry.bucket.Bucket;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.test.context.jdbc.Sql;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class BucketsIT extends UnsecuredIntegrationTestBase {
+
+    private final Client client = ClientBuilder.newClient();
+
+    @Test
+    public void testGetBucketsEmpty() throws Exception {
+
+        // Given: a fresh context server with an empty DB
+        // When: the /buckets endpoint is queried
+
+        final Bucket[] buckets = client
+                .target(createURL("buckets"))
+                .request()
+                .get(Bucket[].class);
+
+        // Then: an empty array is returned
+
+        assertNotNull(buckets);
+        assertEquals(0, buckets.length);
+    }
+
+    @Test
+    @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:db/clearDB.sql", "classpath:db/BucketsIT.sql"})
+    public void testGetBuckets() throws Exception {
+
+        // Given: these buckets have been populated in the DB (see BucketsIT.sql)
+
+        String expected = "[" +
+                "{\"identifier\":\"1\"," +
+                "\"name\":\"Bucket 1\"," +
+                "\"createdTimestamp\":1505091060000," +
+                "\"description\":\"This is test bucket 1\"," +
+                "\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1\"}}," +
+                "{\"identifier\":\"2\"," +
+                "\"name\":\"Bucket 2\"," +
+                "\"createdTimestamp\":1505091120000," +
+                "\"description\":\"This is test bucket 2\"," +
+                "\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/2\"}}," +
+                "{\"identifier\":\"3\"," +
+                "\"name\":\"Bucket 3\"," +
+                "\"createdTimestamp\":1505091180000," +
+                "\"description\":\"This is test bucket 3\"," +
+                "\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/3\"}}" +
+                "]";
+
+        // When: the /buckets endpoint is queried
+
+        String bucketsJson = client
+                .target(createURL("buckets"))
+                .request()
+                .get(String.class);
+
+        // Then: the pre-populated list of buckets is returned
+
+        JSONAssert.assertEquals(expected, bucketsJson, false);
+    }
+
+    @Test
+    public void testGetNonexistentBucket() throws Exception {
+        // Given: a fresh context server with an empty DB
+        // When: any /buckets/{id} endpoint is queried
+        Response response = client.target(createURL("buckets/a-nonexistent-identifier")).request().get();
+
+        // Then: a 404 response status is returned
+        assertEquals(404, response.getStatus());
+    }
+
+    @Test
+    public void testCreateBucketGetBucket() throws Exception {
+
+        // Given:
+
+        long testStartTime = System.currentTimeMillis();
+        final Bucket bucket = new Bucket();
+        bucket.setName("Integration Test Bucket");
+        bucket.setDescription("A bucket created by an integration test.");
+
+        // When: a bucket is created on the server
+
+        Bucket createdBucket = client
+                .target(createURL("buckets"))
+                .request()
+                .post(Entity.entity(bucket, MediaType.APPLICATION_JSON), Bucket.class);
+
+        // Then: the server returns the created bucket, with server-set fields populated correctly
+
+        assertBucketsEqual(bucket, createdBucket, false);
+        assertNotNull(createdBucket.getIdentifier());
+        assertTrue(createdBucket.getCreatedTimestamp() - testStartTime > 0L); // both server and client in same JVM, so there shouldn't be skew
+        assertNotNull(createdBucket.getLink());
+        assertNotNull(createdBucket.getLink().getUri());
+        if (createdBucket.getVersionedFlows() != null) {
+            assertEquals(0L, createdBucket.getVersionedFlows().size());
+        }
+
+        // And when /buckets is queried, then the newly created bucket is returned in the list
+
+        final Bucket[] buckets = client
+                .target(createURL("buckets"))
+                .request()
+                .get(Bucket[].class);
+        assertNotNull(buckets);
+        assertEquals(1, buckets.length);
+        assertBucketsEqual(createdBucket, buckets[0], true);
+
+        // And when the link URI is queried, then the newly created bucket is returned
+
+        final Bucket bucketByLink = client
+                .target(createURL(buckets[0].getLink().getUri().toString()))
+                .request()
+                .get(Bucket.class);
+        assertBucketsEqual(createdBucket, bucketByLink, true);
+
+        // And when the bucket is queried by /buckets/ID, then the newly created bucket is returned
+
+        final Bucket bucketById = client
+                .target(createURL("buckets/" + createdBucket.getIdentifier()))
+                .request()
+                .get(Bucket.class);
+        assertBucketsEqual(createdBucket, bucketById, true);
+    }
+
+    @Test
+    public void testUpdateBucket() throws Exception {
+
+        // Given: a bucket exists on the server
+
+        final Bucket bucket = new Bucket();
+        bucket.setName("Integration Test Bucket");
+        bucket.setDescription("A bucket created by an integration test.");
+        Bucket createdBucket = client
+                .target(createURL("buckets"))
+                .request()
+                .post(Entity.entity(bucket, MediaType.APPLICATION_JSON), Bucket.class);
+
+        // When: the bucket is modified by the client and updated on the server
+
+        createdBucket.setName("Renamed Bucket");
+        createdBucket.setDescription("This bucket has been updated by an integration test.");
+
+        final Bucket updatedBucket = client
+                .target(createURL("buckets/" + createdBucket.getIdentifier()))
+                .request()
+                .put(Entity.entity(createdBucket, MediaType.APPLICATION_JSON), Bucket.class);
+
+        // Then: the server returns the updated bucket
+
+        assertBucketsEqual(createdBucket, updatedBucket, true);
+
+    }
+
+    @Test
+    public void testDeleteBucket() throws Exception {
+
+        // Given: a bucket has been created
+
+        final Bucket bucket = new Bucket();
+        bucket.setName("Integration Test Bucket");
+        bucket.setDescription("A bucket created by an integration test.");
+
+        Bucket createdBucket = client
+                .target(createURL("buckets"))
+                .request()
+                .post(Entity.entity(bucket, MediaType.APPLICATION_JSON), Bucket.class);
+
+        // When: that bucket deleted
+
+        final Bucket deletedBucket = client
+                .target(createURL("buckets/" + createdBucket.getIdentifier()))
+                .request()
+                .delete(Bucket.class);
+
+        // Then: the body of the server response matches the bucket that was deleted
+        //  and: the bucket is no longer accessible (resource not found)
+
+        createdBucket.setLink(null); // self URI will not be present in deletedBucket
+        assertBucketsEqual(createdBucket, deletedBucket, true);
+
+        final Response response = client
+                .target(createURL("buckets/" + createdBucket.getIdentifier()))
+                .request()
+                .get();
+        assertEquals(404, response.getStatus());
+    }
+
+    @Test
+    public void getBucketFields() throws Exception {
+
+        // Given: the server is configured to return this fixed response
+
+        String expected = "{\"fields\":[\"created\",\"name\",\"description\",\"id\"]}";
+
+        // When: the server is queried
+
+        String bucketFieldsJson = client
+                .target(createURL("buckets/fields"))
+                .request()
+                .get(String.class);
+
+        // Then: the fixed response is returned to the client
+
+        JSONAssert.assertEquals(expected, bucketFieldsJson, false);
+
+    }
+
+    private static void assertBucketsEqual(Bucket expected, Bucket actual, boolean checkServerSetFields) {
+        assertNotNull(actual);
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getDescription(), actual.getDescription());
+        if (checkServerSetFields) {
+            assertEquals(expected.getIdentifier(), actual.getIdentifier());
+            assertEquals(expected.getCreatedTimestamp(), actual.getCreatedTimestamp());
+            assertEquals(expected.getLink(), actual.getLink());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
new file mode 100644
index 0000000..fc28bee
--- /dev/null
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/FlowsIT.java
@@ -0,0 +1,457 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.web.api;
+
+import org.apache.nifi.registry.bucket.BucketItemType;
+import org.apache.nifi.registry.flow.VersionedComponent;
+import org.apache.nifi.registry.flow.VersionedFlow;
+import org.apache.nifi.registry.flow.VersionedFlowSnapshot;
+import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata;
+import org.apache.nifi.registry.flow.VersionedProcessGroup;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.test.context.jdbc.Sql;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+
+@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:db/clearDB.sql", "classpath:db/FlowsIT.sql"})
+public class FlowsIT extends UnsecuredIntegrationTestBase {
+
+    private final Client client = ClientBuilder.newClient();
+
+    @Test
+    public void testGetFlowsEmpty() throws Exception {
+
+        // Given: an empty bucket with id "3" (see FlowsIT.sql)
+        final String emptyBucketId = "3";
+
+        // When: the /buckets/{id}/flows endpoint is queried
+
+        final VersionedFlow[] flows = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", emptyBucketId)
+                .request()
+                .get(VersionedFlow[].class);
+
+        // Then: an empty array is returned
+
+        assertNotNull(flows);
+        assertEquals(0, flows.length);
+    }
+
+    @Test
+    public void testGetFlows() throws Exception {
+
+        // Given: a few buckets and flows have been populated in the DB (see FlowsIT.sql)
+
+        final String prePopulatedBucketId = "1";
+        final String expected = "[" +
+                "{\"identifier\":\"1\"," +
+                "\"name\":\"Flow 1\"," +
+                "\"description\":\"This is flow 1\"," +
+                "\"bucketIdentifier\":\"1\"," +
+                "\"createdTimestamp\":1505091360000," +
+                "\"modifiedTimestamp\":1505091360000," +
+                "\"type\":\"FLOW\"," +
+                "\"snapshotMetadata\":null," +
+                "\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1/flows/1\"}}," +
+                "{\"identifier\":\"2\",\"name\":\"Flow 2\"," +
+                "\"description\":\"This is flow 2\"," +
+                "\"bucketIdentifier\":\"1\"," +
+                "\"createdTimestamp\":1505091360000," +
+                "\"modifiedTimestamp\":1505091360000," +
+                "\"type\":\"FLOW\"," +
+                "\"versionCount\":0," +
+                "\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1/flows/2\"}}" +
+                "]";
+
+        // When: the /buckets/{id}/flows endpoint is queried
+
+        final String flowsJson = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", prePopulatedBucketId)
+                .request()
+                .get(String.class);
+
+        // Then: the pre-populated list of flows is returned
+
+        JSONAssert.assertEquals(expected, flowsJson, false);
+    }
+
+    @Test
+    public void testCreateFlowGetFlow() throws Exception {
+
+        // Given: an empty bucket with id "3" (see FlowsIT.sql)
+
+        long testStartTime = System.currentTimeMillis();
+        final String bucketId = "3";
+
+        // When: a flow is created
+
+        final VersionedFlow flow = new VersionedFlow();
+        flow.setBucketIdentifier(bucketId);
+        flow.setName("Test Flow");
+        flow.setDescription("This is a flow created by an integration test.");
+
+        final VersionedFlow createdFlow = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", bucketId)
+                .request()
+                .post(Entity.entity(flow, MediaType.APPLICATION_JSON), VersionedFlow.class);
+
+        // Then: the server returns the created flow, with server-set fields populated correctly
+
+        assertFlowsEqual(flow, createdFlow, false);
+        assertNotNull(createdFlow.getIdentifier());
+        assertEquals(0, createdFlow.getVersionCount());
+        assertEquals(createdFlow.getType(), BucketItemType.FLOW);
+        assertTrue(createdFlow.getCreatedTimestamp() - testStartTime > 0L); // both server and client in same JVM, so there shouldn't be skew
+        assertEquals(createdFlow.getCreatedTimestamp(), createdFlow.getModifiedTimestamp());
+        assertNotNull(createdFlow.getLink());
+        assertNotNull(createdFlow.getLink().getUri());
+
+        // And when .../flows is queried, then the newly created flow is returned in the list
+
+        final VersionedFlow[] flows = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", bucketId)
+                .request()
+                .get(VersionedFlow[].class);
+        assertNotNull(flows);
+        assertEquals(1, flows.length);
+        assertFlowsEqual(createdFlow, flows[0], true);
+
+        // And when the link URI is queried, then the newly created flow is returned
+
+        final VersionedFlow flowByLink = client
+                .target(createURL(flows[0].getLink().getUri().toString()))
+                .request()
+                .get(VersionedFlow.class);
+        assertFlowsEqual(createdFlow, flowByLink, true);
+
+        // And when the bucket is queried by .../flows/ID, then the newly created flow is returned
+
+        final VersionedFlow flowById = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}"))
+                .resolveTemplate("bucketId", bucketId)
+                .resolveTemplate("flowId", createdFlow.getIdentifier())
+                .request()
+                .get(VersionedFlow.class);
+        assertFlowsEqual(createdFlow, flowById, true);
+
+    }
+
+    @Test
+    public void testUpdateFlow() throws Exception {
+
+        // Given: a flow exists on the server
+
+        final String bucketId = "3";
+        final VersionedFlow flow = new VersionedFlow();
+        flow.setBucketIdentifier(bucketId);
+        flow.setName("Test Flow");
+        flow.setDescription("This is a flow created by an integration test.");
+        final VersionedFlow createdFlow = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", bucketId)
+                .request()
+                .post(Entity.entity(flow, MediaType.APPLICATION_JSON), VersionedFlow.class);
+
+        // When: the flow is modified by the client and updated on the server
+
+        createdFlow.setName("Renamed Flow");
+        createdFlow.setDescription("This flow has been updated by an integration test.");
+
+        final VersionedFlow updatedFlow = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}"))
+                .resolveTemplate("bucketId", bucketId)
+                .resolveTemplate("flowId", createdFlow.getIdentifier())
+                .request()
+                .put(Entity.entity(createdFlow, MediaType.APPLICATION_JSON), VersionedFlow.class);
+
+        // Then: the server returns the updated flow, with a new modified timestamp
+
+        assertTrue(updatedFlow.getModifiedTimestamp() > createdFlow.getModifiedTimestamp());
+        createdFlow.setModifiedTimestamp(updatedFlow.getModifiedTimestamp());
+        assertFlowsEqual(createdFlow, updatedFlow, true);
+
+    }
+
+    @Test
+    public void testDeleteBucket() throws Exception {
+
+        // Given: a flow exists on the server
+
+        final String bucketId = "3";
+        final VersionedFlow flow = new VersionedFlow();
+        flow.setBucketIdentifier(bucketId);
+        flow.setName("Test Flow");
+        flow.setDescription("This is a flow created by an integration test.");
+        final VersionedFlow createdFlow = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", bucketId)
+                .request()
+                .post(Entity.entity(flow, MediaType.APPLICATION_JSON), VersionedFlow.class);
+
+        // When: the flow is deleted
+
+        final VersionedFlow deletedFlow = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}"))
+                .resolveTemplate("bucketId", bucketId)
+                .resolveTemplate("flowId", createdFlow.getIdentifier())
+                .request()
+                .delete(VersionedFlow.class);
+
+        // Then: the body of the server response matches the flow that was deleted
+        //  and: the flow is no longer accessible (resource not found)
+
+        createdFlow.setLink(null); // self URI will not be present in deletedBucket
+        assertFlowsEqual(createdFlow, deletedFlow, true);
+
+        final Response response = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}"))
+                .resolveTemplate("bucketId", bucketId)
+                .resolveTemplate("flowId", createdFlow.getIdentifier())
+                .request()
+                .get();
+        assertEquals(404, response.getStatus());
+
+    }
+
+    @Test
+    public void testGetFlowVersionsEmpty() throws Exception {
+
+        // Given: a Bucket "2" containing a flow "3" with no snapshots (see FlowsIT.sql)
+        final String bucketId = "2";
+        final String flowId = "3";
+
+        // When: the /buckets/{id}/flows/{id}/versions endpoint is queried
+
+        final VersionedFlowSnapshot[] flowSnapshots = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}/versions"))
+                .resolveTemplate("bucketId", bucketId)
+                .resolveTemplate("flowId", flowId)
+                .request()
+                .get(VersionedFlowSnapshot[].class);
+
+        // Then: an empty array is returned
+
+        assertNotNull(flowSnapshots);
+        assertEquals(0, flowSnapshots.length);
+    }
+
+    @Test
+    public void testGetFlowVersions() throws Exception {
+
+        // Given: a bucket "1" with flow "1" with existing snapshots has been populated in the DB (see FlowsIT.sql)
+
+        final String prePopulatedBucketId = "1";
+        final String prePopulatedFlowId = "1";
+        final String expected = "[" +
+                "{\"bucketIdentifier\":\"1\"," +
+                "\"flowIdentifier\":\"1\"," +
+                "\"flowName\":\"Flow 1\"," +
+                "\"version\":1," +
+                "\"timestamp\":1505091420000," +
+                "\"comments\":\"This is flow 1 snapshot 1\"," +
+                "\"link\":{\"params\":{\"rel\":\"content\"},\"href\":\"buckets/1/flows/1/versions/1\"}}," +
+                "{\"bucketIdentifier\":\"1\"," +
+                "\"flowIdentifier\":\"1\"," +
+                "\"flowName\":\"Flow 1\"," +
+                "\"version\":2," +
+                "\"timestamp\":1505091480000," +
+                "\"comments\":\"This is flow 1 snapshot 2\"," +
+                "\"link\":{\"params\":{\"rel\":\"content\"},\"href\":\"buckets/1/flows/1/versions/2\"}}]";
+
+        // When: the /buckets/{id}/flows/{id}/versions endpoint is queried
+
+        final String flowSnapshotsJson = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}/versions"))
+                .resolveTemplate("bucketId", prePopulatedBucketId)
+                .resolveTemplate("flowId", prePopulatedFlowId)
+                .request()
+                .get(String.class);
+
+        // Then: the pre-populated list of flow versions is returned
+
+        JSONAssert.assertEquals(expected, flowSnapshotsJson, false);
+    }
+
+    @Test
+    public void testCreateFlowVersionGetFlowVersion() throws Exception {
+
+        // Given: an empty Bucket "3" (see FlowsIT.sql) with a newly created flow
+
+        long testStartTime = System.currentTimeMillis();
+        final String bucketId = "2";
+        final VersionedFlow flow = new VersionedFlow();
+        flow.setBucketIdentifier(bucketId);
+        flow.setName("Test Flow for creating snapshots");
+        flow.setDescription("This is a randomly named flow created by an integration test for the purpose of holding snapshots.");
+        final VersionedFlow createdFlow = client
+                .target(createURL("buckets/{bucketId}/flows"))
+                .resolveTemplate("bucketId", bucketId)
+                .request()
+                .post(Entity.entity(flow, MediaType.APPLICATION_JSON), VersionedFlow.class);
+        final String flowId = createdFlow.getIdentifier();
+
+        // When: an initial flow snapshot is created *without* a version
+
+        final VersionedFlowSnapshotMetadata flowSnapshotMetadata = new VersionedFlowSnapshotMetadata();
+        flowSnapshotMetadata.setBucketIdentifier("2");
+        flowSnapshotMetadata.setFlowIdentifier(flowId);
+        flowSnapshotMetadata.setFlowName(createdFlow.getName());
+        flowSnapshotMetadata.setComments("This is snapshot 1, created by an integration test.");
+        final VersionedFlowSnapshot flowSnapshot = new VersionedFlowSnapshot();
+        flowSnapshot.setSnapshotMetadata(flowSnapshotMetadata);
+        flowSnapshot.setFlowContents(new VersionedProcessGroup()); // an empty root process group
+
+        WebTarget clientRequestTarget = client
+                .target(createURL("buckets/{bucketId}/flows/{flowId}/versions"))
+                .resolveTemplate("bucketId", bucketId)
+                .resolveTemplate("flowId", flowId);
+        final Response response =
+                clientRequestTarget.request().post(Entity.entity(flowSnapshot, MediaType.APPLICATION_JSON), Response.class);
+
+        // Then: an error is returned because version != 1
+
+        assertEquals(400, response.getStatus());
+
+        // But When: an initial flow snapshot is created with version == 1
+
+        flowSnapshot.getSnapshotMetadata().setVersion(1);
+        final VersionedFlowSnapshot createdFlowSnapshot =
+                clientRequestTarget.request().post(Entity.entity(flowSnapshot, MediaType.APPLICATION_JSON), VersionedFlowSnapshot.class);
+
+        // Then: the server returns the created flow snapshot, with server-set fields populated correctly :)
+
+        assertFlowSnapshotsEqual(flowSnapshot, createdFlowSnapshot, false);
+        assertTrue(createdFlowSnapshot.getSnapshotMetadata().getTimestamp() - testStartTime > 0L); // both server and client in same JVM, so there shouldn't be skew
+        assertNotNull(createdFlowSnapshot.getSnapshotMetadata().getLink());
+        assertNotNull(createdFlowSnapshot.getSnapshotMetadata().getLink().getUri());
+
+        // And when .../flows/{id}/versions is queried, then the newly created flow snapshot is returned in the list
+
+        final VersionedFlowSnapshotMetadata[] versionedFlowSnapshots =
+                clientRequestTarget.request().get(VersionedFlowSnapshotMetadata[].class);
+        assertNotNull(versionedFlowSnapshots);
+        assertEquals(1, versionedFlowSnapshots.length);
+        assertFlowSnapshotMetadataEqual(createdFlowSnapshot.getSnapshotMetadata(), versionedFlowSnapshots[0], true);
+
+        // And when the link URI is queried, then the newly created flow snapshot is returned
+
+        final VersionedFlowSnapshot flowSnapshotByLink = client
+                .target(createURL(versionedFlowSnapshots[0].getLink().getUri().toString()))
+                .request()
+                .get(VersionedFlowSnapshot.class);
+        assertFlowSnapshotsEqual(createdFlowSnapshot, flowSnapshotByLink, true);
+
+        // And when the bucket is queried by .../versions/{v}, then the newly created flow snapshot is returned
+
+        final VersionedFlowSnapshot flowSnapshotByVersionNumber = clientRequestTarget.path("/1").request().get(VersionedFlowSnapshot.class);
+        assertFlowSnapshotsEqual(createdFlowSnapshot, flowSnapshotByVersionNumber, true);
+
+        // And when the latest URI is queried, then the newly created flow snapshot is returned
+
+        final VersionedFlowSnapshot flowSnapshotByLatest = clientRequestTarget.path("/latest").request().get(VersionedFlowSnapshot.class);
+        assertFlowSnapshotsEqual(createdFlowSnapshot, flowSnapshotByLatest, true);
+
+    }
+
+    private static void assertFlowsEqual(VersionedFlow expected, VersionedFlow actual, boolean checkServerSetFields) {
+        assertNotNull(actual);
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getDescription(), actual.getDescription());
+        assertEquals(expected.getBucketIdentifier(), actual.getBucketIdentifier());
+        assertEquals(expected.getSnapshotMetadata(), actual.getSnapshotMetadata());
+        if (checkServerSetFields) {
+            assertEquals(expected.getIdentifier(), actual.getIdentifier());
+            assertEquals(expected.getVersionCount(), actual.getVersionCount());
+            assertEquals(expected.getCreatedTimestamp(), actual.getCreatedTimestamp());
+            assertEquals(expected.getModifiedTimestamp(), actual.getModifiedTimestamp());
+            assertEquals(expected.getType(), actual.getType());
+            assertEquals(expected.getLink(), actual.getLink());
+        }
+    }
+
+    private static void assertFlowSnapshotsEqual(VersionedFlowSnapshot expected, VersionedFlowSnapshot actual, boolean checkServerSetFields) {
+
+        assertNotNull(actual);
+
+        if (expected.getSnapshotMetadata() != null) {
+            assertFlowSnapshotMetadataEqual(expected.getSnapshotMetadata(), actual.getSnapshotMetadata(), checkServerSetFields);
+        }
+
+        if (expected.getFlowContents() != null) {
+            assertVersionedProcessGroupsEqual(expected.getFlowContents(), actual.getFlowContents());
+        }
+
+    }
+
+    private static void assertFlowSnapshotMetadataEqual(
+            VersionedFlowSnapshotMetadata expected, VersionedFlowSnapshotMetadata actual, boolean checkServerSetFields) {
+
+        assertNotNull(actual);
+        assertEquals(expected.getBucketIdentifier(), actual.getBucketIdentifier());
+        assertEquals(expected.getFlowIdentifier(), actual.getFlowIdentifier());
+        assertEquals(expected.getVersion(), actual.getVersion());
+        assertEquals(expected.getFlowName(), actual.getFlowName());
+        assertEquals(expected.getComments(), actual.getComments());
+        if (checkServerSetFields) {
+            assertEquals(expected.getTimestamp(), actual.getTimestamp());
+        }
+    }
+
+    private static void assertVersionedProcessGroupsEqual(VersionedProcessGroup expected, VersionedProcessGroup actual) {
+        assertNotNull(actual);
+
+        assertEquals(((VersionedComponent)expected), ((VersionedComponent)actual));
+
+        // Poor man's set equality assertion as we are only checking the base type and not doing a recursive check
+        // TODO, this would be a stronger assertion by replacing this with a true VersionedProcessGroup.equals() method that does a deep equality check
+        assertSetsEqual(expected.getProcessGroups(), actual.getProcessGroups());
+        assertSetsEqual(expected.getRemoteProcessGroups(), actual.getRemoteProcessGroups());
+        assertSetsEqual(expected.getProcessors(), actual.getProcessors());
+        assertSetsEqual(expected.getInputPorts(), actual.getInputPorts());
+        assertSetsEqual(expected.getOutputPorts(), actual.getOutputPorts());
+        assertSetsEqual(expected.getConnections(), actual.getConnections());
+        assertSetsEqual(expected.getLabels(), actual.getLabels());
+        assertSetsEqual(expected.getFunnels(), actual.getFunnels());
+        assertSetsEqual(expected.getControllerServices(), actual.getControllerServices());
+    }
+
+
+    private static void assertSetsEqual(Set<? extends VersionedComponent> expected, Set<? extends VersionedComponent> actual) {
+        if (expected != null) {
+            assertNotNull(actual);
+            assertEquals(expected.size(), actual.size());
+            assertTrue(actual.containsAll(expected));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
new file mode 100644
index 0000000..8be31bb
--- /dev/null
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.web.api;
+
+import org.apache.nifi.registry.NiFiRegistryApiTestApplication;
+import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.junit.runner.RunWith;
+import org.springframework.boot.context.embedded.LocalServerPort;
+import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Deploy the Web API Application using an embedded Jetty Server for local integration testing, with the follow characteristics:
+ *
+ * - A NiFiRegistryProperties Bean has to be explicitly provided to the application context, i.e. using an inline @TestConfiguration class
+ * - @DirtiesContext is providing that each (sub)class gets a fresh context
+ * - The database is embed H2 using volatile (in-memory) persistence
+ * - Custom SQL is clearing the DB before each test method by default, unless method overrides this behavior
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = NiFiRegistryApiTestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
+@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:db/clearDB.sql")
+public abstract class IntegrationTestBase {
+
+    private static final String CONTEXT_PATH = "/nifi-registry-api-test";
+
+    @TestConfiguration
+    public static class TestConfigurationClass {
+
+        private NiFiRegistryProperties testProperties;
+
+        @Bean
+        public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
+            JettyEmbeddedServletContainerFactory jettyContainerFactory = new JettyEmbeddedServletContainerFactory();
+            jettyContainerFactory.setContextPath(CONTEXT_PATH);
+            return jettyContainerFactory;
+        }
+
+    }
+
+    @LocalServerPort
+    int port;
+
+    String createURL(String resourcePathRelativeToBaseUrl) {
+        if (resourcePathRelativeToBaseUrl == null) {
+            throw new IllegalArgumentException("Resource path cannot be null");
+        }
+
+        StringBuilder baseUri = new StringBuilder().append("http://localhost:").append(port).append(CONTEXT_PATH);
+        if (!resourcePathRelativeToBaseUrl.startsWith("/")) {
+            baseUri.append('/');
+        }
+        baseUri.append(resourcePathRelativeToBaseUrl);
+
+        return baseUri.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredIntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredIntegrationTestBase.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredIntegrationTestBase.java
new file mode 100644
index 0000000..c868bf1
--- /dev/null
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredIntegrationTestBase.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.web.api;
+
+import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Extends the base integration and provide a NiFiRegistryProperties Bean that configures the NiFi Registry to be unsecured
+ */
+public class UnsecuredIntegrationTestBase extends IntegrationTestBase {
+
+    @TestConfiguration
+    public static class TestConfigurationClass {
+
+        private NiFiRegistryProperties testProperties;
+
+        @Bean
+        public synchronized NiFiRegistryProperties getNiFiRegistryProperties() {
+            if (testProperties == null) {
+                testProperties = new NiFiRegistryProperties();
+                try (final FileReader reader = new FileReader("src/test/resources/conf/unsecured/nifi-registry.properties")) {
+                    testProperties.load(reader);
+                } catch (final IOException ioe) {
+                    throw new RuntimeException("Unable to load properties: " + ioe, ioe);
+                }
+            }
+            return testProperties;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/resources/application.properties
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/resources/application.properties b/nifi-registry-web-api/src/test/resources/application.properties
new file mode 100644
index 0000000..29ef094
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/application.properties
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Properties for Spring Boot integration tests
+
+# These verbose log levels can be enabled locally for dev testing, but disable them in the repo to minimize travis logs.
+#logging.level.org.springframework.core.io.support: DEBUG
+#logging.level.org.springframework.context.annotation: DEBUG
+#logging.level.org.springframework.web: DEBUG
+
+#spring.jpa.show-sql=true
+spring.jpa.hibernate.ddl-auto=validate
+spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
+
+spring.datasource.url = jdbc:h2:mem:test
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/resources/conf/providers.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/resources/conf/providers.xml b/nifi-registry-web-api/src/test/resources/conf/providers.xml
new file mode 100644
index 0000000..fd002be
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/conf/providers.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<providers>
+
+    <flowPersistenceProvider>
+        <class>org.apache.nifi.registry.provider.flow.FileSystemFlowPersistenceProvider</class>
+        <property name="Flow Storage Directory">./target/test-classes/flow_storage</property>
+    </flowPersistenceProvider>
+
+</providers>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties b/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties
new file mode 100644
index 0000000..113773c
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/conf/unsecured/nifi-registry.properties
@@ -0,0 +1,25 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# web properties #
+nifi.registry.web.http.host=localhost
+
+# providers properties #
+nifi.registry.providers.configuration.file=./target/test-classes/conf/providers.xml
+
+# database properties
+nifi.registry.db.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/resources/db/BucketsIT.sql
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/resources/db/BucketsIT.sql b/nifi-registry-web-api/src/test/resources/db/BucketsIT.sql
new file mode 100644
index 0000000..2d6bd23
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/db/BucketsIT.sql
@@ -0,0 +1,26 @@
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+-- test data for buckets
+
+insert into bucket (id, name, description, created)
+  values ('1', 'Bucket 1', 'This is test bucket 1', parsedatetime('2017-09-11 12:51:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
+
+insert into bucket (id, name, description, created)
+  values ('2', 'Bucket 2', 'This is test bucket 2', parsedatetime('2017-09-11 12:52:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
+
+insert into bucket (id, name, description, created)
+  values ('3', 'Bucket 3', 'This is test bucket 3', parsedatetime('2017-09-11 12:53:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
+

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/resources/db/FlowsIT.sql
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/resources/db/FlowsIT.sql b/nifi-registry-web-api/src/test/resources/db/FlowsIT.sql
new file mode 100644
index 0000000..ba7c865
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/db/FlowsIT.sql
@@ -0,0 +1,50 @@
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+-- test data for buckets
+
+insert into bucket (id, name, description, created)
+  values ('1', 'Bucket 1', 'This is test bucket 1', parsedatetime('2017-09-11 12:51:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
+
+insert into bucket (id, name, description, created)
+  values ('2', 'Bucket 2', 'This is test bucket 2', parsedatetime('2017-09-11 12:52:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
+
+insert into bucket (id, name, description, created)
+  values ('3', 'Bucket 3', 'This is test bucket 3', parsedatetime('2017-09-11 12:53:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'));
+
+-- test data for flows
+
+insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
+  values ('1', 'Flow 1', 'This is flow 1', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'FLOW', '1');
+
+insert into flow (id) values ('1');
+
+insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
+  values ('2', 'Flow 2', 'This is flow 2', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'FLOW', '1');
+
+insert into flow (id) values ('2');
+
+insert into bucket_item (id, name, description, created, modified, item_type, bucket_id)
+  values ('3', 'Flow 3', 'This is flow 3', parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), parsedatetime('2017-09-11 12:56:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'FLOW', '2');
+
+insert into flow (id) values ('3');
+
+-- test data for flow snapshots
+
+insert into flow_snapshot (flow_id, version, created, comments)
+  values ('1', 1, parsedatetime('2017-09-11 12:57:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'This is flow 1 snapshot 1');
+
+insert into flow_snapshot (flow_id, version, created, comments)
+  values ('1', 2, parsedatetime('2017-09-11 12:58:00.000 UTC', 'yyyy-MM-dd hh:mm:ss.SSS z'), 'This is flow 1 snapshot 2');

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/nifi-registry-web-api/src/test/resources/db/clearDB.sql
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/resources/db/clearDB.sql b/nifi-registry-web-api/src/test/resources/db/clearDB.sql
new file mode 100644
index 0000000..7661df5
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/db/clearDB.sql
@@ -0,0 +1,19 @@
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+DELETE FROM FLOW_SNAPSHOT;
+DELETE FROM FLOW;
+DELETE FROM BUCKET_ITEM;
+DELETE FROM BUCKET;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/74e25494/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c8ab4de..2da3d84 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,12 +40,12 @@
         <module>nifi-registry-security-api</module>
         <module>nifi-registry-security-api-impl</module>
         <module>nifi-registry-security-utils</module>
-	<module>nifi-registry-framework</module>
+	    <module>nifi-registry-framework</module>
         <module>nifi-registry-provider-api</module>
         <module>nifi-registry-web-api</module>
         <module>nifi-registry-web-ui</module>
         <module>nifi-registry-web-docs</module>
-	<module>nifi-registry-bootstrap</module>
+	    <module>nifi-registry-bootstrap</module>
         <module>nifi-registry-docs</module>
         <module>nifi-registry-assembly</module>
 	<module>nifi-registry-client</module>
@@ -355,12 +355,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
-            <version>${org.slf4j.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
@@ -756,6 +750,33 @@
                                 <goals>
                                     <goal>check</goal>
                                 </goals>
+                                <phase>verify</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <!-- Performs execution of Integration Tests using the Maven
+                FailSafe Plugin. The view of integration tests in this context are those
+                tests loading a full web server with API war with no mocks. -->
+            <id>integration-tests</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                                <phase>verify</phase>
                             </execution>
                         </executions>
                     </plugin>
@@ -764,14 +785,12 @@
         </profile>
         <profile>
             <!-- This profile will disable DocLint which performs strict 
-                JavaDoc processing which was introduced in JDK 8. These are technically errors 
-                in the JavaDoc which we need to eventually address. However, if a release 
-                is performed using JDK 8, the JavaDoc generation would fail. By activating 
-                this profile when running on JDK 8 we can ensure the JavaDocs continue to 
-                generate successfully -->
+                JavaDoc processing which was introduced in JDK 8, which is required to build nifi-registry.
+                These are technically errors in the JavaDoc, which we need to eventually address.
+                However, without this, artifact generation currently fails. -->
             <id>disable-doclint</id>
             <activation>
-                <jdk>1.8</jdk>
+                <activeByDefault>true</activeByDefault>
             </activation>
             <build>
                 <pluginManagement>


Mime
View raw message