This is an automated email from the ASF dual-hosted git repository.
zrhoffman 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 95ee202ca3 Refactor Users tests (#6999)
95ee202ca3 is described below
commit 95ee202ca38555c2fa6299f8c0a02d3efad2cb24
Author: Eric Holguin <[email protected]>
AuthorDate: Thu Aug 18 13:52:42 2022 -0600
Refactor Users tests (#6999)
* Refactor users tests
* Move user id function
* remove call to error
* Change client session being used
* fix users register test
* Fix user response
* fix broken tests
* fix user registers validation
* Remove unneeded validation
* fix typo
* Fix query
* Remove error call
* Renamed user test to match route name
* Fix go fmt errors
---
.../testing/api/v3/federation_users_test.go | 10 -
traffic_ops/testing/api/v3/user_current_test.go | 176 +++++++
traffic_ops/testing/api/v3/user_test.go | 536 -------------------
traffic_ops/testing/api/v3/users_register_test.go | 93 ++++
traffic_ops/testing/api/v3/users_test.go | 367 +++++++++++++
.../testing/api/v4/federation_users_test.go | 12 -
traffic_ops/testing/api/v4/user_current_test.go | 115 +++++
traffic_ops/testing/api/v4/user_test.go | 573 ---------------------
traffic_ops/testing/api/v4/users_register_test.go | 93 ++++
traffic_ops/testing/api/v4/users_test.go | 375 ++++++++++++++
10 files changed, 1219 insertions(+), 1131 deletions(-)
diff --git a/traffic_ops/testing/api/v3/federation_users_test.go
b/traffic_ops/testing/api/v3/federation_users_test.go
index c328ef5e8e..15720626a6 100644
--- a/traffic_ops/testing/api/v3/federation_users_test.go
+++ b/traffic_ops/testing/api/v3/federation_users_test.go
@@ -125,16 +125,6 @@ func TestFederationUsers(t *testing.T) {
})
}
-func GetUserID(t *testing.T, username string) func() int {
- return func() int {
- users, _, err := TOSession.GetUserByUsernameWithHdr(username,
nil)
- assert.RequireNoError(t, err, "Get Users Request failed with
error:", err)
- assert.RequireEqual(t, 1, len(users), "Expected response object
length 1, but got %d", len(users))
- assert.RequireNotNil(t, users[0].ID, "Expected ID to not be
nil.")
- return *users[0].ID
- }
-}
-
func CreateTestFederationUsers(t *testing.T) {
// Prerequisite Federation Users
federationUsers := map[string]tc.FederationUserPost{
diff --git a/traffic_ops/testing/api/v3/user_current_test.go
b/traffic_ops/testing/api/v3/user_current_test.go
new file mode 100644
index 0000000000..32a9179067
--- /dev/null
+++ b/traffic_ops/testing/api/v3/user_current_test.go
@@ -0,0 +1,176 @@
+package v3
+
+/*
+ Licensed 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.
+*/
+
+import (
+ "encoding/json"
+ "net/http"
+ "testing"
+
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
+)
+
+func TestUserCurrent(t *testing.T) {
+ WithObjs(t, []TCObj{Tenants, Parameters, Users}, func() {
+
+ opsUserSession := utils.CreateV3Session(t,
Config.TrafficOps.URL, "opsuser", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+
+ methodTests := utils.V3TestCase{
+ "GET": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUserCurrentFields(map[string]interface{}{"Username": "admin"})),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "id":
GetUserID(t, "opsuser")(),
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 3,
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"Email":
"[email protected]", "FullName": "Operations User Updated"})),
+ },
+ "BAD REQUEST when EMPTY EMAIL field": {
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email": "",
+ "fullName":
"Operations User Updated",
+ "id":
GetUserID(t, "opsuser")(),
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 3,
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ user := tc.User{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat, &user)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
+ case "GET":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.GetUserCurrentWithHdr(testCase.RequestHeaders)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp, tc.Alerts{}, err)
+ }
+ })
+ case "PUT":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.UpdateCurrentUser(user)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ }
+ }
+ })
+ }
+ })
+}
+
+func validateUserCurrentFields(expectedResp map[string]interface{})
utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ user := resp.(*tc.UserCurrent)
+ for field, expected := range expectedResp {
+ switch field {
+ case "AddressLine1":
+ assert.RequireNotNil(t, user.AddressLine1,
"Expected AddressLine1 to not be nil.")
+ assert.Equal(t, expected, *user.AddressLine1,
"Expected AddressLine1 to be %v, but got %s", expected, *user.AddressLine1)
+ case "AddressLine2":
+ assert.RequireNotNil(t, user.AddressLine2,
"Expected AddressLine2 to not be nil.")
+ assert.Equal(t, expected, *user.AddressLine2,
"Expected AddressLine2 to be %v, but got %s", expected, *user.AddressLine2)
+ case "City":
+ assert.RequireNotNil(t, user.City, "Expected
City to not be nil.")
+ assert.Equal(t, expected, *user.City, "Expected
City to be %v, but got %s", expected, *user.City)
+ case "Company":
+ assert.RequireNotNil(t, user.Company, "Expected
Company to not be nil.")
+ assert.Equal(t, expected, *user.Company,
"Expected Company to be %v, but got %s", expected, *user.Company)
+ case "Country":
+ assert.RequireNotNil(t, user.Country, "Expected
Country to not be nil.")
+ assert.Equal(t, expected, *user.Country,
"Expected Country to be %v, but got %s", expected, *user.Country)
+ case "Email":
+ assert.RequireNotNil(t, user.Email, "Expected
Email to not be nil.")
+ assert.Equal(t, expected, *user.Email,
"Expected Email to be %v, but got %s", expected, *user.Email)
+ case "FullName":
+ assert.RequireNotNil(t, user.FullName,
"Expected FullName to not be nil.")
+ assert.Equal(t, expected, *user.FullName,
"Expected FullName to be %v, but got %s", expected, *user.FullName)
+ case "ID":
+ assert.RequireNotNil(t, user.ID, "Expected ID
to not be nil.")
+ assert.Equal(t, expected, *user.ID, "Expected
ID to be %v, but got %d", expected, user.ID)
+ case "PhoneNumber":
+ assert.RequireNotNil(t, user.PhoneNumber,
"Expected PhoneNumber to not be nil.")
+ assert.Equal(t, expected, *user.PhoneNumber,
"Expected PhoneNumber to be %v, but got %s", expected, *user.PhoneNumber)
+ case "PostalCode":
+ assert.RequireNotNil(t, user.PostalCode,
"Expected PostalCode to not be nil.")
+ assert.Equal(t, expected, *user.PostalCode,
"Expected PostalCode to be %v, but got %s", expected, *user.PostalCode)
+ case "Role":
+ assert.RequireNotNil(t, user.Role, "Expected
Role to not be nil.")
+ assert.Equal(t, expected, *user.Role, "Expected
Role to be %v, but got %s", expected, *user.Role)
+ case "StateOrProvince":
+ assert.RequireNotNil(t, user.StateOrProvince,
"Expected StateOrProvince to not be nil.")
+ assert.Equal(t, expected,
*user.StateOrProvince, "Expected StateOrProvince to be %v, but got %s",
expected, *user.StateOrProvince)
+ case "Tenant":
+ assert.RequireNotNil(t, user.Tenant, "Expected
Tenant to not be nil.")
+ assert.Equal(t, expected, *user.Tenant,
"Expected Tenant to be %v, but got %s", expected, *user.Tenant)
+ case "TenantID":
+ assert.RequireNotNil(t, user.TenantID,
"Expected Tenant to not be nil.")
+ assert.Equal(t, expected, *user.TenantID,
"Expected TenantID to be %v, but got %d", expected, *user.TenantID)
+ case "Username":
+ assert.RequireNotNil(t, user.UserName,
"Expected Username to not be nil.")
+ assert.Equal(t, expected, *user.UserName,
"Expected Username to be %v, but got %s", expected, *user.UserName)
+ default:
+ t.Errorf("Expected field: %v, does not exist in
response", field)
+ }
+ }
+ }
+}
diff --git a/traffic_ops/testing/api/v3/user_test.go
b/traffic_ops/testing/api/v3/user_test.go
deleted file mode 100644
index b9093d9c07..0000000000
--- a/traffic_ops/testing/api/v3/user_test.go
+++ /dev/null
@@ -1,536 +0,0 @@
-package v3
-
-/*
- Licensed 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.
-*/
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "net/mail"
- "sort"
- "strings"
- "testing"
- "time"
-
- "github.com/apache/trafficcontrol/lib/go-rfc"
- "github.com/apache/trafficcontrol/lib/go-tc"
- "github.com/apache/trafficcontrol/lib/go-util"
- toclient "github.com/apache/trafficcontrol/traffic_ops/v3-client"
-)
-
-func TestUsers(t *testing.T) {
- WithObjs(t, []TCObj{Tenants, Parameters, Users}, func() {
- GetTestUsersIMS(t)
- currentTime := time.Now().UTC().Add(-5 * time.Second)
- time := currentTime.Format(time.RFC1123)
- var header http.Header
- header = make(map[string][]string)
- header.Set(rfc.IfModifiedSince, time)
- SortTestUsers(t)
- UpdateTestUsers(t)
- GetTestUsersIMSAfterChange(t, header)
- RolenameCapitalizationTest(t)
- OpsUpdateAdminTest(t)
- UserSelfUpdateTest(t)
- UserUpdateOwnRoleTest(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)
- }
- })
-}
-
-func GetTestUsersIMSAfterChange(t *testing.T, header http.Header) {
- _, reqInf, err := TOSession.GetUsersWithHdr(header)
- if err != nil {
- t.Fatalf("Expected no error, but got %v", err.Error())
- }
- if reqInf.StatusCode != http.StatusOK {
- t.Fatalf("Expected 200 status code, got %v", reqInf.StatusCode)
- }
- currentTime := time.Now().UTC()
- currentTime = currentTime.Add(1 * time.Second)
- timeStr := currentTime.Format(time.RFC1123)
- header.Set(rfc.IfModifiedSince, timeStr)
- _, reqInf, err = TOSession.GetUsersWithHdr(header)
- if err != nil {
- t.Fatalf("Expected no error, but got %v", err.Error())
- }
- if reqInf.StatusCode != http.StatusNotModified {
- t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode)
- }
-}
-
-const SessionUserName = "admin" // TODO make dynamic?
-
-func GetTestUsersIMS(t *testing.T) {
- var header http.Header
- header = make(map[string][]string)
- futureTime := time.Now().AddDate(0, 0, 1)
- time := futureTime.Format(time.RFC1123)
- header.Set(rfc.IfModifiedSince, time)
- _, reqInf, err := TOSession.GetUsersWithHdr(header)
- if err != nil {
- t.Fatalf("Expected no error, but got %v", err.Error())
- }
- if reqInf.StatusCode != http.StatusNotModified {
- t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode)
- }
-}
-
-func CreateTestUsers(t *testing.T) {
- for _, user := range testData.Users {
-
- resp, _, err := TOSession.CreateUser(&user)
- if err != nil {
- t.Errorf("could not CREATE user: %v", err)
- }
- t.Log("Response: ", resp.Alerts)
- }
-}
-
-func RolenameCapitalizationTest(t *testing.T) {
-
- roles, _, _, err := TOSession.GetRoles()
- if err != nil {
- t.Errorf("could not get roles: %v", err)
- }
- if len(roles) == 0 {
- t.Fatal("there should be at least one role to test the user")
- }
-
- tenants, _, err := TOSession.Tenants()
- if err != nil {
- t.Errorf("could not get tenants: %v", err)
- }
- if len(tenants) == 0 {
- t.Fatal("there should be at least one tenant to test the user")
- }
-
- // this user never does anything, so the role and tenant aren't
important
- blob := fmt.Sprintf(`
- {
- "username": "test_user",
- "email": "[email protected]",
- "fullName": "full name is required",
- "localPasswd": "better_twelve",
- "confirmLocalPasswd": "better_twelve",
- "role": %d,
- "tenantId": %d
- }`, *roles[0].ID, tenants[0].ID)
-
- reader := strings.NewReader(blob)
- request, err := http.NewRequest("POST", fmt.Sprintf("%v%s/users",
TOSession.URL, TestAPIBase), reader)
- if err != nil {
- t.Errorf("could not make new request: %v", err)
- }
- resp, err := TOSession.Client.Do(request)
- if err != nil {
- t.Errorf("could not do request: %v", err)
- }
-
- buf := new(bytes.Buffer)
- buf.ReadFrom(resp.Body)
- strResp := buf.String()
- if !strings.Contains(strResp, "roleName") {
- t.Error("incorrect json was returned for POST")
- }
-
- request, err = http.NewRequest("GET",
fmt.Sprintf("%v%s/users?username=test_user", TOSession.URL, TestAPIBase), nil)
- resp, err = TOSession.Client.Do(request)
-
- buf = new(bytes.Buffer)
- buf.ReadFrom(resp.Body)
- strResp = buf.String()
- if !strings.Contains(strResp, "rolename") {
- t.Error("incorrect json was returned for GET")
- }
-
-}
-
-func OpsUpdateAdminTest(t *testing.T) {
- toReqTimeout := time.Second *
time.Duration(Config.Default.Session.TimeoutInSecs)
- opsTOClient, _, err := toclient.LoginWithAgent(TOSession.URL,
"opsuser", "pa$$word", true, "to-api-v3-client-tests/opsuser", true,
toReqTimeout)
- if err != nil {
- t.Fatalf("failed to get log in with opsuser: %v", err.Error())
- }
-
- resp, _, err := TOSession.GetUserByUsername("admin")
- if err != nil {
- t.Errorf("cannot GET user by name: 'admin', %v", err)
- }
- user := resp[0]
-
- fullName := "oops"
- email := "[email protected]"
- user.FullName = &fullName
- user.Email = &email
-
- _, _, err = opsTOClient.UpdateUserByID(*user.ID, &user)
- if err == nil {
- t.Error("ops user incorrectly updated an admin")
- }
-}
-
-func SortTestUsers(t *testing.T) {
- var header http.Header
- var sortedList []string
- resp, _, err := TOSession.GetUsersWithHdr(header)
- if err != nil {
- t.Fatalf("Expected no error, but got %v", err.Error())
- }
- for i, _ := range resp {
- sortedList = append(sortedList, *resp[i].Username)
- }
-
- res := sort.SliceIsSorted(sortedList, func(p, q int) bool {
- return sortedList[p] < sortedList[q]
- })
- if res != true {
- t.Errorf("list is not sorted by their names: %v", sortedList)
- }
-}
-
-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{Address: 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); 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-v3-client-tests/opsuser", true,
toReqTimeout)
- if err != nil {
- t.Fatalf("failed to get log in with opsuser: %v", err.Error())
- }
-
- resp, _, err := TOSession.GetUserByUsername("opsuser")
- if err != nil {
- t.Fatalf("cannot GET user by name: 'opsuser', %v\n", err)
- }
- if len(resp) < 1 {
- t.Fatalf("no users returned when requesting user 'opsuser'")
- }
- user := resp[0]
-
- if user.ID == nil {
- t.Fatalf("user 'opsuser' has a null or missing ID - cannot
proceed")
- }
-
- user.FullName = util.StrPtr("Oops-man")
- user.Email = util.StrPtr("[email protected]")
-
- var updateResp *tc.UpdateUserResponse
- updateResp, _, err = opsTOClient.UpdateUserByID(*user.ID, &user)
- if err != nil {
- t.Fatalf("cannot UPDATE user by id: %v - %v\n", err, updateResp)
- }
-
- // Make sure it got updated
- resp2, _, err := TOSession.GetUserByID(*user.ID)
- if err != nil {
- t.Fatalf("cannot GET user by id: '%d', %v\n", *user.ID, err)
- }
- if len(resp2) < 1 {
- t.Fatalf("no results returned when requesting user #%d",
*user.ID)
- }
- updatedUser := resp2[0]
-
- if updatedUser.FullName == nil {
- t.Errorf("user was not correctly updated, FullName is null or
missing")
- } else if *updatedUser.FullName != "Oops-man" {
- t.Errorf("results do not match actual: '%s', expected:
'Oops-man'\n", *updatedUser.FullName)
- }
-
- if updatedUser.Email == nil {
- t.Errorf("user was not correctly updated, Email is null or
missing")
- } else if *updatedUser.Email != "[email protected]" {
- t.Errorf("results do not match actual: '%s', expected:
'[email protected]'\n", *updatedUser.Email)
- }
-
- // Same thing using /user/current
- user.FullName = util.StrPtr("ops-man")
- user.Email = util.StrPtr("[email protected]")
- updateResp, _, err = opsTOClient.UpdateCurrentUser(user)
- if err != nil {
- t.Fatalf("error updating current user: %v - %v", err,
updateResp)
- }
-
- // Make sure it got updated
- resp2, _, err = TOSession.GetUserByID(*user.ID)
- if err != nil {
- t.Fatalf("error getting user #%d: %v", *user.ID, err)
- }
-
- if len(resp2) < 1 {
- t.Fatalf("no user returned when requesting user #%d", *user.ID)
- }
-
- if resp2[0].FullName == nil {
- t.Errorf("FullName missing or null after update")
- } else if *resp2[0].FullName != "ops-man" {
- t.Errorf("Expected FullName to be 'ops-man', but it was '%s'",
*resp2[0].FullName)
- }
-
- if resp2[0].Email == nil {
- t.Errorf("Email missing or null after update")
- } else if *resp2[0].Email != "[email protected]" {
- t.Errorf("Expected Email to be restored to
'[email protected]', but it was '%s'", *resp2[0].Email)
- }
-
- // now test using an invalid email address
- currentEmail := *user.Email
- user.Email = new(string)
- updateResp, _, err = TOSession.UpdateCurrentUser(user)
- if err == nil {
- t.Fatal("error was expected updating user with email: '' - got
none")
- }
-
- // Ensure it wasn't actually updated
- resp2, _, err = TOSession.GetUserByID(*user.ID)
- if err != nil {
- t.Fatalf("error getting user #%d: %v", *user.ID, err)
- }
-
- if len(resp2) < 1 {
- t.Fatalf("no user returned when requesting user #%d", *user.ID)
- }
-
- if resp2[0].Email == nil {
- t.Errorf("Email missing or null after update")
- } else if *resp2[0].Email != currentEmail {
- t.Errorf("Expected Email to still be '%s', but it was '%s'",
currentEmail, *resp2[0].Email)
- }
-}
-
-func UserUpdateOwnRoleTest(t *testing.T) {
- resp, _, err := TOSession.GetUserByUsername(SessionUserName)
- if err != nil {
- t.Errorf("cannot GET user by name: '%s', %v", SessionUserName,
err)
- }
- user := resp[0]
-
- *user.Role = *user.Role + 1
- _, _, err = TOSession.UpdateUserByID(*user.ID, &user)
- if err == nil {
- t.Error("user incorrectly updated their role")
- }
-}
-
-func UpdateTestUsers(t *testing.T) {
- firstUsername := *testData.Users[0].Username
- resp, _, err := TOSession.GetUserByUsername(firstUsername)
- if err != nil {
- t.Errorf("cannot GET user by name: '%s', %v", firstUsername,
err)
- }
- user := resp[0]
- newCity := "kidz kable kown"
- *user.City = newCity
-
- var updateResp *tc.UpdateUserResponse
- updateResp, _, err = TOSession.UpdateUserByID(*user.ID, &user)
- if err != nil {
- t.Errorf("cannot UPDATE user by id: %v - %v", err,
updateResp.Alerts)
- }
-
- // Make sure it got updated
- resp2, _, err := TOSession.GetUserByID(*user.ID)
- if err != nil {
- t.Errorf("cannot GET user by id: '%d', %v", *user.ID, err)
- }
- updatedUser := resp2[0]
- if *updatedUser.City != newCity {
- t.Errorf("results do not match actual: %s, expected: %s",
*updatedUser.City, newCity)
- }
- if resp[0].RegistrationSent != resp2[0].RegistrationSent {
- t.Errorf("registration_sent value shouldn't have been updated,
expectd: %s, got: %s", resp[0].RegistrationSent, resp2[0].RegistrationSent)
- }
-
-}
-
-func GetTestUsers(t *testing.T) {
- _, _, err := TOSession.GetUsers()
- if err != nil {
- t.Errorf("cannot GET users: %v", err)
- }
-}
-
-func GetTestUserCurrent(t *testing.T) {
- user, _, err := TOSession.GetUserCurrent()
- if err != nil {
- t.Errorf("cannot GET current user: %v", err)
- }
- if user.UserName == nil {
- t.Errorf("current user expected: %v actual: %v",
SessionUserName, nil)
- }
- if *user.UserName != SessionUserName {
- t.Errorf("current user expected: %v actual: %v",
SessionUserName, *user.UserName)
- }
-}
-
-func UserTenancyTest(t *testing.T) {
- users, _, err := TOSession.GetUsers()
- if err != nil {
- t.Errorf("cannot GET users: %v", err)
- }
- tenant3Found := false
- tenant4Found := false
- tenant3Username := "tenant3user"
- tenant4Username := "tenant4user"
- tenant3User := tc.User{}
-
- // assert admin user can view tenant3user and tenant4user
- for _, user := range users {
- if *user.Username == tenant3Username {
- tenant3Found = true
- tenant3User = user
- } else if *user.Username == tenant4Username {
- tenant4Found = true
- }
- if tenant3Found && tenant4Found {
- break
- }
- }
- if !tenant3Found || !tenant4Found {
- t.Error("expected admin to be able to view tenants: tenant3 and
tenant4")
- }
-
- toReqTimeout := time.Second *
time.Duration(Config.Default.Session.TimeoutInSecs)
- tenant4TOClient, _, err := toclient.LoginWithAgent(TOSession.URL,
"tenant4user", "pa$$word", true, "to-api-v3-client-tests/tenant4user", true,
toReqTimeout)
- if err != nil {
- t.Fatalf("failed to log in with tenant4user: %v", err.Error())
- }
-
- usersReadableByTenant4, _, err := tenant4TOClient.GetUsers()
- if err != nil {
- t.Error("tenant4user cannot GET users")
- }
-
- tenant4canReadItself := false
- for _, user := range usersReadableByTenant4 {
- // assert that tenant4user cannot read tenant3user
- if *user.Username == tenant3Username {
- t.Error("expected tenant4user to be unable to read
tenant3user")
- }
- // assert that tenant4user can read itself
- if *user.Username == tenant4Username {
- tenant4canReadItself = true
- }
- }
- if !tenant4canReadItself {
- t.Error("expected tenant4user to be able to read itself")
- }
-
- // assert that tenant4user cannot update tenant3user
- if _, _, err = tenant4TOClient.UpdateUserByID(*tenant3User.ID,
&tenant3User); err == nil {
- t.Error("expected tenant4user to be unable to update
tenant4user")
- }
-
- // assert that tenant4user cannot create a user outside of its tenant
- rootTenant, _, err := TOSession.TenantByName("root")
- if err != nil {
- t.Error("expected to be able to GET the root tenant")
- }
- newUser := testData.Users[0]
- newUser.Email = util.StrPtr("[email protected]")
- newUser.Username = util.StrPtr("testusertenancy")
- newUser.TenantID = &rootTenant.ID
- if _, _, err = tenant4TOClient.CreateUser(&newUser); err == nil {
- t.Error("expected tenant4user to be unable to create a new user
in the root tenant")
- }
-}
-
-// ForceDeleteTestUsers forcibly deletes the users from the db.
-func ForceDeleteTestUsers(t *testing.T) {
-
- // NOTE: Special circumstances! This should *NOT* be done without a
really good reason!
- // Connects directly to the DB to remove users rather than going thru
the client.
- // This is required here because the DeleteUser action does not really
delete users, but disables them.
- db, err := OpenConnection()
- if err != nil {
- t.Error("cannot open db")
- }
- defer db.Close()
-
- var usernames []string
- for _, user := range testData.Users {
- usernames = append(usernames, `'`+*user.Username+`'`)
- }
-
- // there is a constraint that prevents users from being deleted when
they have a log
- q := `DELETE FROM log WHERE NOT tm_user = (SELECT id FROM tm_user WHERE
username = 'admin')`
- err = execSQL(db, q)
- if err != nil {
- t.Errorf("cannot execute SQL: %s; SQL is %s", err.Error(), q)
- }
-
- q = `DELETE FROM tm_user WHERE username IN (` + strings.Join(usernames,
",") + `)`
- err = execSQL(db, q)
- if err != nil {
- t.Errorf("cannot execute SQL: %s; SQL is %s", err.Error(), q)
- }
-}
-
-func DeleteTestUsers(t *testing.T) {
- for _, user := range testData.Users {
-
- resp, _, err := TOSession.GetUserByUsername(*user.Username)
- if err != nil {
- t.Errorf("cannot GET user by name: %v - %v",
*user.Username, err)
- }
-
- if resp != nil {
- respUser := resp[0]
-
- _, _, err := TOSession.DeleteUserByID(*respUser.ID)
- if err != nil {
- t.Errorf("cannot DELETE user by name: '%s' %v",
*respUser.Username, err)
- }
-
- // Make sure it got deleted
- resp, _, err :=
TOSession.GetUserByUsername(*user.Username)
- if err != nil {
- t.Errorf("error deleting user by name: %s",
err.Error())
- }
- if len(resp) > 0 {
- t.Errorf("expected user: %s to be deleted",
*user.Username)
- }
- }
- }
-}
diff --git a/traffic_ops/testing/api/v3/users_register_test.go
b/traffic_ops/testing/api/v3/users_register_test.go
new file mode 100644
index 0000000000..050aae9b7b
--- /dev/null
+++ b/traffic_ops/testing/api/v3/users_register_test.go
@@ -0,0 +1,93 @@
+package v3
+
+/*
+ Licensed 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.
+*/
+
+import (
+ "encoding/json"
+ "net/http"
+ "testing"
+
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
+)
+
+func TestUsersRegister(t *testing.T) {
+ if includeSystemTests {
+ WithObjs(t, []TCObj{Tenants, Parameters}, func() {
+
+ methodTests := utils.V3TestCase{
+ "POST": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ RequestBody:
map[string]interface{}{
+ "addressLine1":
"address of ops",
+ "addressLine2":
"place",
+ "city":
"somewhere",
+ "company":
"else",
+ "country":
"UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 3,
+ "tenant":
"root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username":
"opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
validateDeletion("[email protected]")),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ userRegistration :=
tc.UserRegistrationRequest{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err,
"Error occurred when marshalling request body: %v", err)
+ err =
json.Unmarshal(dat, &userRegistration)
+ assert.NoError(t, err,
"Error occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
+ case "POST":
+ t.Run(name, func(t
*testing.T) {
+ alerts, reqInf,
err := testCase.ClientSession.RegisterNewUser(userRegistration.TenantID,
userRegistration.Role, userRegistration.Email)
+ for _, check :=
range testCase.Expectations {
+
check(t, reqInf, nil, alerts, err)
+ }
+ })
+ }
+ }
+ })
+ }
+ })
+ }
+}
+
+func validateDeletion(email string) utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ db, err := OpenConnection()
+ assert.RequireNoError(t, err, "Cannot open db")
+ defer db.Close()
+ q := `DELETE FROM tm_user WHERE email = '` + email + `'`
+ err = execSQL(db, q)
+ assert.NoError(t, err, "Cannot execute SQL to delete registered
users: %s; SQL is %s", err, q)
+ }
+}
diff --git a/traffic_ops/testing/api/v3/users_test.go
b/traffic_ops/testing/api/v3/users_test.go
new file mode 100644
index 0000000000..3d6f6d92f8
--- /dev/null
+++ b/traffic_ops/testing/api/v3/users_test.go
@@ -0,0 +1,367 @@
+package v3
+
+/*
+ Licensed 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.
+*/
+
+import (
+ "encoding/json"
+ "net/http"
+ "sort"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/apache/trafficcontrol/lib/go-rfc"
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
+)
+
+func TestUsers(t *testing.T) {
+ WithObjs(t, []TCObj{Tenants, Parameters, Users}, func() {
+
+ opsUserSession := utils.CreateV3Session(t,
Config.TrafficOps.URL, "opsuser", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+ tenant4UserSession := utils.CreateV3Session(t,
Config.TrafficOps.URL, "tenant4user", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+
+ currentTime := time.Now().UTC().Add(-15 * time.Second)
+ currentTimeRFC := currentTime.Format(time.RFC1123)
+ tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)
+
+ methodTests := utils.V3TestCase{
+ "GET": {
+ "NOT MODIFIED when NO CHANGES made": {
+ ClientSession: TOSession,
+ RequestHeaders:
http.Header{rfc.IfModifiedSince: {tomorrow}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusNotModified)),
+ },
+ "OK when CHANGES made": {
+ ClientSession: TOSession,
+ RequestHeaders:
http.Header{rfc.IfModifiedSince: {currentTimeRFC}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1),
+ validateUsersSort()),
+ },
+ "ADMIN can view CHILD TENANTS": {
+ ClientSession: TOSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1),
+
validateTenants(map[string]bool{"tenant3": true, "tenant4": true})),
+ },
+ "CHILD TENANT should NOT read PARENT TENANT": {
+ ClientSession: tenant4UserSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseHasLength(1),
+
validateTenants(map[string]bool{"tenant3": false, "tenant4": true})),
+ },
+ },
+ "POST": {
+ "FORBIDDEN when CHILD TENANT creates USER with
PARENT TENANCY": {
+ ClientSession: tenant4UserSession,
+ RequestBody: map[string]interface{}{
+ "email":
"[email protected]",
+ "fullName": "Outside
Tenancy",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 3,
+ "tenantId":
GetTenantID(t, "tenant3")(),
+ "username":
"outsideTenantUser",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ EndpointId: GetUserID(t, "steering"),
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "updated
line 1",
+ "addressLine2": "updated
line 2",
+ "city": "updated
city name",
+ "company": "new
company",
+ "country": "US",
+ "email":
"[email protected]",
+ "fullName": "Steering
User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "newUser": false,
+ "role": 6,
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username":
"steering",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"AddressLine1": "updated
line 1",
+ "AddressLine2":
"updated line 2", "City": "updated city name", "Company": "new company",
+ "Country": "US",
"Email": "[email protected]", "FullName": "Steering User Updated"})),
+ },
+ "OK when UPDATING SELF": {
+ EndpointId: GetUserID(t, "opsuser"),
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 3,
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"Email":
"[email protected]", "FullName": "Operations User Updated"})),
+ },
+ "BAD REQUEST when updating OWN ROLE": {
+ EndpointId: GetUserID(t, "opsuser"),
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 9999,
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ "FORBIDDEN when OPERATIONS USER updates ADMIN
USER": {
+ EndpointId: GetUserID(t, "admin"),
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "email":
"[email protected]",
+ "fullName": "oops",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 4,
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "admin",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ "FORBIDDEN when CHILD TENANT USER updates
PARENT TENANT USER": {
+ EndpointId: GetUserID(t,
"tenant3user"),
+ ClientSession: tenant4UserSession,
+ RequestBody: map[string]interface{}{
+ "email":
"[email protected]",
+ "fullName": "Parent
tenant test",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": 4,
+ "tenant": "tenant2",
+ "tenantId":
GetTenantID(t, "tenant2")(),
+ "username":
"tenant3user",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ user := tc.User{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat, &user)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
+ case "GET":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.GetUsersWithHdr(testCase.RequestHeaders)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp, tc.Alerts{}, err)
+ }
+ })
+ case "POST":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.CreateUser(&user)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ case "PUT":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.UpdateUserByID(testCase.EndpointId(), &user)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ }
+ }
+ })
+ }
+ })
+}
+
+func validateUsersFields(expectedResp map[string]interface{}) utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ userResp := resp.([]tc.User)
+ for field, expected := range expectedResp {
+ for _, user := range userResp {
+ switch field {
+ case "AddressLine1":
+ assert.RequireNotNil(t,
user.AddressLine1, "Expected AddressLine1 to not be nil.")
+ assert.Equal(t, expected,
*user.AddressLine1, "Expected AddressLine1 to be %v, but got %s", expected,
*user.AddressLine1)
+ case "AddressLine2":
+ assert.RequireNotNil(t,
user.AddressLine2, "Expected AddressLine2 to not be nil.")
+ assert.Equal(t, expected,
*user.AddressLine2, "Expected AddressLine2 to be %v, but got %s", expected,
*user.AddressLine2)
+ case "City":
+ assert.RequireNotNil(t, user.City,
"Expected City to not be nil.")
+ assert.Equal(t, expected, *user.City,
"Expected City to be %v, but got %s", expected, *user.City)
+ case "Company":
+ assert.RequireNotNil(t, user.Company,
"Expected Company to not be nil.")
+ assert.Equal(t, expected,
*user.Company, "Expected Company to be %v, but got %s", expected, *user.Company)
+ case "Country":
+ assert.RequireNotNil(t, user.Country,
"Expected Country to not be nil.")
+ assert.Equal(t, expected,
*user.Country, "Expected Country to be %v, but got %s", expected, *user.Country)
+ case "Email":
+ assert.RequireNotNil(t, user.Email,
"Expected Email to not be nil.")
+ assert.Equal(t, expected, *user.Email,
"Expected Email to be %v, but got %s", expected, *user.Email)
+ case "FullName":
+ assert.RequireNotNil(t, user.FullName,
"Expected FullName to not be nil.")
+ assert.Equal(t, expected,
*user.FullName, "Expected FullName to be %v, but got %s", expected,
*user.FullName)
+ case "ID":
+ assert.RequireNotNil(t, user.ID,
"Expected ID to not be nil.")
+ assert.Equal(t, expected, *user.ID,
"Expected ID to be %v, but got %d", expected, user.ID)
+ case "PhoneNumber":
+ assert.RequireNotNil(t,
user.PhoneNumber, "Expected PhoneNumber to not be nil.")
+ assert.Equal(t, expected,
*user.PhoneNumber, "Expected PhoneNumber to be %v, but got %s", expected,
*user.PhoneNumber)
+ case "PostalCode":
+ assert.RequireNotNil(t,
user.PostalCode, "Expected PostalCode to not be nil.")
+ assert.Equal(t, expected,
*user.PostalCode, "Expected PostalCode to be %v, but got %s", expected,
*user.PostalCode)
+ case "RegistrationSent":
+ assert.RequireNotNil(t,
user.RegistrationSent, "Expected RegistrationSent to not be nil.")
+ assert.Equal(t, expected,
*user.RegistrationSent, "Expected RegistrationSent to be %v, but got %v",
expected, *user.RegistrationSent)
+ case "Role":
+ assert.RequireNotNil(t, user.Role,
"Expected Role to not be nil.")
+ assert.Equal(t, expected, *user.Role,
"Expected Role to be %v, but got %s", expected, *user.Role)
+ case "StateOrProvince":
+ assert.RequireNotNil(t,
user.StateOrProvince, "Expected StateOrProvince to not be nil.")
+ assert.Equal(t, expected,
*user.StateOrProvince, "Expected StateOrProvince to be %v, but got %s",
expected, *user.StateOrProvince)
+ case "Tenant":
+ assert.RequireNotNil(t, user.Tenant,
"Expected Tenant to not be nil.")
+ assert.Equal(t, expected, *user.Tenant,
"Expected Tenant to be %v, but got %s", expected, *user.Tenant)
+ case "TenantID":
+ assert.RequireNotNil(t, user.TenantID,
"Expected Tenant to not be nil.")
+ assert.Equal(t, expected,
*user.TenantID, "Expected TenantID to be %v, but got %d", expected,
*user.TenantID)
+ case "Username":
+ assert.RequireNotNil(t, user.Username,
"Expected Username to not be nil.")
+ assert.Equal(t, expected,
*user.Username, "Expected Username to be %v, but got %s", expected,
*user.Username)
+ default:
+ t.Errorf("Expected field: %v, does not
exist in response", field)
+ }
+ }
+ }
+ }
+}
+
+func validateTenants(expectedTenants map[string]bool) utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ userResp := resp.([]tc.User)
+
+ for _, user := range userResp {
+ for tenant, expected := range expectedTenants {
+ assert.RequireNotNil(t, user.Tenant, "Expected
Users response to not be nil.")
+ if *user.Tenant == tenant && !expected {
+ t.Errorf("Tenant: %s was not expected",
*user.Tenant)
+ }
+ }
+ }
+ }
+}
+
+func validateUsersUpdateCreateFields(expectedResp map[string]interface{})
utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ assert.RequireNotEqual(t, resp.(tc.User), tc.User{}, "Expected
a non empty response.")
+ userResp := resp.(tc.User)
+ users := []tc.User{userResp}
+ validateUsersFields(expectedResp)(t, toclientlib.ReqInf{},
users, tc.Alerts{}, nil)
+ }
+}
+
+func validateUsersSort() utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{},
alerts tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ var usernames []string
+ usersResp := resp.([]tc.User)
+ for _, user := range usersResp {
+ assert.RequireNotNil(t, user.Username, "Expected
Username to not be nil.")
+ usernames = append(usernames, *user.Username)
+ }
+ assert.Equal(t, true, sort.StringsAreSorted(usernames), "List
is not sorted by their usernames: %v", usernames)
+ }
+}
+
+func GetUserID(t *testing.T, username string) func() int {
+ return func() int {
+ users, _, err := TOSession.GetUserByUsernameWithHdr(username,
nil)
+ assert.RequireNoError(t, err, "Get Users Request failed with
error:", err)
+ assert.RequireEqual(t, 1, len(users), "Expected response object
length 1, but got %d", len(users))
+ assert.RequireNotNil(t, users[0].ID, "Expected ID to not be
nil.")
+ return *users[0].ID
+ }
+}
+
+func CreateTestUsers(t *testing.T) {
+ for _, user := range testData.Users {
+ resp, _, err := TOSession.CreateUser(&user)
+ assert.RequireNoError(t, err, "Could not create user: %v -
alerts: %+v", err, resp.Alerts)
+ }
+}
+
+// ForceDeleteTestUsers forcibly deletes the users from the db.
+// NOTE: Special circumstances! This should *NOT* be done without a really
good reason!
+// Connects directly to the DB to remove users rather than going through the
client.
+// This is required here because the DeleteUser action does not really delete
users, but disables them.
+func ForceDeleteTestUsers(t *testing.T) {
+
+ db, err := OpenConnection()
+ assert.RequireNoError(t, err, "Cannot open db")
+ defer db.Close()
+
+ var usernames []string
+ for _, user := range testData.Users {
+ usernames = append(usernames, `'`+*user.Username+`'`)
+ }
+
+ // there is a constraint that prevents users from being deleted when
they have a log
+ q := `DELETE FROM log WHERE NOT tm_user = (SELECT id FROM tm_user WHERE
username = 'admin')`
+ err = execSQL(db, q)
+ assert.RequireNoError(t, err, "Cannot execute SQL: %v; SQL is %s", err,
q)
+
+ q = `DELETE FROM tm_user WHERE username IN (` + strings.Join(usernames,
",") + `)`
+ err = execSQL(db, q)
+ assert.NoError(t, err, "Cannot execute SQL: %v; SQL is %s", err, q)
+}
diff --git a/traffic_ops/testing/api/v4/federation_users_test.go
b/traffic_ops/testing/api/v4/federation_users_test.go
index 2984c6bc3c..8b5f9a14ab 100644
--- a/traffic_ops/testing/api/v4/federation_users_test.go
+++ b/traffic_ops/testing/api/v4/federation_users_test.go
@@ -218,18 +218,6 @@ func validateFederationUserIDSort(desc bool)
utils.CkReqFunc {
}
}
-func GetUserID(t *testing.T, username string) func() int {
- return func() int {
- opts := client.NewRequestOptions()
- opts.QueryParameters.Set("username", username)
- users, _, err := TOSession.GetUsers(opts)
- assert.RequireNoError(t, err, "Get Users Request failed with
error:", err)
- assert.RequireEqual(t, 1, len(users.Response), "Expected
response object length 1, but got %d", len(users.Response))
- assert.RequireNotNil(t, users.Response[0].ID, "Expected ID to
not be nil.")
- return *users.Response[0].ID
- }
-}
-
func CreateTestFederationUsers(t *testing.T) {
// Prerequisite Federation Users
federationUsers := map[string]tc.FederationUserPost{
diff --git a/traffic_ops/testing/api/v4/user_current_test.go
b/traffic_ops/testing/api/v4/user_current_test.go
new file mode 100644
index 0000000000..8284e34c27
--- /dev/null
+++ b/traffic_ops/testing/api/v4/user_current_test.go
@@ -0,0 +1,115 @@
+package v4
+
+/*
+ Licensed 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.
+*/
+
+import (
+ "encoding/json"
+ "net/http"
+ "testing"
+
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+)
+
+func TestUserCurrent(t *testing.T) {
+ WithObjs(t, []TCObj{Tenants, Parameters, Users}, func() {
+
+ opsUserSession := utils.CreateV4Session(t,
Config.TrafficOps.URL, "opsuser", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+
+ methodTests := utils.V4TestCase{
+ "GET": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"Username": "admin"})),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role":
"operations",
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"Email":
"[email protected]", "FullName": "Operations User Updated"})),
+ },
+ "BAD REQUEST when EMPTY EMAIL field": {
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email": "",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role":
"operations",
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ user := tc.UserV4{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat, &user)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
+ case "GET":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.GetUserCurrent(testCase.RequestOpts)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ case "PUT":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.UpdateCurrentUser(user, testCase.RequestOpts)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ }
+ }
+ })
+ }
+ })
+}
diff --git a/traffic_ops/testing/api/v4/user_test.go
b/traffic_ops/testing/api/v4/user_test.go
deleted file mode 100644
index 35864892b4..0000000000
--- a/traffic_ops/testing/api/v4/user_test.go
+++ /dev/null
@@ -1,573 +0,0 @@
-package v4
-
-/*
- Licensed 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.
-*/
-
-import (
- "fmt"
- "net/http"
- "net/mail"
- "sort"
- "strconv"
- "strings"
- "testing"
- "time"
-
- "github.com/apache/trafficcontrol/lib/go-rfc"
- "github.com/apache/trafficcontrol/lib/go-tc"
- "github.com/apache/trafficcontrol/lib/go-util"
- client "github.com/apache/trafficcontrol/traffic_ops/v4-client"
-)
-
-func TestUsers(t *testing.T) {
- WithObjs(t, []TCObj{Tenants, Parameters, Users}, func() {
- GetTestUsersIMS(t)
- currentTime := time.Now().UTC().Add(-5 * time.Second)
- time := currentTime.Format(time.RFC1123)
- var header http.Header
- header = make(map[string][]string)
- header.Set(rfc.IfModifiedSince, time)
- SortTestUsers(t)
- UpdateTestUsers(t)
- GetTestUsersIMSAfterChange(t, header)
- OpsUpdateAdminTest(t)
- UserSelfUpdateTest(t)
- UserUpdateOwnRoleTest(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)
- }
- })
-}
-
-func GetTestUsersIMSAfterChange(t *testing.T, header http.Header) {
- opts := client.NewRequestOptions()
- opts.Header = header
- resp, reqInf, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("Expected no error, but got: %v - alerts: %+v", err,
resp.Alerts)
- }
- if reqInf.StatusCode != http.StatusOK {
- t.Fatalf("Expected 200 status code, got %v", reqInf.StatusCode)
- }
-
- currentTime := time.Now().UTC()
- currentTime = currentTime.Add(1 * time.Second)
- timeStr := currentTime.Format(time.RFC1123)
- opts.Header.Set(rfc.IfModifiedSince, timeStr)
-
- resp, reqInf, err = TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("Expected no error, but got: %v - alerts: %+v", err,
resp.Alerts)
- }
- if reqInf.StatusCode != http.StatusNotModified {
- t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode)
- }
-}
-
-const SessionUserName = "admin" // TODO make dynamic?
-
-func GetTestUsersIMS(t *testing.T) {
- futureTime := time.Now().AddDate(0, 0, 1)
- time := futureTime.Format(time.RFC1123)
-
- opts := client.NewRequestOptions()
- opts.Header.Set(rfc.IfModifiedSince, time)
-
- resp, reqInf, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("Expected no error, but got: %v - alerts: %+v", err,
resp.Alerts)
- }
- if reqInf.StatusCode != http.StatusNotModified {
- t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode)
- }
-}
-
-func CreateTestUsers(t *testing.T) {
- for _, user := range testData.Users {
- resp, _, err := TOSession.CreateUser(user,
client.RequestOptions{})
- if err != nil {
- t.Errorf("could not create user: %v - alerts: %+v",
err, resp.Alerts)
- }
- }
-}
-
-func OpsUpdateAdminTest(t *testing.T) {
- toReqTimeout := time.Second *
time.Duration(Config.Default.Session.TimeoutInSecs)
- opsTOClient, _, err := client.LoginWithAgent(TOSession.URL, "opsuser",
"pa$$word", true, "to-api-v3-client-tests/opsuser", true, toReqTimeout)
- if err != nil {
- t.Fatalf("failed to get log in with opsuser: %v", err.Error())
- }
-
- opts := client.NewRequestOptions()
- opts.QueryParameters.Set("username", "admin")
- resp, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Errorf("cannot get users filtered by username 'admin': %v -
alerts: %+v", err, resp.Alerts)
- }
- if len(resp.Response) != 1 {
- t.Fatalf("Expected exactly one user to exist with username
'admin', found: %d", len(resp.Response))
- }
- user := resp.Response[0]
- if user.ID == nil {
- t.Fatal("Traffic Ops returned a representation for the 'admin'
user with null or undefined ID")
- }
-
- fullName := "oops"
- email := "[email protected]"
- user.FullName = &fullName
- user.Email = &email
-
- _, _, err = opsTOClient.UpdateUser(*user.ID, user,
client.RequestOptions{})
- if err == nil {
- t.Error("ops user incorrectly updated an admin")
- }
-}
-
-func SortTestUsers(t *testing.T) {
- resp, _, err := TOSession.GetUsers(client.RequestOptions{})
- if err != nil {
- t.Fatalf("Expected no error, but got: %v - alerts: %+v", err,
resp.Alerts)
- }
- sortedList := make([]string, 0, len(resp.Response))
- for _, user := range resp.Response {
- sortedList = append(sortedList, user.Username)
- }
-
- if !sort.StringsAreSorted(sortedList) {
- t.Errorf("list is not sorted by their names: %v", sortedList)
- }
-}
-
-func UserRegistrationTest(t *testing.T) {
- ForceDeleteTestUsers(t)
- var emails []string
- opts := client.NewRequestOptions()
- for _, user := range testData.Users {
- if user.Tenant == nil || user.Email == nil {
- t.Error("Found User in the testing data with null or
undefined Tenant and/or Email address")
- continue
- }
- opts.QueryParameters.Set("name", *user.Tenant)
- resp, _, err := TOSession.GetTenants(opts)
- if err != nil {
- t.Fatalf("could not get Tenants filtered by name '%s':
%v - alerts: %+v", *user.Tenant, err, resp.Alerts)
- }
- if len(resp.Response) != 1 {
- t.Fatalf("Expected exactly one Tenant to exist with the
name '%s', found: %d", *user.Tenant, len(resp.Response))
- }
- tenant := resp.Response[0]
-
- regResp, _, err := TOSession.RegisterNewUser(uint(tenant.ID),
user.Role, rfc.EmailAddress{Address: mail.Address{Address: *user.Email}},
client.RequestOptions{})
- if err != nil {
- t.Fatalf("could not register user: %v - alerts: %+v",
err, regResp.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); 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 := client.LoginWithAgent(TOSession.URL, "opsuser",
"pa$$word", true, "to-api-v3-client-tests/opsuser", true, toReqTimeout)
- if err != nil {
- t.Fatalf("failed to get log in with opsuser: %v", err.Error())
- }
-
- opts := client.NewRequestOptions()
- opts.QueryParameters.Set("username", "opsuser")
- resp, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("cannot get users filtered by username 'opsuser': %v -
alerts: %+v", err, resp.Alerts)
- }
- if len(resp.Response) < 1 {
- t.Fatalf("no users returned when requesting user 'opsuser'")
- }
- user := resp.Response[0]
-
- if user.ID == nil {
- t.Fatalf("user 'opsuser' has a null or missing ID - cannot
proceed")
- }
-
- user.FullName = util.StrPtr("Oops-man")
- user.Email = util.StrPtr("[email protected]")
-
- updateResp, _, err := opsTOClient.UpdateUser(*user.ID, user,
client.RequestOptions{})
- if err != nil {
- t.Fatalf("cannot update user: %v - alerts: %+v", err,
updateResp.Alerts)
- }
-
- // Make sure it got updated
- opts.QueryParameters.Del("username")
- opts.QueryParameters.Set("id", strconv.Itoa(*user.ID))
- resp2, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("cannot get users filtered by ID %d: %v - alerts:
%+v", *user.ID, err, resp2.Alerts)
- }
- if len(resp2.Response) < 1 {
- t.Fatalf("no results returned when requesting user #%d",
*user.ID)
- }
- updatedUser := resp2.Response[0]
-
- if updatedUser.FullName == nil {
- t.Errorf("user was not correctly updated, FullName is null or
missing")
- } else if *updatedUser.FullName != "Oops-man" {
- t.Errorf("results do not match actual: '%s', expected:
'Oops-man'\n", *updatedUser.FullName)
- }
-
- if updatedUser.Email == nil {
- t.Errorf("user was not correctly updated, Email is null or
missing")
- } else if *updatedUser.Email != "[email protected]" {
- t.Errorf("results do not match actual: '%s', expected:
'[email protected]'\n", *updatedUser.Email)
- }
-
- // Same thing using /user/current
- user.FullName = util.StrPtr("ops-man")
- user.Email = util.StrPtr("[email protected]")
- updateResp, _, err = opsTOClient.UpdateCurrentUser(user,
client.RequestOptions{})
- if err != nil {
- t.Fatalf("error updating current user: %v - alerts: %+v", err,
updateResp.Alerts)
- }
-
- // Make sure it got updated
- resp2, _, err = TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("error getting user #%d: %v - alerts: %+v", *user.ID,
err, resp2.Alerts)
- }
-
- if len(resp2.Response) < 1 {
- t.Fatalf("no user returned when requesting user #%d", *user.ID)
- }
-
- if resp2.Response[0].FullName == nil {
- t.Errorf("FullName missing or null after update")
- } else if *resp2.Response[0].FullName != "ops-man" {
- t.Errorf("Expected FullName to be 'ops-man', but it was '%s'",
*resp2.Response[0].FullName)
- }
-
- if resp2.Response[0].Email == nil {
- t.Errorf("Email missing or null after update")
- } else if *resp2.Response[0].Email != "[email protected]" {
- t.Errorf("Expected Email to be restored to
'[email protected]', but it was '%s'", *resp2.Response[0].Email)
- }
-
- // now test using an invalid email address
- currentEmail := *user.Email
- user.Email = new(string)
- updateResp, _, err = TOSession.UpdateCurrentUser(user,
client.RequestOptions{})
- if err == nil {
- t.Fatal("error was expected updating user with email: '' - got
none")
- }
-
- // Ensure it wasn't actually updated
- resp2, _, err = TOSession.GetUsers(opts)
- if err != nil {
- t.Fatalf("error getting user #%d: %v - alerts: %+v", *user.ID,
err, resp2.Alerts)
- }
-
- if len(resp2.Response) < 1 {
- t.Fatalf("no user returned when requesting user #%d", *user.ID)
- }
-
- if resp2.Response[0].Email == nil {
- t.Errorf("Email missing or null after update")
- } else if *resp2.Response[0].Email != currentEmail {
- t.Errorf("Expected Email to still be '%s', but it was '%s'",
currentEmail, *resp2.Response[0].Email)
- }
-}
-
-func UserUpdateOwnRoleTest(t *testing.T) {
- opts := client.NewRequestOptions()
- opts.QueryParameters.Set("username", SessionUserName)
- resp, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Errorf("cannot get users filtered by username '%s': %v -
alerts: %+v", SessionUserName, err, resp.Alerts)
- }
- user := resp.Response[0]
- if user.ID == nil {
- t.Fatalf("Traffic Ops returned a representation for user '%s'
with null or undefined ID", SessionUserName)
- }
-
- user.Role = user.Role + "_updated"
- _, _, err = TOSession.UpdateUser(*user.ID, user,
client.RequestOptions{})
- if err == nil {
- t.Error("user incorrectly updated their role")
- }
-}
-
-func UpdateTestUsers(t *testing.T) {
- if len(testData.Users) < 1 {
- t.Fatal("Need at least one User to test updating users")
- }
- firstUsername := testData.Users[0].Username
-
- opts := client.NewRequestOptions()
- opts.QueryParameters.Set("username", firstUsername)
- resp, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Errorf("cannot get users filtered by username '%s': %v -
alerts: %+v", firstUsername, err, resp.Alerts)
- }
- if len(resp.Response) != 1 {
- t.Fatalf("Expected exactly one user to exist with username
'%s', found: %d", firstUsername, len(resp.Response))
- }
- user := resp.Response[0]
- if user.City == nil || user.ID == nil {
- t.Fatal("Traffic Ops returned a representation for a user with
null or undefined ID and/or City")
- }
- newCity := "kidz kable kown"
- *user.City = newCity
-
- var updateResp tc.UpdateUserResponseV4
- updateResp, _, err = TOSession.UpdateUser(*user.ID, user,
client.RequestOptions{})
- if err != nil {
- t.Errorf("cannot update user: %v - alerts: %+v", err,
updateResp.Alerts)
- }
-
- // Make sure it got updated
- opts.QueryParameters.Del("username")
- opts.QueryParameters.Set("id", strconv.Itoa(*user.ID))
- resp2, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Errorf("cannot get users filtered by id %d: %v - alerts:
%+v", *user.ID, err, resp2.Alerts)
- }
- if len(resp2.Response) != 1 {
- t.Fatalf("Expected exactly one user to exist with ID %d, found:
%d", *user.ID, len(resp2.Response))
- }
- updatedUser := resp2.Response[0]
- if updatedUser.City == nil {
- t.Error("Traffic Ops returned a representation of a user with
null or undefined City")
- } else if *updatedUser.City != newCity {
- t.Errorf("results do not match actual: %s, expected: %s",
*updatedUser.City, newCity)
- }
-
- if user.RegistrationSent == nil {
- if updatedUser.RegistrationSent != nil {
- t.Errorf("Updated user has registration sent time when
original did not (and no registration was sent): %s",
*updatedUser.RegistrationSent)
- }
- } else if updatedUser.RegistrationSent == nil {
- t.Errorf("Updated user was supposed to have registration sent
time '%s', but it had null or undefined", *user.RegistrationSent)
- } else if *resp.Response[0].RegistrationSent !=
*resp2.Response[0].RegistrationSent {
- t.Errorf("registration_sent value shouldn't have been updated,
expectd: %s, got: %s", *resp.Response[0].RegistrationSent,
*resp2.Response[0].RegistrationSent)
- }
-
-}
-
-func GetTestUsers(t *testing.T) {
- resp, _, err := TOSession.GetUsers(client.RequestOptions{})
- if err != nil {
- t.Errorf("cannot get users: %v - alerts: %+v", err, resp.Alerts)
- }
- if len(resp.Response) < 1 {
- t.Fatalf("expected a users list, got nothing")
- }
-}
-
-func GetTestUserCurrent(t *testing.T) {
- user, _, err := TOSession.GetUserCurrent(client.RequestOptions{})
- if err != nil {
- t.Errorf("cannot get current user: %v - alerts: %+v", err,
user.Alerts)
- }
- if user.Response.Username != SessionUserName {
- t.Errorf("current user expected: '%s' actual: '%s'",
SessionUserName, user.Response.Username)
- }
-}
-
-func UserTenancyTest(t *testing.T) {
- users, _, err := TOSession.GetUsers(client.RequestOptions{})
- if err != nil {
- t.Errorf("cannot get users: %v - alerts: %+v", err,
users.Alerts)
- }
- tenant3Found := false
- tenant4Found := false
- tenant3Username := "tenant3user"
- tenant4Username := "tenant4user"
- tenant3User := tc.UserV4{}
-
- // assert admin user can view tenant3user and tenant4user
- for _, user := range users.Response {
- if user.ID == nil {
- t.Error("Traffic Ops returned a representation for a
user with null or undefined ID")
- continue
- }
- if user.Username == tenant3Username {
- tenant3Found = true
- tenant3User = user
- } else if user.Username == tenant4Username {
- tenant4Found = true
- }
- if tenant3Found && tenant4Found {
- break
- }
- }
- if !tenant3Found || !tenant4Found {
- t.Error("expected admin to be able to view tenants: tenant3 and
tenant4")
- }
-
- toReqTimeout := time.Second *
time.Duration(Config.Default.Session.TimeoutInSecs)
- tenant4TOClient, _, err := client.LoginWithAgent(TOSession.URL,
"tenant4user", "pa$$word", true, "to-api-v3-client-tests/tenant4user", true,
toReqTimeout)
- if err != nil {
- t.Fatalf("failed to log in with tenant4user: %v", err.Error())
- }
-
- usersReadableByTenant4, _, err :=
tenant4TOClient.GetUsers(client.RequestOptions{})
- if err != nil {
- t.Errorf("tenant4user cannot get users: %v - alerts: %+v", err,
usersReadableByTenant4.Alerts)
- }
-
- tenant4canReadItself := false
- for _, user := range usersReadableByTenant4.Response {
- // assert that tenant4user cannot read tenant3user
- if user.Username == tenant3Username {
- t.Error("expected tenant4user to be unable to read
tenant3user")
- }
- // assert that tenant4user can read itself
- if user.Username == tenant4Username {
- tenant4canReadItself = true
- }
- }
- if !tenant4canReadItself {
- t.Error("expected tenant4user to be able to read itself")
- }
-
- // assert that tenant4user cannot update tenant3user
- if _, _, err = tenant4TOClient.UpdateUser(*tenant3User.ID, tenant3User,
client.RequestOptions{}); err == nil {
- t.Error("expected tenant4user to be unable to update
tenant4user")
- }
-
- // assert that tenant4user cannot create a user outside of its tenant
- opts := client.NewRequestOptions()
- opts.QueryParameters.Set("name", "root")
- resp, _, err := TOSession.GetTenants(opts)
- if err != nil {
- t.Errorf("Unexpected error getting the root Tenant: %v -
alerts: %+v", err, resp.Alerts)
- }
- if len(resp.Response) != 1 {
- t.Fatalf("Expected exactly one Tenant to exist with the name
'root', found: %d", len(resp.Response))
- }
- rootTenant := resp.Response[0]
-
- if len(testData.Users) < 1 {
- t.Fatal("Need at least one User to continue testing User
Tenancy")
- }
- newUser := testData.Users[0]
- newUser.Email = util.StrPtr("[email protected]")
- newUser.Username = "testusertenancy"
- newUser.TenantID = rootTenant.ID
- if _, _, err = tenant4TOClient.CreateUser(newUser,
client.RequestOptions{}); err == nil {
- t.Error("expected tenant4user to be unable to create a new user
in the root tenant")
- }
-}
-
-// ForceDeleteTestUsers forcibly deletes the users from the db.
-func ForceDeleteTestUsers(t *testing.T) {
-
- // NOTE: Special circumstances! This should *NOT* be done without a
really good reason!
- // Connects directly to the DB to remove users rather than going thru
the client.
- // This is required here because the DeleteUser action does not really
delete users, but disables them.
- db, err := OpenConnection()
- if err != nil {
- t.Error("cannot open db")
- }
- defer db.Close()
-
- var usernames []string
- for _, user := range testData.Users {
- usernames = append(usernames, `'`+user.Username+`'`)
- }
-
- // there is a constraint that prevents users from being deleted when
they have a log
- q := `DELETE FROM log WHERE NOT tm_user = (SELECT id FROM tm_user WHERE
username = 'admin')`
- err = execSQL(db, q)
- if err != nil {
- t.Errorf("cannot execute SQL: %s; SQL is %s", err.Error(), q)
- }
-
- q = `DELETE FROM tm_user WHERE username IN (` + strings.Join(usernames,
",") + `)`
- err = execSQL(db, q)
- if err != nil {
- t.Errorf("cannot execute SQL: %s; SQL is %s", err.Error(), q)
- }
-}
-
-func ForceDeleteTestUsersByUsernames(t *testing.T, usernames []string) {
-
- // NOTE: Special circumstances! This should *NOT* be done without a
really good reason!
- // Connects directly to the DB to remove users rather than going thru
the client.
- // This is required here because the DeleteUser action does not really
delete users, but disables them.
- db, err := OpenConnection()
- if err != nil {
- t.Error("cannot open db")
- }
- defer db.Close()
-
- for i, u := range usernames {
- usernames[i] = `'` + u + `'`
- }
- // there is a constraint that prevents users from being deleted when
they have a log
- q := `DELETE FROM log WHERE NOT tm_user = (SELECT id FROM tm_user WHERE
username = 'admin')`
- err = execSQL(db, q)
- if err != nil {
- t.Errorf("cannot execute SQL: %s; SQL is %s", err.Error(), q)
- }
-
- q = `DELETE FROM tm_user WHERE username IN (` + strings.Join(usernames,
",") + `)`
- err = execSQL(db, q)
- if err != nil {
- t.Errorf("cannot execute SQL: %s; SQL is %s", err.Error(), q)
- }
-}
-
-func DeleteTestUsers(t *testing.T) {
- opts := client.NewRequestOptions()
- for _, user := range testData.Users {
- opts.QueryParameters.Set("username", user.Username)
- resp, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Errorf("cannot get users filtered by username '%s':
%v - alerts: %+v", user.Username, err, resp.Alerts)
- }
- if len(resp.Response) > 0 {
- respUser := resp.Response[0]
- if respUser.ID == nil {
- t.Error("Traffic Ops returned a representation
for a user with null or undefined ID")
- continue
- }
-
- delResp, _, err := TOSession.DeleteUser(*respUser.ID,
client.RequestOptions{})
- if err != nil {
- t.Errorf("cannot delete user '%s': %v - alerts:
%+v", user.Username, err, delResp.Alerts)
- }
-
- // Make sure it got deleted
- resp, _, err := TOSession.GetUsers(opts)
- if err != nil {
- t.Errorf("error getting users filtered by
username after supposed deletion: %v - alerts: %+v", err, resp.Alerts)
- }
- if len(resp.Response) > 0 {
- t.Errorf("expected user: %s to be deleted",
user.Username)
- }
- }
- }
-}
diff --git a/traffic_ops/testing/api/v4/users_register_test.go
b/traffic_ops/testing/api/v4/users_register_test.go
new file mode 100644
index 0000000000..023be22ada
--- /dev/null
+++ b/traffic_ops/testing/api/v4/users_register_test.go
@@ -0,0 +1,93 @@
+package v4
+
+/*
+ Licensed 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.
+*/
+
+import (
+ "encoding/json"
+ "net/http"
+ "testing"
+
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
+)
+
+func TestUsersRegister(t *testing.T) {
+ if includeSystemTests {
+ WithObjs(t, []TCObj{Tenants, Parameters}, func() {
+
+ methodTests := utils.V4TestCase{
+ "POST": {
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ RequestBody:
map[string]interface{}{
+ "addressLine1":
"address of ops",
+ "addressLine2":
"place",
+ "city":
"somewhere",
+ "company":
"else",
+ "country":
"UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role":
"operations",
+ "tenant":
"root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username":
"opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
validateDeletion("[email protected]")),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ userRegistration :=
tc.UserRegistrationRequestV4{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err,
"Error occurred when marshalling request body: %v", err)
+ err =
json.Unmarshal(dat, &userRegistration)
+ assert.NoError(t, err,
"Error occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
+ case "POST":
+ t.Run(name, func(t
*testing.T) {
+ alerts, reqInf,
err := testCase.ClientSession.RegisterNewUser(userRegistration.TenantID,
userRegistration.Role, userRegistration.Email, testCase.RequestOpts)
+ for _, check :=
range testCase.Expectations {
+
check(t, reqInf, nil, alerts, err)
+ }
+ })
+ }
+ }
+ })
+ }
+ })
+ }
+}
+
+func validateDeletion(email string) utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ db, err := OpenConnection()
+ assert.RequireNoError(t, err, "Cannot open db")
+ defer db.Close()
+ q := `DELETE FROM tm_user WHERE email = '` + email + `'`
+ err = execSQL(db, q)
+ assert.NoError(t, err, "Cannot execute SQL to delete registered
users: %s; SQL is %s", err, q)
+ }
+}
diff --git a/traffic_ops/testing/api/v4/users_test.go
b/traffic_ops/testing/api/v4/users_test.go
new file mode 100644
index 0000000000..f7023c7163
--- /dev/null
+++ b/traffic_ops/testing/api/v4/users_test.go
@@ -0,0 +1,375 @@
+package v4
+
+/*
+ Licensed 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.
+*/
+
+import (
+ "encoding/json"
+ "net/http"
+ "net/url"
+ "sort"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/apache/trafficcontrol/lib/go-rfc"
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/assert"
+ "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
+ "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
+ client "github.com/apache/trafficcontrol/traffic_ops/v4-client"
+)
+
+func TestUsers(t *testing.T) {
+ WithObjs(t, []TCObj{Tenants, Parameters, Users}, func() {
+
+ opsUserSession := utils.CreateV4Session(t,
Config.TrafficOps.URL, "opsuser", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+ tenant4UserSession := utils.CreateV4Session(t,
Config.TrafficOps.URL, "tenant4user", "pa$$word",
Config.Default.Session.TimeoutInSecs)
+
+ currentTime := time.Now().UTC().Add(-15 * time.Second)
+ currentTimeRFC := currentTime.Format(time.RFC1123)
+ tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)
+
+ methodTests := utils.V4TestCase{
+ "GET": {
+ "NOT MODIFIED when NO CHANGES made": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{Header: http.Header{rfc.IfModifiedSince: {tomorrow}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusNotModified)),
+ },
+ "OK when CHANGES made": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{Header: http.Header{rfc.IfModifiedSince:
{currentTimeRFC}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
+ },
+ "OK when VALID request": {
+ ClientSession: TOSession,
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1),
+ validateUsersSort()),
+ },
+ "ADMIN can view CHILD TENANT": {
+ ClientSession: TOSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"tenant": {"tenant4"}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseLengthGreaterOrEqual(1),
+
validateUsersFields(map[string]interface{}{"Tenant": "tenant4"})),
+ },
+ "EMPTY RESPONSE when CHILD TENANT reads PARENT
TENANT": {
+ ClientSession: tenant4UserSession,
+ RequestOpts:
client.RequestOptions{QueryParameters: url.Values{"tenant": {"tenant3"}}},
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
utils.ResponseHasLength(0)),
+ },
+ },
+ "POST": {
+ "FORBIDDEN when CHILD TENANT creates USER with
PARENT TENANCY": {
+ ClientSession: tenant4UserSession,
+ RequestBody: map[string]interface{}{
+ "email":
"[email protected]",
+ "fullName": "Outside
Tenancy",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role":
"operations",
+ "tenantId":
GetTenantID(t, "tenant3")(),
+ "username":
"outsideTenantUser",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ "PUT": {
+ "OK when VALID request": {
+ EndpointId: GetUserID(t, "steering"),
+ ClientSession: TOSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "updated
line 1",
+ "addressLine2": "updated
line 2",
+ "city": "updated
city name",
+ "company": "new
company",
+ "country": "US",
+ "email":
"[email protected]",
+ "fullName": "Steering
User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "newUser": false,
+ "role":
"steering",
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username":
"steering",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"AddressLine1": "updated
line 1",
+ "AddressLine2":
"updated line 2", "City": "updated city name", "Company": "new company",
+ "Country": "US",
"Email": "[email protected]", "FullName": "Steering User Updated"})),
+ },
+ "OK when UPDATING SELF": {
+ EndpointId: GetUserID(t, "opsuser"),
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role":
"operations",
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+
validateUsersUpdateCreateFields(map[string]interface{}{"Email":
"[email protected]", "FullName": "Operations User Updated"})),
+ },
+ "NOT FOUND when UPDATING SELF with ROLE that
DOESNT EXIST": {
+ EndpointId: GetUserID(t, "opsuser"),
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "addressLine1": "address
of ops",
+ "addressLine2": "place",
+ "city":
"somewhere",
+ "company": "else",
+ "country": "UK",
+ "email":
"[email protected]",
+ "fullName":
"Operations User Updated",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role":
"operations_updated",
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "opsuser",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusNotFound)),
+ },
+ "FORBIDDEN when OPERATIONS USER updates ADMIN
USER": {
+ EndpointId: GetUserID(t, "admin"),
+ ClientSession: opsUserSession,
+ RequestBody: map[string]interface{}{
+ "email":
"[email protected]",
+ "fullName": "oops",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": "admin",
+ "tenant": "root",
+ "tenantId":
GetTenantID(t, "root")(),
+ "username": "admin",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ "FORBIDDEN when CHILD TENANT USER updates
PARENT TENANT USER": {
+ EndpointId: GetUserID(t,
"tenant3user"),
+ ClientSession: tenant4UserSession,
+ RequestBody: map[string]interface{}{
+ "email":
"[email protected]",
+ "fullName": "Parent
tenant test",
+ "localPasswd":
"pa$$word",
+ "confirmLocalPasswd":
"pa$$word",
+ "role": "admin",
+ "tenant": "tenant2",
+ "tenantId":
GetTenantID(t, "tenant2")(),
+ "username":
"tenant3user",
+ },
+ Expectations:
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
+ },
+ },
+ }
+
+ for method, testCases := range methodTests {
+ t.Run(method, func(t *testing.T) {
+ for name, testCase := range testCases {
+ user := tc.UserV4{}
+
+ if testCase.RequestBody != nil {
+ dat, err :=
json.Marshal(testCase.RequestBody)
+ assert.NoError(t, err, "Error
occurred when marshalling request body: %v", err)
+ err = json.Unmarshal(dat, &user)
+ assert.NoError(t, err, "Error
occurred when unmarshalling request body: %v", err)
+ }
+
+ switch method {
+ case "GET":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.GetUsers(testCase.RequestOpts)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ case "POST":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.CreateUser(user, testCase.RequestOpts)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ case "PUT":
+ t.Run(name, func(t *testing.T) {
+ resp, reqInf, err :=
testCase.ClientSession.UpdateUser(testCase.EndpointId(), user,
testCase.RequestOpts)
+ for _, check := range
testCase.Expectations {
+ check(t,
reqInf, resp.Response, resp.Alerts, err)
+ }
+ })
+ }
+ }
+ })
+ }
+ })
+}
+
+func validateUsersFields(expectedResp map[string]interface{}) utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ userResp := resp.([]tc.UserV4)
+ for field, expected := range expectedResp {
+ for _, user := range userResp {
+ switch field {
+ case "AddressLine1":
+ assert.RequireNotNil(t,
user.AddressLine1, "Expected AddressLine1 to not be nil.")
+ assert.Equal(t, expected,
*user.AddressLine1, "Expected AddressLine1 to be %v, but got %s", expected,
*user.AddressLine1)
+ case "AddressLine2":
+ assert.RequireNotNil(t,
user.AddressLine2, "Expected AddressLine2 to not be nil.")
+ assert.Equal(t, expected,
*user.AddressLine2, "Expected AddressLine2 to be %v, but got %s", expected,
*user.AddressLine2)
+ case "City":
+ assert.RequireNotNil(t, user.City,
"Expected City to not be nil.")
+ assert.Equal(t, expected, *user.City,
"Expected City to be %v, but got %s", expected, *user.City)
+ case "Company":
+ assert.RequireNotNil(t, user.Company,
"Expected Company to not be nil.")
+ assert.Equal(t, expected,
*user.Company, "Expected Company to be %v, but got %s", expected, *user.Company)
+ case "Country":
+ assert.RequireNotNil(t, user.Country,
"Expected Country to not be nil.")
+ assert.Equal(t, expected,
*user.Country, "Expected Country to be %v, but got %s", expected, *user.Country)
+ case "Email":
+ assert.RequireNotNil(t, user.Email,
"Expected Email to not be nil.")
+ assert.Equal(t, expected, *user.Email,
"Expected Email to be %v, but got %s", expected, *user.Email)
+ case "FullName":
+ assert.RequireNotNil(t, user.FullName,
"Expected FullName to not be nil.")
+ assert.Equal(t, expected,
*user.FullName, "Expected FullName to be %v, but got %s", expected,
*user.FullName)
+ case "ID":
+ assert.RequireNotNil(t, user.ID,
"Expected ID to not be nil.")
+ assert.Equal(t, expected, *user.ID,
"Expected ID to be %v, but got %d", expected, user.ID)
+ case "PhoneNumber":
+ assert.RequireNotNil(t,
user.PhoneNumber, "Expected PhoneNumber to not be nil.")
+ assert.Equal(t, expected,
*user.PhoneNumber, "Expected PhoneNumber to be %v, but got %s", expected,
*user.PhoneNumber)
+ case "PostalCode":
+ assert.RequireNotNil(t,
user.PostalCode, "Expected PostalCode to not be nil.")
+ assert.Equal(t, expected,
*user.PostalCode, "Expected PostalCode to be %v, but got %s", expected,
*user.PostalCode)
+ case "RegistrationSent":
+ assert.RequireNotNil(t,
user.RegistrationSent, "Expected RegistrationSent to not be nil.")
+ assert.Equal(t, expected,
*user.RegistrationSent, "Expected RegistrationSent to be %v, but got %v",
expected, *user.RegistrationSent)
+ case "Role":
+ assert.Equal(t, expected, user.Role,
"Expected Role to be %v, but got %s", expected, user.Role)
+ case "StateOrProvince":
+ assert.RequireNotNil(t,
user.StateOrProvince, "Expected StateOrProvince to not be nil.")
+ assert.Equal(t, expected,
*user.StateOrProvince, "Expected StateOrProvince to be %v, but got %s",
expected, *user.StateOrProvince)
+ case "Tenant":
+ assert.RequireNotNil(t, user.Tenant,
"Expected Tenant to not be nil.")
+ assert.Equal(t, expected, *user.Tenant,
"Expected Tenant to be %v, but got %s", expected, *user.Tenant)
+ case "TenantID":
+ assert.Equal(t, expected,
user.TenantID, "Expected TenantID to be %v, but got %d", expected,
user.TenantID)
+ case "Username":
+ assert.Equal(t, expected,
user.Username, "Expected Username to be %v, but got %s", expected,
user.Username)
+ default:
+ t.Errorf("Expected field: %v, does not
exist in response", field)
+ }
+ }
+ }
+ }
+}
+
+func validateUsersUpdateCreateFields(expectedResp map[string]interface{})
utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ assert.RequireNotEqual(t, resp.(tc.UserV4), tc.UserV4{},
"Expected a non empty response.")
+ userResp := resp.(tc.UserV4)
+ users := []tc.UserV4{userResp}
+ validateUsersFields(expectedResp)(t, toclientlib.ReqInf{},
users, tc.Alerts{}, nil)
+ }
+}
+
+func validateUsersSort() utils.CkReqFunc {
+ return func(t *testing.T, _ toclientlib.ReqInf, resp interface{},
alerts tc.Alerts, _ error) {
+ assert.RequireNotNil(t, resp, "Expected Users response to not
be nil.")
+ var usernames []string
+ usersResp := resp.([]tc.UserV4)
+ for _, user := range usersResp {
+ usernames = append(usernames, user.Username)
+ }
+ assert.Equal(t, true, sort.StringsAreSorted(usernames), "List
is not sorted by their usernames: %v", usernames)
+ }
+}
+
+func GetUserID(t *testing.T, username string) func() int {
+ return func() int {
+ opts := client.NewRequestOptions()
+ opts.QueryParameters.Set("username", username)
+ users, _, err := TOSession.GetUsers(opts)
+ assert.RequireNoError(t, err, "Get Users Request failed with
error:", err)
+ assert.RequireEqual(t, 1, len(users.Response), "Expected
response object length 1, but got %d", len(users.Response))
+ assert.RequireNotNil(t, users.Response[0].ID, "Expected ID to
not be nil.")
+ return *users.Response[0].ID
+ }
+}
+
+func CreateTestUsers(t *testing.T) {
+ for _, user := range testData.Users {
+ resp, _, err := TOSession.CreateUser(user,
client.RequestOptions{})
+ assert.RequireNoError(t, err, "Could not create user: %v -
alerts: %+v", err, resp.Alerts)
+ }
+}
+
+// ForceDeleteTestUsers forcibly deletes the users from the db.
+// NOTE: Special circumstances! This should *NOT* be done without a really
good reason!
+// Connects directly to the DB to remove users rather than going through the
client.
+// This is required here because the DeleteUser action does not really delete
users, but disables them.
+func ForceDeleteTestUsers(t *testing.T) {
+
+ db, err := OpenConnection()
+ assert.RequireNoError(t, err, "Cannot open db")
+ defer db.Close()
+
+ var usernames []string
+ for _, user := range testData.Users {
+ usernames = append(usernames, `'`+user.Username+`'`)
+ }
+
+ // there is a constraint that prevents users from being deleted when
they have a log
+ q := `DELETE FROM log WHERE NOT tm_user = (SELECT id FROM tm_user WHERE
username = 'admin')`
+ err = execSQL(db, q)
+ assert.RequireNoError(t, err, "Cannot execute SQL: %v; SQL is %s", err,
q)
+
+ q = `DELETE FROM tm_user WHERE username IN (` + strings.Join(usernames,
",") + `)`
+ err = execSQL(db, q)
+ assert.NoError(t, err, "Cannot execute SQL: %v; SQL is %s", err, q)
+}
+
+// ForceDeleteTestUsersByUsernames forcibly deletes the users passed in from a
slice of usernames from the db.
+// NOTE: Special circumstances! This should *NOT* be done without a really
good reason!
+// Connects directly to the DB to remove users rather than going through the
client.
+// This is required here because the DeleteUser action does not really delete
users, but disables them.
+func ForceDeleteTestUsersByUsernames(t *testing.T, usernames []string) {
+
+ db, err := OpenConnection()
+ assert.RequireNoError(t, err, "Cannot open db")
+ defer db.Close()
+
+ for i, u := range usernames {
+ usernames[i] = `'` + u + `'`
+ }
+ // there is a constraint that prevents users from being deleted when
they have a log
+ q := `DELETE FROM log WHERE NOT tm_user = (SELECT id FROM tm_user WHERE
username = 'admin')`
+ err = execSQL(db, q)
+ assert.RequireNoError(t, err, "Cannot execute SQL: %s; SQL is %s", err,
q)
+
+ q = `DELETE FROM tm_user WHERE username IN (` + strings.Join(usernames,
",") + `)`
+ err = execSQL(db, q)
+ assert.NoError(t, err, "Cannot execute SQL: %s; SQL is %s", err, q)
+}