You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ra...@apache.org on 2020/04/22 18:39:58 UTC

[trafficcontrol] branch master updated: CDN-in-a-Box SMTP server + user registration API test (#4649)

This is an automated email from the ASF dual-hosted git repository.

rawlin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 68022ea  CDN-in-a-Box SMTP server + user registration API test (#4649)
68022ea is described below

commit 68022eae9575ceef91d9a33e6754c7583d8fcca4
Author: Zach Hoffman <za...@zrhoffman.net>
AuthorDate: Wed Apr 22 12:39:49 2020 -0600

    CDN-in-a-Box SMTP server + user registration API test (#4649)
    
    * Add a relayless SMTP server to CDN-in-a-Box
    
    * Add an API test for user registration
    
    * Name container smtp, not mail
    
    * Only run system tests if includeSystemTests is explicitly enabled
    
    * Comment that UserRegistrationTest deletes test users and must come last
    
    * Traffic Ops container depends on SMTP container
---
 CHANGELOG.md                                       |  1 +
 docs/source/admin/quick_howto/ciab.rst             | 67 +++++++++++-----------
 docs/source/development/traffic_ops.rst            |  2 +-
 .../cdn-in-a-box/docker-compose.expose-ports.yml   |  3 +
 infrastructure/cdn-in-a-box/docker-compose.yml     | 15 +++++
 infrastructure/cdn-in-a-box/smtp/Dockerfile        | 30 ++++++++++
 infrastructure/cdn-in-a-box/smtp/run.sh            | 42 ++++++++++++++
 infrastructure/cdn-in-a-box/traffic_ops/config.sh  |  4 +-
 infrastructure/cdn-in-a-box/traffic_ops/run-go.sh  | 15 +++++
 .../cdn-in-a-box/traffic_ops/to-access.sh          |  1 +
 .../traffic_ops_integration_test/config.sh         |  3 +-
 infrastructure/cdn-in-a-box/variables.env          |  2 +
 traffic_ops/testing/api/conf/traffic-ops-test.conf |  3 +-
 traffic_ops/testing/api/config/config.go           |  5 +-
 traffic_ops/testing/api/v1/phys_locations_test.go  |  2 +-
 traffic_ops/testing/api/v2/tc-fixtures.json        |  7 +++
 traffic_ops/testing/api/v2/traffic_ops_test.go     |  9 ++-
 traffic_ops/testing/api/v2/user_test.go            | 33 +++++++++++
 18 files changed, 202 insertions(+), 42 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee6ae21..20797e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - Added an API 1.5 endpoint to renew certificates
 - Added ability to create multiple objects from generic API Create with a single POST.
 - Added debugging functionality to CDN-in-a-Box.
+- Added an SMTP server to CDN-in-a-Box.
 - Traffic Ops Golang Endpoints
   - /api/2.0 for all of the most recent route versions
   - /api/1.1/cachegroupparameters/{{cachegroupID}}/{{parameterID}} `(DELETE)`
diff --git a/docs/source/admin/quick_howto/ciab.rst b/docs/source/admin/quick_howto/ciab.rst
index c49533c..3986708 100644
--- a/docs/source/admin/quick_howto/ciab.rst
+++ b/docs/source/admin/quick_howto/ciab.rst
@@ -47,38 +47,41 @@ In a typical scenario, if the steps in `Building`_ have been followed, all that'
 .. _ciab-service-info:
 .. table:: Service Info
 
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Service                         | Ports exposed and their usage                                | Username                              | Password                                  |
-	+=================================+==============================================================+=======================================+===========================================+
-	| DNS                             | DNS name resolution on 9353                                  | N/A                                   | N/A                                       |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Edge Tier Cache                 | Apache Trafficserver HTTP caching reverse proxy on port 9000 | N/A                                   | N/A                                       |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Mid Tier Cache                  | Apache Trafficserver HTTP caching forward proxy on port 9100 | N/A                                   | N/A                                       |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Mock Origin Server              | Example web page served on port 9200                         | N/A                                   | N/A                                       |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Monitor                 | Web interface and API on port 80                             | N/A                                   | N/A                                       |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Ops                     | Main API endpoints on port 6443, with a direct route to the  | ``TO_ADMIN_USER`` in `variables.env`_ | ``TO_ADMIN_PASSWORD`` in `variables.env`_ |
-	|                                 | Perl API on port 60443\ [3]_                                 |                                       |                                           |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Ops PostgresQL Database | PostgresQL connections accepted on port 5432 (database name: | ``DB_USER`` in `variables.env`_       | ``DB_USER_PASS`` in `variables.env`_      |
-	|                                 | ``DB_NAME`` in `variables.env`_)                             |                                       |                                           |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Portal                  | Web interface on 443 (Javascript required)                   | ``TO_ADMIN_USER`` in `variables.env`_ | ``TO_ADMIN_PASSWORD`` in `variables.env`_ |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Router                  | Web interfaces on ports 3080 (HTTP) and 3443 (HTTPS), with a | N/A                                   | N/A                                       |
-	|                                 | DNS service on 53 and an API on 3333 (HTTP) and 2222 (HTTPS) |                                       |                                           |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Vault                   | Riak key-value store on port 8010                            | ``TV_ADMIN_USER`` in `variables.env`_ | ``TV_ADMIN_PASSWORD`` in `variables.env`_ |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Stats                   | N/A                                                          | N/A                                   | N/A                                       |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
-	| Traffic Stats Influxdb          | Influxdbd connections accepted on port 8086 (database name:  | ``INFLUXDB_ADMIN_USER`` in            | ``INFLUXDB_ADMIN_PASSWORD`` in            |
-	|                                 | ``cache_stats``, ``daily_stats`` and                         | `variables.env`_                      | `variables.env`_                          |
-	|                                 | ``deliveryservice_stats``)                                   |                                       |                                           |
-	+---------------------------------+--------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Service                         | Ports exposed and their usage                                  | Username                              | Password                                  |
+	+=================================+================================================================+=======================================+===========================================+
+	| DNS                             | DNS name resolution on 9353                                    | N/A                                   | N/A                                       |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Edge Tier Cache                 | Apache Trafficserver HTTP caching reverse proxy on port 9000   | N/A                                   | N/A                                       |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Mid Tier Cache                  | Apache Trafficserver HTTP caching forward proxy on port 9100   | N/A                                   | N/A                                       |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Mock Origin Server              | Example web page served on port 9200                           | N/A                                   | N/A                                       |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| SMTP Server                     | Passwordless, cleartext SMTP server on port 25 (no relay)      | N/A                                   | N/A                                       |
+	|                                 | Web interface exposed on port 4443 (port 443 in the container) |                                       |                                           |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Monitor                 | Web interface and API on port 80                               | N/A                                   | N/A                                       |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Ops                     | Main API endpoints on port 6443, with a direct route to the    | ``TO_ADMIN_USER`` in `variables.env`_ | ``TO_ADMIN_PASSWORD`` in `variables.env`_ |
+	|                                 | Perl API on port 60443\ [3]_                                   |                                       |                                           |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Ops PostgresQL Database | PostgresQL connections accepted on port 5432 (database name:   | ``DB_USER`` in `variables.env`_       | ``DB_USER_PASS`` in `variables.env`_      |
+	|                                 | ``DB_NAME`` in `variables.env`_)                               |                                       |                                           |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Portal                  | Web interface on 443 (Javascript required)                     | ``TO_ADMIN_USER`` in `variables.env`_ | ``TO_ADMIN_PASSWORD`` in `variables.env`_ |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Router                  | Web interfaces on ports 3080 (HTTP) and 3443 (HTTPS), with a   | N/A                                   | N/A                                       |
+	|                                 | DNS service on 53 and an API on 3333 (HTTP) and 2222 (HTTPS)   |                                       |                                           |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Vault                   | Riak key-value store on port 8010                              | ``TV_ADMIN_USER`` in `variables.env`_ | ``TV_ADMIN_PASSWORD`` in `variables.env`_ |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Stats                   | N/A                                                            | N/A                                   | N/A                                       |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
+	| Traffic Stats Influxdb          | Influxdbd connections accepted on port 8086 (database name:    | ``INFLUXDB_ADMIN_USER`` in            | ``INFLUXDB_ADMIN_PASSWORD`` in            |
+	|                                 | ``cache_stats``, ``daily_stats`` and                           | `variables.env`_                      | `variables.env`_                          |
+	|                                 | ``deliveryservice_stats``)                                     |                                       |                                           |
+	+---------------------------------+----------------------------------------------------------------+---------------------------------------+-------------------------------------------+
 
 .. seealso:: :ref:`tr-api` and :ref:`tm-api`
 
diff --git a/docs/source/development/traffic_ops.rst b/docs/source/development/traffic_ops.rst
index 5598686..5bfa0cb 100644
--- a/docs/source/development/traffic_ops.rst
+++ b/docs/source/development/traffic_ops.rst
@@ -31,7 +31,7 @@ The two different implementations have different requirements, but they do share
 - `Goose <https://bitbucket.org/liamstask/goose/>`_ (although the ``postinstall`` Perl script will install this if desired)
 - `PostgreSQL 9.6.6 <https://www.postgresql.org/download/>`_ - the machine where (either implementation of) Traffic Ops is running must have the client tool set (e.g. :manpage:`psql(1)`), but the actual database can be run anywhere so long as it is accessible.
 - :manpage:`openssl(1SSL)` is recommended to generate server certificates, though not strictly required if certificates can be obtained by other means.
-- Some kind of SMTP server is required for certain :ref:`to-api` endpoints to work, but for purposes unrelated to them an SMTP server is not required.
+- Some kind of SMTP server is required for certain :ref:`to-api` endpoints to work, but for purposes unrelated to them an SMTP server is not required. :ref:`ciab` comes with a relayless SMTP server for testing (you can view the emails that Traffic Ops sends, but they aren't sent anywhere outside CDN-in-a-Box).
 
 .. tip:: Alternatively, development and testing can be done using :ref:`ciab` - albeit somewhat more slowly.
 
diff --git a/infrastructure/cdn-in-a-box/docker-compose.expose-ports.yml b/infrastructure/cdn-in-a-box/docker-compose.expose-ports.yml
index e0be026..8f9ff14 100644
--- a/infrastructure/cdn-in-a-box/docker-compose.expose-ports.yml
+++ b/infrastructure/cdn-in-a-box/docker-compose.expose-ports.yml
@@ -68,3 +68,6 @@ services:
     ports:
       - "9353:53/tcp"
       - "9353:53/udp"
+  smtp:
+    ports:
+      - "4443:443"
diff --git a/infrastructure/cdn-in-a-box/docker-compose.yml b/infrastructure/cdn-in-a-box/docker-compose.yml
index c7875a2..e3ead3f 100644
--- a/infrastructure/cdn-in-a-box/docker-compose.yml
+++ b/infrastructure/cdn-in-a-box/docker-compose.yml
@@ -65,6 +65,7 @@ services:
     depends_on:
       - db
       - enroller
+      - smtp
       - trafficops-perl
     domainname: infra.ciab.test
     env_file:
@@ -289,6 +290,20 @@ services:
       - shared:/shared
     hostname: dns
     domainname: infra.ciab.test
+  smtp:
+    build:
+      context: .
+      dockerfile: smtp/Dockerfile
+    hostname: smtp
+    depends_on:
+      - dns
+    env_file:
+      - variables.env
+    volumes:
+      - shared:/shared
+      - ./dns/set-dns.sh:/usr/local/sbin/set-dns.sh
+      - ./dns/insert-self-into-dns.sh:/usr/local/sbin/insert-self-into-dns.sh
+    domainname: infra.ciab.test
 
 volumes:
   schemas:
diff --git a/infrastructure/cdn-in-a-box/smtp/Dockerfile b/infrastructure/cdn-in-a-box/smtp/Dockerfile
new file mode 100644
index 0000000..a02529d
--- /dev/null
+++ b/infrastructure/cdn-in-a-box/smtp/Dockerfile
@@ -0,0 +1,30 @@
+# 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.
+
+FROM maildev/maildev:2.0.0-beta3
+
+USER root
+RUN apk add --no-cache \
+		bash \
+		bind-tools
+
+COPY traffic_ops/to-access.sh /
+COPY smtp/run.sh /usr/bin/
+
+# Unset entrypoint
+ENTRYPOINT []
+CMD ["/usr/bin/env", "run.sh"]
diff --git a/infrastructure/cdn-in-a-box/smtp/run.sh b/infrastructure/cdn-in-a-box/smtp/run.sh
new file mode 100755
index 0000000..7997038
--- /dev/null
+++ b/infrastructure/cdn-in-a-box/smtp/run.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# 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.
+
+trap 'echo "Error on line ${LINENO} of ${0}"; exit 1' ERR;
+set -o errexit -o nounset;
+set-dns.sh;
+insert-self-into-dns.sh;
+source /to-access.sh;
+
+# Source the CIAB-CA shared SSL environment
+until [[ -v 'X509_GENERATION_COMPLETE' ]]; do
+  echo 'Waiting on X509 vars to be defined';
+  sleep 1;
+  if [[ ! -e "$X509_CA_ENV_FILE" ]]; then
+    continue;
+  fi;
+  source "$X509_CA_ENV_FILE";
+done;
+
+# It crashes if STARTTLS is not hidden, see maildev/maildev#274
+exec bin/maildev \
+  --smtp="$SMTP_PORT" \
+  --hide-extensions='STARTTLS' \
+  --https \
+  --web=443 \
+  --https-key="${X509_CA_DIR}/${INFRA_SUBDOMAIN}.${TLD_DOMAIN}.key" \
+  --https-cert="${X509_CA_DIR}/${INFRA_SUBDOMAIN}.${TLD_DOMAIN}.crt";
diff --git a/infrastructure/cdn-in-a-box/traffic_ops/config.sh b/infrastructure/cdn-in-a-box/traffic_ops/config.sh
index 2137372..c165ed6 100755
--- a/infrastructure/cdn-in-a-box/traffic_ops/config.sh
+++ b/infrastructure/cdn-in-a-box/traffic_ops/config.sh
@@ -136,10 +136,10 @@ cat <<-EOF >/opt/traffic_ops/app/conf/cdn.conf
     },
     "inactivity_timeout" : 60,
     "smtp" : {
-        "enabled" : false,
+        "enabled" : true,
         "user" : "",
         "password" : "",
-        "address" : ""
+        "address" : "${SMTP_FQDN}:${SMTP_PORT}"
     },
     "InfluxEnabled": true,
     "influxdb_conf_path": "/opt/traffic_ops/app/conf/production/influx.conf",
diff --git a/infrastructure/cdn-in-a-box/traffic_ops/run-go.sh b/infrastructure/cdn-in-a-box/traffic_ops/run-go.sh
index 867c4f7..4f517b7 100755
--- a/infrastructure/cdn-in-a-box/traffic_ops/run-go.sh
+++ b/infrastructure/cdn-in-a-box/traffic_ops/run-go.sh
@@ -59,6 +59,21 @@ while ! nc "$TO_PERL_FQDN" $TO_PERL_PORT </dev/null 2>/dev/null; do
         sleep 3
 done
 
+(
+maxtries=10
+for ((tries = 0; tries < maxtries; tries++)); do
+        if nc -zvw2 "$SMTP_FQDN" "$SMTP_PORT"; then
+          echo "${SMTP_FQDN}:${SMTP_PORT} was found."
+          break;
+        fi;
+        echo "waiting for ${SMTP_FQDN}:${SMTP_PORT}"
+        sleep 3
+done
+if (( tries == maxtries )); then
+  echo "SMTP service was not found at ${SMTP_FQDN}:${SMTP_PORT} after ${maxtries} tries. Skipping..."
+fi
+)
+
 cd /opt/traffic_ops/app
 
 CDNCONF=/opt/traffic_ops/app/conf/cdn.conf
diff --git a/infrastructure/cdn-in-a-box/traffic_ops/to-access.sh b/infrastructure/cdn-in-a-box/traffic_ops/to-access.sh
index 35f3278..e3ab8bd 100755
--- a/infrastructure/cdn-in-a-box/traffic_ops/to-access.sh
+++ b/infrastructure/cdn-in-a-box/traffic_ops/to-access.sh
@@ -27,6 +27,7 @@ export DNS_FQDN="$DNS_SERVER.$INFRA_FQDN"
 export EDGE_FQDN="$EDGE_HOST.$INFRA_FQDN"
 export MID_FQDN="$MID_HOST.$INFRA_FQDN"
 export ORIGIN_FQDN="$ORIGIN_HOST.$INFRA_FQDN"
+export SMTP_FQDN="$SMTP_HOST.$INFRA_FQDN"
 export TO_FQDN="$TO_HOST.$INFRA_FQDN"
 export TO_PERL_FQDN="$TO_PERL_HOST.$INFRA_FQDN"
 export TM_FQDN="$TM_HOST.$INFRA_FQDN"
diff --git a/infrastructure/cdn-in-a-box/traffic_ops_integration_test/config.sh b/infrastructure/cdn-in-a-box/traffic_ops_integration_test/config.sh
index 6b2e416..536209a 100755
--- a/infrastructure/cdn-in-a-box/traffic_ops_integration_test/config.sh
+++ b/infrastructure/cdn-in-a-box/traffic_ops_integration_test/config.sh
@@ -45,7 +45,8 @@ cat <<-EOF >/opt/integration/app/traffic-ops-test.conf
         },
         "session": {
             "timeoutInSecs": 60
-        }
+        },
+        "includeSystemTests": true
     },
     "trafficOps": {
         "URL": "https://$TO_HOST:$TO_PORT",
diff --git a/infrastructure/cdn-in-a-box/variables.env b/infrastructure/cdn-in-a-box/variables.env
index 01f8e73..8a9bdfa 100644
--- a/infrastructure/cdn-in-a-box/variables.env
+++ b/infrastructure/cdn-in-a-box/variables.env
@@ -56,6 +56,8 @@ GRAFANA_ADMIN_PASSWORD=grafanaadminpassword
 GRAFANA_PORT=443
 MID_HOST=mid
 ORIGIN_HOST=origin
+SMTP_HOST=smtp
+SMTP_PORT=25
 TM_HOST=trafficmonitor
 TM_PORT=80
 TM_EMAIL=tmonitor@cdn.example.com
diff --git a/traffic_ops/testing/api/conf/traffic-ops-test.conf b/traffic_ops/testing/api/conf/traffic-ops-test.conf
index 6273bb5..e443d59 100644
--- a/traffic_ops/testing/api/conf/traffic-ops-test.conf
+++ b/traffic_ops/testing/api/conf/traffic-ops-test.conf
@@ -9,7 +9,8 @@
         },
         "session": {
             "timeoutInSecs": 60
-        }
+        },
+        "includeSystemTests": false
     },
     "trafficOps": {
         "URL": "https://localhost:8443",
diff --git a/traffic_ops/testing/api/config/config.go b/traffic_ops/testing/api/config/config.go
index 51e0fe2..0574133 100644
--- a/traffic_ops/testing/api/config/config.go
+++ b/traffic_ops/testing/api/config/config.go
@@ -109,8 +109,9 @@ type TrafficOpsDB struct {
 
 // Default - config section
 type Default struct {
-	Session Session   `json:"session"`
-	Log     Locations `json:"logLocations"`
+	Session            Session   `json:"session"`
+	Log                Locations `json:"logLocations"`
+	IncludeSystemTests bool      `json:"includeSystemTests"`
 }
 
 // Session - config section
diff --git a/traffic_ops/testing/api/v1/phys_locations_test.go b/traffic_ops/testing/api/v1/phys_locations_test.go
index 9378c17..e2b150d 100644
--- a/traffic_ops/testing/api/v1/phys_locations_test.go
+++ b/traffic_ops/testing/api/v1/phys_locations_test.go
@@ -16,8 +16,8 @@ package v1
 */
 
 import (
-	"testing"
 	"sort"
+	"testing"
 
 	tc "github.com/apache/trafficcontrol/lib/go-tc"
 )
diff --git a/traffic_ops/testing/api/v2/tc-fixtures.json b/traffic_ops/testing/api/v2/tc-fixtures.json
index 771ce8f..3ed7661 100644
--- a/traffic_ops/testing/api/v2/tc-fixtures.json
+++ b/traffic_ops/testing/api/v2/tc-fixtures.json
@@ -944,6 +944,13 @@
             "name": "use_tenancy",
             "secure": false,
             "value": "1"
+        },
+        {
+            "configFile": "global",
+            "lastUpdated": "2020-04-21T05:19:43.853831+00:00",
+            "name": "tm.instance_name",
+            "secure": false,
+            "value": "Traffic Ops API Tests"
         }
     ],
     "physLocations": [
diff --git a/traffic_ops/testing/api/v2/traffic_ops_test.go b/traffic_ops/testing/api/v2/traffic_ops_test.go
index 6777140..41f4df2 100644
--- a/traffic_ops/testing/api/v2/traffic_ops_test.go
+++ b/traffic_ops/testing/api/v2/traffic_ops_test.go
@@ -30,13 +30,15 @@ import (
 )
 
 var (
-	Config   config.Config
-	testData TrafficControl
+	Config             config.Config
+	testData           TrafficControl
+	includeSystemTests bool
 )
 
 func TestMain(m *testing.M) {
 	configFileName := flag.String("cfg", "traffic-ops-test.conf", "The config file path")
 	tcFixturesFileName := flag.String("fixtures", "tc-fixtures.json", "The test fixtures for the API test tool")
+	cliIncludeSystemTests := *flag.Bool("includeSystemTests", false, "Whether to enable tests that have environment dependencies beyond a database")
 	flag.Parse()
 
 	// Skip loading configuration when run with `go test -list=<pat>`. The -list
@@ -56,6 +58,9 @@ func TestMain(m *testing.M) {
 		os.Exit(1)
 	}
 
+	// CLI option overrides config
+	includeSystemTests = Config.Default.IncludeSystemTests || cliIncludeSystemTests
+
 	if err = log.InitCfg(Config); err != nil {
 		fmt.Printf("Error initializing loggers: %v\n", err)
 		os.Exit(1)
diff --git a/traffic_ops/testing/api/v2/user_test.go b/traffic_ops/testing/api/v2/user_test.go
index 88a4636..d023005 100644
--- a/traffic_ops/testing/api/v2/user_test.go
+++ b/traffic_ops/testing/api/v2/user_test.go
@@ -17,7 +17,9 @@ package v2
 import (
 	"bytes"
 	"fmt"
+	"github.com/apache/trafficcontrol/lib/go-rfc"
 	"net/http"
+	"net/mail"
 	"strings"
 	"testing"
 	"time"
@@ -37,6 +39,10 @@ func TestUsers(t *testing.T) {
 		GetTestUsers(t)
 		GetTestUserCurrent(t)
 		UserTenancyTest(t)
+		if includeSystemTests {
+			// UserRegistrationTest deletes test users before registering new users, so it must come after the other user tests.
+			UserRegistrationTest(t)
+		}
 	})
 }
 
@@ -136,6 +142,33 @@ func OpsUpdateAdminTest(t *testing.T) {
 	}
 }
 
+func UserRegistrationTest(t *testing.T) {
+	ForceDeleteTestUsers(t)
+	var emails []string
+	for _, user := range testData.Users {
+		tenant, _, err := TOSession.TenantByName(*user.Tenant)
+		if err != nil {
+			t.Fatalf("could not get tenant %v: %v", *user.Tenant, err)
+		}
+		resp, _, err := TOSession.RegisterNewUser(uint(tenant.ID), uint(*user.Role), rfc.EmailAddress{mail.Address{Address: *user.Email}})
+		if err != nil {
+			t.Fatalf("could not register user: %v", err)
+		}
+		t.Log("Response: ", resp.Alerts)
+		emails = append(emails, fmt.Sprintf(`'%v'`, *user.Email))
+	}
+
+	db, err := OpenConnection()
+	if err != nil {
+		t.Error("cannot open db")
+	}
+	defer db.Close()
+	q := `DELETE FROM tm_user WHERE email IN (` + strings.Join(emails, ",") + `)`
+	if err := execSQL(db, q, "tm_user"); err != nil {
+		t.Errorf("cannot execute SQL to delete registered users: %s; SQL is %s", err.Error(), q)
+	}
+}
+
 func UserSelfUpdateTest(t *testing.T) {
 	toReqTimeout := time.Second * time.Duration(Config.Default.Session.TimeoutInSecs)
 	opsTOClient, _, err := toclient.LoginWithAgent(TOSession.URL, "opsuser", "pa$$word", true, "to-api-v2-client-tests/opsuser", true, toReqTimeout)