func StartRunnerAndMakeConnection(manifest *manifest.Manifest, reporter reporter.Reporter, killChannel chan bool) (*TestRunner, error) { port, err := conn.GetPortFromEnvironmentVariable(common.GaugePortEnvName) if err != nil { port = 0 } gaugeConnectionHandler, connHandlerErr := conn.NewGaugeConnectionHandler(port, nil) if connHandlerErr != nil { return nil, connHandlerErr } testRunner, err := startRunner(manifest, strconv.Itoa(gaugeConnectionHandler.ConnectionPortNumber()), reporter, killChannel) if err != nil { return nil, err } runnerConnection, connectionError := gaugeConnectionHandler.AcceptConnection(config.RunnerConnectionTimeout(), testRunner.ErrorChannel) testRunner.Connection = runnerConnection if connectionError != nil { logger.Debug("Runner connection error: %s", connectionError) err := testRunner.killRunner() if err != nil { logger.Debug("Error while killing runner: %s", err) } return nil, connectionError } return testRunner, nil }
// DownloadAndUnzip downloads the zip file from given download link and unzips it. // Returns the unzipped file path. func DownloadAndUnzip(downloadLink string, tempDir string) (string, error) { logger.Debug("Downloading => %s", downloadLink) downloadedFile, err := common.Download(downloadLink, tempDir) if err != nil { return "", fmt.Errorf("Could not download file %s: %s", downloadLink, err.Error()) } logger.Debug("Downloaded to %s", downloadedFile) unzippedPluginDir, err := common.UnzipArchive(downloadedFile, tempDir) if err != nil { return "", fmt.Errorf("Failed to Unzip file %s: %s", downloadedFile, err.Error()) } logger.Debug("Unzipped to => %s\n", unzippedPluginDir) return unzippedPluginDir, nil }
func (p *plugin) kill(wg *sync.WaitGroup) error { defer wg.Done() if p.IsProcessRunning() { defer p.connection.Close() conn.SendProcessKillMessage(p.connection) exited := make(chan bool, 1) go func() { for { if p.IsProcessRunning() { time.Sleep(100 * time.Millisecond) } else { exited <- true return } } }() select { case done := <-exited: if done { logger.Debug("Plugin [%s] with pid [%d] has exited", p.descriptor.Name, p.pluginCmd.Process.Pid) } case <-time.After(config.PluginConnectionTimeout()): logger.Warning("Plugin [%s] with pid [%d] did not exit after %.2f seconds. Forcefully killing it.", p.descriptor.Name, p.pluginCmd.Process.Pid, config.PluginConnectionTimeout().Seconds()) err := p.pluginCmd.Process.Kill() if err != nil { logger.Warning("Error while killing plugin %s : %s ", p.descriptor.Name, err.Error()) } return err } } return nil }
func (plugin *plugin) kill(wg *sync.WaitGroup) error { defer wg.Done() if plugin.isStillRunning() { exited := make(chan bool, 1) go func() { for { if plugin.isStillRunning() { time.Sleep(100 * time.Millisecond) } else { exited <- true return } } }() select { case done := <-exited: if done { logger.Debug("Plugin [%s] with pid [%d] has exited", plugin.descriptor.Name, plugin.pluginCmd.Process.Pid) } case <-time.After(config.PluginConnectionTimeout()): logger.Warning("Plugin [%s] with pid [%d] did not exit after %.2f seconds. Forcefully killing it.", plugin.descriptor.Name, plugin.pluginCmd.Process.Pid, config.PluginConnectionTimeout().Seconds()) return plugin.pluginCmd.Process.Kill() } } return nil }
// DownloadAndUnzip downloads the zip file from given download link and unzips it. // Returns the unzipped file path. func DownloadAndUnzip(downloadLink string, tempDir string) (string, error) { logger.Info("Downloading %s", filepath.Base(downloadLink)) logger.Debug("Download URL %s", downloadLink) downloadedFile, err := Download(downloadLink, tempDir, "", false) if err != nil { return "", err } logger.Debug("Downloaded to %s", downloadedFile) unzippedPluginDir, err := common.UnzipArchive(downloadedFile, tempDir) if err != nil { return "", fmt.Errorf("Failed to Unzip file %s: %s", downloadedFile, err.Error()) } logger.Debug("Unzipped to => %s\n", unzippedPluginDir) return unzippedPluginDir, nil }
func (handler *Handler) killPlugin(pluginID string) { plugin := handler.pluginsMap[pluginID] logger.Debug("Killing Plugin %s %s\n", plugin.descriptor.Name, plugin.descriptor.Version) err := plugin.pluginCmd.Process.Kill() if err != nil { logger.Errorf("Failed to kill plugin %s %s. %s\n", plugin.descriptor.Name, plugin.descriptor.Version, err.Error()) } handler.removePlugin(pluginID) }
func (e *parallelSpecExecution) startSpecsExecution(specCollection *filter.SpecCollection, suiteResults chan *result.SuiteResult, reporter reporter.Reporter) { testRunner, err := runner.StartRunnerAndMakeConnection(e.manifest, reporter, make(chan bool)) if err != nil { logger.Error("Failed: " + err.Error()) logger.Debug("Skipping %s specifications", strconv.Itoa(len(specCollection.Specs))) suiteResults <- &result.SuiteResult{UnhandledErrors: []error{streamExecError{specsSkipped: specCollection.SpecNames(), message: fmt.Sprintf("Failed to start runner. %s", err.Error())}}} return } e.startSpecsExecutionWithRunner(specCollection, suiteResults, testRunner, reporter) }
func (e *parallelExecution) startSpecsExecution(s *gauge.SpecCollection, reporter reporter.Reporter, resChan chan *result.SuiteResult) { defer e.wg.Done() runner, err := runner.StartRunnerAndMakeConnection(e.manifest, reporter, make(chan bool)) if err != nil { logger.Errorf("Failed to start runner. %s", err.Error()) logger.Debug("Skipping %d specifications", s.Size()) resChan <- &result.SuiteResult{UnhandledErrors: []error{streamExecError{specsSkipped: s.SpecNames(), message: fmt.Sprintf("Failed to start runner. %s", err.Error())}}} return } e.startSpecsExecutionWithRunner(s, resChan, runner, reporter) }
func (t *TestRunner) waitAndGetErrorMessage() { go func() { pState, err := t.Cmd.Process.Wait() t.mutex.Lock() t.Cmd.ProcessState = pState t.mutex.Unlock() if err != nil { logger.Debug("Runner exited with error: %s", err) t.ErrorChannel <- fmt.Errorf("Runner exited with error: %s\n", err.Error()) } }() }
func checkPluginUpdates() []UpdateInfo { var pluginsToUpdate []UpdateInfo plugins, err := plugin.GetAllInstalledPluginsWithVersion() if err != nil { return pluginsToUpdate } logger.Debug("Checking updates...") for _, plugin := range plugins { desc, result := getInstallDescription(plugin.Name, true) if result.Error != nil { continue } pluginsToUpdate = append(pluginsToUpdate, createPluginUpdateDetail(plugin.Version.String(), *desc)...) } return pluginsToUpdate }
func getInstallDescription(plugin string, silent bool) (*installDescription, InstallResult) { versionInstallDescriptionJSONFile := plugin + "-install.json" versionInstallDescriptionJSONUrl, result := constructPluginInstallJSONURL(plugin) if !result.Success { return nil, installError(fmt.Errorf("Could not construct plugin install json file URL. %s", result.Error)) } tempDir := common.GetTempDir() defer common.Remove(tempDir) downloadedFile, downloadErr := util.Download(versionInstallDescriptionJSONUrl, tempDir, versionInstallDescriptionJSONFile, silent) if downloadErr != nil { logger.Debug("Failed to download %s file: %s", versionInstallDescriptionJSONFile, downloadErr) return nil, installError(fmt.Errorf("Invalid plugin. Could not download %s file.", versionInstallDescriptionJSONFile)) } return getInstallDescriptionFromJSON(downloadedFile) }