diff --git a/frontend/client/views/settings/index.vue b/frontend/client/views/settings/index.vue index f9772984..35473c4a 100644 --- a/frontend/client/views/settings/index.vue +++ b/frontend/client/views/settings/index.vue @@ -54,7 +54,7 @@ - + @@ -103,6 +103,9 @@ + + + @@ -355,6 +358,7 @@ import Notification from 'vue-bulma-notification-fixed' import {mapGetters} from 'vuex' import ManagePermissions from './permissions/manage-permissions' + import ManageSettings from './settings/manage-settings' import {EventBus} from '../../app' const NotificationComponent = Vue.extend(Notification) @@ -382,7 +386,8 @@ TabPane, Modal, Collapse, - CollapseItem + CollapseItem, + ManageSettings }, data () { diff --git a/frontend/client/views/settings/settings/manage-settings.vue b/frontend/client/views/settings/settings/manage-settings.vue new file mode 100644 index 00000000..4ab11861 --- /dev/null +++ b/frontend/client/views/settings/settings/manage-settings.vue @@ -0,0 +1,153 @@ + + + + + + + + + + {{ props.row.display_name }} + + + + + + + No settings found. + + + + + + + + + + + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f6f49bb6..c3fe474d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -4878,7 +4878,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4915,7 +4916,8 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -4924,7 +4926,8 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5027,7 +5030,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5037,6 +5041,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5056,11 +5061,13 @@ }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5077,6 +5084,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5155,7 +5163,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5165,6 +5174,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5240,7 +5250,8 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5270,6 +5281,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5287,6 +5299,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5325,11 +5338,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.2", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -19241,6 +19256,11 @@ } } }, + "vue-js-toggle-button": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/vue-js-toggle-button/-/vue-js-toggle-button-1.3.2.tgz", + "integrity": "sha512-LS+pvX5lXEhX+Gei5MOAEw7bx99/A+9idFhMtBgz72ApsEHlW69Y7bk+ZKC1rLRUxchL5WlQ+MhJXqXewhkfjg==" + }, "vue-loader": { "version": "11.3.4", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-11.3.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 07088158..9ee5aec8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -56,6 +56,7 @@ "vue-bulma-progress-bar": "^1.0.2", "vue-bulma-tabs": "^1.1.3", "vue-good-table": "^1.19.2", + "vue-js-toggle-button": "^1.3.2", "vue-lodash": "^1.0.4", "vue-nprogress": "0.1.5", "vue-router": "^3.0.1", diff --git a/gaia.go b/gaia.go index ee5430f2..7160254d 100644 --- a/gaia.go +++ b/gaia.go @@ -249,6 +249,11 @@ type Config struct { } } +type StoreConfig struct { + ID int + Poll bool +} + // String returns a pipeline type string back func (p PipelineType) String() string { return string(p) diff --git a/handlers/handler.go b/handlers/handler.go index 77be132f..7bf42059 100644 --- a/handlers/handler.go +++ b/handlers/handler.go @@ -64,6 +64,11 @@ func InitHandlers(e *echo.Echo) error { e.GET(p+"pipeline/latest", PipelineGetAllWithLatestRun) e.POST(p+"pipeline/periodicschedules", PipelineCheckPeriodicSchedules) + // Settings + e.POST(p+"settings/poll/on", SettingsPollOn) + e.POST(p+"settings/poll/off", SettingsPollOff) + e.GET(p+"settings/poll", SettingsPollGet) + // PipelineRun e.POST(p+"pipelinerun/:pipelineid/:runid/stop", PipelineStop) e.GET(p+"pipelinerun/:pipelineid/:runid", PipelineRunGet) diff --git a/handlers/settings.go b/handlers/settings.go new file mode 100644 index 00000000..d1973d81 --- /dev/null +++ b/handlers/settings.go @@ -0,0 +1,85 @@ +package handlers + +import ( + "net/http" + + "github.com/gaia-pipeline/gaia/services" + "github.com/gaia-pipeline/gaia/workers/pipeline" + + "github.com/gaia-pipeline/gaia" + "github.com/labstack/echo" +) + +// SettingsPollOn turn on polling functionality. +func SettingsPollOn(c echo.Context) error { + storeService, err := services.StorageService() + if err != nil { + return c.String(http.StatusInternalServerError, "Something went wrong while getting storage service.") + } + configStore, err := storeService.SettingsGet() + if err != nil { + return c.String(http.StatusInternalServerError, "Something went wrong while retrieving settings information.") + } + if configStore == nil { + configStore = &gaia.StoreConfig{} + } + + gaia.Cfg.Poll = true + err = pipeline.StartPoller() + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + } + + configStore.Poll = true + err = storeService.SettingsPut(configStore) + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + } + return c.String(http.StatusOK, "Polling is turned on.") +} + +// SettingsPollOff turn off polling functionality. +func SettingsPollOff(c echo.Context) error { + storeService, err := services.StorageService() + if err != nil { + return c.String(http.StatusInternalServerError, "Something went wrong while getting storage service.") + } + configStore, err := storeService.SettingsGet() + if err != nil { + return c.String(http.StatusInternalServerError, "Something went wrong while retrieving settings information.") + } + if configStore == nil { + configStore = &gaia.StoreConfig{} + } + gaia.Cfg.Poll = false + err = pipeline.StopPoller() + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + } + configStore.Poll = true + err = storeService.SettingsPut(configStore) + return c.String(http.StatusOK, "Polling is turned off.") +} + +type pollStatus struct { + Status bool +} + +// SettingsPollGet get status of polling functionality. +func SettingsPollGet(c echo.Context) error { + storeService, err := services.StorageService() + if err != nil { + return c.String(http.StatusInternalServerError, "Something went wrong while getting storage service.") + } + configStore, err := storeService.SettingsGet() + if err != nil { + return c.String(http.StatusInternalServerError, "Something went wrong while retrieving settings information.") + } + var ps pollStatus + if configStore == nil { + ps.Status = gaia.Cfg.Poll + } else { + ps.Status = configStore.Poll + } + return c.JSON(http.StatusOK, ps) +} diff --git a/handlers/settings_test.go b/handlers/settings_test.go new file mode 100644 index 00000000..046ee3e9 --- /dev/null +++ b/handlers/settings_test.go @@ -0,0 +1,269 @@ +package handlers + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gaia-pipeline/gaia" + "github.com/gaia-pipeline/gaia/services" + gStore "github.com/gaia-pipeline/gaia/store" + hclog "github.com/hashicorp/go-hclog" + "github.com/labstack/echo" +) + +type status struct { + Status bool +} + +type mockSettingStoreService struct { + gStore.GaiaStore + get func() (*gaia.StoreConfig, error) + put func(*gaia.StoreConfig) error +} + +func (m mockSettingStoreService) SettingsGet() (*gaia.StoreConfig, error) { + return m.get() +} + +func (m mockSettingStoreService) SettingsPut(c *gaia.StoreConfig) error { + return m.put(c) +} + +func TestSetPollerToggle(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestSetPollerON") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: false, + } + + // // Initialize echo + e := echo.New() + InitHandlers(e) + get := func() (*gaia.StoreConfig, error) { + return nil, nil + } + put := func(*gaia.StoreConfig) error { + return nil + } + m := mockSettingStoreService{get: get, put: put} + services.MockStorageService(&m) + defer func() { + services.MockStorageService(nil) + }() + + t.Run("switching it on twice should fail", func(t2 *testing.T) { + req := httptest.NewRequest(echo.POST, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/on") + + SettingsPollOn(c) + retStatus := http.StatusOK + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + + req2 := httptest.NewRequest(echo.POST, "/", nil) + req2.Header.Set("Content-Type", "application/json") + rec2 := httptest.NewRecorder() + c2 := e.NewContext(req2, rec2) + c2.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/on") + + SettingsPollOn(c2) + secondRetStatus := http.StatusBadRequest + if rec2.Code != secondRetStatus { + t.Fatalf("expected response code %v got %v", secondRetStatus, rec2.Code) + } + }) + t.Run("switching it on while the setting is on should fail", func(t *testing.T) { + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + req := httptest.NewRequest(echo.POST, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/on") + + SettingsPollOn(c) + retStatus := http.StatusBadRequest + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + }) + t.Run("switching it off while the setting is on should pass", func(t *testing.T) { + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + req := httptest.NewRequest(echo.POST, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/off") + + SettingsPollOff(c) + retStatus := http.StatusOK + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + if gaia.Cfg.Poll != false { + t.Fatalf("poll value should have been set to false. was: %v", gaia.Cfg.Poll) + } + }) + t.Run("switching it off while the setting is off should fail", func(t *testing.T) { + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: false, + } + req := httptest.NewRequest(echo.POST, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/off") + + SettingsPollOff(c) + retStatus := http.StatusBadRequest + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + }) + t.Run("getting the value should return the correct setting", func(t *testing.T) { + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + req := httptest.NewRequest(echo.GET, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll") + + SettingsPollGet(c) + retStatus := http.StatusOK + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + var s status + json.NewDecoder(rec.Body).Decode(&s) + if s.Status != true { + t.Fatalf("expected returned status to be true. was: %v", s.Status) + } + }) +} + +func TestGettingSettingFromDBTakesPrecedence(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestGettingSettingFromDBTakesPrecedence") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: false, + } + + // // Initialize echo + e := echo.New() + InitHandlers(e) + get := func() (*gaia.StoreConfig, error) { + return &gaia.StoreConfig{ + Poll: true, + }, nil + } + put := func(*gaia.StoreConfig) error { + return nil + } + m := mockSettingStoreService{get: get, put: put} + services.MockStorageService(&m) + defer services.MockStorageService(nil) + req := httptest.NewRequest(echo.GET, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/") + + SettingsPollGet(c) + retStatus := http.StatusOK + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + var s status + json.NewDecoder(rec.Body).Decode(&s) + if s.Status != true { + t.Fatalf("expected returned status to be true from storage. was: %v", s.Status) + } +} + +func TestSettingPollerOnAlsoSavesSettingsInDB(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestSettingPollerOnAlsoSavesSettingsInDB") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: false, + } + + // // Initialize echo + e := echo.New() + InitHandlers(e) + get := func() (*gaia.StoreConfig, error) { + return &gaia.StoreConfig{ + Poll: true, + }, nil + } + putCalled := false + put := func(*gaia.StoreConfig) error { + putCalled = true + return nil + } + m := mockSettingStoreService{get: get, put: put} + services.MockStorageService(&m) + defer services.MockStorageService(nil) + req := httptest.NewRequest(echo.POST, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/setttings/poll/on") + + SettingsPollOn(c) + retStatus := http.StatusOK + if rec.Code != retStatus { + t.Fatalf("expected response code %v got %v", retStatus, rec.Code) + } + + if putCalled != true { + t.Fatal("SettingPut should have been called. Was not.") + } + putCalled = false + SettingsPollOff(c) + if putCalled != true { + t.Fatal("SettingPut should have been called. Was not.") + } +} diff --git a/store/settings.go b/store/settings.go new file mode 100644 index 00000000..efdfc240 --- /dev/null +++ b/store/settings.go @@ -0,0 +1,51 @@ +package store + +import ( + "encoding/json" + + bolt "github.com/coreos/bbolt" + "github.com/gaia-pipeline/gaia" +) + +// SettingsPut puts settings into the store. +func (s *BoltStore) SettingsPut(c *gaia.StoreConfig) error { + return s.db.Update(func(tx *bolt.Tx) error { + // Get settings bucket + b := tx.Bucket(settingsBucket) + + // Marshal pipeline data into bytes. + buf, err := json.Marshal(c) + if err != nil { + return err + } + + // Persist bytes to settings bucket. + return b.Put([]byte("gaia_config_settings"), buf) + }) +} + +// SettingsGet gets a pipeline by given id. +func (s *BoltStore) SettingsGet() (*gaia.StoreConfig, error) { + var config = &gaia.StoreConfig{} + + return config, s.db.View(func(tx *bolt.Tx) error { + // Get bucket + b := tx.Bucket(settingsBucket) + + // Get pipeline + v := b.Get([]byte("gaia_config_settings")) + + // Check if we found the pipeline + if v == nil { + return nil + } + + // Unmarshal pipeline object + err := json.Unmarshal(v, config) + if err != nil { + return err + } + + return nil + }) +} diff --git a/store/store.go b/store/store.go index 159c244d..1b9432ad 100644 --- a/store/store.go +++ b/store/store.go @@ -27,6 +27,9 @@ var ( // Name of the bucket where we store all pipeline runs. pipelineRunBucket = []byte("PipelineRun") + + // Name of the bucket where we store information about settings + settingsBucket = []byte("Settings") ) const ( @@ -69,6 +72,8 @@ type GaiaStore interface { UserPermissionsPut(perms *gaia.UserPermission) error UserPermissionsGet(username string) (*gaia.UserPermission, error) UserPermissionsDelete(username string) error + SettingsPut(config *gaia.StoreConfig) error + SettingsGet() (*gaia.StoreConfig, error) } // Compile time interface compliance check for BoltStore. If BoltStore @@ -138,6 +143,11 @@ func (s *BoltStore) setupDatabase() error { if err != nil { return err } + bucketName = settingsBucket + err = s.db.Update(c) + if err != nil { + return err + } // Make sure that the user "admin" does exist admin, err := s.UserGet(adminUsername) diff --git a/workers/pipeline/ticker.go b/workers/pipeline/ticker.go index b734effd..07efe547 100644 --- a/workers/pipeline/ticker.go +++ b/workers/pipeline/ticker.go @@ -3,6 +3,7 @@ package pipeline import ( "bytes" "crypto/sha256" + "errors" "fmt" "io" "io/ioutil" @@ -22,6 +23,50 @@ const ( tickerIntervalSeconds = 5 ) +var pollerDone = make(chan struct{}, 1) +var isPollerRunning bool + +// StopPoller sends a done signal to the polling timer if it's running. +func StopPoller() error { + if isPollerRunning { + isPollerRunning = false + select { + case pollerDone <- struct{}{}: + } + return nil + } + return errors.New("poller is not running") +} + +// StartPoller starts the poller if it's not already running. +func StartPoller() error { + if isPollerRunning { + return errors.New("poller is already running") + } + if gaia.Cfg.Poll { + if gaia.Cfg.PVal < 1 || gaia.Cfg.PVal > 99 { + errorMessage := fmt.Sprintf("Invalid value defined for poll interval. Will be using default of 1. Value was: %d, should be between 1-99.", gaia.Cfg.PVal) + gaia.Cfg.Logger.Info(errorMessage) + gaia.Cfg.PVal = 1 + } + pollTicker := time.NewTicker(time.Duration(gaia.Cfg.PVal) * time.Minute) + go func() { + defer pollTicker.Stop() + for { + select { + case <-pollTicker.C: + updateAllCurrentPipelines() + case <-pollerDone: + pollTicker.Stop() + return + } + } + }() + isPollerRunning = true + } + return nil +} + // InitTicker inititates the pipeline ticker. // This periodic job will check for new pipelines. func InitTicker() { @@ -43,23 +88,7 @@ func InitTicker() { } }() - if gaia.Cfg.Poll { - if gaia.Cfg.PVal < 1 || gaia.Cfg.PVal > 99 { - errorMessage := fmt.Sprintf("Invalid value defined for poll interval. Will be using default of 1. Value was: %d, should be between 1-99.", gaia.Cfg.PVal) - gaia.Cfg.Logger.Info(errorMessage) - gaia.Cfg.PVal = 1 - } - pollTicker := time.NewTicker(time.Duration(gaia.Cfg.PVal) * time.Minute) - go func() { - defer pollTicker.Stop() - for { - select { - case <-pollTicker.C: - updateAllCurrentPipelines() - } - } - }() - } + StartPoller() } // checkActivePipelines looks up all files in the pipeline folder. diff --git a/workers/pipeline/ticker_test.go b/workers/pipeline/ticker_test.go index ca535e7c..7e5bc0b5 100644 --- a/workers/pipeline/ticker_test.go +++ b/workers/pipeline/ticker_test.go @@ -65,3 +65,123 @@ func TestCheckActivePipelines(t *testing.T) { t.Error("cannot find pipeline in store") } } + +func TestTurningThePollerOn(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestTurningThePollerOn") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + + defer StopPoller() + err := StartPoller() + if err != nil { + t.Fatal("error was not expected. got: ", err) + } +} + +func TestTurningThePollerOnWhilePollingIsDisabled(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestTurningThePollerOnWhilePollingIsDisabled") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: false, + } + + err := StartPoller() + if err != nil { + t.Fatal("error was not expected. got: ", err) + } + if isPollerRunning != false { + t.Fatal("expected isPollerRunning to be false. was: ", isPollerRunning) + } +} + +func TestTurningThePollerOnWhilePollingIsEnabled(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestTurningThePollerOnWhilePollingIsEnabled") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + defer StopPoller() + err := StartPoller() + if err != nil { + t.Fatal("error was not expected. got: ", err) + } + if isPollerRunning != true { + t.Fatal("expected isPollerRunning to be true. was: ", isPollerRunning) + } +} + +func TestTurningThePollerOff(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestTurningThePollerOff") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + + err := StartPoller() + if err != nil { + t.Fatal("error was not expected. got: ", err) + } + if isPollerRunning != true { + t.Fatal("expected isPollerRunning to be true. was: ", isPollerRunning) + } + + err = StopPoller() + if err != nil { + t.Fatal("error was not expected. got: ", err) + } + if isPollerRunning != false { + t.Fatal("expected isPollerRunning to be false. was: ", isPollerRunning) + } +} + +func TestTogglePoller(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestTogglePoller") + dataDir := tmp + + gaia.Cfg = &gaia.Config{ + Logger: hclog.NewNullLogger(), + DataPath: dataDir, + HomePath: dataDir, + PipelinePath: dataDir, + Poll: true, + } + + err := StartPoller() + if err != nil { + t.Fatal("error was not expected. got: ", err) + } + err = StartPoller() + if err == nil { + t.Fatal("starting the poller again should have failed") + } + err = StopPoller() + if err != nil { + t.Fatal("stopping the poller while it's running should not have failed. got: ", err) + } + err = StopPoller() + if err == nil { + t.Fatal("stopping the poller again while it's stopped should have failed.") + } +}