github.com/goravel/framework@v1.13.9/auth/auth_test.go (about)

     1  package auth
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/golang-jwt/jwt/v5"
    11  	testifymock "github.com/stretchr/testify/mock"
    12  	"github.com/stretchr/testify/suite"
    13  	"gorm.io/gorm/clause"
    14  
    15  	authcontract "github.com/goravel/framework/contracts/auth"
    16  	cachemock "github.com/goravel/framework/contracts/cache/mocks"
    17  	configmock "github.com/goravel/framework/contracts/config/mocks"
    18  	ormmock "github.com/goravel/framework/contracts/database/orm/mocks"
    19  	"github.com/goravel/framework/contracts/http"
    20  	"github.com/goravel/framework/database/orm"
    21  	"github.com/goravel/framework/support/carbon"
    22  )
    23  
    24  var testUserGuard = "user"
    25  
    26  type User struct {
    27  	orm.Model
    28  	Name string
    29  }
    30  
    31  type Context struct {
    32  	ctx      context.Context
    33  	request  http.ContextRequest
    34  	response http.ContextResponse
    35  	values   map[string]any
    36  	mu       sync.RWMutex
    37  }
    38  
    39  func (mc *Context) Deadline() (deadline time.Time, ok bool) {
    40  	return mc.ctx.Deadline()
    41  }
    42  
    43  func (mc *Context) Done() <-chan struct{} {
    44  	return mc.ctx.Done()
    45  }
    46  
    47  func (mc *Context) Err() error {
    48  	return mc.ctx.Err()
    49  }
    50  
    51  func (mc *Context) Value(key interface{}) any {
    52  	if k, ok := key.(string); ok {
    53  		mc.mu.RLock()
    54  		v, ok := mc.values[k]
    55  		mc.mu.RUnlock()
    56  
    57  		if ok {
    58  			return v
    59  		}
    60  	}
    61  
    62  	return mc.ctx.Value(key)
    63  }
    64  
    65  func (mc *Context) Context() context.Context {
    66  	return mc.ctx
    67  }
    68  
    69  func (mc *Context) WithValue(key string, value any) {
    70  	mc.mu.Lock()
    71  	mc.values[key] = value
    72  	mc.mu.Unlock()
    73  }
    74  
    75  func (mc *Context) Request() http.ContextRequest {
    76  	return mc.request
    77  }
    78  
    79  func (mc *Context) Response() http.ContextResponse {
    80  	return mc.response
    81  }
    82  
    83  func Background() http.Context {
    84  	return &Context{
    85  		ctx:      context.Background(),
    86  		request:  nil,
    87  		response: nil,
    88  		values:   make(map[string]any),
    89  	}
    90  }
    91  
    92  type AuthTestSuite struct {
    93  	suite.Suite
    94  	auth       *Auth
    95  	mockCache  *cachemock.Cache
    96  	mockConfig *configmock.Config
    97  	mockOrm    *ormmock.Orm
    98  	mockDB     *ormmock.Query
    99  }
   100  
   101  func TestAuthTestSuite(t *testing.T) {
   102  	suite.Run(t, new(AuthTestSuite))
   103  }
   104  
   105  func (s *AuthTestSuite) SetupTest() {
   106  	s.mockCache = &cachemock.Cache{}
   107  	s.mockConfig = &configmock.Config{}
   108  	s.mockOrm = &ormmock.Orm{}
   109  	s.mockDB = &ormmock.Query{}
   110  	s.auth = NewAuth(testUserGuard, s.mockCache, s.mockConfig, s.mockOrm)
   111  }
   112  
   113  func (s *AuthTestSuite) TestLoginUsingID_EmptySecret() {
   114  	s.mockConfig.On("GetString", "jwt.secret").Return("").Once()
   115  
   116  	token, err := s.auth.LoginUsingID(Background(), 1)
   117  	s.Empty(token)
   118  	s.ErrorIs(err, ErrorEmptySecret)
   119  
   120  	s.mockConfig.AssertExpectations(s.T())
   121  }
   122  
   123  func (s *AuthTestSuite) TestLoginUsingID_InvalidKey() {
   124  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Once()
   125  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   126  
   127  	token, err := s.auth.LoginUsingID(Background(), "")
   128  	s.Empty(token)
   129  	s.ErrorIs(err, ErrorInvalidKey)
   130  
   131  	s.mockConfig.AssertExpectations(s.T())
   132  }
   133  
   134  func (s *AuthTestSuite) TestLoginUsingID() {
   135  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   136  
   137  	// jwt.ttl > 0
   138  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   139  
   140  	token, err := s.auth.LoginUsingID(Background(), 1)
   141  	s.NotEmpty(token)
   142  	s.Nil(err)
   143  
   144  	// jwt.ttl == 0
   145  	s.mockConfig.On("GetInt", "jwt.ttl").Return(0).Once()
   146  
   147  	token, err = s.auth.LoginUsingID(Background(), 1)
   148  	s.NotEmpty(token)
   149  	s.Nil(err)
   150  
   151  	s.mockConfig.AssertExpectations(s.T())
   152  }
   153  
   154  func (s *AuthTestSuite) TestLogin_Model() {
   155  
   156  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Once()
   157  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   158  
   159  	var user User
   160  	user.ID = 1
   161  	user.Name = "Goravel"
   162  	token, err := s.auth.Login(Background(), &user)
   163  	s.NotEmpty(token)
   164  	s.Nil(err)
   165  
   166  	s.mockConfig.AssertExpectations(s.T())
   167  }
   168  
   169  func (s *AuthTestSuite) TestLogin_CustomModel() {
   170  	type CustomUser struct {
   171  		ID   uint `gorm:"primaryKey"`
   172  		Name string
   173  	}
   174  
   175  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Once()
   176  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   177  
   178  	var user CustomUser
   179  	user.ID = 1
   180  	user.Name = "Goravel"
   181  	token, err := s.auth.Login(Background(), &user)
   182  	s.NotEmpty(token)
   183  	s.Nil(err)
   184  
   185  	s.mockConfig.AssertExpectations(s.T())
   186  }
   187  
   188  func (s *AuthTestSuite) TestLogin_ErrorModel() {
   189  	type ErrorUser struct {
   190  		ID   uint
   191  		Name string
   192  	}
   193  
   194  	var errorUser ErrorUser
   195  	errorUser.ID = 1
   196  	errorUser.Name = "Goravel"
   197  	token, err := s.auth.Login(Background(), &errorUser)
   198  	s.Empty(token)
   199  	s.EqualError(err, "the primaryKey field was not found in the model, set primaryKey like orm.Model")
   200  }
   201  
   202  func (s *AuthTestSuite) TestLogin_NoPrimaryKey() {
   203  	type User struct {
   204  		ID   uint
   205  		Name string
   206  	}
   207  
   208  	ctx := Background()
   209  	var user User
   210  	user.ID = 1
   211  	user.Name = "Goravel"
   212  	token, err := s.auth.Login(ctx, &user)
   213  	s.Empty(token)
   214  	s.ErrorIs(err, ErrorNoPrimaryKeyField)
   215  }
   216  
   217  func (s *AuthTestSuite) TestParse_TokenDisabled() {
   218  	token := "1"
   219  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(true).Once()
   220  
   221  	payload, err := s.auth.Parse(Background(), token)
   222  	s.Nil(payload)
   223  	s.EqualError(err, "token is disabled")
   224  }
   225  
   226  func (s *AuthTestSuite) TestParse_TokenInvalid() {
   227  
   228  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Once()
   229  
   230  	token := "1"
   231  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   232  
   233  	payload, err := s.auth.Parse(Background(), token)
   234  	s.Nil(payload)
   235  	s.NotNil(err)
   236  
   237  	s.mockConfig.AssertExpectations(s.T())
   238  }
   239  
   240  func (s *AuthTestSuite) TestParse_TokenExpired() {
   241  
   242  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   243  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   244  
   245  	ctx := Background()
   246  
   247  	now := carbon.Now()
   248  	issuedAt := now.ToStdTime()
   249  	expireAt := now.AddMinutes(2).ToStdTime()
   250  	token, err := s.auth.LoginUsingID(ctx, 1)
   251  	s.Nil(err)
   252  
   253  	carbon.SetTestNow(now.AddMinutes(2))
   254  
   255  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   256  
   257  	payload, err := s.auth.Parse(ctx, token)
   258  	s.Equal(&authcontract.Payload{
   259  		Guard:    testUserGuard,
   260  		Key:      "1",
   261  		ExpireAt: jwt.NewNumericDate(expireAt).Local(),
   262  		IssuedAt: jwt.NewNumericDate(issuedAt).Local(),
   263  	}, payload)
   264  	s.ErrorIs(err, ErrorTokenExpired)
   265  
   266  	carbon.UnsetTestNow()
   267  
   268  	s.mockConfig.AssertExpectations(s.T())
   269  }
   270  
   271  func (s *AuthTestSuite) TestParse_InvalidCache() {
   272  	auth := NewAuth(testUserGuard, nil, s.mockConfig, s.mockOrm)
   273  	ctx := Background()
   274  	payload, err := auth.Parse(ctx, "1")
   275  	s.Nil(payload)
   276  	s.EqualError(err, "cache support is required")
   277  }
   278  
   279  func (s *AuthTestSuite) TestParse_Success() {
   280  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   281  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   282  
   283  	ctx := Background()
   284  	token, err := s.auth.LoginUsingID(ctx, 1)
   285  	s.Nil(err)
   286  
   287  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   288  
   289  	payload, err := s.auth.Parse(ctx, token)
   290  	s.Equal(&authcontract.Payload{
   291  		Guard:    testUserGuard,
   292  		Key:      "1",
   293  		ExpireAt: jwt.NewNumericDate(carbon.Now().AddMinutes(2).ToStdTime()).Local(),
   294  		IssuedAt: jwt.NewNumericDate(carbon.Now().ToStdTime()).Local(),
   295  	}, payload)
   296  	s.Nil(err)
   297  
   298  	s.mockConfig.AssertExpectations(s.T())
   299  }
   300  
   301  func (s *AuthTestSuite) TestParse_SuccessWithPrefix() {
   302  	carbon.SetTestNow(carbon.Now())
   303  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   304  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   305  
   306  	ctx := Background()
   307  	token, err := s.auth.LoginUsingID(ctx, 1)
   308  	s.Nil(err)
   309  
   310  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   311  
   312  	payload, err := s.auth.Parse(ctx, "Bearer "+token)
   313  	s.Equal(&authcontract.Payload{
   314  		Guard:    testUserGuard,
   315  		Key:      "1",
   316  		ExpireAt: jwt.NewNumericDate(carbon.Now().AddMinutes(2).ToStdTime()).Local(),
   317  		IssuedAt: jwt.NewNumericDate(carbon.Now().ToStdTime()).Local(),
   318  	}, payload)
   319  	s.Nil(err)
   320  
   321  	carbon.UnsetTestNow()
   322  	s.mockConfig.AssertExpectations(s.T())
   323  }
   324  
   325  func (s *AuthTestSuite) TestParse_ExpiredAndInvalid() {
   326  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Once()
   327  
   328  	ctx := Background()
   329  	token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiIxIiwic3ViIjoidXNlciIsImV4cCI6MTY4OTk3MDE3MiwiaWF0IjoxNjg5OTY2NTcyfQ.GApXNbicqzjF2jHsSCJ1AdziHnI1grPuJ5ddSQjGJUQ"
   330  
   331  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   332  
   333  	_, err := s.auth.Parse(ctx, token)
   334  	s.ErrorIs(err, ErrorInvalidToken)
   335  
   336  	s.mockConfig.AssertExpectations(s.T())
   337  }
   338  
   339  func (s *AuthTestSuite) TestUser_NoParse() {
   340  	ctx := Background()
   341  	var user User
   342  	err := s.auth.User(ctx, user)
   343  	s.EqualError(err, "parse token first")
   344  
   345  	s.mockConfig.AssertExpectations(s.T())
   346  }
   347  
   348  func (s *AuthTestSuite) TestUser_DBError() {
   349  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   350  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   351  
   352  	ctx := Background()
   353  	token, err := s.auth.LoginUsingID(ctx, 1)
   354  	s.Nil(err)
   355  
   356  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   357  
   358  	payload, err := s.auth.Parse(ctx, token)
   359  	s.NotNil(payload)
   360  	s.Nil(err)
   361  
   362  	var user User
   363  
   364  	s.mockOrm.On("Query").Return(s.mockDB)
   365  	s.mockDB.On("FindOrFail", &user, clause.Eq{Column: clause.PrimaryColumn, Value: "1"}).Return(errors.New("error")).Once()
   366  
   367  	err = s.auth.User(ctx, &user)
   368  	s.EqualError(err, "error")
   369  
   370  	s.mockConfig.AssertExpectations(s.T())
   371  }
   372  
   373  func (s *AuthTestSuite) TestUser_Expired() {
   374  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Times(3)
   375  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Twice()
   376  
   377  	ctx := Background()
   378  	token, err := s.auth.LoginUsingID(ctx, 1)
   379  	s.NotEmpty(token)
   380  	s.Nil(err)
   381  
   382  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   383  
   384  	carbon.SetTestNow(carbon.Now().AddMinutes(2))
   385  
   386  	payload, err := s.auth.Parse(ctx, token)
   387  	s.NotNil(payload)
   388  	s.ErrorIs(err, ErrorTokenExpired)
   389  
   390  	var user User
   391  	err = s.auth.User(ctx, &user)
   392  	s.EqualError(err, "token expired")
   393  
   394  	s.mockConfig.On("GetInt", "jwt.refresh_ttl").Return(2).Once()
   395  
   396  	token, err = s.auth.Refresh(ctx)
   397  	s.NotEmpty(token)
   398  	s.Nil(err)
   399  
   400  	s.mockOrm.On("Query").Return(s.mockDB)
   401  	s.mockDB.On("FindOrFail", &user, clause.Eq{Column: clause.PrimaryColumn, Value: "1"}).Return(nil).Once()
   402  
   403  	err = s.auth.User(ctx, &user)
   404  	s.Nil(err)
   405  
   406  	carbon.UnsetTestNow()
   407  
   408  	s.mockConfig.AssertExpectations(s.T())
   409  }
   410  
   411  func (s *AuthTestSuite) TestUser_RefreshExpired() {
   412  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   413  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   414  
   415  	ctx := Background()
   416  	token, err := s.auth.LoginUsingID(ctx, 1)
   417  	s.NotEmpty(token)
   418  	s.Nil(err)
   419  
   420  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   421  
   422  	carbon.SetTestNow(carbon.Now().AddMinutes(2))
   423  
   424  	payload, err := s.auth.Parse(ctx, token)
   425  	s.NotNil(payload)
   426  	s.ErrorIs(err, ErrorTokenExpired)
   427  
   428  	var user User
   429  	err = s.auth.User(ctx, &user)
   430  	s.EqualError(err, "token expired")
   431  
   432  	s.mockConfig.On("GetInt", "jwt.refresh_ttl").Return(1).Once()
   433  
   434  	carbon.SetTestNow(carbon.Now().AddMinutes(2))
   435  
   436  	token, err = s.auth.Refresh(ctx)
   437  	s.Empty(token)
   438  	s.EqualError(err, "refresh time exceeded")
   439  
   440  	carbon.UnsetTestNow()
   441  
   442  	s.mockConfig.AssertExpectations(s.T())
   443  }
   444  
   445  func (s *AuthTestSuite) TestUser_Success() {
   446  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   447  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   448  
   449  	ctx := Background()
   450  	token, err := s.auth.LoginUsingID(ctx, 1)
   451  	s.Nil(err)
   452  
   453  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   454  
   455  	payload, err := s.auth.Parse(ctx, token)
   456  	s.NotNil(payload)
   457  	s.Nil(err)
   458  
   459  	var user User
   460  	s.mockOrm.On("Query").Return(s.mockDB)
   461  	s.mockDB.On("FindOrFail", &user, clause.Eq{Column: clause.PrimaryColumn, Value: "1"}).Return(nil).Once()
   462  
   463  	err = s.auth.User(ctx, &user)
   464  	s.Nil(err)
   465  
   466  	s.mockConfig.AssertExpectations(s.T())
   467  	s.mockCache.AssertExpectations(s.T())
   468  	s.mockOrm.AssertExpectations(s.T())
   469  	s.mockDB.AssertExpectations(s.T())
   470  }
   471  
   472  func (s *AuthTestSuite) TestUser_Success_MultipleParse() {
   473  	testAdminGuard := "admin"
   474  
   475  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   476  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   477  
   478  	ctx := Background()
   479  	token1, err := s.auth.LoginUsingID(ctx, 1)
   480  	s.Nil(err)
   481  
   482  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   483  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   484  
   485  	ctx = Background()
   486  	token2, err := s.auth.Guard(testAdminGuard).LoginUsingID(ctx, 2)
   487  	s.Nil(err)
   488  
   489  	s.mockCache.On("GetBool", "jwt:disabled:"+token1, false).Return(false).Once()
   490  
   491  	payload, err := s.auth.Parse(ctx, token1)
   492  	s.Nil(err)
   493  	s.NotNil(payload)
   494  	s.Equal(testUserGuard, payload.Guard)
   495  	s.Equal("1", payload.Key)
   496  
   497  	s.mockCache.On("GetBool", "jwt:disabled:"+token2, false).Return(false).Once()
   498  
   499  	payload, err = s.auth.Guard(testAdminGuard).Parse(ctx, token2)
   500  	s.Nil(err)
   501  	s.NotNil(payload)
   502  	s.Equal(testAdminGuard, payload.Guard)
   503  	s.Equal("2", payload.Key)
   504  
   505  	var user1 User
   506  	s.mockOrm.On("Query").Return(s.mockDB)
   507  	s.mockDB.On("FindOrFail", &user1, clause.Eq{Column: clause.PrimaryColumn, Value: "1"}).Return(nil).Once()
   508  
   509  	err = s.auth.User(ctx, &user1)
   510  	s.Nil(err)
   511  
   512  	var user2 User
   513  	s.mockOrm.On("Query").Return(s.mockDB)
   514  	s.mockDB.On("FindOrFail", &user2, clause.Eq{Column: clause.PrimaryColumn, Value: "2"}).Return(nil).Once()
   515  
   516  	err = s.auth.Guard(testAdminGuard).User(ctx, &user2)
   517  	s.Nil(err)
   518  
   519  	s.mockConfig.AssertExpectations(s.T())
   520  	s.mockCache.AssertExpectations(s.T())
   521  	s.mockOrm.AssertExpectations(s.T())
   522  	s.mockDB.AssertExpectations(s.T())
   523  }
   524  
   525  func (s *AuthTestSuite) TestRefresh_NotParse() {
   526  	ctx := Background()
   527  	token, err := s.auth.Refresh(ctx)
   528  	s.Empty(token)
   529  	s.EqualError(err, "parse token first")
   530  
   531  	s.mockConfig.AssertExpectations(s.T())
   532  }
   533  
   534  func (s *AuthTestSuite) TestRefresh_RefreshTimeExceeded() {
   535  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   536  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   537  
   538  	ctx := Background()
   539  	token, err := s.auth.LoginUsingID(ctx, 2)
   540  
   541  	s.Nil(err)
   542  
   543  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   544  
   545  	payload, err := s.auth.Parse(ctx, token)
   546  	s.NotNil(payload)
   547  	s.Nil(err)
   548  
   549  	s.mockConfig.On("GetInt", "jwt.refresh_ttl").Return(1).Once()
   550  
   551  	carbon.SetTestNow(carbon.Now().AddMinutes(4))
   552  
   553  	token, err = s.auth.Refresh(ctx)
   554  	s.Empty(token)
   555  	s.EqualError(err, "refresh time exceeded")
   556  
   557  	carbon.UnsetTestNow()
   558  
   559  	s.mockConfig.AssertExpectations(s.T())
   560  }
   561  
   562  func (s *AuthTestSuite) TestRefresh_Success() {
   563  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Times(4)
   564  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Times(3)
   565  
   566  	ctx := Background()
   567  	token, err := s.auth.LoginUsingID(ctx, 1)
   568  	s.Nil(err)
   569  
   570  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   571  
   572  	payload, err := s.auth.Parse(ctx, token)
   573  	s.NotNil(payload)
   574  	s.Nil(err)
   575  
   576  	// jwt.refresh_ttl > 0
   577  	s.mockConfig.On("GetInt", "jwt.refresh_ttl").Return(1).Once()
   578  
   579  	carbon.SetTestNow(carbon.Now().AddMinutes(2))
   580  
   581  	token, err = s.auth.Refresh(ctx)
   582  	s.NotEmpty(token)
   583  	s.Nil(err)
   584  
   585  	// jwt.refresh_ttl == 0
   586  	s.mockConfig.On("GetInt", "jwt.refresh_ttl").Return(0).Once()
   587  
   588  	carbon.SetTestNow(carbon.Now().AddMinutes(2))
   589  
   590  	token, err = s.auth.Refresh(ctx)
   591  	s.NotEmpty(token)
   592  	s.Nil(err)
   593  
   594  	carbon.UnsetTestNow()
   595  
   596  	s.mockConfig.AssertExpectations(s.T())
   597  }
   598  
   599  func (s *AuthTestSuite) TestLogout_CacheUnsupported() {
   600  	s.auth = NewAuth(testUserGuard, nil, s.mockConfig, s.mockOrm)
   601  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Once()
   602  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Once()
   603  
   604  	ctx := Background()
   605  	token, err := s.auth.LoginUsingID(ctx, 1)
   606  	s.NotEmpty(token)
   607  	s.Nil(err)
   608  	s.EqualError(s.auth.Logout(ctx), "cache support is required")
   609  
   610  	s.mockConfig.AssertExpectations(s.T())
   611  }
   612  
   613  func (s *AuthTestSuite) TestLogout_NotParse() {
   614  	s.Nil(s.auth.Logout(Background()))
   615  }
   616  
   617  func (s *AuthTestSuite) TestLogout_SetDisabledCacheError() {
   618  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   619  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Twice()
   620  
   621  	ctx := Background()
   622  	token, err := s.auth.LoginUsingID(ctx, 1)
   623  	s.Nil(err)
   624  
   625  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   626  
   627  	payload, err := s.auth.Parse(ctx, token)
   628  	s.NotNil(payload)
   629  	s.Nil(err)
   630  
   631  	s.mockCache.On("Put", testifymock.Anything, true, 2*time.Minute).Return(errors.New("error")).Once()
   632  
   633  	s.EqualError(s.auth.Logout(ctx), "error")
   634  
   635  	s.mockConfig.AssertExpectations(s.T())
   636  }
   637  
   638  func (s *AuthTestSuite) TestLogout_Success() {
   639  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   640  	s.mockConfig.On("GetInt", "jwt.ttl").Return(2).Twice()
   641  
   642  	ctx := Background()
   643  	token, err := s.auth.LoginUsingID(ctx, 1)
   644  	s.NotEmpty(token)
   645  	s.Nil(err)
   646  
   647  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   648  
   649  	payload, err := s.auth.Parse(ctx, token)
   650  	s.NotNil(payload)
   651  	s.Nil(err)
   652  
   653  	s.mockCache.On("Put", testifymock.Anything, true, 2*time.Minute).Return(nil).Once()
   654  
   655  	s.Nil(s.auth.Logout(ctx))
   656  
   657  	s.mockConfig.AssertExpectations(s.T())
   658  }
   659  
   660  func (s *AuthTestSuite) TestLogout_Success_TTL_Is_0() {
   661  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   662  	s.mockConfig.On("GetInt", "jwt.ttl").Return(0).Twice()
   663  
   664  	ctx := Background()
   665  	token, err := s.auth.LoginUsingID(ctx, 1)
   666  	s.NotEmpty(token)
   667  	s.Nil(err)
   668  
   669  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   670  
   671  	payload, err := s.auth.Parse(ctx, token)
   672  	s.NotNil(payload)
   673  	s.Nil(err)
   674  
   675  	s.mockCache.On("Forever", testifymock.Anything, true).Return(true).Once()
   676  
   677  	s.Nil(s.auth.Logout(ctx))
   678  
   679  	s.mockConfig.AssertExpectations(s.T())
   680  }
   681  
   682  func (s *AuthTestSuite) TestLogout_Error_TTL_Is_0() {
   683  	s.mockConfig.On("GetString", "jwt.secret").Return("Goravel").Twice()
   684  	s.mockConfig.On("GetInt", "jwt.ttl").Return(0).Twice()
   685  
   686  	ctx := Background()
   687  	token, err := s.auth.LoginUsingID(ctx, 1)
   688  	s.NotEmpty(token)
   689  	s.Nil(err)
   690  
   691  	s.mockCache.On("GetBool", "jwt:disabled:"+token, false).Return(false).Once()
   692  
   693  	payload, err := s.auth.Parse(ctx, token)
   694  	s.NotNil(payload)
   695  	s.Nil(err)
   696  
   697  	s.mockCache.On("Forever", testifymock.Anything, true).Return(false).Once()
   698  
   699  	s.EqualError(s.auth.Logout(ctx), "cache forever failed")
   700  
   701  	s.mockConfig.AssertExpectations(s.T())
   702  }
   703  
   704  func (s *AuthTestSuite) TestMakeAuthContext() {
   705  	testAdminGuard := "admin"
   706  
   707  	ctx := Background()
   708  	s.auth.makeAuthContext(ctx, nil, "1")
   709  	guards, ok := ctx.Value(ctxKey).(Guards)
   710  	s.True(ok)
   711  	s.Equal(&Guard{nil, "1"}, guards[testUserGuard])
   712  
   713  	s.auth.Guard(testAdminGuard).(*Auth).makeAuthContext(ctx, nil, "2")
   714  	guards, ok = ctx.Value(ctxKey).(Guards)
   715  	s.True(ok)
   716  	s.Equal(&Guard{nil, "1"}, guards[testUserGuard])
   717  	s.Equal(&Guard{nil, "2"}, guards[testAdminGuard])
   718  }