Skip to content

Update config validation logic for entities#3306

Open
aaronburtle wants to merge 32 commits intomainfrom
dev/aaronburtle/warn-zero-entities-validate
Open

Update config validation logic for entities#3306
aaronburtle wants to merge 32 commits intomainfrom
dev/aaronburtle/warn-zero-entities-validate

Conversation

@aaronburtle
Copy link
Copy Markdown
Contributor

@aaronburtle aaronburtle commented Mar 23, 2026

Why make this change?

Closes #3267

What is this change?

Alters the validation logic in the following way.

Is top-level config with data-source-files?
├── YES
│ ├── Has datasource? → ValidateEntityPresence (same rules as non-root)
│ ├── No datasource but has entities/autoentities? → ERROR
│ └── No datasource, no entities → VALID (children provide everything)
│ └── For each child → ValidateNonRootConfig(child, filename)

└── NO (standalone or child config)
├── No datasource? → ERROR: "data source is required"
└── Has datasource → ValidateEntityPresence

ValidateEntityPresence

Count resolved autoentities from AutoentityResolutionCounts
total = manual entities + resolved autoentities

total == 0? → ERROR: "No entities found"
total > 0 but autoentities discovered nothing? → WARN: "Autoentities configured but none discovered"

No double messaging. If total is 0, only the error is recorded, not the warning.

How was this tested?

Truth table — top-level config

Variables (1 = present / non-empty, 0 = absent / empty):

  • DSFdata-source-files present
  • DSdata-source present
  • E — manual entities count > 0
  • AEautoentities count > 0 (presence, not resolved count)

Path is determined by IsRootConfig = (DSF == 1) && !IsChildConfig.

# DSF DS E AE AE resolved Path Expected Test
1 0 0 0 0 Non-root Error: "data source is required" TestNonRootWithNoDataSourceProducesError
2 0 0 0 1 Non-root Error: "data source is required" covered by #1 — DS check fires first
3 0 0 1 0 Non-root Error: "data source is required" covered by #1
4 0 0 1 1 Non-root Error: "data source is required" covered by #1
5 0 1 0 0 Non-root Error: "No entities found" TestNonRootWithDataSourceAndNoEntitiesProducesError
6a 0 1 0 1 0 Non-root Error: "No entities found" TestNonRootWithDataSourceAndAutoentitiesResolvingZeroProducesError
6b 0 1 0 1 >0 Non-root Valid TestNonRootWithDataSourceAndAutoentitiesResolvingEntitiesIsValid
7 0 1 1 0 Non-root Valid TestNonRootWithDataSourceAndEntitiesIsValid
8a 0 1 1 1 0 Non-root Valid + Warn TestNonRootWithEntitiesAndAutoentitiesResolvingZeroLogsWarning
8b 0 1 1 1 >0 Non-root Valid covered by #7 / #6b combined
9 1 0 0 0 Root Valid (children carry the load) TestRootWithNoDataSourceAndNoEntitiesIsValid, TestRootConfigWithNoDataSourceAndNoEntitiesParses
10 1 0 0 1 Root Error: "must not define entities or autoentities" TestRootWithNoDataSourceButAutoentitiesProducesError
11 1 0 1 0 Root Error: "must not define entities" TestRootWithNoDataSourceButEntitiesProducesError
12 1 0 1 1 Root Error covered by #11
13 1 1 0 0 Root (with own DS) Error: "No entities found" TestRootWithDataSourceAndNoEntitiesProducesError
14a 1 1 0 1 0 Root (with own DS) Error: "No entities found" TestRootWithDataSourceAndAutoentitiesResolvingZeroProducesError
14b 1 1 0 1 >0 Root (with own DS) Valid TestRootWithDataSourceAndAutoentitiesResolvingEntitiesIsValid
15 1 1 1 0 Root (with own DS) Valid TestRootWithDataSourceAndEntitiesIsValid
16a 1 1 1 1 0 Root (with own DS) Valid + Warn TestRootWithEntitiesAndAutoentitiesResolvingZeroLogsWarning
16b 1 1 1 1 >0 Root (with own DS) Valid covered by #15 / #14b combined

Truth table — child config (validated when iterating root.ChildConfigs)

Children are always treated as non-root regardless of their own data-source-files.

