Skip to content

Commit

Permalink
Namespace checks for IUserManager and ITestWebProvider (#486)
Browse files Browse the repository at this point in the history
* Adding Namespace check for providers #484

* Review edit

* Adding changes also for IUserModule in #485

* Review edits

* Review edits

* adding auth to validateprovider, removing duplicate proj in sln

* missing in merge

* comment null checks

---------

Co-authored-by: Sourabh Namilikonda <[email protected]>
  • Loading branch information
Grant-Archibald-MS and snamilikonda authored Dec 11, 2024
1 parent d1202c7 commit 3c340b4
Show file tree
Hide file tree
Showing 18 changed files with 498 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -23,6 +26,113 @@ public class TestEngineExtensionCheckerTests
Mock<ILogger> MockLogger;
string _template;

const string TEST_WEB_PROVIDER = @"
#r ""Microsoft.PowerApps.TestEngine.dll""
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.Providers;
using Microsoft.PowerApps.TestEngine.Providers.PowerFxModel;
using Microsoft.PowerApps.TestEngine.TestInfra;
using Microsoft.PowerFx.Types;
public class Test : ITestWebProvider
{{
public ITestInfraFunctions? TestInfraFunctions {{ get => throw new NotImplementedException(); set => throw new NotImplementedException(); }}
public ISingleTestInstanceState? SingleTestInstanceState {{ get => throw new NotImplementedException(); set => throw new NotImplementedException(); }}
public ITestState? TestState {{ get => throw new NotImplementedException(); set => throw new NotImplementedException(); }}
public ITestProviderState? ProviderState {{ get => throw new NotImplementedException(); set => throw new NotImplementedException(); }}
public string Name => throw new NotImplementedException();
public string CheckTestEngineObject => throw new NotImplementedException();
public string[] Namespaces => new string[] {{ ""{0}"" }};
public Task<bool> CheckIsIdleAsync()
{{
throw new NotImplementedException();
}}
public Task CheckProviderAsync()
{{
throw new NotImplementedException();
}}
public string GenerateTestUrl(string domain, string queryParams)
{{
throw new NotImplementedException();
}}
public Task<object> GetDebugInfo()
{{
throw new NotImplementedException();
}}
public int GetItemCount(ItemPath itemPath)
{{
throw new NotImplementedException();
}}
public T GetPropertyValueFromControl<T>(ItemPath itemPath)
{{
throw new NotImplementedException();
}}
public Task<Dictionary<string, ControlRecordValue>> LoadObjectModelAsync()
{{
throw new NotImplementedException();
}}
public Task<bool> SelectControlAsync(ItemPath itemPath)
{{
throw new NotImplementedException();
}}
public Task<bool> SetPropertyAsync(ItemPath itemPath, FormulaValue value)
{{
throw new NotImplementedException();
}}
public Task<bool> TestEngineReady()
{{
throw new NotImplementedException();
}}
}}
";

const string TEST_USER_MODULE = @"
#r ""Microsoft.PowerApps.TestEngine.dll""
#r ""Microsoft.Playwright.dll""
using System;
using System.Threading.Tasks;
using Microsoft.Playwright;
using Microsoft.PowerApps.TestEngine.Config;
using Microsoft.PowerApps.TestEngine.System;
using Microsoft.PowerApps.TestEngine.Users;
public class Test : IUserManager
{{
public string[] Namespaces => new string[] {{ ""{0}"" }};
public string Name => throw new NotImplementedException();
public int Priority => throw new NotImplementedException();
public bool UseStaticContext => throw new NotImplementedException();
public string Location {{ get => throw new NotImplementedException(); set => throw new NotImplementedException(); }}
public Task LoginAsUserAsync(string desiredUrl, IBrowserContext context, ITestState testState, ISingleTestInstanceState singleTestInstanceState, IEnvironmentVariable environmentVariable, IUserManagerLogin userManagerLogin)
{{
throw new NotImplementedException();
}}
}}
";

public TestEngineExtensionCheckerTests()
{
MockLogger = new Mock<ILogger>();
Expand Down Expand Up @@ -106,6 +216,75 @@ public void IsValid(string usingStatements, string script, bool useTemplate, str
Assert.Equal(expected, result);
}

[Theory]
[InlineData("", "", "TestEngine", true)] // Empty Allow and Deny list
[InlineData("TestEngine", "", "TestEngine", true)] // No deny list
[InlineData("", "TestEngine", "TestEngine", false)] // Invalid in deny list
[InlineData("TestEngine", "Other", "TestEngine", true)] // Valid in the allow list
[InlineData("TestEngine", "Other", "Other", false)] // Exact match
[InlineData("", "*", "Other", false)] // Any regex match
[InlineData("", "O*", "Other", false)] // Regex match wildcard
[InlineData("", "Test?", "Test1", false)] // Single character match
[InlineData("", "Test?More", "Test1More", false)] // Single character match in the middle
[InlineData("T*", "", "Test1More", true)] // Allow wildcard
[InlineData("T?2", "", "T12", true)] // Allow wildcard
[InlineData("T?2", "T?3", "T12", true)] // Allow wildcard and not match deny
public void IsValidProvider(string allow, string deny, string providerNamespace, bool expected)
{
// Arrange
var assembly = CompileScript(String.Format(TEST_WEB_PROVIDER, providerNamespace));

var checker = new TestEngineExtensionChecker(MockLogger.Object);
checker.GetExtentionContents = (file) => assembly;

var settings = new TestSettingExtensions()
{
Enable = true,
AllowPowerFxNamespaces = new List<string>() { allow },
DenyPowerFxNamespaces = new List<string>() { deny }
};

// Act
var result = checker.ValidateProvider(settings, "testengine.provider.test.dll");

Assert.Equal(expected, result);
}


[Theory]
[InlineData("", "", "TestEngine", true)] // Empty Allow and Deny list
[InlineData("TestEngine", "", "TestEngine", true)] // No deny list
[InlineData("", "TestEngine", "TestEngine", false)] // Invalid in deny list
[InlineData("TestEngine", "Other", "TestEngine", true)] // Valid in the allow list
[InlineData("TestEngine", "Other", "Other", false)] // Exact match
[InlineData("", "*", "Other", false)] // Any regex match
[InlineData("", "O*", "Other", false)] // Regex match wildcard
[InlineData("", "Test?", "Test1", false)] // Single character match
[InlineData("", "Test?More", "Test1More", false)] // Single character match in the middle
[InlineData("T*", "", "Test1More", true)] // Allow wildcard
[InlineData("T?2", "", "T12", true)] // Allow wildcard
[InlineData("T?2", "T?3", "T12", true)] // Allow wildcard and not match deny
public void IsValidUserModule(string allow, string deny, string providerNamespace, bool expected)
{
// Arrange
var assembly = CompileScript(String.Format(TEST_USER_MODULE, providerNamespace));

var checker = new TestEngineExtensionChecker(MockLogger.Object);
checker.GetExtentionContents = (file) => assembly;

var settings = new TestSettingExtensions()
{
Enable = true,
AllowPowerFxNamespaces = new List<string>() { allow },
DenyPowerFxNamespaces = new List<string>() { deny }
};

// Act
var result = checker.ValidateProvider(settings, "testengine.user.test.dll");

Assert.Equal(expected, result);
}


private string _functionTemplate = @"
#r ""Microsoft.PowerFx.Interpreter.dll""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.ComponentModel.Composition.Hosting;
using System.IO;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -78,5 +81,60 @@ public void ModuleMatch(bool checkAssemblies, bool checkResult, string allow, st
Assert.NotNull(catalog);
Assert.Equal(expected, string.Join(",", catalog.Catalogs.Select(c => c.GetType().Name)));
}

[Theory]
[InlineData("provider", true, true)]
[InlineData("provider", true, false)]
[InlineData("provider", false, false)]
[InlineData("user", true, true)]
[InlineData("user", true, false)]
[InlineData("user", false, false)]
[InlineData("auth", true, true)]
[InlineData("auth", true, false)]
[InlineData("auth", false, false)]
public void ProviderMatch(string providerType, bool verify, bool valid)
{
// Arrange
var assemblyName = $"testengine.{providerType}.test.dll";

var setting = new TestSettingExtensions()
{
Enable = true,
CheckAssemblies = true
};
Mock<TestEngineExtensionChecker> mockChecker = new Mock<TestEngineExtensionChecker>();

var loader = new TestEngineModuleMEFLoader(MockLogger.Object);
loader.DirectoryGetFiles = (location, pattern) =>
{
var searchPattern = Regex.Escape(pattern).Replace(@"\*", ".*?");
return pattern.Contains(providerType) ? new List<string>() { assemblyName }.ToArray() : new string[] { };
};

mockChecker.Setup(m => m.ValidateProvider(setting, assemblyName)).Returns(verify);
mockChecker.Setup(m => m.Verify(setting, assemblyName)).Returns(valid);

if (valid)
{
// Use current test assembly as test
loader.LoadAssembly = (file) => new AssemblyCatalog(this.GetType().Assembly);
}

loader.Checker = mockChecker.Object;

// Act
var catalog = loader.LoadModules(setting);

// Assert
if (verify && valid)
{
Assert.NotNull(catalog);
Assert.Equal("AssemblyCatalog,AssemblyCatalog", string.Join(",", catalog.Catalogs.Select(c => c.GetType().Name)));
}
else
{
Assert.Equal("AssemblyCatalog", string.Join(",", catalog.Catalogs.Select(c => c.GetType().Name)));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace Microsoft.PowerApps.TestEngine.Config
{
public class DefaultUserCertificateProvider : IUserCertificateProvider
{
public string[] Namespaces { get; private set; } = new string[] { "TestEngine" };

public string Name => "default";

public X509Certificate2 RetrieveCertificateForUser(string userIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ namespace Microsoft.PowerApps.TestEngine.Config
{
public interface IUserCertificateProvider
{
/// <summary>
/// The namespace of namespaces that this provider relates to
/// </summary>
public string[] Namespaces { get; }

public string Name { get; }
public X509Certificate2 RetrieveCertificateForUser(string userIdentifier);
}
Expand Down
Loading

0 comments on commit 3c340b4

Please sign in to comment.