From ae196daa50b624685de6d381761838cc82ac68e5 Mon Sep 17 00:00:00 2001 From: "Lee E. Hinman" Date: Thu, 6 Jul 2023 15:00:18 -0500 Subject: [PATCH] finish converting test_template --- libbeat/magefile.go | 2 +- libbeat/tests/integration/base_test.go | 1 - libbeat/tests/integration/framework.go | 17 +- libbeat/tests/integration/template_test.go | 340 +++++++++++++++++++++ libbeat/tests/system/test_template.py | 222 -------------- 5 files changed, 347 insertions(+), 235 deletions(-) delete mode 100644 libbeat/tests/system/test_template.py diff --git a/libbeat/magefile.go b/libbeat/magefile.go index 2c3ae40f7b89..5c4b7ada17ea 100644 --- a/libbeat/magefile.go +++ b/libbeat/magefile.go @@ -75,7 +75,7 @@ func IntegTest() { // GoIntegTest starts the docker containers and executes the Go integration tests. func GoIntegTest(ctx context.Context) error { - mg.Deps(Fields) + mg.Deps(Fields, devtools.BuildSystemTestBinary) args := devtools.DefaultGoTestIntegrationFromHostArgs() // ES_USER must be admin in order for the Go Integration tests to function because they require // indices:data/read/search diff --git a/libbeat/tests/integration/base_test.go b/libbeat/tests/integration/base_test.go index 620e9f0f2256..38bebb59f2c3 100644 --- a/libbeat/tests/integration/base_test.go +++ b/libbeat/tests/integration/base_test.go @@ -197,7 +197,6 @@ output.console: mockbeat.WriteConfigFile(cfg) mockbeat.Start() mockbeat.WaitStdErrContains("mockbeat start running.", 10*time.Second) - // mockbeat.WaitForLogs("Home path", 60*time.Second, "error waiting for mockbeat to start") metaFile1, err := mockbeat.LoadMeta() require.NoError(t, err, "error opening meta.json file") diff --git a/libbeat/tests/integration/framework.go b/libbeat/tests/integration/framework.go index fb6f8206f7fb..e19645ce7ebe 100644 --- a/libbeat/tests/integration/framework.go +++ b/libbeat/tests/integration/framework.go @@ -214,7 +214,7 @@ func (b *BeatProc) Stop() { // LogContains looks for `s` as a substring of every log line, // it will open the log file on every call, read it until EOF, // then close it. -func (b *BeatProc) LogContains(s string) string { +func (b *BeatProc) LogContains(s string) bool { t := b.t logFile := b.openLogFile() _, err := logFile.Seek(b.logFileOffset, os.SEEK_SET) @@ -244,25 +244,20 @@ func (b *BeatProc) LogContains(s string) string { } if strings.Contains(line, s) { - return line + return true } } - return "" + return false } // WaitForLogs waits for the specified string s to be present in the logs within // the given timeout duration and fails the test if s is not found. -func (b *BeatProc) WaitForLogs(s string, timeout time.Duration) string { +func (b *BeatProc) WaitForLogs(s string, timeout time.Duration, msgAndArgs ...any) { b.t.Helper() - errMsg := fmt.Sprintf("Error waiting for log %s", s) - var returnValue string require.Eventually(b.t, func() bool { - returnValue = b.LogContains(s) - return returnValue != "" - }, timeout, 100*time.Millisecond, errMsg) - - return returnValue + return b.LogContains(s) + }, timeout, 100*time.Millisecond, msgAndArgs...) } // TempDir returns the temporary directory diff --git a/libbeat/tests/integration/template_test.go b/libbeat/tests/integration/template_test.go index 6522756b3c60..2066aa0efccd 100644 --- a/libbeat/tests/integration/template_test.go +++ b/libbeat/tests/integration/template_test.go @@ -25,6 +25,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "testing" "time" @@ -298,3 +299,342 @@ logging: r, _ := http.Get(u) require.Equal(t, 404, r.StatusCode, "incorrect status code") } + +func TestSetupCmd(t *testing.T) { + EnsureESIsRunning(t) + + cfg := ` +mockbeat: +output: + elasticsearch: + hosts: %s + username: %s + password: %s + allow_older_versions: true +logging: + level: debug +` + dataStream := "mockbeat-9.9.9" + policy := "mockbeat" + esURL := GetESURL(t, "http") + user := esURL.User.Username() + pass, _ := esURL.User.Password() + dataStreamURL, err := FormatDatastreamURL(t, esURL, dataStream) + require.NoError(t, err) + templateURL, err := FormatIndexTemplateURL(t, esURL, dataStream) + require.NoError(t, err) + policyURL, err := FormatPolicyURL(t, esURL, policy) + require.NoError(t, err) + t.Cleanup(func() { + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + }) + // Make sure datastream, template and policy don't exist + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(fmt.Sprintf(cfg, esURL.String(), user, pass)) + mockbeat.Start("setup", "--index-management") + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + + // check template loaded + status, body, err := HttpDo(t, http.MethodGet, templateURL) + require.NoError(t, err) + require.Equal(t, http.StatusOK, status, "incorrect status code") + + var r IndexTemplateResult + err = json.Unmarshal(body, &r) + require.NoError(t, err) + var found bool + for _, t := range r.IndexTemplates { + if t.Name == dataStream { + found = true + } + } + require.Truef(t, found, "data stream should be in: %v", r.IndexTemplates) + + status, body, err = HttpDo(t, http.MethodGet, policyURL) + require.NoError(t, err) + require.Equal(t, http.StatusOK, status, "incorrect status code") + + require.Truef(t, strings.Contains(string(body), "max_primary_shard_size\":\"50gb"), "primary shard not found in %s", string(body)) + + require.Truef(t, strings.Contains(string(body), "max_age\":\"30d"), "max_age not found in %s", string(body)) +} + +func TestSetupCmdTemplateDisabled(t *testing.T) { + EnsureESIsRunning(t) + + cfg := ` +mockbeat: +output: + elasticsearch: + hosts: %s + username: %s + password: %s + allow_older_versions: true +logging: + level: debug +setup: + template: + enabled: false +` + dataStream := "mockbeat-9.9.9" + policy := "mockbeat" + esURL := GetESURL(t, "http") + user := esURL.User.Username() + pass, _ := esURL.User.Password() + dataStreamURL, err := FormatDatastreamURL(t, esURL, dataStream) + require.NoError(t, err) + templateURL, err := FormatIndexTemplateURL(t, esURL, dataStream) + require.NoError(t, err) + policyURL, err := FormatPolicyURL(t, esURL, policy) + require.NoError(t, err) + t.Cleanup(func() { + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + }) + // Make sure datastream, template and policy don't exist + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(fmt.Sprintf(cfg, esURL.String(), user, pass)) + mockbeat.Start("setup", "--index-management") + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + + // check template didn't load + status, body, err := HttpDo(t, http.MethodGet, templateURL) + require.NoError(t, err) + require.Equal(t, http.StatusNotFound, status, "incorrect status code") + + status, body, err = HttpDo(t, http.MethodGet, policyURL) + require.NoError(t, err) + require.Equal(t, http.StatusOK, status, "incorrect status code") + + require.Truef(t, strings.Contains(string(body), "max_primary_shard_size\":\"50gb"), "primary shard not found in %s", string(body)) + + require.Truef(t, strings.Contains(string(body), "max_age\":\"30d"), "max_age not found in %s", string(body)) +} + +func TestSetupCmdTemplateWithOpts(t *testing.T) { + EnsureESIsRunning(t) + + cfg := ` +mockbeat: +output: + elasticsearch: + hosts: %s + username: %s + password: %s + allow_older_versions: true +logging: + level: debug +` + dataStream := "mockbeat-9.9.9" + policy := "mockbeat" + esURL := GetESURL(t, "http") + user := esURL.User.Username() + pass, _ := esURL.User.Password() + dataStreamURL, err := FormatDatastreamURL(t, esURL, dataStream) + require.NoError(t, err) + templateURL, err := FormatIndexTemplateURL(t, esURL, dataStream) + require.NoError(t, err) + policyURL, err := FormatPolicyURL(t, esURL, policy) + require.NoError(t, err) + t.Cleanup(func() { + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + }) + // Make sure datastream, template and policy don't exist + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(fmt.Sprintf(cfg, esURL.String(), user, pass)) + mockbeat.Start("setup", "--index-management", "-E", "setup.ilm.enabled=false", "-E", "setup.template.settings.index.number_of_shards=2") + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + + // check template loaded + status, body, err := HttpDo(t, http.MethodGet, templateURL) + require.NoError(t, err) + require.Equalf(t, http.StatusOK, status, "incorrect status code for :%s", templateURL.String()) + require.Truef(t, strings.Contains(string(body), "number_of_shards\":\"2"), "number of shards not found in %s", string(body)) +} + +func TestTemplateCreatedOnIlmPolicyCreated(t *testing.T) { + EnsureESIsRunning(t) + + cfg := ` +mockbeat: +output: + elasticsearch: + hosts: %s + username: %s + password: %s + allow_older_versions: true +logging: + level: debug +` + dataStream := "mockbeat-9.9.9" + policy := "mockbeat" + esURL := GetESURL(t, "http") + user := esURL.User.Username() + pass, _ := esURL.User.Password() + dataStreamURL, err := FormatDatastreamURL(t, esURL, dataStream) + require.NoError(t, err) + templateURL, err := FormatIndexTemplateURL(t, esURL, dataStream) + require.NoError(t, err) + policyURL, err := FormatPolicyURL(t, esURL, policy) + require.NoError(t, err) + t.Cleanup(func() { + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + }) + // Make sure datastream, template and policy don't exist + _, _, err = HttpDo(t, http.MethodDelete, dataStreamURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, templateURL) + require.NoError(t, err) + _, _, err = HttpDo(t, http.MethodDelete, policyURL) + require.NoError(t, err) + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(fmt.Sprintf(cfg, esURL.String(), user, pass)) + mockbeat.Start("setup", "--index-management", "-E", "setup.ilm.enabled=false") + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + + // check template loaded + status, body, err := HttpDo(t, http.MethodGet, templateURL) + require.NoError(t, err) + require.Equal(t, http.StatusOK, status, "incorrect status code") + + var r IndexTemplateResult + err = json.Unmarshal(body, &r) + require.NoError(t, err) + var found bool + for _, t := range r.IndexTemplates { + if t.Name == dataStream { + found = true + } + } + require.Truef(t, found, "data stream should be in: %v", r.IndexTemplates) + + // check policy not created + status, body, err = HttpDo(t, http.MethodGet, policyURL) + require.NoError(t, err) + require.Equalf(t, http.StatusNotFound, status, "incorrect status code for: %s", policyURL.String()) + + mockbeat.Start("setup", "--index-management", "-E", "setup.template.overwrite=false", "-E", "setup.template.settings.index.number_of_shards=2") + procState, err = mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + + // check policy created + status, body, err = HttpDo(t, http.MethodGet, policyURL) + require.NoError(t, err) + require.Equal(t, http.StatusOK, status, "incorrect status code") + + require.Truef(t, strings.Contains(string(body), "max_primary_shard_size\":\"50gb"), "primary shard not found in %s", string(body)) + + require.Truef(t, strings.Contains(string(body), "max_age\":\"30d"), "max_age not found in %s", string(body)) +} + +func TestExportTemplate(t *testing.T) { + cfg := ` +mockbeat: +output: + console: + enabled: true +logging: + level: debug +` + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(cfg) + mockbeat.Start("export", "template") + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + mockbeat.WaitStdOutContains("mockbeat-9.9.9", 5*time.Second) +} + +func TestExportTemplateDisabled(t *testing.T) { + cfg := ` +mockbeat: +output: + console: + enabled: true +logging: + level: debug +` + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + mockbeat.WriteConfigFile(cfg) + mockbeat.Start("export", "template", "-E", "setup.template.enabled=false") + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + mockbeat.WaitStdOutContains("mockbeat-9.9.9", 5*time.Second) +} + +func TestExportAbsolutePath(t *testing.T) { + cfg := ` +mockbeat: +output: + console: + enabled: true +logging: + level: debug +` + + mockbeat := NewBeat(t, "mockbeat", "../../libbeat.test") + output := filepath.Join(mockbeat.TempDir(), "template", "mockbeat-9.9.9.json") + t.Cleanup(func() { + os.Remove(output) + }) + mockbeat.WriteConfigFile(cfg) + mockbeat.Start("export", "template", "--dir", mockbeat.TempDir()) + procState, err := mockbeat.Process.Wait() + require.NoError(t, err) + require.Equal(t, 0, procState.ExitCode(), "incorrect exit code") + mockbeat.WaitStdOutContains("Writing to", 5*time.Second) + mockbeat.WaitFileContains(output, "mockbeat-9.9.9", 5*time.Second) +} diff --git a/libbeat/tests/system/test_template.py b/libbeat/tests/system/test_template.py deleted file mode 100644 index 20687a87e417..000000000000 --- a/libbeat/tests/system/test_template.py +++ /dev/null @@ -1,222 +0,0 @@ -import json -import logging -import os -import pytest -import shutil -import unittest - -from base import BaseTest -from idxmgmt import IdxMgmt - -INTEGRATION_TESTS = os.environ.get('INTEGRATION_TESTS', False) - - -class TestCommandSetupTemplate(BaseTest): - """ - Test beat command `setup` with focus on template - """ - - def setUp(self): - super(TestCommandSetupTemplate, self).setUp() - - # auto-derived default settings, if nothing else is set - self.setupCmd = "--index-management" - self.data_stream = self.beat_name + "-9.9.9" - self.policy_name = self.beat_name - - self.es = self.es_client() - self.idxmgmt = IdxMgmt(self.es, self.data_stream) - self.idxmgmt.delete(indices=[self.data_stream], policies=[self.policy_name]) - logging.getLogger("urllib3").setLevel(logging.WARNING) - logging.getLogger("elasticsearch").setLevel(logging.ERROR) - - def tearDown(self): - self.idxmgmt.delete(indices=[self.data_stream], policies=[self.policy_name]) - - def render_config(self, **kwargs): - self.render_config_template( - elasticsearch=self.get_elasticsearch_template_config(), - **kwargs - ) - - @unittest.skipUnless(INTEGRATION_TESTS, "integration test") - @pytest.mark.tag('integration') - def test_setup(self): - """ - Test setup cmd with template and ilm-policy subcommands - """ - self.render_config() - exit_code = self.run_beat(logging_args=["-v", "-d", "*"], - extra_args=["setup", self.setupCmd]) - - assert exit_code == 0 - self.idxmgmt.assert_index_template_loaded(self.data_stream) - self.idxmgmt.assert_policy_created(self.policy_name) - - @unittest.skipUnless(INTEGRATION_TESTS, "integration test") - @pytest.mark.tag('integration') - def test_setup_template_default(self): - """ - Test template setup with default config - """ - self.render_config() - exit_code = self.run_beat(logging_args=["-v", "-d", "*"], - extra_args=["setup", self.setupCmd]) - - assert exit_code == 0 - self.idxmgmt.assert_index_template_loaded(self.data_stream) - self.idxmgmt.assert_index_template_index_pattern(self.data_stream, [self.data_stream]) - - self.idxmgmt.assert_policy_created(self.policy_name) - - @unittest.skipUnless(INTEGRATION_TESTS, "integration test") - @pytest.mark.tag('integration') - def test_setup_template_disabled(self): - """ - Test template setup when ilm disabled - """ - self.render_config() - exit_code = self.run_beat(logging_args=["-v", "-d", "*"], - extra_args=["setup", self.setupCmd, - "-E", "setup.template.enabled=false"]) - - assert exit_code == 0 - self.idxmgmt.assert_index_template_not_loaded(self.data_stream) - - self.idxmgmt.assert_policy_created(self.policy_name) - - @unittest.skipUnless(INTEGRATION_TESTS, "integration test") - @pytest.mark.tag('integration') - def test_setup_template_with_opts(self): - """ - Test template setup with config options - """ - self.render_config() - exit_code = self.run_beat(logging_args=["-v", "-d", "*"], - extra_args=["setup", self.setupCmd, - "-E", "setup.ilm.enabled=false", - "-E", "setup.template.settings.index.number_of_shards=2"]) - - assert exit_code == 0 - self.idxmgmt.assert_index_template_loaded(self.data_stream) - - # check that settings are overwritten - resp = self.es.transport.perform_request('GET', '/_index_template/' + self.data_stream) - found = False - for index_template in resp["index_templates"]: - if self.data_stream == index_template["name"]: - found = True - index = index_template["index_template"]["template"]["settings"]["index"] - assert index["number_of_shards"] == "2", index["number_of_shards"] - assert found - - @unittest.skipUnless(INTEGRATION_TESTS, "integration test") - @pytest.mark.tag('integration') - def test_template_created_on_ilm_policy_created(self): - """ - Test template setup overwrites template when new ilm policy is created - """ - - self.render_config() - exit_code = self.run_beat(logging_args=["-v", "-d", "*"], - extra_args=["setup", self.setupCmd, - "-E", "setup.ilm.enabled=false"]) - assert exit_code == 0 - self.idxmgmt.assert_index_template_loaded(self.data_stream) - self.idxmgmt.assert_policy_not_created(self.policy_name) - - # ensure ilm policy is created, triggering overwriting existing template - exit_code = self.run_beat(extra_args=["setup", self.setupCmd, - "-E", "setup.template.overwrite=false", - "-E", "setup.template.settings.index.number_of_shards=2"]) - assert exit_code == 0 - self.idxmgmt.assert_policy_created(self.policy_name) - - -class TestCommandExportTemplate(BaseTest): - """ - Test beat command `export template` - """ - - def setUp(self): - super(TestCommandExportTemplate, self).setUp() - - self.config = "libbeat.yml" - self.output = os.path.join(self.working_dir, self.config) - shutil.copy(os.path.join(self.beat_path, "fields.yml"), self.output) - self.template_name = self.beat_name + "-9.9.9" - - def assert_log_contains_template(self, index_pattern): - assert self.log_contains('Loaded index template') - assert self.log_contains(index_pattern) - - def test_default(self): - """ - Test export template works - """ - self.render_config_template(self.beat_name, self.output, - fields=self.output) - exit_code = self.run_beat( - extra_args=["export", "template"], - config=self.config) - - assert exit_code == 0 - self.assert_log_contains_template(self.template_name) - - def test_load_disabled(self): - """ - Test template also exported when disabled in config - """ - self.render_config_template(self.beat_name, self.output, - fields=self.output) - exit_code = self.run_beat( - extra_args=["export", "template", "-E", "setup.template.enabled=false"], - config=self.config) - - assert exit_code == 0 - self.assert_log_contains_template(self.template_name) - - def test_export_to_file_absolute_path(self): - """ - Test export template to file with absolute file path - """ - self.render_config_template(self.beat_name, self.output, - fields=self.output) - - base_path = os.path.abspath(os.path.join(self.beat_path, os.path.dirname(__file__), "export")) - exit_code = self.run_beat( - extra_args=["export", "template", "--dir=" + base_path], - config=self.config) - - assert exit_code == 0 - - file = os.path.join(base_path, "template", self.template_name + '.json') - with open(file) as f: - template = json.load(f) - assert 'index_patterns' in template - assert template['index_patterns'] == [self.template_name], template - - os.remove(file) - - def test_export_to_file_relative_path(self): - """ - Test export template to file with relative file path - """ - self.render_config_template(self.beat_name, self.output, - fields=self.output) - - path = os.path.join(os.path.dirname(__file__), "export") - exit_code = self.run_beat( - extra_args=["export", "template", "--dir=" + path], - config=self.config) - - assert exit_code == 0 - - base_path = os.path.abspath(os.path.join(self.beat_path, os.path.dirname(__file__), "export")) - file = os.path.join(base_path, "template", self.template_name + '.json') - with open(file) as f: - template = json.load(f) - assert 'index_patterns' in template - assert template['index_patterns'] == [self.template_name], template - - os.remove(file)