# DS E AE AE resolved Expected Test
C1 0 0 0 Error naming the child file: "data source is required" TestChildWithNoDataSourceProducesNamedError
C2 0 * * Error naming the child file: "data source is required" covered by C1
C3 1 0 0 Error naming the child file: "No entities found" TestChildWithDataSourceAndNoEntitiesProducesNamedError
C4a 1 0 1 0 Error naming the child file: "No entities found" TestChildWithDataSourceAndAutoentitiesResolvingZeroProducesNamedError
C4b 1 0 1 >0 Valid covered by C5 (resolved entities behave the same as manual entities)
C5 1 1 0 Valid implicitly via TestRootWithDataSourceAndEntitiesIsValid setup
C6a 1 1 1 0 Valid + Warn naming the child file TestChildWithEntitiesAndAutoentitiesResolvingZeroLogsNamedWarning
C6b 1 1 1 >0 Valid covered by C5

Other scenarios

Scenario Expected Test
Connection-string error gates entity validation (no entity error fires when DB unreachable) IsConfigValid == false due to connection error only TestValidateNonRootZeroEntitiesWithInvalidConnectionString
Config with no entities parses cleanly (constructor no longer throws) and IsConfigValid returns false without throwing parse OK, validate fails TestValidateConfigWithNoEntitiesProducesCleanError (modified)
Root parses successfully without a data source parse OK, IsRootConfig == true TestRootConfigWithNoDataSourceAndNoEntitiesParses
Non-root with DS and no entities parses successfully parse OK, IsRootConfig == false TestNonRootConfigWithDataSourceAndNoEntitiesParses
Autoentities present but resolve to nothing — must not crash, must not double-message with "No entities found" no crash; only "No entities found" if total = 0 ValidateAutoentitiesConfiguration (modified to isValidateOnly: true)

New tests:

TestRootConfigWithNoDataSourceAndNoEntitiesParses Root config (has data-source-files) without datasource parses OK
TestNonRootConfigWithDataSourceAndNoEntitiesParses Non-root config with datasource + no entities parses OK (validation catches it later)
TestNonRootWithDataSourceAndNoEntitiesProducesError Calls ValidateDataSourceAndEntityPresence directly, error recorded
TestNonRootWithNoDataSourceProducesError No datasource, error with "data source is required"
TestNonRootWithDataSourceAndEntitiesIsValid Datasource + entities, no errors
TestRootWithNoDataSourceAndNoEntitiesIsValid Root with child, no own datasource, valid
TestRootWithNoDataSourceButEntitiesProducesError Root with entities but no datasource, error
TestRootWithDataSourceAndEntitiesIsValid Root with own datasource + entities, valid
TestChildWithDataSourceAndNoEntitiesProducesNamedError Child with no entities, error names the child file
TestChildWithNoDataSourceProducesNamedError Child with no datasource, error names the child file
TestNonRootWithDataSourceAndAutoentitiesResolvingZeroProducesError Non-root with only autoentities that resolve to 0
TestNonRootWithDataSourceAndAutoentitiesResolvingEntitiesIsValid Non-root with only autoentities resolving > 0 entities
TestNonRootWithEntitiesAndAutoentitiesResolvingZeroLogsWarning Non-root with manual entities + autoentities resolving 0
TestRootWithNoDataSourceButAutoentitiesProducesError Root with no datasource but autoentities defined
TestRootWithDataSourceAndNoEntitiesProducesError Root with own datasource and zero entities/autoentities
TestRootWithDataSourceAndAutoentitiesResolvingZeroProducesError Root with own datasource and autoentities resolving 0
TestRootWithDataSourceAndAutoentitiesResolvingEntitiesIsValid Root with own datasource and autoentities resolving > 0
TestRootWithEntitiesAndAutoentitiesResolvingZeroLogsWarning Root with own datasource, manual entities, and autoentities resolving 0
TestChildWithDataSourceAndAutoentitiesResolvingZeroProducesNamedError Child with autoentities-only resolving 0
TestChildWithEntitiesAndAutoentitiesResolvingZeroLogsNamedWarning Child with manual entities + autoentities resolving 0

Modified tests:

TestValidateConfigWithNoEntitiesProducesCleanError Replaced main's version (expected parse failure) with ours: parse succeeds, IsConfigValid returns false
ValidateAutoentitiesConfiguration Changed to isValidateOnly: true, asserts no crashes instead of zero errors

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a CLI validation-time warning to help users detect “valid” configs that define no entities (and have no autoentities / multi-config datasource files), aligning dab validate behavior with Issue #3267.

