diff --git a/backend/internal/jwt/suite_test.go b/backend/internal/jwt/suite_test.go new file mode 100644 index 00000000..7f6eb5a7 --- /dev/null +++ b/backend/internal/jwt/suite_test.go @@ -0,0 +1,240 @@ +package jwt + +import ( + "database/sql" + "regexp" + "testing" + + "npm/internal/entity/user" + "npm/internal/model" + "npm/internal/test" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +// +------------+ +// | Setup | +// +------------+ + +type testsuite struct { + suite.Suite + mock sqlmock.Sqlmock + keysRow *sqlmock.Rows + privateKeyString string + publicKeyString string +} + +// SetupTest is executed before each test +func (s *testsuite) SetupTest() { + var err error + s.mock, err = test.Setup() + require.NoError(s.T(), err) + test.InitConfig(s.T()) + + s.publicKeyString = `-----BEGIN PUBLIC KEY----- +MIICCgKCAgEAmjPv7Bnb02rdcMqPIK6EMt7hIYzobgmIwoEtNVP6IaVzPdTo0l5V +prxVH9J2oeJzZPmUjgsru+1db/RqOT4QYma7FGjoVi/AZvGGbiJENOK87K0d3byM +CZ1bridvVOWKU92EvK+uTBfG9wtEpyS4pTC6mt6jKnKJrlRA7pKbHB7jmgBDU+6C +CniYIkXpmHKQu1Q4Mpa5oYzgNMiAnxRmps8BwkVNwzMc7mwdhSn+M+qkVJJO4Q5A +BgHoieR6y5+P2oieX4Z8HwnzxKS79FmTo0JhSVadPxYTRKWLAcVgM7lo/d+KQy7o +v+jFVYNiaeSdAPgfEoYdiJA7NZC4xEVsQMeZLGZp1WpcwJ7DInn0Z4ILsuFIeQGv +nmaq+yFRgJcQT3zANlitqwdK4FWd0DN1PH17YG3oIGvxHCFEClZqeLPte1lB3T3w +xyrw00OfSKBwZ9gAxemxQRu/8/9EnLOM4FlanK8/S4GIPgj05LvE52ZLotXqQU77 +PIXaGwufKkwOx0oHmy82wZpc4A18Po6UMcsnyfR+ykKHacuRKCHnJjCEszKR8t/i +BqL4+sCPZfE/6FSjZi1tHGTybMGVTEL/HnJEHOZqvWbKwl6xLln38UWi7YG/FFs/ +ymcpxqEnMWQCs8ZmA1q6nPkzHkjYGmr5SyC6jaFaKJN1SgCsaP2sF80CAwEAAQ== +-----END PUBLIC KEY-----` + + s.privateKeyString = `-----BEGIN PRIVATE KEY----- +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 +-----END PRIVATE KEY-----` + + // These rows need to be intantiated for each test as they are + // read in the db object, and their row position is not resettable + // between tests. + s.keysRow = sqlmock.NewRows([]string{ + "public_key", + "private_key", + }).AddRow( + s.publicKeyString, + s.privateKeyString, + ) +} + +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestExampleTestSuite(t *testing.T) { + suite.Run(t, new(testsuite)) +} + +// +------------+ +// | Tests | +// +------------+ + +func (s *testsuite) TestLoadKeys() { + // Required for clean test runs + currentKeys = KeysModel{} + + // first query, no rows + s.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "jwt_keys" WHERE "jwt_keys"."is_deleted" = $1`)). + WithArgs(0). + WillReturnError(sql.ErrNoRows) + + // insert row + s.mock.ExpectBegin() + s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "jwt_keys" ("created_at","updated_at","is_deleted","public_key","private_key") VALUES ($1,$2,$3,$4,$5) RETURNING "id"`)). + WithArgs( + sqlmock.AnyArg(), + sqlmock.AnyArg(), + 0, + sqlmock.AnyArg(), + sqlmock.AnyArg(), + ). + WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("10")) + s.mock.ExpectCommit() + + // last query, load existing row + s.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "jwt_keys" WHERE "jwt_keys"."is_deleted" = $1`)). + WithArgs(0). + WillReturnRows(s.keysRow) + + // Load and create first + err := LoadKeys() + require.NoError(s.T(), err) + + // Load something we just created + k := KeysModel{} + err = k.LoadLatest() + require.NoError(s.T(), err) + + require.NoError(s.T(), s.mock.ExpectationsWereMet()) +} + +func (s *testsuite) TestGetPrivateKey() { + // Required for clean test runs + privateKey = nil + currentKeys = KeysModel{} + + // First call, expect error as currentKeys isn't loaded + _, err := GetPrivateKey() + assert.Equal(s.T(), "Could not get Private Key from configuration", err.Error()) + + // Set currentKeys and try again + currentKeys = KeysModel{ + ModelBase: model.ModelBase{ + ID: 10, + }, + PrivateKey: s.privateKeyString, + PublicKey: s.publicKeyString, + } + + // Get after currentKeys is set + _, err = GetPrivateKey() + require.NoError(s.T(), err) + require.NoError(s.T(), s.mock.ExpectationsWereMet()) +} + +func (s *testsuite) TestGetPublicKey() { + // Required for clean test runs + publicKey = nil + currentKeys = KeysModel{} + + // First call, expect error as currentKeys isn't loaded + _, err := GetPublicKey() + assert.Equal(s.T(), "Could not get Public Key from configuration", err.Error()) + + // Set currentKeys and try again + currentKeys = KeysModel{ + ModelBase: model.ModelBase{ + ID: 10, + }, + PrivateKey: s.privateKeyString, + PublicKey: s.publicKeyString, + } + + // Get after currentKeys is set + _, err = GetPublicKey() + require.NoError(s.T(), err) + require.NoError(s.T(), s.mock.ExpectationsWereMet()) +} + +func (s *testsuite) TestGenerate() { + currentKeys = KeysModel{ + ModelBase: model.ModelBase{ + ID: 10, + }, + PrivateKey: s.privateKeyString, + PublicKey: s.publicKeyString, + } + + usr := user.Model{ + ModelBase: model.ModelBase{ + ID: 10, + }, + } + + // test 1, user key + r, err := Generate(&usr, false) + require.NoError(s.T(), err) + assert.Greater(s.T(), len(r.Token), 20) + + // test 2, sse key + r, err = Generate(&usr, true) + require.NoError(s.T(), err) + assert.Greater(s.T(), len(r.Token), 20) + + require.NoError(s.T(), s.mock.ExpectationsWereMet()) +} diff --git a/backend/internal/logger/logger_test.go b/backend/internal/logger/logger_test.go index 54321d09..7e88f87b 100644 --- a/backend/internal/logger/logger_test.go +++ b/backend/internal/logger/logger_test.go @@ -45,11 +45,13 @@ func TestDebug(t *testing.T) { assert.NoError(t, Configure(&Config{ LogThreshold: DebugLevel, + Formatter: "json", })) Debug("This is a %s message", "test") assert.Contains(t, buf.String(), "DEBUG") assert.Contains(t, buf.String(), "This is a test message") + Get() } func TestInfo(t *testing.T) { @@ -118,6 +120,16 @@ func TestConfigure(t *testing.T) { }, wantErr: false, }, + { + name: "configure json", + args: args{ + &Config{ + LogThreshold: InfoLevel, + Formatter: "json", + }, + }, + wantErr: false, + }, { name: "invalid log level", args: args{ @@ -125,6 +137,13 @@ func TestConfigure(t *testing.T) { }, wantErr: true, }, + { + name: "invalid config struct", + args: args{ + nil, + }, + wantErr: true, + }, } for _, tt := range tests { tt := tt diff --git a/backend/internal/model/pageinfo_test.go b/backend/internal/model/pageinfo_test.go new file mode 100644 index 00000000..810a103d --- /dev/null +++ b/backend/internal/model/pageinfo_test.go @@ -0,0 +1,27 @@ +package model + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPageInfoGetSort(t *testing.T) { + t.Parallel() + pi := PageInfo{} + def := Sort{ + Field: "name", + Direction: "asc", + } + defined := Sort{ + Field: "nickname", + Direction: "desc", + } + // default + sort := pi.GetSort(def) + assert.Equal(t, sort, []Sort{def}) + // defined + pi.Sort = []Sort{defined} + sort = pi.GetSort(def) + assert.Equal(t, sort, []Sort{defined}) +}