-
Notifications
You must be signed in to change notification settings - Fork 5
fix(api): allow missing required variable when a brick is added + app validation #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 40 commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
4df8f58
fix: improve error logging message in HandleBrickCreate function
dido18 650906d
test: rename TestBrickCreate to TestBrickCreateFromAppExample and upd…
dido18 59a73d2
fix: log a warning for missing mandatory variables in BrickCreate and…
dido18 18a0030
revert some changes
dido18 a8c8314
fix: update test cases for BrickCreate to improve clarity and logging
dido18 289e6af
fix: correct typo in comment for BrickCreate function to enhance clarity
dido18 ad54d74
fix: improve warning message for missing mandatory variables in Brick…
dido18 1e8e541
feat: add validation for app descriptors and corresponding test cases
dido18 58a4227
fix: correct expected error message for missing required variable in …
dido18 7878a2c
refactor: rename validation functions and update test cases for clari…
dido18 ef6c2de
fix: rename variable for clarity and validate app descriptor in Handl…
dido18 84f1256
fix: update error code to BadRequestErr in HandleAppStart and add cor…
dido18 9bc05ac
refactor: consolidate brick validation into AppDescriptor and update …
dido18 05f12bf
fix: ensure bricks index is not nil and capture error from ValidateBr…
dido18 70e1dbb
test: add YAML test cases for app descriptor validation with empty an…
dido18 38b49bc
test: add test case for validation of non-existing variable in app de…
dido18 3708460
fix: enhance brick validation to collect all errors and add new test …
dido18 d8028b6
fix: update ValidateBricks to return all validation errors as a slice…
dido18 6a17436
fix: update error handling in ValidateBricks to yield all validation …
dido18 c7a2e55
fix: refactor ValidateBricks to return a single error and update rela…
dido18 5742d45
test: add dummy app configuration and main.py for brick creation tests
dido18 1b18b36
fix: add logging for missing required variables in BrickCreate function
dido18 36319aa
chore: remove unused app.golden.yaml test data file
dido18 d9992fe
fix: clean up app.yaml by removing unused variables section
dido18 89bb0b9
refactor: move ValidateBricks function to a new file and update refer…
dido18 8acb1cc
refactor: update app type references from appspecification to app
dido18 4b525b3
FIX
dido18 7a9bdf2
refactor: log a warning for undeclared variables in brick configuration
dido18 7f935b9
Update internal/orchestrator/app/validator.go
dido18 1661442
refactor: rename variable for clarity in ValidateBricks function
dido18 2ccabd8
refactor: improve error handling and logging in validation functions
dido18 def6889
refactor: update test cases to use YAML content instead of filenames …
dido18 7a8ad44
refactor: remove obsolete YAML test files and clean up validator tests
dido18 ee2db2d
refactor: remove redundant brick validation from app restart process
dido18 c264066
refactor: improve error messages for brick update and validation proc…
dido18 98a2ae1
fix: correct typo in error message for required brick variable
dido18 18b6daf
refactor: improve error messages and update brick handling in service…
dido18 95728f2
refactor: update brick handling and improve test coverage for variabl…
dido18 d183dae
fix: correct typo in TODO comment for variable handling in tests
dido18 e1da66c
fix: remove hardcoded VERSION variable from build task in Taskfile
dido18 02df117
Update internal/orchestrator/bricks/bricks_test.go
dido18 37a4cf4
Add comprehensive AI model support documentation for AppLab
dido18 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package app | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "log/slog" | ||
|
|
||
| "github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex" | ||
| ) | ||
|
|
||
| // ValidateBricks checks that all bricks referenced in the given AppDescriptor exist in the provided BricksIndex, | ||
| // It collects and returns all validation errors as a single joined error, allowing the caller to see all issues at once rather than stopping at the first error. | ||
| func ValidateBricks(a AppDescriptor, index *bricksindex.BricksIndex) error { | ||
| if index == nil { | ||
| return fmt.Errorf("bricks index cannot be nil") | ||
| } | ||
|
|
||
| var allErrors error | ||
|
|
||
| for _, appBrick := range a.Bricks { | ||
| indexBrick, found := index.FindBrickByID(appBrick.ID) | ||
| if !found { | ||
| allErrors = errors.Join(allErrors, fmt.Errorf("brick %q not found", appBrick.ID)) | ||
| continue // Skip further validation for this brick since it doesn't exist | ||
| } | ||
|
|
||
| for appBrickVariableName := range appBrick.Variables { | ||
| _, exist := indexBrick.GetVariable(appBrickVariableName) | ||
| if !exist { | ||
| // TODO: we should return warnings | ||
| slog.Warn("[skip] variable does not exist into the brick definition", "variable", appBrickVariableName, "brick", indexBrick.ID) | ||
| } | ||
| } | ||
|
|
||
| // Check that all required brick variables are provided by app | ||
| for _, indexBrickVariable := range indexBrick.Variables { | ||
| if indexBrickVariable.IsRequired() { | ||
| if _, exist := appBrick.Variables[indexBrickVariable.Name]; !exist { | ||
| allErrors = errors.Join(allErrors, fmt.Errorf("variable %q is required by brick %q", indexBrickVariable.Name, indexBrick.ID)) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return allErrors | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| package app | ||
|
|
||
| import ( | ||
| "errors" | ||
| "os" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/arduino/go-paths-helper" | ||
|
|
||
| "github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex" | ||
| ) | ||
|
|
||
| func TestValidateAppDescriptorBricks(t *testing.T) { | ||
| bricksIndex := &bricksindex.BricksIndex{ | ||
| Bricks: []bricksindex.Brick{ | ||
| { | ||
| ID: "arduino:arduino_cloud", | ||
| Name: "Arduino Cloud", | ||
| Description: "Connects to Arduino Cloud", | ||
| Variables: []bricksindex.BrickVariable{ | ||
| { | ||
| Name: "ARDUINO_DEVICE_ID", | ||
| Description: "Arduino Cloud Device ID", | ||
| DefaultValue: "", // Required (no default value) | ||
| }, | ||
| { | ||
| Name: "ARDUINO_SECRET", | ||
| Description: "Arduino Cloud Secret", | ||
| DefaultValue: "", // Required (no default value) | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| testCases := []struct { | ||
| name string | ||
| yamlContent string | ||
| expectedError error | ||
| }{ | ||
| { | ||
| name: "valid with all required filled", | ||
| yamlContent: ` | ||
| name: App ok | ||
| description: App ok | ||
| bricks: | ||
| - arduino:arduino_cloud: | ||
| variables: | ||
| ARDUINO_DEVICE_ID: "my-device-id" | ||
| ARDUINO_SECRET: "my-secret" | ||
| `, | ||
| expectedError: nil, | ||
| }, | ||
| { | ||
| name: "valid with missing bricks", | ||
| yamlContent: ` | ||
| name: App with no bricks | ||
| description: App with no bricks description | ||
| `, | ||
| expectedError: nil, | ||
| }, | ||
| { | ||
| name: "valid with empty list of bricks", | ||
| yamlContent: ` | ||
| name: App with empty bricks | ||
| description: App with empty bricks | ||
|
|
||
| bricks: [] | ||
| `, | ||
| expectedError: nil, | ||
| }, | ||
| { | ||
| name: "valid if required variable is empty string", | ||
| yamlContent: ` | ||
| name: App with an empty variable | ||
| description: App with an empty variable | ||
| bricks: | ||
| - arduino:arduino_cloud: | ||
| variables: | ||
| ARDUINO_DEVICE_ID: "my-device-id" | ||
| ARDUINO_SECRET: | ||
| `, | ||
| expectedError: nil, | ||
| }, | ||
| { | ||
| name: "invalid if required variable is omitted", | ||
| yamlContent: ` | ||
| name: App with no required variables | ||
| description: App with no required variables | ||
| bricks: | ||
| - arduino:arduino_cloud | ||
| `, | ||
| expectedError: errors.Join( | ||
| errors.New("variable \"ARDUINO_DEVICE_ID\" is required by brick \"arduino:arduino_cloud\""), | ||
| errors.New("variable \"ARDUINO_SECRET\" is required by brick \"arduino:arduino_cloud\""), | ||
| ), | ||
| }, | ||
| { | ||
| name: "invalid if a required variable among two is omitted", | ||
| yamlContent: ` | ||
| name: App only one required variable filled | ||
| description: App only one required variable filled | ||
| bricks: | ||
| - arduino:arduino_cloud: | ||
| variables: | ||
| ARDUINO_DEVICE_ID: "my-device-id" | ||
| `, | ||
| expectedError: errors.New("variable \"ARDUINO_SECRET\" is required by brick \"arduino:arduino_cloud\""), | ||
| }, | ||
| { | ||
| name: "invalid if brick id not found", | ||
| yamlContent: ` | ||
| name: App no existing brick | ||
| description: App no existing brick | ||
| bricks: | ||
| - arduino:not_existing_brick: | ||
| variables: | ||
| ARDUINO_DEVICE_ID: "my-device-id" | ||
| ARDUINO_SECRET: "LAKDJ" | ||
| `, | ||
| expectedError: errors.New("brick \"arduino:not_existing_brick\" not found"), | ||
| }, | ||
| { | ||
| name: "log a warning if variable does not exist in the brick", | ||
| yamlContent: ` | ||
| name: App with non existing variable | ||
| description: App with non existing variable | ||
| bricks: | ||
| - arduino:arduino_cloud: | ||
| variables: | ||
| NOT_EXISTING_VARIABLE: "this-is-a-not-existing-variable-for-the-brick" | ||
| ARDUINO_DEVICE_ID: "my-device-id" | ||
| ARDUINO_SECRET: "my-secret" | ||
| `, | ||
| expectedError: nil, | ||
| }, | ||
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| err := paths.New(tempDir).MkdirAll() | ||
| require.NoError(t, err) | ||
| appYaml := paths.New(tempDir, "app.yaml") | ||
| err = os.WriteFile(appYaml.String(), []byte(tc.yamlContent), 0600) | ||
| require.NoError(t, err) | ||
|
|
||
| appDescriptor, err := ParseDescriptorFile(appYaml) | ||
| require.NoError(t, err) | ||
|
|
||
| err = ValidateBricks(appDescriptor, bricksIndex) | ||
| if tc.expectedError == nil { | ||
| assert.NoError(t, err, "Expected no validation errors") | ||
| } else { | ||
| require.Error(t, err, "Expected validation error") | ||
| assert.Equal(t, tc.expectedError.Error(), err.Error(), "Error message should match") | ||
| } | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.