Changes:

  • Adds a WarnIfNoEntitiesDefined(RuntimeConfig) helper and invokes it during dab validate.
  • Refactors IsConfigValid to log the new structural warning regardless of overall validation outcome.
  • Adds a CLI unit test that verifies the warning is logged for a minimal config with zero entities.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/Cli/ConfigGenerator.cs Introduces and invokes the new “zero entities” warning helper during dab validate.
src/Cli.Tests/ValidateConfigTests.cs Adds a unit test verifying the warning is emitted for an empty-entities config.

Comment thread src/Cli/ConfigGenerator.cs Outdated
Comment thread src/Cli/ConfigGenerator.cs Outdated
@aaronburtle aaronburtle self-assigned this Mar 23, 2026
@aaronburtle aaronburtle added 2.0 bug Something isn't working labels Mar 23, 2026
@aaronburtle aaronburtle moved this from Todo to Review In Progress in Data API builder Mar 23, 2026
@aaronburtle aaronburtle added this to the March 2026 milestone Mar 23, 2026
@anushakolan
Copy link
Copy Markdown
Contributor

/azp run

@Aniruddh25
Copy link
Copy Markdown
Collaborator

Aniruddh25 commented Apr 10, 2026

if (data-source-files not present)
{
   error if data-source missing
}

// data-source-files are present or data-source is present:

if (entities and autoentities)
{
    error when none
}
else if (only entities)
{
    error when none
}
else if (only autoentities)
{
    error when none
}
else
{
    error unless data-source absent
    (already handled)
}

after offline discussion

@aaronburtle aaronburtle force-pushed the dev/aaronburtle/warn-zero-entities-validate branch from 4bb0609 to 5c93d5e Compare April 27, 2026 22:29
@aaronburtle aaronburtle changed the title Warn when dab validate finds zero entities in the config Update config validation logic for entities Apr 29, 2026
Comment thread src/Core/Configurations/RuntimeConfigProvider.cs Outdated
Comment thread src/Core/Configurations/RuntimeConfigValidator.cs
Comment thread src/Core/Configurations/RuntimeConfigValidator.cs
Comment thread src/Service.Tests/Configuration/ConfigurationTests.cs Outdated
Runtime.Rest is null ||
Runtime.Rest.Enabled) &&
DataSource.DatabaseType != DatabaseType.CosmosDB_NoSQL;
DataSource?.DatabaseType != DatabaseType.CosmosDB_NoSQL;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If DataSource is not present in case of root config, this will evaluate to false even though the child configs with a DataSource are of type SQL.

The condition should be either its null or if not null, Db type !=NoSQL

if (!TryCreateSourceObjectForNewEntity(
options,
initialRuntimeConfig.DataSource.DatabaseType == DatabaseType.CosmosDB_NoSQL,
initialRuntimeConfig.DataSource!.DatabaseType == DatabaseType.CosmosDB_NoSQL,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how are we sure DataSource is not null here?

What happens when a new entity is being added to a config with a null data source? Is that allowed? If not, where is the check that will prevent this?

[NotNullWhen(true)] ref RuntimeConfig runtimeConfig)
{
DatabaseType dbType = runtimeConfig.DataSource.DatabaseType;
DatabaseType dbType = runtimeConfig.DataSource!.DatabaseType;
Copy link
Copy Markdown
Collaborator

@Aniruddh25 Aniruddh25 May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we be sure DataSource is null when trying to update the datasource? Does the caller perform any checks?

Same question for all null forgiveness operator usage in this file.

""entities"": {}
}";

// The root config should parse without error (no data-source required for root).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldnt the test also check that IsConfigValid returns true?

[TestMethod]
public void TestNonRootConfigWithDataSourceAndNoEntitiesParses()
{
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(INITIAL_CONFIG, out RuntimeConfig? config));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What makes this a Non root config? Does INITIAL_CONFIG string specify that?

[TestMethod]
public void TestNonRootWithDataSourceAndNoEntitiesProducesError()
{
RuntimeConfig config = BuildTestConfig(hasDataSource: true, entities: new());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What makes it non-root?

Copy link
Copy Markdown
Collaborator

@Aniruddh25 Aniruddh25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsRestEnabled check needs to be fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.0 bug Something isn't working

Projects

Status: Review In Progress

Development

Successfully merging this pull request may close these issues.

[Bug]: dab validate should at least warn when zero entities are in the config.

5 participants