// Test all phases from a domain lyfe cycle, but now working with a group of domains func domainsLifeCycle(domainDAO dao.DomainDAO) { domains := newDomains() // Create domains domainResults := domainDAO.SaveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Couldn't save domain %s in database", domainResult.Domain.FQDN), domainResult.Error) } } for _, domain := range domains { // Search and compare created domains if domainRetrieved, err := domainDAO.FindByFQDN(domain.FQDN); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find created domain %s in database", domain.FQDN), err) } else if !utils.CompareDomain(*domain, domainRetrieved) { utils.Fatalln(fmt.Sprintf("Domain %s created is being persisted wrongly", domain.FQDN), nil) } } // Update domains for _, domain := range domains { domain.Owners = []model.Owner{} } domainResults = domainDAO.SaveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Couldn't update domain %s in database", domainResult.Domain.FQDN), domainResult.Error) } } for _, domain := range domains { // Search and compare updated domains if domainRetrieved, err := domainDAO.FindByFQDN(domain.FQDN); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find updated domain %s in database", domain.FQDN), err) } else if !utils.CompareDomain(*domain, domainRetrieved) { utils.Fatalln(fmt.Sprintf("Domain %s updated in being persisted wrongly", domain.FQDN), nil) } } // Check if find all really return all domains allDomainsChannel, err := domainDAO.FindAllAsync() if err != nil { utils.Fatalln("Error while retrieving all domains from database", err) } var allDomains []model.Domain for { domainRetrieved := <-allDomainsChannel if domainRetrieved.Error != nil { utils.Fatalln("Error while retrieving all domains from database", err) } else if domainRetrieved.Domain == nil { break } allDomains = append(allDomains, *domainRetrieved.Domain) } if len(allDomains) != len(domains) { utils.Fatalln(fmt.Sprintf("FindAll method is not returning all domains we expected %d but got %d", len(domains), len(allDomains)), nil) } // Detected a problem in FindAsync method on 2014-01-17 where we were returning the same // object many times because we were reusing the same pointer. For that reason we are // going to add a test to check if the items returned are the same set of the inserted // ones for _, domain := range domains { found := false for _, domainRetrieved := range allDomains { if domainRetrieved.Id.Hex() == domain.Id.Hex() { found = true break } } if !found { utils.Fatalln("FindAll method is not returning all objects "+ "that were inserted, apparently there are duplicated objects in the result set", nil) } } // Remove domains domainResults = domainDAO.RemoveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Error while trying to remove domain %s from database", domainResult.Domain.FQDN), domainResult.Error) } } for _, domain := range domains { // Check removals if _, err := domainDAO.FindByFQDN(domain.FQDN); err == nil { utils.Fatalln(fmt.Sprintf("Domain %s was not removed from database", domain.FQDN), nil) } } // Let's add and remove the domains again to test the remove all method domainResults = domainDAO.SaveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Couldn't save domain %s in database", domainResult.Domain.FQDN), domainResult.Error) } } if err := domainDAO.RemoveAll(); err != nil { utils.Fatalln("Couldn't remove all domains", err) } allDomainsChannel, err = domainDAO.FindAllAsync() if err != nil { utils.Fatalln("Error while retrieving all domains from database", err) } allDomains = []model.Domain{} for { domainRetrieved := <-allDomainsChannel if domainRetrieved.Error != nil { utils.Fatalln("Error while retrieving all domains from database", err) } else if domainRetrieved.Domain == nil { break } allDomains = append(allDomains, *domainRetrieved.Domain) } if len(allDomains) > 0 { utils.Fatalln("RemoveAll method is not removing the domains from the database", nil) } }
// Method that starts the injector job, retrieving the data from the database and adding // the same data into a channel for a querier start sending DNS requests. There are two // parameters, one to control the scan go routines and sinalize to the main thread the // end, and other to define a channel to report errors while loading the data. This method // is asynchronous and will finish sending a poison pill (error or nil domain) to indicate // to the querier that there are no more domains func (i *Injector) Start(scanGroup *sync.WaitGroup, errorsChannel chan error) chan *model.Domain { // Create the output channel where we are going to add the domains retrieved from the // database for the querier domainsToQueryChannel := make(chan *model.Domain, i.DomainsBufferSize) // Add one more to the group of scan go routines scanGroup.Add(1) go func() { // Initialize Domain DAO using injected database connection domainDAO := dao.DomainDAO{ Database: i.Database, } // Load all domains from database to begin the scan domainChannel, err := domainDAO.FindAllAsync() // Low level error was detected. No domain was processed yet, but we still need to // shutdown the querier and by consequence the collector, so we send back the error // and add the poison pill if err != nil { errorsChannel <- err domainsToQueryChannel <- nil // Tells the scan information structure that the injector is done model.FinishLoadingDomainsForScan() scanGroup.Done() return } // Dispatch the asynchronous part of the method for { // Get domain from the database (one-by-one) domainResult := <-domainChannel // Send back the error to the caller thread. We don't log the error here directly // into the log interface because sometimes we want to do something when an error // occurs, like in a test enviroment if domainResult.Error != nil { errorsChannel <- domainResult.Error } // Problem detected while retrieving a domain or we don't have domains anymore, send // the poison pill to alert the querier if domainResult.Error != nil || domainResult.Domain == nil { domainsToQueryChannel <- nil // Tells the scan information structure that the injector is done model.FinishLoadingDomainsForScan() scanGroup.Done() return } // The logic that decides if a domain is going to be a part of this scan or not is // inside the domain object for better unit testing if domainResult.Domain.ShouldBeScanned(i.MaxOKVerificationDays, i.MaxErrorVerificationDays, i.MaxExpirationAlertDays) { // Send to the querier domainsToQueryChannel <- domainResult.Domain // Count domain for the scan information to estimate the scan progress model.LoadedDomainForScan() } } }() return domainsToQueryChannel }