2017-03-10 19:24:48 +00:00
package server
import (
2017-10-26 23:02:57 +00:00
"bytes"
2017-03-10 19:24:48 +00:00
"context"
2017-10-26 23:02:57 +00:00
"encoding/json"
2017-03-10 19:24:48 +00:00
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/log"
"github.com/influxdata/chronograf/mocks"
"github.com/influxdata/chronograf/oauth2"
)
type MockUsers struct { }
func TestService_Me ( t * testing . T ) {
type fields struct {
2017-11-02 15:59:53 +00:00
UsersStore chronograf . UsersStore
OrganizationsStore chronograf . OrganizationsStore
Logger chronograf . Logger
UseAuth bool
2017-03-10 19:24:48 +00:00
}
type args struct {
w * httptest . ResponseRecorder
r * http . Request
}
tests := [ ] struct {
name string
fields fields
args args
principal oauth2 . Principal
wantStatus int
wantContentType string
wantBody string
} {
{
name : "Existing user" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
} ,
fields : fields {
UseAuth : true ,
2017-10-18 18:45:33 +00:00
Logger : log . New ( log . DebugLevel ) ,
2017-11-02 15:59:53 +00:00
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-11-02 15:59:53 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
ID : 0 ,
Name : "The Bad Place" ,
} , nil
} ,
} ,
2017-03-10 19:24:48 +00:00
UsersStore : & mocks . UsersStore {
2017-11-01 13:12:19 +00:00
AllF : func ( ctx context . Context ) ( [ ] chronograf . User , error ) {
// This function gets to verify that there is at least one first user
return [ ] chronograf . User { { } } , nil
} ,
2017-10-18 18:17:42 +00:00
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
2017-10-19 18:17:40 +00:00
if q . Name == nil || q . Provider == nil || q . Scheme == nil {
return nil , fmt . Errorf ( "Invalid user query: missing Name, Provider, and/or Scheme" )
}
2017-03-10 19:24:48 +00:00
return & chronograf . User {
2017-10-17 00:30:23 +00:00
Name : "me" ,
2017-10-24 23:17:59 +00:00
Provider : "github" ,
Scheme : "oauth2" ,
2017-10-17 00:30:23 +00:00
} , nil
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-03-10 19:24:48 +00:00
} ,
} ,
principal : oauth2 . Principal {
Subject : "me" ,
2017-10-24 23:17:59 +00:00
Issuer : "github" ,
2017-03-10 19:24:48 +00:00
} ,
wantStatus : http . StatusOK ,
wantContentType : "application/json" ,
2017-11-02 23:13:51 +00:00
wantBody : ` { "name" : "me" , "provider" : "github" , "scheme" : "oauth2" , "links" : { "self" : "/chronograf/v1/users/0" } , "currentOrganization" : { "id" : "0" , "name" : "The Bad Place" } , "roles" : [ { "name" : "member" , "organization" : "0" } ] }
2017-03-10 19:24:48 +00:00
` ,
} ,
{
name : "New user" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
} ,
fields : fields {
UseAuth : true ,
2017-10-18 18:45:33 +00:00
Logger : log . New ( log . DebugLevel ) ,
2017-11-02 15:59:53 +00:00
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-11-02 15:59:53 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
ID : 0 ,
Name : "The Bad Place" ,
} , nil
} ,
} ,
2017-03-10 19:24:48 +00:00
UsersStore : & mocks . UsersStore {
2017-11-01 13:12:19 +00:00
AllF : func ( ctx context . Context ) ( [ ] chronograf . User , error ) {
// This function gets to verify that there is at least one first user
return [ ] chronograf . User { { } } , nil
} ,
2017-10-18 18:17:42 +00:00
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
2017-10-19 18:17:40 +00:00
if q . Name == nil || q . Provider == nil || q . Scheme == nil {
return nil , fmt . Errorf ( "Invalid user query: missing Name, Provider, and/or Scheme" )
}
2017-10-18 18:45:33 +00:00
return nil , chronograf . ErrUserNotFound
2017-03-10 19:24:48 +00:00
} ,
AddF : func ( ctx context . Context , u * chronograf . User ) ( * chronograf . User , error ) {
return u , nil
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-03-10 19:24:48 +00:00
} ,
} ,
principal : oauth2 . Principal {
Subject : "secret" ,
2017-10-24 23:17:59 +00:00
Issuer : "auth0" ,
2017-03-10 19:24:48 +00:00
} ,
wantStatus : http . StatusOK ,
wantContentType : "application/json" ,
2017-11-03 13:47:54 +00:00
wantBody : ` { "name" : "secret" , "roles" : [ { "name" : "member" , "organization" : "0" } ] , "provider" : "auth0" , "scheme" : "oauth2" , "links" : { "self" : "/chronograf/v1/users/0" } , "organizations" : [ { "id" : "0" , "name" : "The Bad Place" } ] , "currentOrganization" : { "id" : "0" , "name" : "The Bad Place" } }
2017-03-10 19:24:48 +00:00
` ,
} ,
{
name : "Error adding user" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
} ,
fields : fields {
UseAuth : true ,
2017-11-02 15:59:53 +00:00
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-11-02 15:59:53 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
ID : 0 ,
Name : "The Bad Place" ,
} , nil
} ,
} ,
2017-03-10 19:24:48 +00:00
UsersStore : & mocks . UsersStore {
2017-11-01 13:12:19 +00:00
AllF : func ( ctx context . Context ) ( [ ] chronograf . User , error ) {
// This function gets to verify that there is at least one first user
return [ ] chronograf . User { { } } , nil
} ,
2017-10-18 18:17:42 +00:00
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
2017-10-18 18:45:33 +00:00
return nil , chronograf . ErrUserNotFound
2017-03-10 19:24:48 +00:00
} ,
AddF : func ( ctx context . Context , u * chronograf . User ) ( * chronograf . User , error ) {
return nil , fmt . Errorf ( "Why Heavy?" )
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-03-10 19:24:48 +00:00
} ,
Logger : log . New ( log . DebugLevel ) ,
} ,
principal : oauth2 . Principal {
Subject : "secret" ,
2017-10-24 23:17:59 +00:00
Issuer : "heroku" ,
2017-03-10 19:24:48 +00:00
} ,
wantStatus : http . StatusInternalServerError ,
wantContentType : "application/json" ,
wantBody : ` { "code":500,"message":"Unknown error: error storing user secret: Why Heavy?"} ` ,
} ,
{
name : "No Auth" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
} ,
fields : fields {
UseAuth : false ,
Logger : log . New ( log . DebugLevel ) ,
} ,
wantStatus : http . StatusOK ,
wantContentType : "application/json" ,
wantBody : ` { "links" : { "self" : "/chronograf/v1/users/me" } }
` ,
} ,
{
name : "Empty Principal" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
} ,
fields : fields {
UseAuth : true ,
Logger : log . New ( log . DebugLevel ) ,
} ,
wantStatus : http . StatusUnprocessableEntity ,
principal : oauth2 . Principal {
Subject : "" ,
2017-10-17 00:30:23 +00:00
Issuer : "" ,
2017-03-10 19:24:48 +00:00
} ,
} ,
}
for _ , tt := range tests {
tt . args . r = tt . args . r . WithContext ( context . WithValue ( context . Background ( ) , oauth2 . PrincipalKey , tt . principal ) )
2017-10-26 22:01:20 +00:00
s := & Service {
2017-10-31 20:41:17 +00:00
Store : & mocks . Store {
2017-11-02 15:59:53 +00:00
UsersStore : tt . fields . UsersStore ,
OrganizationsStore : tt . fields . OrganizationsStore ,
2017-10-31 20:41:17 +00:00
} ,
Logger : tt . fields . Logger ,
UseAuth : tt . fields . UseAuth ,
2017-03-10 19:24:48 +00:00
}
2017-10-26 22:01:20 +00:00
s . Me ( tt . args . w , tt . args . r )
2017-03-10 19:24:48 +00:00
resp := tt . args . w . Result ( )
content := resp . Header . Get ( "Content-Type" )
body , _ := ioutil . ReadAll ( resp . Body )
if resp . StatusCode != tt . wantStatus {
t . Errorf ( "%q. Me() = %v, want %v" , tt . name , resp . StatusCode , tt . wantStatus )
}
if tt . wantContentType != "" && content != tt . wantContentType {
t . Errorf ( "%q. Me() = %v, want %v" , tt . name , content , tt . wantContentType )
}
2017-11-02 23:13:51 +00:00
if tt . wantBody == "" {
continue
}
if eq , err := jsonEqual ( tt . wantBody , string ( body ) ) ; err != nil || ! eq {
2017-03-10 19:24:48 +00:00
t . Errorf ( "%q. Me() = \n***%v***\n,\nwant\n***%v***" , tt . name , string ( body ) , tt . wantBody )
}
}
}
2017-10-26 23:02:57 +00:00
func TestService_MeOrganizations ( t * testing . T ) {
type fields struct {
2017-10-31 20:41:17 +00:00
UsersStore chronograf . UsersStore
OrganizationsStore chronograf . OrganizationsStore
Logger chronograf . Logger
UseAuth bool
2017-10-26 23:02:57 +00:00
}
type args struct {
w * httptest . ResponseRecorder
r * http . Request
orgRequest * meOrganizationRequest
auth mocks . Authenticator
}
tests := [ ] struct {
name string
fields fields
args args
principal oauth2 . Principal
wantStatus int
wantContentType string
wantBody string
} {
{
name : "Set the current User's organization" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
orgRequest : & meOrganizationRequest {
2017-11-01 14:37:32 +00:00
Organization : "1337" ,
2017-10-26 23:02:57 +00:00
} ,
auth : mocks . Authenticator { } ,
} ,
fields : fields {
UseAuth : true ,
Logger : log . New ( log . DebugLevel ) ,
UsersStore : & mocks . UsersStore {
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
if q . Name == nil || q . Provider == nil || q . Scheme == nil {
return nil , fmt . Errorf ( "Invalid user query: missing Name, Provider, and/or Scheme" )
}
return & chronograf . User {
Name : "me" ,
Provider : "github" ,
Scheme : "oauth2" ,
2017-10-31 20:41:17 +00:00
Roles : [ ] chronograf . Role {
{
Name : AdminRoleName ,
Organization : "1337" ,
} ,
} ,
2017-10-26 23:02:57 +00:00
} , nil
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-10-26 23:02:57 +00:00
} ,
2017-10-27 17:02:02 +00:00
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-10-27 17:02:02 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
if q . ID == nil {
return nil , fmt . Errorf ( "Invalid organization query: missing ID" )
}
return & chronograf . Organization {
ID : 1337 ,
Name : "The ShillBillThrilliettas" ,
} , nil
} ,
} ,
2017-10-26 23:02:57 +00:00
} ,
principal : oauth2 . Principal {
Subject : "me" ,
Issuer : "github" ,
} ,
wantStatus : http . StatusOK ,
wantContentType : "application/json" ,
2017-11-02 23:13:51 +00:00
wantBody : ` { "name":"me","roles":[ { "name":"admin","organization":"1337"}, { "name":"member","organization":"0"}],"provider":"github","scheme":"oauth2","links": { "self":"/chronograf/v1/users/0"},"organizations":[ { "id":"1337","name":"The ShillBillThrilliettas"}],"currentOrganization": { "id":"1337","name":"The ShillBillThrilliettas"}} ` ,
2017-10-26 23:02:57 +00:00
} ,
{
name : "Change the current User's organization" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
orgRequest : & meOrganizationRequest {
2017-11-01 14:37:32 +00:00
Organization : "1337" ,
2017-10-26 23:02:57 +00:00
} ,
auth : mocks . Authenticator { } ,
} ,
fields : fields {
UseAuth : true ,
Logger : log . New ( log . DebugLevel ) ,
UsersStore : & mocks . UsersStore {
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
if q . Name == nil || q . Provider == nil || q . Scheme == nil {
return nil , fmt . Errorf ( "Invalid user query: missing Name, Provider, and/or Scheme" )
}
return & chronograf . User {
Name : "me" ,
Provider : "github" ,
Scheme : "oauth2" ,
2017-10-31 20:41:17 +00:00
Roles : [ ] chronograf . Role {
{
Name : AdminRoleName ,
Organization : "1337" ,
} ,
} ,
2017-10-26 23:02:57 +00:00
} , nil
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-10-26 23:02:57 +00:00
} ,
2017-10-27 17:02:02 +00:00
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-10-27 17:02:02 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
if q . ID == nil {
return nil , fmt . Errorf ( "Invalid organization query: missing ID" )
}
return & chronograf . Organization {
ID : 1337 ,
Name : "The ThrillShilliettos" ,
} , nil
} ,
} ,
2017-10-26 23:02:57 +00:00
} ,
principal : oauth2 . Principal {
Subject : "me" ,
Issuer : "github" ,
Organization : "1338" ,
} ,
wantStatus : http . StatusOK ,
wantContentType : "application/json" ,
2017-11-02 23:13:51 +00:00
wantBody : ` { "name" : "me" , "roles" : [ { "name" : "admin" , "organization" : "1337" } , { "name" : "member" , "organization" : "0" } ] , "provider" : "github" , "scheme" : "oauth2" , "links" : { "self" : "/chronograf/v1/users/0" } , "organizations" : [ { "id" : "1337" , "name" : "The ThrillShilliettos" } ] , "currentOrganization" : { "id" : "1337" , "name" : "The ThrillShilliettos" } }
2017-11-02 15:59:53 +00:00
` ,
2017-10-26 23:02:57 +00:00
} ,
2017-10-27 17:14:14 +00:00
{
name : "Unable to find requested user in valid organization" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
orgRequest : & meOrganizationRequest {
2017-11-01 14:37:32 +00:00
Organization : "1337" ,
2017-10-27 17:14:14 +00:00
} ,
auth : mocks . Authenticator { } ,
} ,
fields : fields {
UseAuth : true ,
Logger : log . New ( log . DebugLevel ) ,
UsersStore : & mocks . UsersStore {
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
if q . Name == nil || q . Provider == nil || q . Scheme == nil {
return nil , fmt . Errorf ( "Invalid user query: missing Name, Provider, and/or Scheme" )
}
2017-10-31 20:41:17 +00:00
return nil , chronograf . ErrUserNotFound
2017-10-27 17:14:14 +00:00
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-10-27 17:14:14 +00:00
} ,
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-10-27 17:14:14 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
if q . ID == nil {
return nil , fmt . Errorf ( "Invalid organization query: missing ID" )
}
return & chronograf . Organization {
ID : 1337 ,
Name : "The ShillBillThrilliettas" ,
} , nil
} ,
} ,
} ,
principal : oauth2 . Principal {
Subject : "me" ,
Issuer : "github" ,
Organization : "1338" ,
} ,
wantStatus : http . StatusBadRequest ,
wantContentType : "application/json" ,
wantBody : ` { "code":400,"message":"user not found"} ` ,
} ,
{
name : "Unable to find requested organization" ,
args : args {
w : httptest . NewRecorder ( ) ,
r : httptest . NewRequest ( "GET" , "http://example.com/foo" , nil ) ,
orgRequest : & meOrganizationRequest {
2017-11-01 14:37:32 +00:00
Organization : "1337" ,
2017-10-27 17:14:14 +00:00
} ,
auth : mocks . Authenticator { } ,
} ,
fields : fields {
UseAuth : true ,
Logger : log . New ( log . DebugLevel ) ,
UsersStore : & mocks . UsersStore {
GetF : func ( ctx context . Context , q chronograf . UserQuery ) ( * chronograf . User , error ) {
if q . Name == nil || q . Provider == nil || q . Scheme == nil {
return nil , fmt . Errorf ( "Invalid user query: missing Name, Provider, and/or Scheme" )
}
return & chronograf . User {
Name : "me" ,
Provider : "github" ,
Scheme : "oauth2" ,
2017-10-31 20:41:17 +00:00
Roles : [ ] chronograf . Role {
{
Name : AdminRoleName ,
Organization : "1337" ,
} ,
} ,
2017-10-27 17:14:14 +00:00
} , nil
} ,
2017-11-02 23:13:51 +00:00
UpdateF : func ( ctx context . Context , u * chronograf . User ) error {
return nil
} ,
2017-10-27 17:14:14 +00:00
} ,
OrganizationsStore : & mocks . OrganizationsStore {
2017-11-02 20:47:45 +00:00
DefaultOrganizationF : func ( ctx context . Context ) ( * chronograf . Organization , error ) {
return & chronograf . Organization {
2017-11-02 23:41:57 +00:00
ID : 0 ,
2017-11-02 20:47:45 +00:00
} , nil
} ,
2017-10-27 17:14:14 +00:00
GetF : func ( ctx context . Context , q chronograf . OrganizationQuery ) ( * chronograf . Organization , error ) {
return nil , chronograf . ErrOrganizationNotFound
} ,
} ,
} ,
principal : oauth2 . Principal {
Subject : "me" ,
Issuer : "github" ,
Organization : "1338" ,
} ,
wantStatus : http . StatusBadRequest ,
wantContentType : "application/json" ,
wantBody : ` { "code":400,"message":"organization not found"} ` ,
} ,
2017-10-26 23:02:57 +00:00
}
for _ , tt := range tests {
tt . args . r = tt . args . r . WithContext ( context . WithValue ( context . Background ( ) , oauth2 . PrincipalKey , tt . principal ) )
s := & Service {
2017-10-31 20:41:17 +00:00
Store : & Store {
UsersStore : tt . fields . UsersStore ,
OrganizationsStore : tt . fields . OrganizationsStore ,
} ,
Logger : tt . fields . Logger ,
UseAuth : tt . fields . UseAuth ,
2017-10-26 23:02:57 +00:00
}
buf , _ := json . Marshal ( tt . args . orgRequest )
tt . args . r . Body = ioutil . NopCloser ( bytes . NewReader ( buf ) )
tt . args . auth . Principal = tt . principal
s . MeOrganization ( & tt . args . auth ) ( tt . args . w , tt . args . r )
resp := tt . args . w . Result ( )
content := resp . Header . Get ( "Content-Type" )
body , _ := ioutil . ReadAll ( resp . Body )
if resp . StatusCode != tt . wantStatus {
t . Errorf ( "%q. Me() = %v, want %v" , tt . name , resp . StatusCode , tt . wantStatus )
}
if tt . wantContentType != "" && content != tt . wantContentType {
t . Errorf ( "%q. Me() = %v, want %v" , tt . name , content , tt . wantContentType )
}
if eq , err := jsonEqual ( tt . wantBody , string ( body ) ) ; err != nil || ! eq {
t . Errorf ( "%q. Me() = \n***%v***\n,\nwant\n***%v***" , tt . name , string ( body ) , tt . wantBody )
}
}
}