diff --git a/internal/runtime/alloy_test.go b/internal/runtime/alloy_test.go index a9c7efcf01..fb93e5853a 100644 --- a/internal/runtime/alloy_test.go +++ b/internal/runtime/alloy_test.go @@ -43,7 +43,7 @@ func TestController_LoadSource_Evaluation(t *testing.T) { require.NoError(t, err) require.NotNil(t, f) - err = ctrl.LoadSource(f, nil) + err = ctrl.LoadSource(f, nil, "") require.NoError(t, err) require.Len(t, ctrl.loader.Components(), 4) @@ -54,6 +54,41 @@ func TestController_LoadSource_Evaluation(t *testing.T) { require.Equal(t, "hello, world!", out.(testcomponents.PassthroughExports).Output) } +var modulePathTestFile = ` + testcomponents.tick "ticker" { + frequency = "1s" + } + testcomponents.passthrough "static" { + input = module_path + } + testcomponents.passthrough "ticker" { + input = testcomponents.tick.ticker.tick_time + } + testcomponents.passthrough "forwarded" { + input = testcomponents.passthrough.ticker.output + } +` + +func TestController_LoadSource_WithModulePath_Evaluation(t *testing.T) { + defer verifyNoGoroutineLeaks(t) + ctrl := New(testOptions(t)) + defer cleanUpController(ctrl) + + f, err := ParseSource(t.Name(), []byte(modulePathTestFile)) + require.NoError(t, err) + require.NotNil(t, f) + + err = ctrl.LoadSource(f, nil, "path/to/config/main.alloy") + require.NoError(t, err) + require.Len(t, ctrl.loader.Components(), 4) + + // Check the inputs and outputs of things that should be immediately resolved + // without having to run the components. + in, out := getFields(t, ctrl.loader.Graph(), "testcomponents.passthrough.static") + require.Equal(t, "path/to/config", in.(testcomponents.PassthroughConfig).Input) + require.Equal(t, "path/to/config", out.(testcomponents.PassthroughExports).Output) +} + func getFields(t *testing.T, g *dag.Graph, nodeID string) (component.Arguments, component.Exports) { t.Helper() diff --git a/internal/runtime/import_test.go b/internal/runtime/import_test.go index dab9400d31..1b6ec2eb3b 100644 --- a/internal/runtime/import_test.go +++ b/internal/runtime/import_test.go @@ -27,13 +27,15 @@ const mainFile = "main.alloy" // The tests are using the .txtar files stored in the testdata folder. type testImportFile struct { - description string // description at the top of the txtar file - main string // root config that the controller should load - module string // module imported by the root config - nestedModule string // nested module that can be imported by the module - reloadConfig string // root config that the controller should apply on reload - otherNestedModule string // another nested module - update *updateFile // update can be used to update the content of a file at runtime + description string // description at the top of the txtar file + main string // root config that the controller should load + module string // module imported by the root config + nestedModule string // nested module that can be imported by the module + reloadConfig string // root config that the controller should apply on reload + otherNestedModule string // another nested module + nestedPathModule string // a module in a subdirectory + deeplyNestedPathModule string // a module in a sub-subdirectory + update *updateFile // update can be used to update the content of a file at runtime } type updateFile struct { @@ -70,6 +72,10 @@ func buildTestImportFile(t *testing.T, filename string) testImportFile { tc.reloadConfig = string(alloyConfig.Data) case "other_nested_module.alloy": tc.otherNestedModule = string(alloyConfig.Data) + case "nested_test/module.alloy": + tc.nestedPathModule = string(alloyConfig.Data) + case "nested_test/utils/module.alloy": + tc.deeplyNestedPathModule = string(alloyConfig.Data) } } return tc @@ -91,6 +97,18 @@ func TestImportFile(t *testing.T) { require.NoError(t, os.WriteFile("other_nested_module.alloy", []byte(tc.otherNestedModule), 0664)) } + if tc.nestedPathModule != "" || tc.deeplyNestedPathModule != "" { + require.NoError(t, os.Mkdir("nested_test", 0700)) + defer os.RemoveAll("nested_test") + if tc.nestedPathModule != "" { + require.NoError(t, os.WriteFile("nested_test/module.alloy", []byte(tc.nestedPathModule), 0664)) + } + if tc.deeplyNestedPathModule != "" { + require.NoError(t, os.Mkdir("nested_test/utils", 0700)) + require.NoError(t, os.WriteFile("nested_test/utils/module.alloy", []byte(tc.deeplyNestedPathModule), 0664)) + } + } + if tc.update != nil { testConfig(t, tc.main, tc.reloadConfig, func() { require.NoError(t, os.WriteFile(tc.update.name, []byte(tc.update.updateConfig), 0664)) @@ -146,13 +164,14 @@ func TestImportHTTP(t *testing.T) { } type testImportFileFolder struct { - description string // description at the top of the txtar file - main string // root config that the controller should load - module1 string // module imported by the root config - module2 string // another module imported by the root config - removed string // module will be removed in the dir on update - added string // module which will be added in the dir on update - update *updateFile // update can be used to update the content of a file at runtime + description string // description at the top of the txtar file + main string // root config that the controller should load + module1 string // module imported by the root config + module2 string // another module imported by the root config + utilsModule2 string // another module in a nested subdirectory + removed string // module will be removed in the dir on update + added string // module which will be added in the dir on update + update *updateFile // update can be used to update the content of a file at runtime } func buildTestImportFileFolder(t *testing.T, filename string) testImportFileFolder { @@ -168,6 +187,8 @@ func buildTestImportFileFolder(t *testing.T, filename string) testImportFileFold tc.module1 = string(alloyConfig.Data) case "module2.alloy": tc.module2 = string(alloyConfig.Data) + case "utils/module2.alloy": + tc.utilsModule2 = string(alloyConfig.Data) case "added.alloy": tc.added = string(alloyConfig.Data) case "removed.alloy": @@ -184,6 +205,12 @@ func buildTestImportFileFolder(t *testing.T, filename string) testImportFileFold name: "module2.alloy", updateConfig: string(alloyConfig.Data), } + case "utils/update_module2.alloy": + require.Nil(t, tc.update) + tc.update = &updateFile{ + name: "utils/module2.alloy", + updateConfig: string(alloyConfig.Data), + } } } return tc @@ -210,6 +237,12 @@ func TestImportFileFolder(t *testing.T) { require.NoError(t, os.WriteFile(filepath.Join(dir, "removed.alloy"), []byte(tc.removed), 0700)) } + if tc.utilsModule2 != "" { + nestedDir := filepath.Join(dir, "utils") + require.NoError(t, os.Mkdir(nestedDir, 0700)) + require.NoError(t, os.WriteFile(filepath.Join(nestedDir, "module2.alloy"), []byte(tc.utilsModule2), 0700)) + } + // TODO: ideally we would like to check the health of the node but that's not yet possible for import nodes. // We should expect that adding or removing files in the dir is gracefully handled and the node should be // healthy once it polls the content of the dir again. @@ -265,7 +298,7 @@ func testConfig(t *testing.T, config string, reloadConfig string, update func()) defer verifyNoGoroutineLeaks(t) ctrl, f := setup(t, config) - err := ctrl.LoadSource(f, nil) + err := ctrl.LoadSource(f, nil, "") require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -303,7 +336,7 @@ func testConfig(t *testing.T, config string, reloadConfig string, update func()) require.NotNil(t, f) // Reload the controller with the new config. - err = ctrl.LoadSource(f, nil) + err = ctrl.LoadSource(f, nil, "") require.NoError(t, err) // Export should be -10 after update @@ -317,7 +350,7 @@ func testConfig(t *testing.T, config string, reloadConfig string, update func()) func testConfigError(t *testing.T, config string, expectedError string) { defer verifyNoGoroutineLeaks(t) ctrl, f := setup(t, config) - err := ctrl.LoadSource(f, nil) + err := ctrl.LoadSource(f, nil, "") require.ErrorContains(t, err, expectedError) ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup diff --git a/internal/runtime/testdata/import_file/import_file_18.txtar b/internal/runtime/testdata/import_file/import_file_18.txtar new file mode 100644 index 0000000000..36584f2f22 --- /dev/null +++ b/internal/runtime/testdata/import_file/import_file_18.txtar @@ -0,0 +1,50 @@ +Import nested passthrough module with relative import path. + +-- main.alloy -- +testcomponents.count "inc" { + frequency = "10ms" + max = 10 +} + +import.file "testImport" { + filename = "nested_test/module.alloy" +} + +testImport.a "cc" { + input = testcomponents.count.inc.count +} + +testcomponents.summation "sum" { + input = testImport.a.cc.output +} + +-- nested_test/module.alloy -- +import.file "testImport" { + filename = file.path_join(module_path, "utils/module.alloy") +} + +declare "a" { + argument "input" {} + + testImport.a "cc" { + input = argument.input.value + } + + export "output" { + value = testImport.a.cc.output + } +} + +-- nested_test/utils/module.alloy -- +declare "a" { + argument "input" {} + + testcomponents.passthrough "pt" { + input = argument.input.value + lag = "1ms" + } + + export "output" { + value = testcomponents.passthrough.pt.output + } +} diff --git a/internal/runtime/testdata/import_file/import_file_19.txtar b/internal/runtime/testdata/import_file/import_file_19.txtar new file mode 100644 index 0000000000..728855b84a --- /dev/null +++ b/internal/runtime/testdata/import_file/import_file_19.txtar @@ -0,0 +1,49 @@ +Import string with import file with relative import path. + +-- main.alloy -- +testcomponents.count "inc" { + frequency = "10ms" + max = 10 +} + +import.string "testImport" { + content = ` + import.file "testImport" { + filename = file.path_join(module_path, "nested_test/module.alloy") + } + + declare "a" { + argument "input" {} + + testImport.a "cc" { + input = argument.input.value + } + + export "output" { + value = testImport.a.cc.output + } + } + ` +} + +testImport.a "cc" { + input = testcomponents.count.inc.count +} + +testcomponents.summation "sum" { + input = testImport.a.cc.output +} + +-- nested_test/module.alloy -- +declare "a" { + argument "input" {} + + testcomponents.passthrough "pt" { + input = argument.input.value + lag = "1ms" + } + + export "output" { + value = testcomponents.passthrough.pt.output + } +} diff --git a/internal/runtime/testdata/import_file/import_file_20.txtar b/internal/runtime/testdata/import_file/import_file_20.txtar new file mode 100644 index 0000000000..7fd7f3b697 --- /dev/null +++ b/internal/runtime/testdata/import_file/import_file_20.txtar @@ -0,0 +1,50 @@ +Import nested passthrough module with relative import path in a declare. + +-- main.alloy -- +testcomponents.count "inc" { + frequency = "10ms" + max = 10 +} + +import.file "testImport" { + filename = "nested_test/module.alloy" +} + +testImport.a "cc" { + input = testcomponents.count.inc.count +} + +testcomponents.summation "sum" { + input = testImport.a.cc.output +} + +-- nested_test/module.alloy -- +declare "a" { + argument "input" {} + + import.file "testImport" { + filename = file.path_join(module_path, "utils/module.alloy") + } + + testImport.a "cc" { + input = argument.input.value + } + + export "output" { + value = testImport.a.cc.output + } +} + +-- nested_test/utils/module.alloy -- +declare "a" { + argument "input" {} + + testcomponents.passthrough "pt" { + input = argument.input.value + lag = "1ms" + } + + export "output" { + value = testcomponents.passthrough.pt.output + } +} diff --git a/internal/runtime/testdata/import_file_folder/import_file_folder_7.txtar b/internal/runtime/testdata/import_file_folder/import_file_folder_7.txtar new file mode 100644 index 0000000000..8c2ae7866b --- /dev/null +++ b/internal/runtime/testdata/import_file_folder/import_file_folder_7.txtar @@ -0,0 +1,58 @@ +Import nested folder with relative path. + +-- main.alloy -- +testcomponents.count "inc" { + frequency = "10ms" + max = 10 +} + +import.file "testImport" { + filename = "tmpTest" +} + +testImport.a "cc" { + input = testcomponents.count.inc.count +} + +testcomponents.summation "sum" { + input = testImport.a.cc.output +} + +-- module1.alloy -- +import.file "testImport" { + filename = file.path_join(module_path, "utils") +} +declare "a" { + argument "input" {} + + testImport.b "cc" { + input = argument.input.value + } + + export "output" { + value = testImport.b.cc.output + } +} + +-- utils/module2.alloy -- +declare "b" { + argument "input" {} + + testcomponents.passthrough "pt" { + input = argument.input.value + lag = "1ms" + } + + export "output" { + value = testcomponents.passthrough.pt.output + } +} + +-- utils/update_module2.alloy -- +declare "b" { + argument "input" {} + + export "output" { + value = -argument.input.value + } +} diff --git a/internal/runtime/testdata/import_git/import_git_4.txtar b/internal/runtime/testdata/import_git/import_git_4.txtar new file mode 100644 index 0000000000..f4f8feef9c --- /dev/null +++ b/internal/runtime/testdata/import_git/import_git_4.txtar @@ -0,0 +1,21 @@ +Import a module that contains an import.file with a relative import path. + +-- main.alloy -- +testcomponents.count "inc" { + frequency = "10ms" + max = 10 +} + +import.git "testImport" { + // Requires repo.git.tar to be extracted + repository = "./testdata/repo.git" + path = "module_import_file.alloy" +} + +testImport.a "cc" { + input = testcomponents.count.inc.count +} + +testcomponents.summation "sum" { + input = testImport.a.cc.output +} diff --git a/internal/runtime/testdata/import_git/import_git_5.txtar b/internal/runtime/testdata/import_git/import_git_5.txtar new file mode 100644 index 0000000000..c5cefee502 --- /dev/null +++ b/internal/runtime/testdata/import_git/import_git_5.txtar @@ -0,0 +1,21 @@ +Import a module that contains an import.file with a relative import path inside of a declare. + +-- main.alloy -- +testcomponents.count "inc" { + frequency = "10ms" + max = 10 +} + +import.git "testImport" { + // Requires repo.git.tar to be extracted + repository = "./testdata/repo.git" + path = "module_import_file_in_declare.alloy" +} + +testImport.a "cc" { + input = testcomponents.count.inc.count +} + +testcomponents.summation "sum" { + input = testImport.a.cc.output +} diff --git a/internal/runtime/testdata/repo.git.tar b/internal/runtime/testdata/repo.git.tar index 53147ced4e..eb55d336fe 100644 Binary files a/internal/runtime/testdata/repo.git.tar and b/internal/runtime/testdata/repo.git.tar differ