diff --git a/tests/e2e_test.go b/tests/e2e_test.go
index e4ead809990d01829484d103805026a4272c802d..1fa8ce98d86890869e2f903a3a9d0ee14e43c6c3 100644
--- a/tests/e2e_test.go
+++ b/tests/e2e_test.go
@@ -3,71 +3,13 @@
 package e2e
 
 import (
-	"encoding/base64"
 	"io/ioutil"
-	"math/rand"
-	"os/exec"
 	"path/filepath"
 	"strings"
 	"testing"
 	"time"
 )
 
-const (
-	cli         = "../rekor-cli"
-	nodeDataDir = "node"
-)
-
-func runCli(t *testing.T, arg ...string) string {
-	cmd := exec.Command(cli, arg...)
-	b, err := cmd.CombinedOutput()
-	if err != nil {
-		t.Log(string(b))
-		t.Fatal(err)
-	}
-	return string(b)
-}
-
-func runCliErr(t *testing.T, arg ...string) {
-	cmd := exec.Command(cli, arg...)
-	b, err := cmd.CombinedOutput()
-	if err == nil {
-		t.Log(string(b))
-		t.Fatalf("expected error, got %s", string(b))
-	}
-}
-
-func readFile(t *testing.T, p string) string {
-	b, err := ioutil.ReadFile(p)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return strings.TrimSpace(string(b))
-}
-
-// createdSignedArtifact gets the test dir setup correctly with some random artifacts and keys.
-func createdSignedArtifact(t *testing.T, artifactPath, sigPath string) {
-	t.Helper()
-	// First let's generate some random data so we don't have to worry about dupes.
-	rand.Seed(time.Now().UnixNano())
-	data := [100]byte{}
-	if _, err := rand.Read(data[:]); err != nil {
-		t.Fatal(err)
-	}
-
-	artifact := base64.StdEncoding.EncodeToString(data[:])
-	// Write this to a file
-	if err := ioutil.WriteFile(artifactPath, []byte(artifact), 0644); err != nil {
-		t.Fatal(err)
-	}
-
-	// Sign it with our key and write that to a file
-	signature := Sign(t, strings.NewReader(artifact))
-	if err := ioutil.WriteFile(sigPath, []byte(signature), 0644); err != nil {
-		t.Fatal(err)
-	}
-}
-
 func TestDuplicates(t *testing.T) {
 	artifactPath := filepath.Join(t.TempDir(), "artifact")
 	sigPath := filepath.Join(t.TempDir(), "signature.asc")
@@ -99,3 +41,37 @@ func TestDuplicates(t *testing.T) {
 		t.Errorf("Expected [Created entry at], got %s", out)
 	}
 }
+
+func TestUploadVerify(t *testing.T) {
+
+	// Create a random artifact and sign it.
+	artifactPath := filepath.Join(t.TempDir(), "artifact")
+	sigPath := filepath.Join(t.TempDir(), "signature.asc")
+
+	createdSignedArtifact(t, artifactPath, sigPath)
+
+	// Write the public key to a file
+	pubPath := filepath.Join(t.TempDir(), "pubKey.asc")
+	if err := ioutil.WriteFile(pubPath, []byte(publicKey), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	// Verify should fail initially
+	runCliErr(t, "verify", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
+
+	// It should upload successfully.
+	out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
+	if !strings.Contains(out, "Created entry at") {
+		t.Errorf("Expected [Created entry at], got %s", out)
+	}
+
+	// We have to wait some time for the log to get signed and included.
+	time.Sleep(3 * time.Second)
+
+	// Now we should be able to verify it.
+	out = runCli(t, "verify", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
+	if !strings.Contains(out, "Inclusion Proof:") {
+		t.Errorf("Expected [Inclusion Proof] in response, got %s", out)
+	}
+
+}
diff --git a/tests/util.go b/tests/util.go
new file mode 100644
index 0000000000000000000000000000000000000000..41bb1d8216a707f2d8caf0b72c8aa0a83aa4f804
--- /dev/null
+++ b/tests/util.go
@@ -0,0 +1,70 @@
+// +build e2e
+
+package e2e
+
+import (
+	"encoding/base64"
+	"io/ioutil"
+	"math/rand"
+	"os/exec"
+	"strings"
+	"testing"
+	"time"
+)
+
+const (
+	cli         = "../rekor-cli"
+	nodeDataDir = "node"
+)
+
+func runCli(t *testing.T, arg ...string) string {
+	t.Helper()
+	cmd := exec.Command(cli, arg...)
+	b, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Log(string(b))
+		t.Fatal(err)
+	}
+	return string(b)
+}
+
+func runCliErr(t *testing.T, arg ...string) {
+	t.Helper()
+	cmd := exec.Command(cli, arg...)
+	b, err := cmd.CombinedOutput()
+	if err == nil {
+		t.Log(string(b))
+		t.Fatalf("expected error, got %s", string(b))
+	}
+}
+
+func readFile(t *testing.T, p string) string {
+	b, err := ioutil.ReadFile(p)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return strings.TrimSpace(string(b))
+}
+
+// createdSignedArtifact gets the test dir setup correctly with some random artifacts and keys.
+func createdSignedArtifact(t *testing.T, artifactPath, sigPath string) {
+	t.Helper()
+	// First let's generate some random data so we don't have to worry about dupes.
+	rand.Seed(time.Now().UnixNano())
+	data := [100]byte{}
+	if _, err := rand.Read(data[:]); err != nil {
+		t.Fatal(err)
+	}
+
+	artifact := base64.StdEncoding.EncodeToString(data[:])
+	// Write this to a file
+	if err := ioutil.WriteFile(artifactPath, []byte(artifact), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	// Sign it with our key and write that to a file
+	signature := Sign(t, strings.NewReader(artifact))
+	if err := ioutil.WriteFile(sigPath, []byte(signature), 0644); err != nil {
+		t.Fatal(err)
+	}
+}