Repository: moov-io/customers
Pull request #189 (2020-09-24 14:43:33)

templater 2: move watchman into own package

codecov-commenter: # [Codecov](https://codecov.io/gh/moov-io/customers/pull/189?src=pr&el=h1) Report
> Merging [#189](https://codecov.io/gh/moov-io/customers/pull/189?src=pr&el=desc) into [master](https://codecov.io/gh/moov-io/customers/commit/3f863b623933b88110e782817b963f3484372afc?el=desc) will **decrease** coverage by `0.74%`.
> The diff coverage is `45.21%`.


```diff
@@            Coverage Diff             @@
##           master     #189      +/-   ##
==========================================
- Coverage   62.18%   61.43%   -0.75%     
==========================================
  Files          46       47       +1     
  Lines        2422     2515      +93     
==========================================
+ Hits         1506     1545      +39     
- Misses        632      672      +40     
- Partials      284      298      +14     
```

vxio: > Looks good! Usually we call it `watchman.Client` to avoid the duplicate names.

+1; I was going to mention this too but didn't want to be too nit picky heh
alovak: @adamdecaf @vxio it's changed ->`watchman.NewClient()` and `watchman.Client` 😁

Patch:
diff --git a/cmd/server/main.go b/cmd/server/main.go
index ca14102..621c082 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -25,6 +25,8 @@ import (
 	"github.com/moov-io/customers/pkg/accounts"
 	"github.com/moov-io/customers/pkg/configuration"
 	"github.com/moov-io/customers/pkg/customers"
+	"github.com/moov-io/customers/pkg/documents"
+	"github.com/moov-io/customers/pkg/documents/storage"
 	"github.com/moov-io/customers/pkg/fed"
 	"github.com/moov-io/customers/pkg/paygate"
 	"github.com/moov-io/customers/pkg/secrets"
@@ -32,6 +34,7 @@ import (
 	"github.com/moov-io/customers/pkg/validator/microdeposits"
 	"github.com/moov-io/customers/pkg/validator/mx"
 	"github.com/moov-io/customers/pkg/validator/plaid"
+	"github.com/moov-io/customers/pkg/watchman"
 
 	"github.com/go-kit/kit/log"
 	"github.com/gorilla/mux"
@@ -89,8 +92,8 @@ func main() {
 	accountsRepo := accounts.NewRepo(logger, db)
 	customerRepo := customers.NewCustomerRepo(logger, db)
 	customerSSNRepo := customers.NewCustomerSSNRepository(logger, db)
-	disclaimerRepo := customers.NewDisclaimerRepo(logger, db)
-	documentRepo := customers.NewDocumentRepo(logger, db)
+	disclaimerRepo := documents.NewDisclaimerRepo(logger, db)
+	documentRepo := documents.NewDocumentRepo(logger, db)
 	validationsRepo := validator.NewRepo(db)
 
 	// Start Admin server (with Prometheus metrics)
@@ -120,7 +123,7 @@ func main() {
 	// Create our Watchman client
 	debugWatchmanCalls := util.Or(os.Getenv("WATCHMAN_DEBUG_CALLS"), "false")
 	watchmanEndpoint := util.Or(os.Getenv("WATCHMAN_ENDPOINT"), os.Getenv("OFAC_ENDPOINT"))
-	watchmanClient := customers.NewWatchmanClient(logger, watchmanEndpoint, util.Yes(debugWatchmanCalls))
+	watchmanClient := watchman.NewClient(logger, watchmanEndpoint, util.Yes(debugWatchmanCalls))
 	if watchmanClient == nil {
 		panic("No Watchman client created, see WATCHMAN_ENDPOINT")
 	}
@@ -129,7 +132,7 @@ func main() {
 
 	// Register our admin routes
 	customers.AddApprovalRoutes(logger, adminServer, customerRepo, customerSSNRepo, ofac)
-	customers.AddDisclaimerAdminRoutes(logger, adminServer, disclaimerRepo, documentRepo)
+	documents.AddDisclaimerAdminRoutes(logger, adminServer, disclaimerRepo, documentRepo)
 
 	// Setup Customer SSN storage wrapper
 	ctx := context.Background()
@@ -167,8 +170,8 @@ func main() {
 	addPingRoute(router)
 	accounts.RegisterRoutes(logger, router, accountsRepo, validationsRepo, fedClient, stringKeeper, transitStringKeeper, validationStrategies, &accountOfacSeacher)
 	customers.AddCustomerRoutes(logger, router, customerRepo, customerSSNStorage, ofac)
-	customers.AddDisclaimerRoutes(logger, router, disclaimerRepo)
-	customers.AddDocumentRoutes(logger, router, documentRepo, customers.GetBucket(bucketName, cloudProvider, signer))
+	documents.AddDisclaimerRoutes(logger, router, disclaimerRepo)
+	documents.AddDocumentRoutes(logger, router, documentRepo, storage.GetBucket(bucketName, cloudProvider, signer))
 	customers.AddOFACRoutes(logger, router, customerRepo, ofac)
 
 	// Add Configuration routes
@@ -178,7 +181,7 @@ func main() {
 	// Optionally serve /files/ as our fileblob routes
 	// Note: FILEBLOB_BASE_URL needs to match something that's routed to /files/...
 	if cloudProvider == "file" {
-		customers.AddFileblobRoutes(logger, router, signer, customers.GetBucket(bucketName, cloudProvider, signer))
+		storage.AddFileblobRoutes(logger, router, signer, storage.GetBucket(bucketName, cloudProvider, signer))
 	}
 
 	// Start business HTTP server
@@ -245,7 +248,7 @@ func setupStorageBucket(logger log.Logger, bucketName, cloudProvider string) *fi
 			secret = "secret"
 			logger.Log("main", "WARNING!!!! USING INSECURE DEFAULT FILE STORAGE, set FILEBLOB_HMAC_SECRET for ANY production usage")
 		}
-		signer, err := customers.FileblobSigner(baseURL, secret)
+		signer, err := storage.FileblobSigner(baseURL, secret)
 		if err != nil {
 			panic(fmt.Sprintf("fileBucket: %v", err))
 		}
diff --git a/pkg/accounts/accounts_ofac.go b/pkg/accounts/accounts_ofac.go
index 0afdd41..0e2ef43 100644
--- a/pkg/accounts/accounts_ofac.go
+++ b/pkg/accounts/accounts_ofac.go
@@ -3,21 +3,16 @@ package accounts
 import (
 	"context"
 	"fmt"
+	"time"
+
 	"github.com/moov-io/customers/pkg/client"
-	watchman "github.com/moov-io/watchman/client"
+	"github.com/moov-io/customers/pkg/watchman"
 	"github.com/pkg/errors"
-	"time"
 )
 
 type AccountOfacSearcher struct {
 	Repo           Repository
-	WatchmanClient WatchmanClient
-}
-
-type WatchmanClient interface {
-	Ping() error
-
-	Search(ctx context.Context, name string, requestID string) (*watchman.OfacSdn, error)
+	WatchmanClient watchman.Client
 }
 
 // StoreAccountOFACSearch performs OFAC searches against the Account's HolderName and nickname if populated.
@@ -38,6 +33,9 @@ func (s *AccountOfacSearcher) StoreAccountOFACSearch(account *client.Account, re
 	if err != nil {
 		return fmt.Errorf("AccountOfacSearcher.StoreAccountOFACSearch: name search for account=%s: %v", account.AccountID, err)
 	}
+	if sdn == nil {
+		return nil
+	}
 	err = s.Repo.saveAccountOFACSearch(account.AccountID, &client.OfacSearch{
 		EntityID:  sdn.EntityID,
 		SdnName:   sdn.SdnName,
diff --git a/pkg/customers/approval_ofac.go b/pkg/customers/approval_ofac.go
index 738e3d9..928ead1 100644
--- a/pkg/customers/approval_ofac.go
+++ b/pkg/customers/approval_ofac.go
@@ -15,7 +15,8 @@ import (
 	moovhttp "github.com/moov-io/base/http"
 	"github.com/moov-io/customers/pkg/client"
 	"github.com/moov-io/customers/pkg/route"
-	watchman "github.com/moov-io/watchman/client"
+	"github.com/moov-io/customers/pkg/watchman"
+	watchmanClient "github.com/moov-io/watchman/client"
 
 	"github.com/go-kit/kit/log"
 	"github.com/gorilla/mux"
@@ -31,10 +32,10 @@ type ofacSearchResult struct {
 
 type OFACSearcher struct {
 	repo           CustomerRepository
-	watchmanClient WatchmanClient
+	watchmanClient watchman.Client
 }
 
-func NewOFACSearcher(repo CustomerRepository, client WatchmanClient) *OFACSearcher {
+func NewOFACSearcher(repo CustomerRepository, client watchman.Client) *OFACSearcher {
 	return &OFACSearcher{
 		repo:           repo,
 		watchmanClient: client,
@@ -55,7 +56,7 @@ func (s *OFACSearcher) storeCustomerOFACSearch(cust *client.Customer, requestID
 	if err != nil {
 		return fmt.Errorf("OFACSearcher.storeCustomerOFACSearch: name search for customer=%s: %v", cust.CustomerID, err)
 	}
-	var nickSDN *watchman.OfacSdn
+	var nickSDN *watchmanClient.OfacSdn
 	if cust.NickName != "" {
 		nickSDN, err = s.watchmanClient.Search(ctx, cust.NickName, requestID)
 		if err != nil {
diff --git a/pkg/customers/disclaimers.go b/pkg/documents/disclaimers.go
similarity index 99%
rename from pkg/customers/disclaimers.go
rename to pkg/documents/disclaimers.go
index 6698367..3b660c8 100644
--- a/pkg/customers/disclaimers.go
+++ b/pkg/documents/disclaimers.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package documents
 
 import (
 	"database/sql"
diff --git a/pkg/customers/documents.go b/pkg/documents/documents.go
similarity index 97%
rename from pkg/customers/documents.go
rename to pkg/documents/documents.go
index ac08e18..1b65fa8 100644
--- a/pkg/customers/documents.go
+++ b/pkg/documents/documents.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package documents
 
 import (
 	"bytes"
@@ -20,6 +20,7 @@ import (
 	moovhttp "github.com/moov-io/base/http"
 
 	"github.com/moov-io/customers/pkg/client"
+	"github.com/moov-io/customers/pkg/documents/storage"
 	"github.com/moov-io/customers/pkg/route"
 
 	"github.com/go-kit/kit/log"
@@ -33,7 +34,7 @@ var (
 	maxDocumentSize int64 = 20 * 1024 * 1024 // 20MB
 )
 
-func AddDocumentRoutes(logger log.Logger, r *mux.Router, repo DocumentRepository, bucketFactory bucketFunc) {
+func AddDocumentRoutes(logger log.Logger, r *mux.Router, repo DocumentRepository, bucketFactory storage.BucketFunc) {
 	r.Methods("GET").Path("/customers/{customerID}/documents").HandlerFunc(getCustomerDocuments(logger, repo))
 	r.Methods("POST").Path("/customers/{customerID}/documents").HandlerFunc(uploadCustomerDocument(logger, repo, bucketFactory))
 	r.Methods("GET").Path("/customers/{customerID}/documents/{documentId}").HandlerFunc(retrieveRawDocument(logger, repo, bucketFactory))
@@ -82,7 +83,7 @@ func readDocumentType(v string) (string, error) {
 	return "", fmt.Errorf("unknown Document type: %s", orig)
 }
 
-func uploadCustomerDocument(logger log.Logger, repo DocumentRepository, bucketFactory bucketFunc) http.HandlerFunc {
+func uploadCustomerDocument(logger log.Logger, repo DocumentRepository, bucketFactory storage.BucketFunc) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		w = route.Responder(logger, w, r)
 		// TODO(adam): should we store x-namespace along with the Document?
@@ -163,7 +164,7 @@ func uploadCustomerDocument(logger log.Logger, repo DocumentRepository, bucketFa
 	}
 }
 
-func retrieveRawDocument(logger log.Logger, repo DocumentRepository, bucketFactory bucketFunc) http.HandlerFunc {
+func retrieveRawDocument(logger log.Logger, repo DocumentRepository, bucketFactory storage.BucketFunc) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		w = route.Responder(logger, w, r)
 
diff --git a/pkg/customers/bucket.go b/pkg/documents/storage/bucket.go
similarity index 96%
rename from pkg/customers/bucket.go
rename to pkg/documents/storage/bucket.go
index a4fa6e4..90d6006 100644
--- a/pkg/customers/bucket.go
+++ b/pkg/documents/storage/bucket.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package storage
 
 import (
 	"context"
@@ -22,9 +22,9 @@ import (
 	"gocloud.dev/gcp"
 )
 
-type bucketFunc func() (*blob.Bucket, error)
+type BucketFunc func() (*blob.Bucket, error)
 
-func GetBucket(bucketName, cloudProvider string, FileblobSigner *fileblob.URLSignerHMAC) bucketFunc {
+func GetBucket(bucketName, cloudProvider string, FileblobSigner *fileblob.URLSignerHMAC) BucketFunc {
 	return func() (*blob.Bucket, error) {
 		ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
 		defer cancelFn()
diff --git a/pkg/customers/files.go b/pkg/documents/storage/files.go
similarity index 93%
rename from pkg/customers/files.go
rename to pkg/documents/storage/files.go
index 3fca817..40a5042 100644
--- a/pkg/customers/files.go
+++ b/pkg/documents/storage/files.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package storage
 
 import (
 	"context"
@@ -21,7 +21,7 @@ import (
 	"gocloud.dev/blob/fileblob"
 )
 
-func AddFileblobRoutes(logger log.Logger, r *mux.Router, signer *fileblob.URLSignerHMAC, bucketFactory bucketFunc) {
+func AddFileblobRoutes(logger log.Logger, r *mux.Router, signer *fileblob.URLSignerHMAC, bucketFactory BucketFunc) {
 	if v := os.Getenv("FILEBLOB_BASE_URL"); v != "" {
 		u, err := url.Parse(v)
 		if u != nil && err == nil {
@@ -32,7 +32,7 @@ func AddFileblobRoutes(logger log.Logger, r *mux.Router, signer *fileblob.URLSig
 	}
 }
 
-func proxyLocalFile(logger log.Logger, signer *fileblob.URLSignerHMAC, bucketFactory bucketFunc) http.HandlerFunc {
+func proxyLocalFile(logger log.Logger, signer *fileblob.URLSignerHMAC, bucketFactory BucketFunc) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		w = route.Responder(logger, w, r)
 
diff --git a/pkg/customers/watchman.go b/pkg/watchman/watchman.go
similarity index 96%
rename from pkg/customers/watchman.go
rename to pkg/watchman/watchman.go
index f18f28d..2f870a6 100644
--- a/pkg/customers/watchman.go
+++ b/pkg/watchman/watchman.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package watchman
 
 import (
 	"context"
@@ -17,7 +17,7 @@ import (
 	"github.com/go-kit/kit/log"
 )
 
-type WatchmanClient interface {
+type Client interface {
 	Ping() error
 
 	Search(ctx context.Context, name string, requestID string) (*watchman.OfacSdn, error)
@@ -157,12 +157,12 @@ func (c *moovWatchmanClient) Search(ctx context.Context, name string, requestID
 	return nil, nil // Nothing found
 }
 
-// NewWatchmanClient returns an WatchmanClient instance and will default to using the Watchman address in
+// NewClient returns an WatchmanClient instance and will default to using the Watchman address in
 // moov's standard Kubernetes setup.
 //
 // endpoint is a DNS record responsible for routing us to an Watchman instance.
 // Example: http://watchman.apps.svc.cluster.local:8080
-func NewWatchmanClient(logger log.Logger, endpoint string, debug bool) WatchmanClient {
+func NewClient(logger log.Logger, endpoint string, debug bool) Client {
 	conf := watchman.NewConfiguration()
 	conf.BasePath = "http://localhost" + bind.HTTP("watchman")
 	conf.Debug = debug


Test patch:
diff --git a/pkg/accounts/accounts_ofac_test.go b/pkg/accounts/accounts_ofac_test.go
index 397b779..c6b7ff4 100644
--- a/pkg/accounts/accounts_ofac_test.go
+++ b/pkg/accounts/accounts_ofac_test.go
@@ -5,13 +5,26 @@
 package accounts
 
 import (
-	"github.com/moov-io/customers/pkg/client"
 	"testing"
+
+	"github.com/moov-io/customers/pkg/client"
+	"github.com/moov-io/customers/pkg/watchman"
+	watchmanClient "github.com/moov-io/watchman/client"
 )
 
 func TestStoreAccountOFACSearchSuccess(t *testing.T) {
 	mockRepository := mockRepository{}
-	accountOfacSearcher := createTestOFACSearcher(&mockRepository, nil)
+	watchmanClient := watchman.NewTestWatchmanClient(&watchmanClient.OfacSdn{
+		EntityID: "123",
+		SdnName:  "dummy_sdn",
+		SdnType:  "dummy_sdn_type",
+		Programs: nil,
+		Title:    "dummy_title",
+		Remarks:  "dummy_remarks",
+		Match:    10.2,
+	}, nil)
+
+	accountOfacSearcher := createTestOFACSearcher(&mockRepository, watchmanClient)
 	requestID := "someRequestId"
 	account := &client.Account{
 		AccountID:  "123",
diff --git a/pkg/accounts/router_test.go b/pkg/accounts/router_test.go
index 6ce6bda..139824e 100644
--- a/pkg/accounts/router_test.go
+++ b/pkg/accounts/router_test.go
@@ -15,55 +15,27 @@ import (
 	"strings"
 	"testing"
 
-	watchman "github.com/moov-io/watchman/client"
-	"github.com/stretchr/testify/assert"
-
-	"github.com/moov-io/customers/internal/testclient"
-
 	"github.com/moov-io/base"
-	"github.com/stretchr/testify/require"
-
+	"github.com/moov-io/customers/internal/testclient"
 	"github.com/moov-io/customers/pkg/client"
 	"github.com/moov-io/customers/pkg/fed"
 	"github.com/moov-io/customers/pkg/secrets"
-
 	"github.com/moov-io/customers/pkg/validator"
 	"github.com/moov-io/customers/pkg/validator/testvalidator"
+	"github.com/moov-io/customers/pkg/watchman"
 
 	"github.com/go-kit/kit/log"
 	"github.com/gorilla/mux"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
-type testWatchmanClient struct {
-	// error to be returned instead of field from above
-	err error
-}
-
-func (c *testWatchmanClient) Ping() error {
-	return c.err
-}
-
-func (c *testWatchmanClient) Search(_ context.Context, name string, _ string) (*watchman.OfacSdn, error) {
-	if c.err != nil {
-		return nil, c.err
-	}
-	return &watchman.OfacSdn{
-		EntityID: "123",
-		SdnName:  "dummy_sdn",
-		SdnType:  "dummy_sdn_type",
-		Programs: nil,
-		Title:    "dummy_title",
-		Remarks:  "dummy_remarks",
-		Match:    10.2,
-	}, nil
-}
-
-func createTestOFACSearcher(repo Repository, watchmanClient WatchmanClient) *AccountOfacSearcher {
+func createTestOFACSearcher(repo Repository, watchmanClient watchman.Client) *AccountOfacSearcher {
 	if repo == nil {
 		repo = &testAccountRepository{}
 	}
 	if watchmanClient == nil {
-		watchmanClient = &testWatchmanClient{}
+		watchmanClient = watchman.NewTestWatchmanClient(nil, nil)
 	}
 	return &AccountOfacSearcher{Repo: repo, WatchmanClient: watchmanClient}
 }
diff --git a/pkg/customers/approval_ofac_test.go b/pkg/customers/approval_ofac_test.go
index c810394..1b57902 100644
--- a/pkg/customers/approval_ofac_test.go
+++ b/pkg/customers/approval_ofac_test.go
@@ -16,24 +16,25 @@ import (
 	"github.com/gorilla/mux"
 	"github.com/moov-io/base"
 	"github.com/moov-io/customers/pkg/client"
-	watchman "github.com/moov-io/watchman/client"
+	"github.com/moov-io/customers/pkg/watchman"
+	watchmanClient "github.com/moov-io/watchman/client"
 )
 
-func createTestOFACSearcher(repo CustomerRepository, watchmanClient WatchmanClient) *OFACSearcher {
+func createTestOFACSearcher(repo CustomerRepository, client watchman.Client) *OFACSearcher {
 	if repo == nil {
 		repo = &testCustomerRepository{}
 	}
-	if watchmanClient == nil {
-		watchmanClient = &testWatchmanClient{}
+	if client == nil {
+		client = &watchman.TestWatchmanClient{}
 	}
-	return &OFACSearcher{repo: repo, watchmanClient: watchmanClient}
+	return &OFACSearcher{repo: repo, watchmanClient: client}
 }
 
 func TestOFACSearcher__nil(t *testing.T) {
 	repo := createTestCustomerRepository(t)
 	defer repo.close()
 
-	ofacClient := &testWatchmanClient{}
+	ofacClient := &watchman.TestWatchmanClient{}
 	searcher := createTestOFACSearcher(repo, ofacClient)
 
 	if err := searcher.storeCustomerOFACSearch(nil, "requestID"); err == nil {
@@ -45,14 +46,13 @@ func TestOFACSearcher__storeCustomerOFACSearch(t *testing.T) {
 	repo := createTestCustomerRepository(t)
 	defer repo.close()
 
-	ofacClient := &testWatchmanClient{}
-	searcher := createTestOFACSearcher(repo, ofacClient)
-
-	ofacClient.sdn = &watchman.OfacSdn{
+	ofacClient := watchman.NewTestWatchmanClient(&watchmanClient.OfacSdn{
 		EntityID: "1241421",
 		SdnName:  "Jane Doe",
 		Match:    0.99,
-	}
+	}, nil)
+	searcher := createTestOFACSearcher(repo, ofacClient)
+
 	customerID := base.ID()
 	if err := searcher.storeCustomerOFACSearch(&client.Customer{CustomerID: customerID}, "requestID"); err != nil {
 		t.Fatal(err)
@@ -129,7 +129,7 @@ func TestOFACApproval__refresh(t *testing.T) {
 			Match:    1.0,
 		},
 	}
-	testWatchmanClient := &testWatchmanClient{}
+	testWatchmanClient := watchman.NewTestWatchmanClient(nil, nil)
 	ofac := &OFACSearcher{
 		repo:           repo,
 		watchmanClient: testWatchmanClient,
@@ -179,7 +179,7 @@ func TestOFACApproval__refreshErr(t *testing.T) {
 			Match:    0.88,
 		},
 	}
-	testWatchmanClient := &testWatchmanClient{err: errors.New("bad error")}
+	testWatchmanClient := watchman.NewTestWatchmanClient(nil, errors.New("bad error"))
 	ofac := &OFACSearcher{
 		repo:           repo,
 		watchmanClient: testWatchmanClient,
diff --git a/pkg/customers/disclaimers_test.go b/pkg/documents/disclaimers_test.go
similarity index 99%
rename from pkg/customers/disclaimers_test.go
rename to pkg/documents/disclaimers_test.go
index d81ca71..9dfad0f 100644
--- a/pkg/customers/disclaimers_test.go
+++ b/pkg/documents/disclaimers_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package documents
 
 import (
 	"bytes"
diff --git a/pkg/customers/documents_test.go b/pkg/documents/documents_test.go
similarity index 95%
rename from pkg/customers/documents_test.go
rename to pkg/documents/documents_test.go
index 0b471c0..48143f8 100644
--- a/pkg/customers/documents_test.go
+++ b/pkg/documents/documents_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package documents
 
 import (
 	"bytes"
@@ -25,6 +25,7 @@ import (
 
 	"github.com/moov-io/customers/internal/database"
 	"github.com/moov-io/customers/pkg/client"
+	"github.com/moov-io/customers/pkg/documents/storage"
 
 	"github.com/go-kit/kit/log"
 	"github.com/gorilla/mux"
@@ -73,7 +74,7 @@ func TestDocuments__getCustomerDocuments(t *testing.T) {
 	req.Header.Set("x-request-id", "test")
 
 	router := mux.NewRouter()
-	AddDocumentRoutes(log.NewNopLogger(), router, repo, testBucket)
+	AddDocumentRoutes(log.NewNopLogger(), router, repo, storage.TestBucket)
 	router.ServeHTTP(w, req)
 	w.Flush()
 
@@ -120,7 +121,7 @@ func TestDocuments__readDocumentType(t *testing.T) {
 }
 
 func multipartRequest(t *testing.T) *http.Request {
-	fd, err := os.Open(filepath.Join("..", "..", "testdata", "colorado.jpg"))
+	fd, err := os.Open(filepath.Join("testdata", "colorado.jpg"))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -156,7 +157,7 @@ func TestDocumentsUploadAndRetrieval(t *testing.T) {
 	req.Header.Set("x-request-id", "test")
 
 	router := mux.NewRouter()
-	AddDocumentRoutes(log.NewNopLogger(), router, repo, testBucket)
+	AddDocumentRoutes(log.NewNopLogger(), router, repo, storage.TestBucket)
 	router.ServeHTTP(w, req)
 	w.Flush()
 
@@ -194,7 +195,7 @@ func TestDocuments__delete(t *testing.T) {
 	repo := &sqlDocumentRepository{db.DB, log.NewNopLogger()}
 
 	router := mux.NewRouter()
-	AddDocumentRoutes(log.NewNopLogger(), router, repo, testBucket)
+	AddDocumentRoutes(log.NewNopLogger(), router, repo, storage.TestBucket)
 
 	customerID := base.ID()
 	// create document
@@ -232,7 +233,7 @@ func TestDocuments__uploadCustomerDocument(t *testing.T) {
 	req.URL = u // replace query params with invalid values
 
 	router := mux.NewRouter()
-	AddDocumentRoutes(log.NewNopLogger(), router, repo, testBucket)
+	AddDocumentRoutes(log.NewNopLogger(), router, repo, storage.TestBucket)
 	router.ServeHTTP(w, req)
 	w.Flush()
 
diff --git a/pkg/customers/bucket_test.go b/pkg/documents/storage/bucket_test.go
similarity index 76%
rename from pkg/customers/bucket_test.go
rename to pkg/documents/storage/bucket_test.go
index 990b2ab..414b126 100644
--- a/pkg/customers/bucket_test.go
+++ b/pkg/documents/storage/bucket_test.go
@@ -2,31 +2,12 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package storage
 
 import (
 	"context"
-	"fmt"
 	"io/ioutil"
 	"testing"
-	"time"
-
-	"gocloud.dev/blob"
-)
-
-var (
-	testBucket bucketFunc = func() (*blob.Bucket, error) {
-		signer, err := FileblobSigner("http://localhost:8087", "secret")
-		if err != nil {
-			panic(fmt.Sprintf("testBucket: %v", err))
-		}
-
-		ctx, cancelFn := context.WithTimeout(context.TODO(), 1*time.Second)
-		defer cancelFn()
-
-		dir, _ := ioutil.TempDir("", "testBucket")
-		return fileBucket(ctx, dir, signer)
-	}
 )
 
 func TestBucket__openBucket(t *testing.T) {
diff --git a/pkg/customers/files_test.go b/pkg/documents/storage/files_test.go
similarity index 88%
rename from pkg/customers/files_test.go
rename to pkg/documents/storage/files_test.go
index 4936c99..3ec349c 100644
--- a/pkg/customers/files_test.go
+++ b/pkg/documents/storage/files_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package storage
 
 import (
 	"context"
@@ -15,8 +15,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/moov-io/base"
-
 	"github.com/go-kit/kit/log"
 	"github.com/gorilla/mux"
 	"gocloud.dev/blob"
@@ -24,13 +22,13 @@ import (
 
 func TestFiles__proxyLocalFile(t *testing.T) {
 	// first, upload a file
-	bucket, err := testBucket()
+	bucket, err := TestBucket()
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	customerID, documentID := base.ID(), base.ID()
-	documentKey := makeDocumentKey(customerID, documentID)
+	// customerID, documentID := base.ID(), base.ID()
+	documentKey := "hello" // makeDocumentKey(customerID, documentID)
 
 	ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
 	defer cancelFn()
@@ -42,7 +40,7 @@ func TestFiles__proxyLocalFile(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	fd, err := os.Open(filepath.Join("..", "..", "testdata", "colorado.jpg"))
+	fd, err := os.Open(filepath.Join("..", "testdata", "colorado.jpg"))
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/pkg/documents/storage/test_bucket.go b/pkg/documents/storage/test_bucket.go
new file mode 100644
index 0000000..8d5ca3b
--- /dev/null
+++ b/pkg/documents/storage/test_bucket.go
@@ -0,0 +1,25 @@
+package storage
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"time"
+
+	"gocloud.dev/blob"
+)
+
+var (
+	TestBucket BucketFunc = func() (*blob.Bucket, error) {
+		signer, err := FileblobSigner("http://localhost:8087", "secret")
+		if err != nil {
+			panic(fmt.Sprintf("testBucket: %v", err))
+		}
+
+		ctx, cancelFn := context.WithTimeout(context.TODO(), 1*time.Second)
+		defer cancelFn()
+
+		dir, _ := ioutil.TempDir("", "testBucket")
+		return fileBucket(ctx, dir, signer)
+	}
+)
diff --git a/testdata/colorado.jpg b/pkg/documents/testdata/colorado.jpg
similarity index 100%
rename from testdata/colorado.jpg
rename to pkg/documents/testdata/colorado.jpg
diff --git a/pkg/watchman/test_watchman.go b/pkg/watchman/test_watchman.go
new file mode 100644
index 0000000..ba01a8f
--- /dev/null
+++ b/pkg/watchman/test_watchman.go
@@ -0,0 +1,33 @@
+package watchman
+
+import (
+	"context"
+
+	watchman "github.com/moov-io/watchman/client"
+)
+
+type TestWatchmanClient struct {
+	sdn *watchman.OfacSdn
+
+	// error to be returned instead of field from above
+	err error
+}
+
+func NewTestWatchmanClient(sdn *watchman.OfacSdn, err error) *TestWatchmanClient {
+	return &TestWatchmanClient{
+		sdn: sdn,
+		err: err,
+	}
+}
+
+func (c *TestWatchmanClient) Ping() error {
+	return c.err
+}
+
+func (c *TestWatchmanClient) Search(_ context.Context, name string, _ string) (*watchman.OfacSdn, error) {
+	if c.err != nil {
+		return nil, c.err
+	}
+
+	return c.sdn, nil
+}
diff --git a/pkg/customers/watchman_test.go b/pkg/watchman/watchman_test.go
similarity index 91%
rename from pkg/customers/watchman_test.go
rename to pkg/watchman/watchman_test.go
index cd581e3..451d0eb 100644
--- a/pkg/customers/watchman_test.go
+++ b/pkg/watchman/watchman_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by an Apache License
 // license that can be found in the LICENSE file.
 
-package customers
+package watchman
 
 import (
 	"context"
@@ -20,27 +20,9 @@ import (
 	"github.com/ory/dockertest/v3"
 )
 
-type testWatchmanClient struct {
-	sdn *watchman.OfacSdn
-
-	// error to be returned instead of field from above
-	err error
-}
-
-func (c *testWatchmanClient) Ping() error {
-	return c.err
-}
-
-func (c *testWatchmanClient) Search(_ context.Context, name string, _ string) (*watchman.OfacSdn, error) {
-	if c.err != nil {
-		return nil, c.err
-	}
-	return c.sdn, nil
-}
-
 type watchmanDeployment struct {
 	res    *dockertest.Resource
-	client WatchmanClient
+	client Client
 }
 
 func (d *watchmanDeployment) close(t *testing.T) {
@@ -73,7 +55,7 @@ func spawnWatchman(t *testing.T) *watchmanDeployment {
 		t.Fatal(err)
 	}
 
-	client := NewWatchmanClient(log.NewNopLogger(), fmt.Sprintf("http://localhost:%s", resource.GetPort("8080/tcp")), false)
+	client := NewClient(log.NewNopLogger(), fmt.Sprintf("http://localhost:%s", resource.GetPort("8080/tcp")), false)
 	err = pool.Retry(func() error {
 		return client.Ping()
 	})
@@ -85,7 +67,7 @@ func spawnWatchman(t *testing.T) *watchmanDeployment {
 
 func TestWatchman__client(t *testing.T) {
 	endpoint := ""
-	if client := NewWatchmanClient(log.NewNopLogger(), endpoint, false); client == nil {
+	if client := NewClient(log.NewNopLogger(), endpoint, false); client == nil {
 		t.Fatal("expected non-nil client")
 	}
 
@@ -138,7 +120,7 @@ func TestWatchman__search(t *testing.T) {
 }
 
 func TestWatchman_ping(t *testing.T) {
-	client := &testWatchmanClient{}
+	client := &TestWatchmanClient{}
 
 	// Ping tests
 	if err := client.Ping(); err != nil {