diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 00000000..d8967db3 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,29 @@ +name: "Database integration tests" + +on: + push: + pull_request: + branches: [ main ] + +jobs: + mongodb-integration-test: + name: MongoDB integration test + runs-on: ubuntu-latest + services: + mysql: + image: mongo:4.2.2 + ports: + - "27017:27017" + steps: + - name: Set up Go 1.x + uses: actions/setup-go@v4 + with: + go-version: ^1.20 + + - name: Check out code into the Go module directory + uses: actions/checkout@v4 + + - name: Run MongoDB integration test + run: | + make integration-test + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 130aa464..7431892f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,74 @@ Please note we have a code of conduct, please follow it in all your interactions 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. +## Testing + +### Adding new integration tests + +Integration tests play a crucial role in validating the correct integration of our codebase with its dependencies. To ensure the effectiveness of our testing suite, we encourage contributors to adhere to the following guidelines when adding new integration tests: + +1. **Identification in Test Names:** + - All new integration tests should be clearly identifiable by having the word `Integration` in their names. For example: + ```go + func TestMongoIntegration(t *testing.T) { + // Test implementation + } + ``` + +2. **Short Test Skip:** + - Each integration test should begin with a specific check to skip the test if it is being run in short mode, for example: + ```go + func TestMongoIntegration(t *testing.T) { + if testing.Short() { + t.Skip() + } + // Test implementation + } + ``` + ```go + var _ = Describe("Some test", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + // Test implementation + }) + }) + ``` + + + +3. **Conditional Execution with Makefile:** + - Integration tests are designed to be executed explicitly. To run integration tests, use the Makefile target `integration-test`. This ensures that these tests are separate from unit tests and are run independently when needed. Unit tests are executed with the `-short` tag. + ```bash + make integration-test + ``` + +By following these guidelines, you contribute to a testing environment that accurately assesses the integration of our project with its dependencies. This separation of unit and integration tests allows for efficient testing and ensures that integration tests are only run when explicitly triggered, promoting a focused and effective testing strategy. + +### Running Database Integration Tests Locally + +To execute the database integration tests locally, follow these steps: + +1. Start the Docker containers configured in the `docker-compose-integration-test.yml` file located in the `deployments` directory: + + ```bash + $ make integration-test-compose-up + ``` + + This command initializes the required environment for running the integration tests. + +2. Run the tests using the following command: + + ```bash + $ make integration-test + ``` + + This Makefile target executes the database integration tests. + +Ensure that you have Docker installed on your machine before running the tests. + + ## Code of Conduct ### Our Pledge diff --git a/Makefile b/Makefile index d8e68af2..96962c0f 100644 --- a/Makefile +++ b/Makefile @@ -168,13 +168,26 @@ run-client-linux-json: build-client-linux ## Performs all unit tests using ginkgo test: - cd api && $(GO) test -coverprofile=c.out ./... + cd api && $(GO) test -coverprofile=c.out ./... -short cd api && $(GO) tool cover -func=c.out cd api && $(GO) tool cover -html=c.out -o coverage.html - cd client && $(GO) test -coverprofile=d.out ./... + cd client && $(GO) test -coverprofile=d.out ./... -short cd client && $(GO) tool cover -func=d.out - cd cli && $(GO) test -coverprofile=e.out ./... + cd cli && $(GO) test -coverprofile=e.out ./... -short cd cli && $(GO) tool cover -func=e.out +## Composes huskyCI integration test environment using docker-compose +integration-test-compose-up: + docker-compose -f deployments/docker-compose-integration-test.yml down -v + docker-compose -f deployments/docker-compose-integration-test.yml up -d --build --force-recreate + +## Composes down the integration test docker compose +integration-test-compose-down: + docker-compose -f deployments/docker-compose-integration-test.yml down -v + +## Run all integration tests. The tests must contain the 'Integration' on his name +integration-test: + cd api && $(GO) test -race ./... -run Integration + ## Builds and push securityTest containers with the latest tags update-containers: build-containers push-containers diff --git a/api/db/mongo/mongo_integration_test.go b/api/db/mongo/mongo_integration_test.go new file mode 100644 index 00000000..0a8cb58f --- /dev/null +++ b/api/db/mongo/mongo_integration_test.go @@ -0,0 +1,332 @@ +// Copyright 2019 Globo.com authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package db + +import ( + "testing" + "time" + + "github.com/globocom/huskyCI/api/log" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "gopkg.in/mgo.v2/bson" +) + +var collectionTest = "integration_test_collection" + +type mongoTestObj struct { + Attr1 string `bson:"attribute_1"` + Attr2 int `bson:"attribute_2"` +} + +func TestMongoIntegration(t *testing.T) { + if testing.Short() { + t.Skip() + } + + log.InitLog(true, "", "", "log_test", "log_test") + RegisterFailHandler(Fail) + RunSpecs(t, "MongoDB Suite") +} + +var _ = BeforeSuite(func() { + mongoAddress := "localhost" + dbName := "integration-test" + username := "" + password := "" + dbPort := 27017 + connectionPool := 10 + connectionTimeout := time.Duration(1 * time.Second) + + errConnect := Connect(mongoAddress, dbName, username, password, connectionPool, dbPort, connectionTimeout) + Expect(errConnect).To(BeNil()) + Expect(Conn).To(Not(BeNil())) +}) + +var _ = AfterSuite(func() { + colletction := Conn.Session.DB("").C(collectionTest) + err := colletction.DropCollection() + Expect(err).To(BeNil()) +}) + +var _ = Describe("Connect", func() { + Context("When connect to MongoDB with valid parameters", func() { + It("Should return no error when send ping", func() { + errPing := Conn.Session.Ping() + Expect(errPing).To(BeNil()) + }) + }) +}) + +var _ = Describe("Insert", func() { + Context("When insert a object", func() { + It("Should insert with success", func() { + newObj := mongoTestObj{ + Attr1: "insert-1", + Attr2: 11, + } + + errInsert := Conn.Insert(newObj, collectionTest) + Expect(errInsert).To(BeNil()) + + result := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "insert-1"}, nil, collectionTest, &result) + Expect(errGet).To(BeNil()) + + expectedResult := []mongoTestObj{ + { + Attr1: "insert-1", + Attr2: 11, + }, + } + + Expect(result).To(Equal(expectedResult)) + }) + }) +}) + +var _ = Describe("Update", func() { + Context("When update a object", func() { + It("Should update with success", func() { + err := Conn.Insert(mongoTestObj{Attr1: "update-1", Attr2: 11}, collectionTest) + Expect(err).To(BeNil()) + + updatedQuery := bson.M{ + "$set": mongoTestObj{ + Attr1: "update-2", + Attr2: 111, + }, + } + + errupdate := Conn.Update(bson.M{"attribute_1": "update-1"}, updatedQuery, collectionTest) + Expect(errupdate).To(BeNil()) + + result := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "update-2"}, nil, collectionTest, &result) + Expect(errGet).To(BeNil()) + + expectedResult := []mongoTestObj{ + { + Attr1: "update-2", + Attr2: 111, + }, + } + + Expect(result).To(Equal(expectedResult)) + }) + }) +}) + +var _ = Describe("UpdateAll", func() { + Context("When update objects", func() { + It("Should update all with success", func() { + errInsert1 := Conn.Insert(mongoTestObj{Attr1: "update-all-1", Attr2: 11}, collectionTest) + Expect(errInsert1).To(BeNil()) + + errInsert2 := Conn.Insert(mongoTestObj{Attr1: "update-all-1", Attr2: 22}, collectionTest) + Expect(errInsert2).To(BeNil()) + + updatedQuery := bson.M{ + "$set": mongoTestObj{ + Attr1: "update-all-2", + Attr2: 33, + }, + } + + errupdate := Conn.UpdateAll(bson.M{"attribute_1": "update-all-1"}, updatedQuery, collectionTest) + Expect(errupdate).To(BeNil()) + + result := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "update-all-2"}, nil, collectionTest, &result) + Expect(errGet).To(BeNil()) + + expectedResult := []mongoTestObj{ + { + Attr1: "update-all-2", + Attr2: 33, + }, + { + Attr1: "update-all-2", + Attr2: 33, + }, + } + + Expect(result).To(Equal(expectedResult)) + }) + }) +}) + +var _ = Describe("FindAndModify", func() { + Context("When find and modify a object", func() { + It("Should modify with success", func() { + objToInsert := mongoTestObj{Attr1: "find-and-modify-1", Attr2: 11} + err := Conn.Insert(objToInsert, collectionTest) + Expect(err).To(BeNil()) + + updatedQuery := bson.M{ + "$set": mongoTestObj{ + Attr1: "find-and-modify-2", + Attr2: 33, + }, + } + + resultFindModify := mongoTestObj{} + errFindModify := Conn.FindAndModify(bson.M{"attribute_1": "find-and-modify-1"}, updatedQuery, collectionTest, &resultFindModify) + Expect(errFindModify).To(BeNil()) + + resultGet := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "find-and-modify-2"}, nil, collectionTest, &resultGet) + Expect(errGet).To(BeNil()) + Expect(resultFindModify).To(Equal(objToInsert)) + + expectedResult := []mongoTestObj{ + { + Attr1: "find-and-modify-2", + Attr2: 33, + }, + } + + Expect(resultGet).To(Equal(expectedResult)) + }) + }) +}) + +var _ = Describe("Search", func() { + Context("When search a object", func() { + It("Should return with success", func() { + objToInsert := mongoTestObj{Attr1: "search-1", Attr2: 11} + err := Conn.Insert(objToInsert, collectionTest) + Expect(err).To(BeNil()) + + resultSearch := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "search-1"}, nil, collectionTest, &resultSearch) + Expect(errGet).To(BeNil()) + + expectedResult := []mongoTestObj{ + objToInsert, + } + + Expect(resultSearch).To(Equal(expectedResult)) + }) + }) +}) + +var _ = Describe("Aggregation", func() { + Context("When run aggregation with count", func() { + It("Should return count with success", func() { + objToInsert1 := mongoTestObj{Attr1: "aggregation-test", Attr2: 11} + err1 := Conn.Insert(objToInsert1, collectionTest) + Expect(err1).To(BeNil()) + + objToInsert2 := mongoTestObj{Attr1: "aggregation-test", Attr2: 22} + err2 := Conn.Insert(objToInsert2, collectionTest) + Expect(err2).To(BeNil()) + + aggregationQuery := []bson.M{ + { + "$match": bson.M{ + "attribute_1": bson.M{ + "$eq": "aggregation-test", + }, + }, + }, + { + "$match": bson.M{ + "attribute_2": bson.M{ + "$gte": 1, + }, + }, + }, + { + "$group": bson.M{ + "_id": nil, + "count": bson.M{ + "$sum": 1, + }, + }, + }, + } + + resultSearch, errGet := Conn.Aggregation(aggregationQuery, collectionTest) + Expect(errGet).To(BeNil()) + expectedResult := []bson.M{ + {"_id": nil, "count": 2}, + } + + Expect(resultSearch).To(Equal(expectedResult)) + }) + }) +}) + +var _ = Describe("SearchOne", func() { + Context("When search a object", func() { + It("Should return with success", func() { + objToInsert := mongoTestObj{Attr1: "search-one-1", Attr2: 11} + err := Conn.Insert(objToInsert, collectionTest) + Expect(err).To(BeNil()) + + resultSearch := mongoTestObj{} + errGet := Conn.SearchOne(bson.M{"attribute_1": "search-one-1"}, nil, collectionTest, &resultSearch) + Expect(errGet).To(BeNil()) + Expect(resultSearch).To(Equal(objToInsert)) + }) + }) +}) + +var _ = Describe("Upsert", func() { + Context("When upsert a object that doesn't exists", func() { + It("Should insert with success", func() { + obj := mongoTestObj{ + Attr1: "upsert-1", + Attr2: 11, + } + + query := bson.M{"attribute_1": "upsert-1"} + _, err := Conn.Upsert(query, obj, collectionTest) + Expect(err).To(BeNil()) + + result := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "upsert-1"}, nil, collectionTest, &result) + Expect(errGet).To(BeNil()) + + expectedResult := []mongoTestObj{ + { + Attr1: "upsert-1", + Attr2: 11, + }, + } + + Expect(result).To(Equal(expectedResult)) + }) + }) + Context("When upsert a object that already exists", func() { + It("Should update with success", func() { + errInsert := Conn.Insert(mongoTestObj{Attr1: "upsert-2", Attr2: 11}, collectionTest) + Expect(errInsert).To(BeNil()) + + obj := mongoTestObj{ + Attr1: "upsert-2", + Attr2: 22, + } + + query := bson.M{"attribute_1": "upsert-2"} + _, err := Conn.Upsert(query, obj, collectionTest) + Expect(err).To(BeNil()) + + result := []mongoTestObj{} + errGet := Conn.Search(bson.M{"attribute_1": "upsert-2"}, nil, collectionTest, &result) + Expect(errGet).To(BeNil()) + + expectedResult := []mongoTestObj{ + { + Attr1: "upsert-2", + Attr2: 22, + }, + } + + Expect(result).To(Equal(expectedResult)) + }) + }) +}) diff --git a/api/db/mongo_requests_integration_test.go b/api/db/mongo_requests_integration_test.go new file mode 100644 index 00000000..1ba2d8ad --- /dev/null +++ b/api/db/mongo_requests_integration_test.go @@ -0,0 +1,950 @@ +// Copyright 2019 Globo.com authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package db + +import ( + "testing" + "time" + + mongoHuskyCI "github.com/globocom/huskyCI/api/db/mongo" + "github.com/globocom/huskyCI/api/log" + "github.com/globocom/huskyCI/api/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "gopkg.in/mgo.v2" + "gopkg.in/mgo.v2/bson" +) + +var huskydbMongoRequestsTest MongoRequests + +func TestHuskyDBMongoRequestsIntegration(t *testing.T) { + if testing.Short() { + t.Skip() + } + + huskydbMongoRequestsTest = MongoRequests{} + log.InitLog(true, "", "", "log_test", "log_test") + RegisterFailHandler(Fail) + RunSpecs(t, "MongoRequests Suite") +} + +var _ = BeforeSuite(func() { + if testing.Short() { + return + } + + mongoAddress := "localhost" + dbName := "integration-test" + username := "" + password := "" + dbPort := 27017 + connectionTimeout := time.Duration(1 * time.Second) + connectionPool := 10 + maxOpenConns := 10 + maxIdleConns := 10 + connMaxLifetime := time.Duration(1 * time.Second) + + errConnect := huskydbMongoRequestsTest.ConnectDB(mongoAddress, dbName, username, password, connectionTimeout, connectionPool, dbPort, maxOpenConns, maxIdleConns, connMaxLifetime) + Expect(errConnect).To(BeNil()) + + prepareGetMetricByTypeData() +}) + +func prepareGetMetricByTypeData() { + analysisToInsert1 := types.Analysis{ + RID: "GetMetricByType - rid1", + URL: "GetMetricByType - url1", + Branch: "GetMetricByType - branch1", + CommitAuthors: []string{"author1", "author2"}, + Status: "GetMetricByType - status1", + Result: "GetMetricByType - result1", + ErrorFound: "GetMetricByType - errorFound1", + Containers: []types.Container{ + { + CID: "GetMetricByType - CID1", + SecurityTest: types.SecurityTest{ + Name: "GetMetricByType - Name1", + Image: "GetMetricByType - Image1", + ImageTag: "GetMetricByType - ImageTag1", + Cmd: "GetMetricByType - Cmd1", + Type: "GetMetricByType - Type1", + Language: "GetMetricByType - Language1", + Default: true, + TimeOutInSeconds: 10, + }, + CStatus: "GetMetricByType - CStatus1", + COutput: "GetMetricByType - COutput1", + CResult: "GetMetricByType - CResult1", + CInfo: "GetMetricByType - CInfo1", + StartedAt: time.Now(), + FinishedAt: time.Now().Add(1 * time.Minute), + }, + }, + StartedAt: time.Now(), + FinishedAt: time.Now().Add(1 * time.Minute), + Codes: []types.Code{ + { + Language: "go", + Files: []string{"gofile1", "gofile2"}, + }, + }, + HuskyCIResults: types.HuskyCIResults{ + GoResults: types.GoResults{ + HuskyCIGosecOutput: types.HuskyCISecurityTestOutput{ + NoSecVulns: []types.HuskyCIVulnerability{ + { + Language: "NoSecVulns.Language", + SecurityTool: "NoSecVulns.SecurityTool", + Severity: "NoSecVulns.Severity", + Confidence: "NoSecVulns.Confidence", + File: "NoSecVulns.File", + Line: "NoSecVulns.Line", + Code: "NoSecVulns.Code", + Details: "NoSecVulns.Details", + Type: "NoSecVulns.Type", + Title: "NoSecVulns.Title", + VunerableBelow: "NoSecVulns.VunerableBelow", + Version: "NoSecVulns.Version", + Occurrences: 1, + }, + }, + LowVulns: []types.HuskyCIVulnerability{ + { + Language: "LowVulns.Language", + SecurityTool: "LowVulns.SecurityTool", + Severity: "LowVulns.Severity", + Confidence: "LowVulns.Confidence", + File: "LowVulns.File", + Line: "LowVulns.Line", + Code: "LowVulns.Code", + Details: "LowVulns.Details", + Type: "LowVulns.Type", + Title: "LowVulns.Title", + VunerableBelow: "LowVulns.VunerableBelow", + Version: "LowVulns.Version", + Occurrences: 2, + }, + }, + MediumVulns: []types.HuskyCIVulnerability{ + { + Language: "MediumVulns.Language", + SecurityTool: "MediumVulns.SecurityTool", + Severity: "MediumVulns.Severity", + Confidence: "MediumVulns.Confidence", + File: "MediumVulns.File", + Line: "MediumVulns.Line", + Code: "MediumVulns.Code", + Details: "MediumVulns.Details", + Type: "MediumVulns.Type", + Title: "MediumVulns.Title", + VunerableBelow: "MediumVulns.VunerableBelow", + Version: "MediumVulns.Version", + Occurrences: 3, + }, + }, + HighVulns: []types.HuskyCIVulnerability{ + { + Language: "HighVulns.Language", + SecurityTool: "HighVulns.SecurityTool", + Severity: "HighVulns.Severity", + Confidence: "HighVulns.Confidence", + File: "HighVulns.File", + Line: "HighVulns.Line", + Code: "HighVulns.Code", + Details: "HighVulns.Details", + Type: "HighVulns.Type", + Title: "HighVulns.Title", + VunerableBelow: "HighVulns.VunerableBelow", + Version: "HighVulns.Version", + Occurrences: 4, + }, + }, + }, + }, + }, + } + + errInsert := mongoHuskyCI.Conn.Insert(analysisToInsert1, mongoHuskyCI.AnalysisCollection) + Expect(errInsert).To(BeNil()) + + analysisToInsert2 := types.Analysis{ + RID: "GetMetricByType - rid2", + URL: "GetMetricByType - url2", + Branch: "GetMetricByType - branch2", + CommitAuthors: []string{"author1", "author2"}, + Status: "GetMetricByType - status2", + Result: "GetMetricByType - result2", + ErrorFound: "GetMetricByType - errorFound2", + Containers: []types.Container{ + { + CID: "GetMetricByType - CID2", + SecurityTest: types.SecurityTest{ + Name: "GetMetricByType - Name2", + Image: "GetMetricByType - Image2", + ImageTag: "GetMetricByType - ImageTag2", + Cmd: "GetMetricByType - Cmd2", + Type: "GetMetricByType - Type2", + Language: "GetMetricByType - Language2", + Default: true, + TimeOutInSeconds: 20, + }, + CStatus: "GetMetricByType - CStatus2", + COutput: "GetMetricByType - COutput2", + CResult: "GetMetricByType - CResult2", + CInfo: "GetMetricByType - CInfo2", + StartedAt: time.Now(), + FinishedAt: time.Now().Add(1 * time.Minute), + }, + }, + StartedAt: time.Now(), + FinishedAt: time.Now().Add(1 * time.Minute), + Codes: []types.Code{ + { + Language: "go", + Files: []string{"gofile1", "gofile2"}, + }, + }, + HuskyCIResults: types.HuskyCIResults{}, + } + + errInsert = mongoHuskyCI.Conn.Insert(analysisToInsert2, mongoHuskyCI.AnalysisCollection) + Expect(errInsert).To(BeNil()) +} + +var _ = AfterSuite(func() { + if testing.Short() { + return + } + + err := mongoHuskyCI.Conn.Session.DB("").DropDatabase() + Expect(err).To(BeNil()) +}) + +var _ = Describe("DBRepository", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When try to find one", func() { + It("Should return mgo.ErrNotFound and empty types.Repository{} when not found", func() { + query := map[string]interface{}{"repositoryURL": "not found URL"} + + repository, err := huskydbMongoRequestsTest.FindOneDBRepository(query) + Expect(err).To(Equal(mgo.ErrNotFound)) + + expectedResult := types.Repository{} + Expect(repository).To(Equal(expectedResult)) + }) + It("Should return no error and types.Repository{} correctly", func() { + repositoryToInsert := types.Repository{ + URL: "http://github.com/findonerepository", + } + + errInsert := huskydbMongoRequestsTest.InsertDBRepository(repositoryToInsert) + Expect(errInsert).To(BeNil()) + + query := map[string]interface{}{"repositoryURL": repositoryToInsert.URL} + + repository, errGet := huskydbMongoRequestsTest.FindOneDBRepository(query) + Expect(errGet).To(BeNil()) + Expect(repository).To(Equal(repositoryToInsert)) + }) + }) + Context("When try to find all", func() { + It("Should return no error and empty repository array when not found", func() { + query := map[string]interface{}{"repositoryURL": "not found URL"} + + repository, err := huskydbMongoRequestsTest.FindAllDBRepository(query) + Expect(err).To(BeNil()) + + expectedResult := []types.Repository{} + Expect(repository).To(Equal(expectedResult)) + }) + It("Should return no error and types.Repository{} correctly", func() { + repositoryToInsert1 := types.Repository{ + URL: "http://github.com/findallrepository", + } + + errInsert := huskydbMongoRequestsTest.InsertDBRepository(repositoryToInsert1) + Expect(errInsert).To(BeNil()) + + repositoryToInsert2 := types.Repository{ + URL: "http://github.com/findallrepository", + } + + errInsert = huskydbMongoRequestsTest.InsertDBRepository(repositoryToInsert2) + Expect(errInsert).To(BeNil()) + + query := map[string]interface{}{ + "repositoryURL": "http://github.com/findallrepository", + } + + expectedResult := []types.Repository{ + repositoryToInsert1, + repositoryToInsert2, + } + + result, errGet := huskydbMongoRequestsTest.FindAllDBRepository(query) + Expect(errGet).To(BeNil()) + Expect(result).To(Equal(expectedResult)) + }) + }) + Context("When update one", func() { + It("Should return no error and update correctly", func() { + repositoryToInsert := types.Repository{ + URL: "http://github.com/updateOneRepository", + CreatedAt: time.Date(2023, 11, 20, 0, 0, 0, 0, time.UTC).Local(), + } + + errInsert := huskydbMongoRequestsTest.InsertDBRepository(repositoryToInsert) + Expect(errInsert).To(BeNil()) + + repositoryToUpdate := types.Repository{ + URL: "http://github.com/updateOneRepository", + CreatedAt: time.Date(2024, 11, 20, 0, 0, 0, 0, time.UTC).Local(), + } + + query := map[string]interface{}{"repositoryURL": repositoryToInsert.URL} + updateQuery := map[string]interface{}{ + "repositoryURL": repositoryToUpdate.URL, + "createdAt": repositoryToUpdate.CreatedAt, + } + errUpdate := huskydbMongoRequestsTest.UpdateOneDBRepository(query, updateQuery) + Expect(errUpdate).To(BeNil()) + + repository, errGet := huskydbMongoRequestsTest.FindOneDBRepository(query) + Expect(errGet).To(BeNil()) + Expect(repository).To(Equal(repositoryToUpdate)) + }) + }) +}) + +var _ = Describe("DBSecurityTest", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When try to find one", func() { + It("Should return mgo.ErrNotFound and empty types.SecurityTest{} when not found", func() { + query := map[string]interface{}{"name": "security_test_name"} + + repository, err := huskydbMongoRequestsTest.FindOneDBSecurityTest(query) + Expect(err).To(Equal(mgo.ErrNotFound)) + + expectedResult := types.SecurityTest{} + Expect(repository).To(Equal(expectedResult)) + }) + It("Should return no error and types.SecurityTest{} correctly", func() { + securityTestToInsert := types.SecurityTest{ + Name: "security_test_name", + Image: "some image", + Cmd: "some cmd", + Language: "some language", + Type: "some type", + Default: false, + TimeOutInSeconds: 10, + } + + errInsert := huskydbMongoRequestsTest.InsertDBSecurityTest(securityTestToInsert) + Expect(errInsert).To(BeNil()) + + query := map[string]interface{}{"name": "security_test_name"} + + repository, errGet := huskydbMongoRequestsTest.FindOneDBSecurityTest(query) + Expect(errGet).To(BeNil()) + Expect(repository).To(Equal(securityTestToInsert)) + }) + }) + Context("When try to find all", func() { + It("Should return no error and empty types.SecurityTest{} array when not found", func() { + query := map[string]interface{}{"type": "type_find_all"} + + repository, err := huskydbMongoRequestsTest.FindAllDBSecurityTest(query) + Expect(err).To(BeNil()) + + expectedResult := []types.SecurityTest{} + Expect(repository).To(Equal(expectedResult)) + }) + It("Should return no error and types.SecurityTest{} correctly", func() { + securityTestToInsert1 := types.SecurityTest{ + Name: "security_test_name_1", + Image: "some image", + Cmd: "some cmd", + Language: "some language", + Type: "type_find_all", + Default: false, + TimeOutInSeconds: 10, + } + + errInsert := huskydbMongoRequestsTest.InsertDBSecurityTest(securityTestToInsert1) + Expect(errInsert).To(BeNil()) + + securityTestToInsert2 := types.SecurityTest{ + Name: "security_test_name_2", + Image: "some image", + Cmd: "some cmd", + Language: "some language", + Type: "type_find_all", + Default: false, + TimeOutInSeconds: 10, + } + + errInsert = huskydbMongoRequestsTest.InsertDBSecurityTest(securityTestToInsert2) + Expect(errInsert).To(BeNil()) + + expectResult := []types.SecurityTest{ + securityTestToInsert1, + securityTestToInsert2, + } + + query := map[string]interface{}{"type": "type_find_all"} + repository, errGet := huskydbMongoRequestsTest.FindAllDBSecurityTest(query) + Expect(errGet).To(BeNil()) + Expect(repository).To(Equal(expectResult)) + }) + }) + Context("When updated one", func() { + It("Should return no error and update correctly", func() { + securityTestToInsert := types.SecurityTest{ + Name: "security_test_update_one", + Image: "some image", + Cmd: "some cmd", + Language: "some language", + Type: "some type", + Default: false, + TimeOutInSeconds: 10, + } + + errInsert := huskydbMongoRequestsTest.InsertDBSecurityTest(securityTestToInsert) + Expect(errInsert).To(BeNil()) + + securityTestToUpdate := types.SecurityTest{ + Name: "security_test_update_one", + Image: "changed image", + Cmd: "changed cmd", + Language: "changed language", + Type: "changed type", + Default: true, + TimeOutInSeconds: 20, + } + + query := map[string]interface{}{"name": "security_test_update_one"} + _, errUpdate := huskydbMongoRequestsTest.UpsertOneDBSecurityTest(query, securityTestToUpdate) + Expect(errUpdate).To(BeNil()) + + repository, errGet := huskydbMongoRequestsTest.FindOneDBSecurityTest(query) + Expect(errGet).To(BeNil()) + Expect(repository).To(Equal(securityTestToUpdate)) + }) + }) +}) + +var _ = Describe("DBAnalysis", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When try to find one", func() { + It("Should return mgo.ErrNotFound and empty types.Analysis{} when not found", func() { + query := map[string]interface{}{"RID": "test-id"} + + analysis, err := huskydbMongoRequestsTest.FindOneDBAnalysis(query) + Expect(err).To(Equal(mgo.ErrNotFound)) + + expectedResult := types.Analysis{} + Expect(analysis).To(Equal(expectedResult)) + }) + It("Should return no error and types.Analysis{} correctly", func() { + analysisToInsert := types.Analysis{ + RID: "test-id", + URL: "some url", + Branch: "some branch", + Status: "some status", + Result: "some result", + Containers: []types.Container{}, + } + + errInsert := huskydbMongoRequestsTest.InsertDBAnalysis(analysisToInsert) + Expect(errInsert).To(BeNil()) + + query := map[string]interface{}{"RID": "test-id"} + + analysis, errGet := huskydbMongoRequestsTest.FindOneDBAnalysis(query) + Expect(errGet).To(BeNil()) + Expect(analysis).To(Equal(analysisToInsert)) + }) + }) + Context("When try to find all", func() { + It("Should return no error and empty types.Analysis{} array when not found", func() { + query := map[string]interface{}{"status": "status-find-all-not-found"} + + analysis, err := huskydbMongoRequestsTest.FindAllDBAnalysis(query) + Expect(err).To(BeNil()) + + expectedResult := []types.Analysis{} + Expect(analysis).To(Equal(expectedResult)) + }) + It("Should return no error and []types.Analysis{} correctly", func() { + analysisToInsert1 := types.Analysis{ + RID: "test-id-1", + URL: "some url", + Branch: "some branch", + Status: "status-find-all", + Result: "some result", + Containers: []types.Container{}, + } + + errInsert := huskydbMongoRequestsTest.InsertDBAnalysis(analysisToInsert1) + Expect(errInsert).To(BeNil()) + + analysisToInsert2 := types.Analysis{ + RID: "test-id-2", + URL: "some url", + Branch: "some branch", + Status: "status-find-all", + Result: "some result", + Containers: []types.Container{}, + } + + errInsert = huskydbMongoRequestsTest.InsertDBAnalysis(analysisToInsert2) + Expect(errInsert).To(BeNil()) + + expectedResult := []types.Analysis{ + analysisToInsert1, + analysisToInsert2, + } + + query := map[string]interface{}{"status": "status-find-all"} + analysis, errGet := huskydbMongoRequestsTest.FindAllDBAnalysis(query) + Expect(errGet).To(BeNil()) + Expect(analysis).To(Equal(expectedResult)) + }) + }) + Context("When update one", func() { + It("Should return no error and update correctly", func() { + analysisToInsert := types.Analysis{ + RID: "test-id-update-one", + URL: "some url", + Branch: "some branch", + Status: "some status", + Result: "some result", + Containers: []types.Container{}, + } + + errInsert := huskydbMongoRequestsTest.InsertDBAnalysis(analysisToInsert) + Expect(errInsert).To(BeNil()) + + analysisToUpdate := types.Analysis{ + RID: "test-id-update-one", + URL: "changed url", + Branch: "some branch", + Status: "some status", + Result: "some result", + Containers: []types.Container{}, + } + + query := map[string]interface{}{"RID": "test-id-update-one"} + toUpdate := map[string]interface{}{"repositoryURL": analysisToUpdate.URL} + + errUpdate := huskydbMongoRequestsTest.UpdateOneDBAnalysis(query, toUpdate) + Expect(errUpdate).To(BeNil()) + + analysis, errGet := huskydbMongoRequestsTest.FindOneDBAnalysis(query) + Expect(errGet).To(BeNil()) + Expect(analysis).To(Equal(analysisToUpdate)) + }) + }) + Context("When update one analysis container", func() { + It("Should return no error and update correctly", func() { + analysisToInsert := types.Analysis{ + RID: "test-id-update-one-analysis-container", + URL: "some url", + Branch: "some branch", + Status: "some status", + Result: "some result", + Containers: []types.Container{}, + } + + errInsert := huskydbMongoRequestsTest.InsertDBAnalysis(analysisToInsert) + Expect(errInsert).To(BeNil()) + + analysisToUpdate := types.Analysis{ + RID: "test-id-update-one-analysis-container", + URL: "changed url", + Branch: "some branch", + Status: "some status", + Result: "some result", + Containers: []types.Container{}, + } + + query := map[string]interface{}{"RID": "test-id-update-one-analysis-container"} + toUpdate := map[string]interface{}{"repositoryURL": analysisToUpdate.URL} + + errUpdate := huskydbMongoRequestsTest.UpdateOneDBAnalysisContainer(query, toUpdate) + Expect(errUpdate).To(BeNil()) + + analysis, errGet := huskydbMongoRequestsTest.FindOneDBAnalysis(query) + Expect(errGet).To(BeNil()) + Expect(analysis).To(Equal(analysisToUpdate)) + }) + }) +}) + +var _ = Describe("DBUser", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When try to find one", func() { + It("Should return mgo.ErrNotFound and empty types.User{} when not found", func() { + query := map[string]interface{}{"username": "some user name"} + + user, err := huskydbMongoRequestsTest.FindOneDBUser(query) + Expect(err).To(Equal(mgo.ErrNotFound)) + + expectedResult := types.User{} + Expect(user).To(Equal(expectedResult)) + }) + It("Should return no error and types.User{} correctly", func() { + userToInsert := types.User{ + Username: "some user name", + Password: "some password", + Salt: "some salt", + Iterations: 1, + KeyLen: 10, + HashFunction: "some hash function", + } + + errInsert := huskydbMongoRequestsTest.InsertDBUser(userToInsert) + Expect(errInsert).To(BeNil()) + + query := map[string]interface{}{"username": "some user name"} + + user, errGet := huskydbMongoRequestsTest.FindOneDBUser(query) + Expect(errGet).To(BeNil()) + Expect(user).To(Equal(userToInsert)) + }) + }) + Context("When update one", func() { + It("Should return no error and update correctly", func() { + userToInsert := types.User{ + Username: "update_one_username", + Password: "some password", + Salt: "some salt", + Iterations: 1, + KeyLen: 10, + HashFunction: "some hash function", + } + + errInsert := huskydbMongoRequestsTest.InsertDBUser(userToInsert) + Expect(errInsert).To(BeNil()) + + userToUpdate := types.User{ + Username: "update_one_username", + Password: "changed password", + Salt: "changed salt", + Iterations: 2, + KeyLen: 20, + HashFunction: "changed hash function", + } + + query := map[string]interface{}{"username": "update_one_username"} + errUpdate := huskydbMongoRequestsTest.UpdateOneDBUser(query, userToUpdate) + Expect(errUpdate).To(BeNil()) + + user, errGet := huskydbMongoRequestsTest.FindOneDBUser(query) + Expect(errGet).To(BeNil()) + Expect(user).To(Equal(userToUpdate)) + }) + }) +}) + +var _ = Describe("DBAccessToken", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When try to find one", func() { + It("Should return mgo.ErrNotFound and empty types.DBToken{} when not found", func() { + query := map[string]interface{}{"uuid": "some uuid"} + + user, err := huskydbMongoRequestsTest.FindOneDBAccessToken(query) + Expect(err).To(Equal(mgo.ErrNotFound)) + + expectedResult := types.DBToken{} + Expect(user).To(Equal(expectedResult)) + }) + It("Should return no error and types.DBToken{} correctly", func() { + dbToken := types.DBToken{ + HuskyToken: "some token", + URL: "some url", + IsValid: true, + Salt: "some salt", + UUID: "some uuid", + } + + errInsert := huskydbMongoRequestsTest.InsertDBAccessToken(dbToken) + Expect(errInsert).To(BeNil()) + + query := map[string]interface{}{"uuid": "some uuid"} + + user, errGet := huskydbMongoRequestsTest.FindOneDBAccessToken(query) + Expect(errGet).To(BeNil()) + Expect(user).To(Equal(dbToken)) + }) + }) + Context("When update one", func() { + It("Should return no error and update correctly", func() { + dbTokenToInsert := types.DBToken{ + HuskyToken: "some token", + URL: "some url", + IsValid: true, + Salt: "some salt", + UUID: "some_update_one_uuid", + } + + errInsert := huskydbMongoRequestsTest.InsertDBAccessToken(dbTokenToInsert) + Expect(errInsert).To(BeNil()) + + dbTokenToUpdate := types.DBToken{ + HuskyToken: "changed token", + URL: "changed url", + IsValid: false, + Salt: "changed salt", + UUID: "some_update_one_uuid", + } + + query := map[string]interface{}{"uuid": "some_update_one_uuid"} + errUpdate := huskydbMongoRequestsTest.UpdateOneDBAccessToken(query, dbTokenToUpdate) + Expect(errUpdate).To(BeNil()) + + user, errGet := huskydbMongoRequestsTest.FindOneDBAccessToken(query) + Expect(errGet).To(BeNil()) + Expect(user).To(Equal(dbTokenToUpdate)) + }) + }) +}) + +var _ = Describe("DockerAPIAddresses", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When update one", func() { + It("Should return no error and modify correctly", func() { + dockerAPIAddressesToInsert := types.DockerAPIAddresses{ + CurrentHostIndex: 0, + HostList: []string{"host1", "host2"}, + } + + errInsert := mongoHuskyCI.Conn.Insert(dockerAPIAddressesToInsert, mongoHuskyCI.DockerAPIAddressesCollection) + Expect(errInsert).To(BeNil()) + + updatedDockerAPIAddressesResult, err := huskydbMongoRequestsTest.FindAndModifyDockerAPIAddresses() + Expect(err).To(BeNil()) + Expect(updatedDockerAPIAddressesResult).To(Equal(dockerAPIAddressesToInsert)) + + dockerAPIAddressesFindResult := []types.DockerAPIAddresses{} + errFind := mongoHuskyCI.Conn.Search(bson.M{}, nil, mongoHuskyCI.DockerAPIAddressesCollection, &dockerAPIAddressesFindResult) + Expect(errFind).To(BeNil()) + + expectedDockerApiAddress := []types.DockerAPIAddresses{ + { + CurrentHostIndex: 1, + HostList: []string{"host1", "host2"}, + }, + } + + Expect(dockerAPIAddressesFindResult).To(Equal(expectedDockerApiAddress)) + }) + }) +}) + +var _ = Describe("GetMetricByType", func() { + BeforeEach(func() { + if testing.Short() { + Skip("Integration tests don't run with 'short' flag") + } + }) + + Context("When get 'language' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + expectedResult := []bson.M{ + {"_id": "go", "count": 2, "language": "go"}, + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("language", queryStringParams) + Expect(errGet).To(BeNil()) + Expect(metric).To(Equal(expectedResult)) + }) + }) + Context("When get 'container' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + expectedResult := []bson.M{ + { + "_id": "GetMetricByType - Name1", + "count": 1, + "container": "GetMetricByType - Name1", + }, + { + "_id": "GetMetricByType - Name2", + "count": 1, + "container": "GetMetricByType - Name2", + }, + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("container", queryStringParams) + Expect(errGet).To(BeNil()) + Expect(metric).To(ConsistOf(expectedResult)) + }) + }) + Context("When get 'analysis' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + expectedResult := []bson.M{ + { + "_id": "GetMetricByType - result2", + "count": 1, + "result": "GetMetricByType - result2", + }, + { + "_id": "GetMetricByType - result1", + "count": 1, + "result": "GetMetricByType - result1", + }, + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("analysis", queryStringParams) + Expect(errGet).To(BeNil()) + Expect(metric).To(ConsistOf(expectedResult)) + }) + }) + Context("When get 'repository' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + expectedResult := []bson.M{ + { + "_id": "repositories", + "totalBranches": 2, + "totalRepositories": 2, + }, + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("repository", queryStringParams) + Expect(errGet).To(BeNil()) + Expect(metric).To(ConsistOf(expectedResult)) + }) + }) + Context("When get 'author' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + expectedResult := []bson.M{ + { + "_id": "commitAuthors", + "totalAuthors": 2, + }, + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("author", queryStringParams) + Expect(errGet).To(BeNil()) + Expect(metric).To(ConsistOf(expectedResult)) + }) + }) + Context("When get 'severity' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + expectedResult := []bson.M{ + { + "_id": "lowvulns", + "count": 1, + "severity": "lowvulns", + }, + { + "_id": "highvulns", + "count": 1, + "severity": "highvulns", + }, + { + "severity": "nosecvulns", + "_id": "nosecvulns", + "count": 1, + }, + { + "count": 1, + "severity": "mediumvulns", + "_id": "mediumvulns", + }, + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("severity", queryStringParams) + Expect(errGet).To(BeNil()) + Expect(metric).To(ConsistOf(expectedResult)) + }) + }) + Context("When get 'historyanalysis' metric", func() { + It("Should return correctly", func() { + queryStringParams := map[string][]string{ + "time_range": {"today"}, + } + + now := time.Now() + expectedResult := bson.M{ + "results": []interface{}{ + bson.M{ + "result": "GetMetricByType - result2", + "count": 1, + }, + bson.M{ + "result": "GetMetricByType - result1", + "count": 1, + }, + }, + "total": 2, + "date": time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, time.Local), + } + + metric, errGet := huskydbMongoRequestsTest.GetMetricByType("historyanalysis", queryStringParams) + Expect(errGet).To(BeNil()) + + firstMetric := metric.([]bson.M)[0] + + Expect(firstMetric["results"]).To(ConsistOf(expectedResult["results"])) + Expect(firstMetric["total"]).To(Equal(expectedResult["total"])) + Expect(firstMetric["date"]).To(Equal(expectedResult["date"])) + }) + }) +}) diff --git a/api/token/token_test.go b/api/token/token_test.go index 95ba54eb..73db4e8c 100644 --- a/api/token/token_test.go +++ b/api/token/token_test.go @@ -213,34 +213,6 @@ var _ = Describe("Token", func() { Expect(err).To(Equal(fakeHash.expectedDecodeSaltError)) }) }) - Context("When GetValidHashFunction returns a false boolean", func() { - It("Should return the expected error", func() { - fakeExt := FakeExternal{ - expectedURL: "MyValidURL", - expectedValidateError: nil, - expectedToken: "MyBrandNewToken", - expectedGenerateError: nil, - } - fakeHash := FakeHashGen{ - expectedSalt: "MySalt", - expectedGenerateSaltError: nil, - expectedDecodedSalt: make([]byte, 0), - expectedDecodeSaltError: nil, - expectedHashName: "", - expectedKeyLength: 32, - expectedIterations: 1024, - } - tokenGen := THandler{ - External: &fakeExt, - HashGen: &fakeHash, - } - accessToken, err := tokenGen.GenerateAccessToken(types.TokenRequest{ - RepositoryURL: "myRepo.com", - }) - Expect(accessToken).To(Equal("")) - Expect(err).To(Equal(errors.New("Invalid hash function"))) - }) - }) Context("When StoreAccessToken returns an error", func() { It("Should return the same error and an empty string", func() { fakeExt := FakeExternal{ diff --git a/api/util/api/api_test.go b/api/util/api/api_test.go index 1d36483c..e76937a7 100644 --- a/api/util/api/api_test.go +++ b/api/util/api/api_test.go @@ -2,6 +2,7 @@ package util_test import ( "errors" + "os" "github.com/globocom/glbgelf" apiContext "github.com/globocom/huskyCI/api/context" @@ -50,6 +51,7 @@ var _ = Describe("Util API", func() { }) }) Context("When checkKubernetesHosts returns an error", func() { + fakeCheck := &apiUtil.FakeCheck{ EnvVarsError: checkHuskyTests[1].envVarsError, KubernetesHostsError: checkHuskyTests[1].dockerHostsError, @@ -60,7 +62,9 @@ var _ = Describe("Util API", func() { CheckHandler: fakeCheck, } It("Should return the same error", func() { + os.Setenv("HUSKYCI_INFRASTRUCTURE_USE", "kubernetes") Expect(huskyCheck.CheckHuskyRequirements(checkHuskyTests[1].configApi)).To(Equal(checkHuskyTests[1].expectedError)) + os.Unsetenv("HUSKYCI_INFRASTRUCTURE_USE") }) }) Context("When checkMongoDB returns an error", func() { diff --git a/deployments/docker-compose-integration-test.yml b/deployments/docker-compose-integration-test.yml new file mode 100644 index 00000000..36d709fa --- /dev/null +++ b/deployments/docker-compose-integration-test.yml @@ -0,0 +1,7 @@ +version: '3.8' +services: + mongodb: + container_name: huskyCI_MongoDB + image: mongo:4.2.2 + ports: + - "27017:27017"