From 62f9387d59601ed52fd723fa632e0a44c4f25ff2 Mon Sep 17 00:00:00 2001
From: Sezal Chug <30494467+sezal98@users.noreply.github.com>
Date: Thu, 31 Oct 2024 13:21:35 +0530
Subject: [PATCH] Configure and updated Runtime REST and CACHE setting using in
CLI (#2435)
## Why make this change?
Resolved issue #2419
This change is made to enable dab users to update/change values of Rest
and Cache runtime settings from CLI commands.
## What is this change?
1. Made changes in ConfigureOptions.cs to include the additional
parameters for Rest and Cache.
2. Changes in ConfigureGenerator.cs to include the function to update
the newly incoming values in the parameters of Rest and Cache runtime
settings
3. Changes in Tests to add individual tests for Enabled, Path and
Request-Body-Strict for Rest Runtime settings and Enabled and TTL for
Cache runtime settings and have two test for multiple parameters in a
single command.
## How was this tested?
- [x] Integration Tests
- [x] Unit Tests
## Sample Request(s)
`dab configure --runtime.rest.enabled false -c {Config-File-Name}`
Updating the Rest.Enabled value
`dab configure --runtime.rest.path "/updating -c {Config-File-Name}`
Updating the Rest.Path value
Errors or Negative Test cases in updating Rest.Path
- updating
- /upda/ting
- /upda ting
- /upda@ting
Cache Sample Requests
Update Enabled
Update TTL
---
src/Cli.Tests/ConfigureOptionsTests.cs | 207 ++++++++++++++++--
src/Cli.Tests/EndToEndTests.cs | 66 ++++++
src/Cli/Commands/ConfigureOptions.cs | 29 +++
src/Cli/ConfigGenerator.cs | 165 ++++++++++++--
.../RuntimeConfigValidatorUtil.cs | 14 ++
5 files changed, 450 insertions(+), 31 deletions(-)
diff --git a/src/Cli.Tests/ConfigureOptionsTests.cs b/src/Cli.Tests/ConfigureOptionsTests.cs
index 770ef7dca3..4228dff9e1 100644
--- a/src/Cli.Tests/ConfigureOptionsTests.cs
+++ b/src/Cli.Tests/ConfigureOptionsTests.cs
@@ -55,18 +55,19 @@ public void TestNoUpdateOnGraphQLDepthLimitInRuntimeSettings(object? depthLimit,
// Arrange
_fileSystem!.AddFile(TEST_RUNTIME_CONFIG_FILE, initialConfig);
+ Assert.IsTrue(_fileSystem!.File.Exists(TEST_RUNTIME_CONFIG_FILE));
// Act: Run Configure with no options
ConfigureOptions options = new(
config: TEST_RUNTIME_CONFIG_FILE
);
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
- Assert.IsTrue(_fileSystem!.File.Exists(TEST_RUNTIME_CONFIG_FILE));
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
-
- string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ // Assert
+ Assert.IsTrue(isSuccess);
// Assert that INITIAL_CONFIG is same as the updated config
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
if (isDepthLimitProvidedInConfig)
{
Assert.IsTrue(updatedConfig.Contains(depthLimitSection));
@@ -100,9 +101,10 @@ public void TestAddDepthLimitForGraphQL()
depthLimit: maxDepthLimit,
config: TEST_RUNTIME_CONFIG_FILE
);
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the Depth Limit is added
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out config));
Assert.IsNotNull(config.Runtime?.GraphQL?.DepthLimit);
@@ -114,8 +116,8 @@ public void TestAddDepthLimitForGraphQL()
/// in runtime. Takes in updated value for graphql.enabled and
/// validates whether the runtime config reflects those updated values
[DataTestMethod]
- [DataRow(false, DisplayName = "Update enabled to be false for GraphQL.")]
- [DataRow(true, DisplayName = "Update enabled to be true for GraphQL.")]
+ [DataRow(false, DisplayName = "Update GraphQL.Enabled to false.")]
+ [DataRow(true, DisplayName = "Validate GraphQL.Enabled to remain true.")]
public void TestUpdateEnabledForGraphQLSettings(bool updatedEnabledValue)
{
// Arrange -> all the setup which includes creating options.
@@ -126,9 +128,10 @@ public void TestUpdateEnabledForGraphQLSettings(bool updatedEnabledValue)
runtimeGraphQLEnabled: updatedEnabledValue,
config: TEST_RUNTIME_CONFIG_FILE
);
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the Enabled Flag is updated
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
Assert.IsNotNull(runtimeConfig.Runtime?.GraphQL?.Enabled);
@@ -153,9 +156,10 @@ public void TestUpdatePathForGraphQLSettings(string updatedPathValue)
runtimeGraphQLPath: updatedPathValue,
config: TEST_RUNTIME_CONFIG_FILE
);
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the Path update is updated
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
Assert.IsNotNull(runtimeConfig.Runtime?.GraphQL?.Path);
@@ -168,8 +172,8 @@ public void TestUpdatePathForGraphQLSettings(string updatedPathValue)
/// Takes in updated value for graphql.allow-introspection and
/// validates whether the runtime config reflects those updated values
[DataTestMethod]
- [DataRow(false, DisplayName = "Update AllowIntrospection to be false for GraphQL.")]
- [DataRow(true, DisplayName = "Update AllowIntrospection to be true for GraphQL.")]
+ [DataRow(false, DisplayName = "Update GraphQL.AllowIntrospection to be false.")]
+ [DataRow(true, DisplayName = "Validate GraphQL.AllowIntrospection to remain true.")]
public void TestUpdateAllowIntrospectionForGraphQLSettings(bool updatedAllowIntrospectionValue)
{
// Arrange -> all the setup which includes creating options.
@@ -180,9 +184,10 @@ public void TestUpdateAllowIntrospectionForGraphQLSettings(bool updatedAllowIntr
runtimeGraphQLAllowIntrospection: updatedAllowIntrospectionValue,
config: TEST_RUNTIME_CONFIG_FILE
);
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the Allow-Introspection value is updated
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
Assert.IsNotNull(runtimeConfig.Runtime?.GraphQL?.AllowIntrospection);
@@ -195,8 +200,8 @@ public void TestUpdateAllowIntrospectionForGraphQLSettings(bool updatedAllowIntr
/// Takes in updated value for multiple mutations.create.enabled and
/// validates whether the runtime config reflects those updated values
[DataTestMethod]
- [DataRow(false, DisplayName = "Update MultipleMutation.Create.Enabled to be false for GraphQL.")]
- [DataRow(true, DisplayName = "Update MultipleMutation.Create.Enabled to be true for GraphQL.")]
+ [DataRow(false, DisplayName = "Update GraphQL.MultipleMutation.Create.Enabled to be false.")]
+ [DataRow(true, DisplayName = "Validate GraphQL.MultipleMutation.Create.Enabled to remain true.")]
public void TestUpdateMultipleMutationCreateEnabledForGraphQLSettings(bool updatedMultipleMutationsCreateEnabledValue)
{
// Arrange -> all the setup which includes creating options.
@@ -207,9 +212,10 @@ public void TestUpdateMultipleMutationCreateEnabledForGraphQLSettings(bool updat
runtimeGraphQLMultipleMutationsCreateEnabled: updatedMultipleMutationsCreateEnabledValue,
config: TEST_RUNTIME_CONFIG_FILE
);
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the Multiple-Mutation.Create.Enabled is updated
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
Assert.IsNotNull(runtimeConfig.Runtime?.GraphQL?.MultipleMutationOptions?.MultipleCreateOptions?.Enabled);
@@ -235,9 +241,10 @@ public void TestUpdateMultipleParametersForGraphQLSettings()
runtimeGraphQLAllowIntrospection: updatedAllowIntrospectionValue,
config: TEST_RUNTIME_CONFIG_FILE
);
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the path is updated and allow introspection is updated
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
Assert.IsNotNull(runtimeConfig.Runtime?.GraphQL?.Path);
@@ -246,6 +253,171 @@ public void TestUpdateMultipleParametersForGraphQLSettings()
Assert.AreEqual(updatedAllowIntrospectionValue, runtimeConfig.Runtime.GraphQL.AllowIntrospection);
}
+ ///
+ /// Tests that running "dab configure --runtime.rest.enabled {value}" on a config with various values results
+ /// in runtime config update. Takes in updated value for rest.enabled and
+ /// validates whether the runtime config reflects those updated values
+ [DataTestMethod]
+ [DataRow(false, DisplayName = "Update Rest.Enabled to false.")]
+ [DataRow(true, DisplayName = "Validate if Rest.Enabled remains true.")]
+ public void TestUpdateEnabledForRestSettings(bool updatedEnabledValue)
+ {
+ // Arrange -> all the setup which includes creating options.
+ SetupFileSystemWithInitialConfig(INITIAL_CONFIG);
+
+ // Act: Attempts to update enabled flag
+ ConfigureOptions options = new(
+ runtimeRestEnabled: updatedEnabledValue,
+ config: TEST_RUNTIME_CONFIG_FILE
+ );
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
+
+ // Assert: Validate the Enabled Flag is updated
+ Assert.IsTrue(isSuccess);
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig.Runtime?.Rest?.Enabled);
+ Assert.AreEqual(updatedEnabledValue, runtimeConfig.Runtime.Rest.Enabled);
+ }
+
+ ///
+ /// Tests that running "dab configure --runtime.rest.path {value}" on a config with various values results
+ /// in runtime config update. Takes in updated value for rest.path and
+ /// validates whether the runtime config reflects those updated values
+ [DataTestMethod]
+ [DataRow("/updatedPath", DisplayName = "Update REST path to /updatedPath.")]
+ [DataRow("/updated_Path", DisplayName = "Ensure underscore is allowed in REST path.")]
+ [DataRow("/updated-Path", DisplayName = "Ensure hyphen is allowed in REST path.")]
+ public void TestUpdatePathForRestSettings(string updatedPathValue)
+ {
+ // Arrange -> all the setup which includes creating options.
+ SetupFileSystemWithInitialConfig(INITIAL_CONFIG);
+
+ // Act: Attempts to update path value
+ ConfigureOptions options = new(
+ runtimeRestPath: updatedPathValue,
+ config: TEST_RUNTIME_CONFIG_FILE
+ );
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
+
+ // Assert: Validate the Path update is updated
+ Assert.IsTrue(isSuccess);
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig.Runtime?.Rest?.Path);
+ Assert.AreEqual(updatedPathValue, runtimeConfig.Runtime.Rest.Path);
+ }
+
+ ///
+ /// Tests that running "dab configure --runtime.rest.request-body-strict" on a config with various values results
+ /// in runtime config update. Takes in updated value for rest.request-body-strict and
+ /// validates whether the runtime config reflects those updated values
+ [DataTestMethod]
+ [DataRow(false, DisplayName = "Update Rest.Request-Body-Strict to false.")]
+ [DataRow(true, DisplayName = "Validate if Rest.Request-body-Strict remains true.")]
+ public void TestUpdateRequestBodyStrictForRestSettings(bool updatedRequestBodyStrictValue)
+ {
+ // Arrange -> all the setup which includes creating options.
+ SetupFileSystemWithInitialConfig(INITIAL_CONFIG);
+
+ // Act: Attempts to update request-body-strict value
+ ConfigureOptions options = new(
+ runtimeRestRequestBodyStrict: updatedRequestBodyStrictValue,
+ config: TEST_RUNTIME_CONFIG_FILE
+ );
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
+
+ // Assert: Validate the RequestBodyStrict Value is updated
+ Assert.IsTrue(isSuccess);
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig.Runtime?.Rest?.RequestBodyStrict);
+ Assert.AreEqual(updatedRequestBodyStrictValue, runtimeConfig.Runtime.Rest.RequestBodyStrict);
+ }
+
+ ///
+ /// Tests that running "dab configure --runtime.rest.enabled {value} --runtime.rest.path {value}"
+ /// on a config with various values results in runtime config update.
+ /// Takes in updated value for enabled and path and further
+ /// validates whether the runtime config reflects those updated values
+ [DataTestMethod]
+ [DataRow(false, "/updatedPath", DisplayName = "Update enabled flag and path in Rest runtime settings.")]
+ public void TestUpdateMultipleParametersRestSettings(bool updatedEnabledValue, string updatedPathValue)
+ {
+ // Arrange -> all the setup which includes creating options.
+ SetupFileSystemWithInitialConfig(INITIAL_CONFIG);
+
+ // Act: Attempts to update the path value and enabled flag
+ ConfigureOptions options = new(
+ runtimeRestPath: updatedPathValue,
+ runtimeRestEnabled: updatedEnabledValue,
+ config: TEST_RUNTIME_CONFIG_FILE
+ );
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
+
+ // Assert: Validate the path is updated and enabled is updated
+ Assert.IsTrue(isSuccess);
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig.Runtime?.Rest?.Path);
+ Assert.IsNotNull(runtimeConfig.Runtime?.Rest?.Enabled);
+ Assert.AreEqual(updatedPathValue, runtimeConfig.Runtime.Rest.Path);
+ Assert.AreEqual(updatedEnabledValue, runtimeConfig.Runtime.Rest.Enabled);
+ }
+
+ ///
+ /// Validates that running "dab configure --runtime.cache.enabled" on a config with various values results
+ /// in runtime config update. Takes in updated value for cache.enabled and
+ /// validates whether the runtime config reflects those updated values.
+ [DataTestMethod]
+ [DataRow(false, DisplayName = "Update Cache.Enabled to false.")]
+ [DataRow(true, DisplayName = "Validate if Cache.Enabled remains true.")]
+ public void TestUpdateEnabledForCacheSettings(bool updatedEnabledValue)
+ {
+ // Arrange -> all the setup which includes creating options.
+ SetupFileSystemWithInitialConfig(INITIAL_CONFIG);
+
+ // Act: Attempts to update cache enabled flag
+ ConfigureOptions options = new(
+ runtimeCacheEnabled: updatedEnabledValue,
+ config: TEST_RUNTIME_CONFIG_FILE
+ );
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
+
+ // Assert: Validate the cache Enabled Flag is updated
+ Assert.IsTrue(isSuccess);
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig.Runtime?.Cache?.Enabled);
+ Assert.AreEqual(updatedEnabledValue, runtimeConfig.Runtime.Cache.Enabled);
+ }
+
+ ///
+ /// Tests that running "dab configure --runtime.cache.ttl-seconds" on a config with various values results
+ /// in runtime config update. Takes in updated value for cache.ttl-seconds and
+ /// validates whether the runtime config reflects those updated values
+ [DataTestMethod]
+ [DataRow(4, DisplayName = "Update global cache TTL to 4.")]
+ public void TestUpdateTTLForCacheSettings(int updatedTtlValue)
+ {
+ // Arrange -> all the setup which includes creating options.
+ SetupFileSystemWithInitialConfig(INITIAL_CONFIG);
+
+ // Act: Attempts to update TTL Value
+ ConfigureOptions options = new(
+ runtimeCacheTtl: updatedTtlValue,
+ config: TEST_RUNTIME_CONFIG_FILE
+ );
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
+
+ // Assert: Validate the TTL Value is updated
+ Assert.IsTrue(isSuccess);
+ string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig.Runtime?.Cache?.TtlSeconds);
+ Assert.AreEqual(updatedTtlValue, runtimeConfig.Runtime.Cache.TtlSeconds);
+ }
+
///
/// Test to update the current depth limit for GraphQL and removal the depth limit using -1.
/// When runtime.graphql.depth-limit has an initial value of 8.
@@ -279,9 +451,10 @@ public void TestUpdateDepthLimitForGraphQL(int? newDepthLimit)
);
// Act: Update Depth Limit
- Assert.IsTrue(TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!));
+ bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!);
// Assert: Validate the Depth Limit is updated
+ Assert.IsTrue(isSuccess);
string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE);
Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out config));
diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs
index a73bcec718..119e285472 100644
--- a/src/Cli.Tests/EndToEndTests.cs
+++ b/src/Cli.Tests/EndToEndTests.cs
@@ -359,6 +359,72 @@ public void TestUpdateGraphQLPathRuntimeSettings(string path, bool isSuccess)
Assert.AreEqual(isSuccess, isError == 0);
}
+ ///
+ /// This test checks behavior of executing `dab configure --runtime.rest.path {value}`
+ /// Validates that path values with permitted characters result in DAB engine starting successfully.
+ /// Ensures that invalid characters provided for path result in failed engine startup
+ /// due to validation failure.
+ ///
+ [DataTestMethod]
+ [DataRow("/updatedPath", true, DisplayName = "Successfully updated Rest Path to /updatedPath.")]
+ [DataRow("/updated-Path", true, DisplayName = "Successfully updated Rest Path to /updated-Path.")]
+ [DataRow("/updated_Path", true, DisplayName = "Successfully updated Rest Path to /updated_Path.")]
+ [DataRow("updatedPath", false, DisplayName = "Failure due to '/' missing.")]
+ [DataRow("/updated Path", false, DisplayName = "Failure due to white spaces.")]
+ [DataRow("/updated.Path", false, DisplayName = "Failure due to reserved char '.'.")]
+ [DataRow("/updated@Path", false, DisplayName = "Failure due reserved chars '@'.")]
+ [DataRow("/updated/Path", false, DisplayName = "Failure due reserved chars '/'.")]
+ public void TestUpdateRestPathRuntimeSettings(string path, bool isSuccess)
+ {
+ // Initialize the config file.
+ string[] initArgs = { "init", "-c", TEST_RUNTIME_CONFIG_FILE, "--host-mode", "development", "--database-type",
+ "mssql", "--connection-string", TEST_ENV_CONN_STRING };
+ Program.Execute(initArgs, _cliLogger!, _fileSystem!, _runtimeConfigLoader!);
+
+ Assert.IsTrue(_runtimeConfigLoader!.TryLoadConfig(TEST_RUNTIME_CONFIG_FILE, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig);
+
+ // Act: Update the Path in the config file.
+ string[] runtimeArgs = { "configure", "-c", TEST_RUNTIME_CONFIG_FILE, "--runtime.rest.path", path };
+ int isError = Program.Execute(runtimeArgs, _cliLogger!, _fileSystem!, _runtimeConfigLoader!);
+
+ // Assert: Check if the Path was updated successfully.
+ Assert.AreEqual(isSuccess, isError == 0);
+ }
+
+ ///
+ /// This test checks behavior of executing `dab configure --runtime.cache.ttl-seconds {value}`
+ /// Validates that path values with permitted characters result in DAB engine starting successfully.
+ /// Ensures that invalid values provided for ttl-seconds result in failed engine startup
+ /// due to validation failure.
+ /// Valid values are [1, INT32.MAX_VALUE] Integer values.
+ ///
+ [DataTestMethod]
+ [DataRow("2", true, DisplayName = "Success in updating Cache TTL to 2.")]
+ [DataRow("10", true, DisplayName = "Success in updating Cache TTL to 10.")]
+ [DataRow("-2", false, DisplayName = "Failure to update cache ttl as value is negative.")]
+ [DataRow("2147483647", true, DisplayName = "Successful update to cache ttl value to INT32_MAX")]
+ [DataRow("2147483648", false, DisplayName = "Failure to update cache ttl as value greater than INT32_MAX")]
+ [DataRow("0", false, DisplayName = "Failure to update cache ttl as value is zero.")]
+ [DataRow("seven", false, DisplayName = "Failure to update cache ttl as a string value.")]
+ public void TestUpdateCacheTtlRuntimeSettings(string ttl, bool isSuccess)
+ {
+ // Initialize the config file.
+ string[] initArgs = { "init", "-c", TEST_RUNTIME_CONFIG_FILE, "--host-mode", "development", "--database-type",
+ "mssql", "--connection-string", TEST_ENV_CONN_STRING };
+ Program.Execute(initArgs, _cliLogger!, _fileSystem!, _runtimeConfigLoader!);
+
+ Assert.IsTrue(_runtimeConfigLoader!.TryLoadConfig(TEST_RUNTIME_CONFIG_FILE, out RuntimeConfig? runtimeConfig));
+ Assert.IsNotNull(runtimeConfig);
+
+ // Act: Update the Cache TTL in the config file.
+ string[] runtimeArgs = { "configure", "-c", TEST_RUNTIME_CONFIG_FILE, "--runtime.cache.ttl-seconds", ttl };
+ int isError = Program.Execute(runtimeArgs, _cliLogger!, _fileSystem!, _runtimeConfigLoader!);
+
+ // Assert: Check if the Cache TTL was updated successfully.
+ Assert.AreEqual(isSuccess, isError == 0);
+ }
+
///
/// Test to verify authentication options with init command containing
/// neither EasyAuth or Simulator as Authentication provider.
diff --git a/src/Cli/Commands/ConfigureOptions.cs b/src/Cli/Commands/ConfigureOptions.cs
index fe84e56669..a6db7fe954 100644
--- a/src/Cli/Commands/ConfigureOptions.cs
+++ b/src/Cli/Commands/ConfigureOptions.cs
@@ -30,20 +30,34 @@ public ConfigureOptions(
string? runtimeGraphQLPath = null,
bool? runtimeGraphQLAllowIntrospection = null,
bool? runtimeGraphQLMultipleMutationsCreateEnabled = null,
+ bool? runtimeRestEnabled = null,
+ string? runtimeRestPath = null,
+ bool? runtimeRestRequestBodyStrict = null,
+ bool? runtimeCacheEnabled = null,
+ int? runtimeCacheTtl = null,
string? config = null)
: base(config)
{
+ // Data Source
DataSourceDatabaseType = dataSourceDatabaseType;
DataSourceConnectionString = dataSourceConnectionString;
DataSourceOptionsDatabase = dataSourceOptionsDatabase;
DataSourceOptionsContainer = dataSourceOptionsContainer;
DataSourceOptionsSchema = dataSourceOptionsSchema;
DataSourceOptionsSetSessionContext = dataSourceOptionsSetSessionContext;
+ // GraphQL
DepthLimit = depthLimit;
RuntimeGraphQLEnabled = runtimeGraphQLEnabled;
RuntimeGraphQLPath = runtimeGraphQLPath;
RuntimeGraphQLAllowIntrospection = runtimeGraphQLAllowIntrospection;
RuntimeGraphQLMultipleMutationsCreateEnabled = runtimeGraphQLMultipleMutationsCreateEnabled;
+ // Rest
+ RuntimeRestEnabled = runtimeRestEnabled;
+ RuntimeRestPath = runtimeRestPath;
+ RuntimeRestRequestBodyStrict = runtimeRestRequestBodyStrict;
+ // Cache
+ RuntimeCacheEnabled = runtimeCacheEnabled;
+ RuntimeCacheTTL = runtimeCacheTtl;
}
[Option("data-source.database-type", Required = false, HelpText = "Database type. Allowed values: MSSQL, PostgreSQL, CosmosDB_NoSQL, MySQL.")]
@@ -79,6 +93,21 @@ public ConfigureOptions(
[Option("runtime.graphql.multiple-mutations.create.enabled", Required = false, HelpText = "Enable/Disable multiple-mutation create operations on DAB's generated GraphQL schema. Default: true (boolean).")]
public bool? RuntimeGraphQLMultipleMutationsCreateEnabled { get; }
+ [Option("runtime.rest.enabled", Required = false, HelpText = "Enable DAB's Rest endpoint. Default: true (boolean).")]
+ public bool? RuntimeRestEnabled { get; }
+
+ [Option("runtime.rest.path", Required = false, HelpText = "Customize DAB's REST endpoint path. Default: '/api' Conditions: Prefix path with '/'.")]
+ public string? RuntimeRestPath { get; }
+
+ [Option("runtime.rest.request-body-strict", Required = false, HelpText = "Prohibit extraneous REST request body fields. Default: true (boolean).")]
+ public bool? RuntimeRestRequestBodyStrict { get; }
+
+ [Option("runtime.cache.enabled", Required = false, HelpText = "Enable DAB's cache globally. (You must also enable each entity's cache separately.). Default: false (boolean).")]
+ public bool? RuntimeCacheEnabled { get; }
+
+ [Option("runtime.cache.ttl-seconds", Required = false, HelpText = "Customize the DAB cache's global default time to live in seconds. Default: 5 seconds (Integer).")]
+ public int? RuntimeCacheTTL { get; }
+
public int Handler(ILogger logger, FileSystemRuntimeConfigLoader loader, IFileSystem fileSystem)
{
logger.LogInformation("{productName} {version}", PRODUCT_NAME, ProductInfo.GetProductVersion());
diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs
index bd406b439d..c59dbf76c0 100644
--- a/src/Cli/ConfigGenerator.cs
+++ b/src/Cli/ConfigGenerator.cs
@@ -533,12 +533,12 @@ public static bool TryConfigureSettings(ConfigureOptions options, FileSystemRunt
return false;
}
- if (!TryConfigureDataSourceOptions(options, ref runtimeConfig))
+ if (!TryUpdateConfiguredDataSourceOptions(options, ref runtimeConfig))
{
return false;
}
- if (!TryConfigureRuntimeOptions(options, ref runtimeConfig))
+ if (!TryUpdateConfiguredRuntimeOptions(options, ref runtimeConfig))
{
return false;
}
@@ -562,7 +562,7 @@ public static bool TryConfigureSettings(ConfigureOptions options, FileSystemRunt
///
/// True if the data source options were successfully configured and the runtime configuration was updated; otherwise, false.
///
- private static bool TryConfigureDataSourceOptions(
+ private static bool TryUpdateConfiguredDataSourceOptions(
ConfigureOptions options,
[NotNullWhen(true)] ref RuntimeConfig runtimeConfig)
{
@@ -694,18 +694,35 @@ private static bool TryUpdateDepthLimit(
/// Options including the graphql runtime parameters.
/// Current config, updated if method succeeds.
/// True if the update was successful, false otherwise.
- private static bool TryConfigureRuntimeOptions(
+ private static bool TryUpdateConfiguredRuntimeOptions(
ConfigureOptions options,
[NotNullWhen(true)] ref RuntimeConfig runtimeConfig)
{
+ // Rest: Enabled, Path, and Request.Body.Strict
+ if (options.RuntimeRestEnabled != null ||
+ options.RuntimeRestPath != null ||
+ options.RuntimeRestRequestBodyStrict != null)
+ {
+ RestRuntimeOptions? updatedRestOptions = runtimeConfig?.Runtime?.Rest ?? new();
+ bool status = TryUpdateConfiguredRestValues(options, ref updatedRestOptions);
+ if (status)
+ {
+ runtimeConfig = runtimeConfig! with { Runtime = runtimeConfig.Runtime! with { Rest = updatedRestOptions } };
+ }
+ else
+ {
+ return false;
+ }
+ }
+
// GraphQL: Enabled, Path, Allow-Introspection and Multiple-Mutations.Create.Enabled
- GraphQLRuntimeOptions? updatedGraphQLOptions = runtimeConfig?.Runtime?.GraphQL;
if (options.RuntimeGraphQLEnabled != null ||
options.RuntimeGraphQLPath != null ||
options.RuntimeGraphQLAllowIntrospection != null ||
options.RuntimeGraphQLMultipleMutationsCreateEnabled != null)
{
- bool status = TryUpdateConfigureGraphQLValues(options, ref updatedGraphQLOptions);
+ GraphQLRuntimeOptions? updatedGraphQLOptions = runtimeConfig?.Runtime?.GraphQL ?? new();
+ bool status = TryUpdateConfiguredGraphQLValues(options, ref updatedGraphQLOptions);
if (status)
{
runtimeConfig = runtimeConfig! with { Runtime = runtimeConfig.Runtime! with { GraphQL = updatedGraphQLOptions } };
@@ -716,9 +733,81 @@ private static bool TryConfigureRuntimeOptions(
}
}
+ // Cache: Enabled and TTL
+ if (options.RuntimeCacheEnabled != null ||
+ options.RuntimeCacheTTL != null)
+ {
+ EntityCacheOptions? updatedCacheOptions = runtimeConfig?.Runtime?.Cache ?? new();
+ bool status = TryUpdateConfiguredCacheValues(options, ref updatedCacheOptions);
+ if (status)
+ {
+ runtimeConfig = runtimeConfig! with { Runtime = runtimeConfig.Runtime! with { Cache = updatedCacheOptions } };
+ }
+ else
+ {
+ return false;
+ }
+ }
+
return runtimeConfig != null;
}
+ ///
+ /// Attempts to update the Config parameters in the Rest runtime settings based on the provided value.
+ /// Validates that any user-provided values are valid and then returns true if the updated Rest options
+ /// need to be overwritten on the existing config parameters
+ ///
+ /// options.
+ /// updatedRestOptions.
+ /// True if the value needs to be updated in the runtime config, else false
+ private static bool TryUpdateConfiguredRestValues(ConfigureOptions options, ref RestRuntimeOptions? updatedRestOptions)
+ {
+ object? updatedValue;
+ try
+ {
+ // Runtime.Rest.Enabled
+ updatedValue = options?.RuntimeRestEnabled;
+ if (updatedValue != null)
+ {
+ updatedRestOptions = updatedRestOptions! with { Enabled = (bool)updatedValue };
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.Rest.Enabled as '{updatedValue}'", updatedValue);
+ }
+
+ // Runtime.Rest.Path
+ updatedValue = options?.RuntimeRestPath;
+ if (updatedValue != null)
+ {
+ bool status = RuntimeConfigValidatorUtil.TryValidateUriComponent(uriComponent: (string)updatedValue, out string exceptionMessage);
+ if (status)
+ {
+ updatedRestOptions = updatedRestOptions! with { Path = (string)updatedValue };
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.Rest.Path as '{updatedValue}'", updatedValue);
+ }
+ else
+ {
+ _logger.LogError("Failed to update RuntimeConfig with Runtime.Rest.Path " +
+ $"as '{updatedValue}'. Error details: {exceptionMessage}", exceptionMessage);
+ return false;
+ }
+ }
+
+ // Runtime.Rest.Request-Body-Strict
+ updatedValue = options?.RuntimeRestRequestBodyStrict;
+ if (updatedValue != null)
+ {
+ updatedRestOptions = updatedRestOptions! with { RequestBodyStrict = (bool)updatedValue };
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.Rest.Request-Body-Strict as '{updatedValue}'", updatedValue);
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Failure in updating RuntimeConfig.Rest with exception message: {exceptionMessage}.", ex.Message);
+ return false;
+ }
+ }
+
///
/// Attempts to update the Config parameters in the GraphQL runtime settings based on the provided value.
/// Validates that any user-provided parameter value is valid and then returns true if the updated GraphQL options
@@ -727,7 +816,7 @@ private static bool TryConfigureRuntimeOptions(
/// options.
/// updatedGraphQLOptions.
/// True if the value needs to be udpated in the runtime config, else false
- private static bool TryUpdateConfigureGraphQLValues(
+ private static bool TryUpdateConfiguredGraphQLValues(
ConfigureOptions options,
ref GraphQLRuntimeOptions? updatedGraphQLOptions)
{
@@ -739,7 +828,7 @@ private static bool TryUpdateConfigureGraphQLValues(
if (updatedValue != null)
{
updatedGraphQLOptions = updatedGraphQLOptions! with { Enabled = (bool)updatedValue };
- _logger.LogInformation($"Updated RuntimeConfig with Runtime.GraphQL.Enabled as '{updatedValue}'");
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.GraphQL.Enabled as '{updatedValue}'", updatedValue);
}
// Runtime.GraphQL.Path
@@ -750,12 +839,11 @@ private static bool TryUpdateConfigureGraphQLValues(
if (status)
{
updatedGraphQLOptions = updatedGraphQLOptions! with { Path = (string)updatedValue };
- _logger.LogInformation($"Updated RuntimeConfig with Runtime.GraphQL.Path as '{updatedValue}'");
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.GraphQL.Path as '{updatedValue}'", updatedValue);
}
else
{
- _logger.LogError($"Failure in updating RuntimeConfig with Runtime.GraphQL.Path " +
- $"as '{updatedValue}' due to exception message: {exceptionMessage}");
+ _logger.LogError("Failure in updating RuntimeConfig with Runtime.GraphQL.Path as '{updatedValue}' due to exception message: {exceptionMessage}", updatedValue, exceptionMessage);
return false;
}
}
@@ -765,7 +853,7 @@ private static bool TryUpdateConfigureGraphQLValues(
if (updatedValue != null)
{
updatedGraphQLOptions = updatedGraphQLOptions! with { AllowIntrospection = (bool)updatedValue };
- _logger.LogInformation($"Updated RuntimeConfig with Runtime.GraphQL.AllowIntrospection as '{updatedValue}'");
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.GraphQL.AllowIntrospection as '{updatedValue}'", updatedValue);
}
// Runtime.GraphQL.Multiple-mutations.Create.Enabled
@@ -774,14 +862,63 @@ private static bool TryUpdateConfigureGraphQLValues(
{
MultipleCreateOptions multipleCreateOptions = new(enabled: (bool)updatedValue);
updatedGraphQLOptions = updatedGraphQLOptions! with { MultipleMutationOptions = new(multipleCreateOptions) };
- _logger.LogInformation($"Updated RuntimeConfig with Runtime.GraphQL.Multiple-Mutations.Create.Enabled as '{updatedValue}'");
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.GraphQL.Multiple-Mutations.Create.Enabled as '{updatedValue}'", updatedValue);
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Failure in updating RuntimeConfig.GraphQL with exception message: {exceptionMessage}.", ex.Message);
+ return false;
+ }
+ }
+
+ ///
+ /// Attempts to update the Config parameters in the Cache runtime settings based on the provided value.
+ /// Validates user-provided parameters and then returns true if the updated Cache options
+ /// need to be overwritten on the existing config parameters
+ ///
+ /// options.
+ /// updatedCacheOptions.
+ /// True if the value needs to be udpated in the runtime config, else false
+ private static bool TryUpdateConfiguredCacheValues(
+ ConfigureOptions options,
+ ref EntityCacheOptions? updatedCacheOptions)
+ {
+ object? updatedValue;
+ try
+ {
+ // Runtime.Cache.Enabled
+ updatedValue = options?.RuntimeCacheEnabled;
+ if (updatedValue != null)
+ {
+ updatedCacheOptions = updatedCacheOptions! with { Enabled = (bool)updatedValue };
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.Cache.Enabled as '{updatedValue}'", updatedValue);
+ }
+
+ // Runtime.Cache.ttl-seconds
+ updatedValue = options?.RuntimeCacheTTL;
+ if (updatedValue != null)
+ {
+ bool status = RuntimeConfigValidatorUtil.IsTTLValid(ttl: (int)updatedValue);
+ if (status)
+ {
+ updatedCacheOptions = updatedCacheOptions! with { TtlSeconds = (int)updatedValue, UserProvidedTtlOptions = true };
+ _logger.LogInformation("Updated RuntimeConfig with Runtime.Cache.ttl-seconds as '{updatedValue}'", updatedValue);
+ }
+ else
+ {
+ _logger.LogError("Failure in updating RuntimeConfig with Runtime.Cache.ttl-seconds as '{updatedValue}' value in TTL is not valid.", updatedValue);
+ return false;
+ }
}
return true;
}
catch (Exception ex)
{
- _logger.LogError($"Failure in updating RuntimeConfig with exception message: {ex.Message}.");
+ _logger.LogError("Failure in updating RuntimeConfig.Cache with exception message: {exceptionMessage}.", ex.Message);
return false;
}
}
diff --git a/src/Core/Configurations/RuntimeConfigValidatorUtil.cs b/src/Core/Configurations/RuntimeConfigValidatorUtil.cs
index cdd9a25cca..be742e586b 100644
--- a/src/Core/Configurations/RuntimeConfigValidatorUtil.cs
+++ b/src/Core/Configurations/RuntimeConfigValidatorUtil.cs
@@ -65,4 +65,18 @@ public static bool DoesUriComponentContainReservedChars(string uriComponent)
{
return _reservedUriCharsRgx.IsMatch(uriComponent);
}
+
+ ///
+ /// Method to validate if the TTL passed by the user is valid
+ ///
+ /// Time to Live
+ public static bool IsTTLValid(int ttl)
+ {
+ if (ttl > 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
}