Skip to content
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

Test to diagnose extension method load instability #1780

Merged
merged 3 commits into from Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/Samples/AspNetCore/Startup.cs
Expand Up @@ -94,6 +94,17 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
}

private string GetApplicationPath(IWebHostEnvironment env)
=> Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
{
var common = Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
if (Directory.Exists(common))
{
return common;
}
if (File.Exists(Path.Combine(env.ContentRootPath, "Views/Default.dothtml")))
{
return env.ContentRootPath;
}
throw new DirectoryNotFoundException("Cannot find the 'Common' directory nor the 'Views' directory in the application root.");
}
}
}
13 changes: 12 additions & 1 deletion src/Samples/AspNetCoreLatest/Startup.cs
Expand Up @@ -105,6 +105,17 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
}

private string GetApplicationPath(IWebHostEnvironment env)
=> Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
{
if (File.Exists(Path.Combine(env.ContentRootPath, "Views/Default.dothtml")))
{
return env.ContentRootPath;
}
var common = Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
if (File.Exists(Path.Combine(common, "Views/Default.dothtml")))
{
return common;
}
throw new DirectoryNotFoundException("Cannot find the 'Common' directory nor the 'Views' directory in the application root.");
}
}
}
158 changes: 1 addition & 157 deletions src/Samples/Common/DotVVM.Samples.Common.csproj
Expand Up @@ -19,167 +19,11 @@
<None Remove="node_modules\**" />
<None Remove="script\**" />
</ItemGroup>
<ItemGroup>
<Content Remove="Views\FeatureSamples\EmbeddedResourceControls\EmbeddedResourceMasterPage.dotmaster" />
<Content Remove="Views\FeatureSamples\ViewModules\ModuleControl.dotcontrol" />
</ItemGroup>
<ItemGroup>
<None Remove="sampleConfig.json" />
<None Remove="tsconfig.react.json" />
<None Remove="Scripts\ControlSamples_NamedCommand_ParameterStaticCommand.js" />
<None Remove="Views\ComplexSamples\NestedComboBox\InnerWrapper.dotcontrol" />
<None Remove="Views\ComplexSamples\NestedComboBox\OuterWrapper.dotcontrol" />
<None Remove="Views\ComplexSamples\SPAErrorReporting\default.dothtml" />
<None Remove="Views\ComplexSamples\SPAErrorReporting\site.dotmaster" />
<None Remove="Views\ComplexSamples\SPAErrorReporting\test.dothtml" />
<None Remove="Views\ComplexSamples\ViewModelPopulate\ViewModelPopulate.dothtml" />
<None Remove="Views\ControlSamples\CheckBox\CheckBox_Objects.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\BindingCTValidation_StringToEnum.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\HeavilyNested.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_Complex_Error.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_Enum.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_Number.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_SelectedValue_ComplexToInt_Error.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_SelectedValue_StringToInt_Error.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_String.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_StringToObject.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\Nullable.dothtml" />
<None Remove="Views\ControlSamples\GridView\GridViewCellDecorators.dothtml" />
<None Remove="Views\ControlSamples\HierarchyRepeater\Basic.dothtml" />
<None Remove="Views\ControlSamples\HierarchyRepeater\NodeControl.dotcontrol" />
<None Remove="Views\ControlSamples\HierarchyRepeater\WithMarkupControl.dothtml" />
<None Remove="Views\ControlSamples\Literal\Literal_NumberBinding.dothtml" />
<None Remove="Views\ControlSamples\MultiSelect\binded.dothtml" />
<None Remove="Views\ControlSamples\MultiSelect\hardcoded.dothtml" />
<None Remove="Views\ControlSamples\NamedCommand\ParameterStaticCommandService.dothtml" />
<None Remove="Views\ControlSamples\RadioButton\Nullable.dothtml" />
<None Remove="Views\ControlSamples\RadioButton\RadioButton_Objects.dothtml" />
<None Remove="Views\ControlSamples\Repeater\IndexInNestedRepeater.dothtml" />
<None Remove="Views\ControlSamples\Repeater\NamedTemplate.dothtml" />
<None Remove="Views\ControlSamples\RouteLink\RouteLinkQueryParameters.dothtml" />
<None Remove="Views\ControlSamples\TemplateHost\Basic.dothtml" />
<None Remove="Views\ControlSamples\TemplateHost\TemplatedListControl.dotcontrol" />
<None Remove="Views\ControlSamples\TemplateHost\TemplatedMarkupControl.dotcontrol" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressQueues.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirect.dotmaster" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirect1.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirect2.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirectSPA.dotmaster" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirectSPA1.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirectSPA2.dothtml" />
<None Remove="Views\ControlSamples\ValidationSummary\MessagesRendering.dothtml" />
<None Remove="Views\ControlSamples\ValidationSummary\Performance.dothtml" />
<None Remove="Views\Errors\CorruptedContentBetweenContentControls.dothtml" />
<None Remove="Views\Errors\ExceptionInLifecycle.dothtml" />
<None Remove="Views\Errors\ExceptionInRender.dothtml" />
<None Remove="Views\Errors\InvalidServiceDirective.dothtml" />
<None Remove="Views\Errors\InvalidLocationFallback.dothtml" />
<None Remove="Views\Errors\MarkupControlInvalidViewModel.dothtml" />
<None Remove="Views\Errors\MarkupControlPropertiesSameName.dotcontrol" />
<None Remove="Views\Errors\MarkupControlPropertiesSameNameWithBase.dotcontrol" />
<None Remove="Views\Errors\MarkupControlPropertiesSameNameWithBase.dothtml" />
<None Remove="Views\Errors\ResourceCircularDependency.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_Master.dotmaster" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_PageA.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_PageB.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiRefresh.dothtml" />
<None Remove="Views\FeatureSamples\Api\CollectionOddEvenWithRestApi.dothtml" />
<None Remove="Views\FeatureSamples\Api\IncludedInPage.dothtml" />
<None Remove="Views\FeatureSamples\Api\IsLoading.dothtml" />
<None Remove="Views\FeatureSamples\Attribute\ToStringConversion.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoEditor.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoForm.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoGridViewColumns.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\BootstrapForm3.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\BootstrapForm4.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\BootstrapForm5.dothtml" />
<None Remove="Views\FeatureSamples\BindingVariables\StaticCommandVariablesWithService_Complex.dothtml" />
<None Remove="Views\FeatureSamples\BindingVariables\StaticCommandVariablesWithService_Complex2.dothtml" />
<None Remove="Views\FeatureSamples\BindingVariables\StaticCommandVariablesWithService_Simple.dothtml" />
<None Remove="Views\FeatureSamples\Caching\CachedValues.dothtml" />
<None Remove="Views\FeatureSamples\CompositeControls\ControlPropertyNamingConflict.dothtml" />
<None Remove="Views\FeatureSamples\CommandActionFilter\CommandActionFilter.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\Basic.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\RouteLink.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\TextBox.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\UsedInControls.dothtml" />
<None Remove="Views\FeatureSamples\EmbeddedResourceControls\EmbeddedResourceMasterPage.dotmaster" />
<None Remove="Views\FeatureSamples\EmbeddedResourceControls\PageWithEmbeddedResourceMasterPage.dothtml" />
<None Remove="Views\FeatureSamples\Formatting\AutoResourceInclusion.dothtml" />
<None Remove="Views\FeatureSamples\Formatting\AutoResourceInclusionMaster.dotmaster" />
<None Remove="Views\FeatureSamples\Formatting\ToStringGlobalFunctionBug.dothtml" />
<None Remove="Views\FeatureSamples\HotReload\ViewChanges.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\ArrayTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\DateTimeTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\DictionaryIndexerTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\GenericMethodTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\ListIndexerTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\ListMethodTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\WebUtilityTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\StringMethodTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JsComponentIntegration\ReactComponentIntegration.dothtml" />
<None Remove="Views\FeatureSamples\JsDirectives\BasicSample.dothtml" />
<None Remove="Views\FeatureSamples\LambdaExpressions\ClientSideFiltering.dothtml" />
<None Remove="Views\FeatureSamples\LambdaExpressions\LambdaExpressions.dothtml" />
<None Remove="Views\FeatureSamples\Localization\Globalize.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\MarkupDefinedProperties.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\MarkupDefinedPropertiesControl.dotcontrol" />
<None Remove="Views\FeatureSamples\MarkupControl\ServiceDependency\ServiceDependencyControl.dotcontrol" />
<None Remove="Views\FeatureSamples\PostbackAbortSignal\LoadAbortViewModel.dothtml" />
<None Remove="Views\FeatureSamples\RenderSettingsModeServer\RepeaterCollectionSetToNull.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\ByteArray.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\DateOnlyTimeOnly.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\TimeSpan.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\EnumSerializationCoercion.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\SerializationDateTimeOffset.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_Validation.dothtml" />
<None Remove="Views\FeatureSamples\StringInterpolation\StringInterpolation.dothtml" />
<None Remove="Views\FeatureSamples\Validation\RangeClientSideValidation.dothtml" />
<None Remove="Views\FeatureSamples\Validation\ValidationTargetIsCollection.dothtml" />
<None Remove="Views\FeatureSamples\Validation\ValidatorValueComplexExpressions.dothtml" />
<None Remove="Views\FeatureSamples\ViewModelDeserialization\PropertyNullAssignment.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\Incrementer.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\IncrementerInRepeater.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\InnerModuleControl.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\LinkModuleControl.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleControl.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInMarkupControl.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInMarkupControlTwice.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPage.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageCommandAmbiguous.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageMasterPage.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageSpaMasterPage.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageSpaMasterPage2.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleMasterPage.dotmaster" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleRegistrationPropagation.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleSpaMasterPage.dotmaster" />
<None Remove="Views\FeatureSamples\MarkupControl\CommandPropertiesInMarkupControl.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\Device.dotcontrol" />
<None Remove="Views\FeatureSamples\MarkupControl\Dialog.dotcontrol" />
<None Remove="Views\FeatureSamples\MarkupControl\StaticCommandInMarkupControl.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\StaticCommandInMarkupControlCallingRegularCommand.dothtml" />
<None Remove="Views\FeatureSamples\PostbackConcurrency\RedirectPostbackQueue.dothtml" />
<None Remove="Views\FeatureSamples\PostbackConcurrency\StressTest.dothtml" />
<None Remove="Views\FeatureSamples\PostBack\RecursiveTextRepeater.dotcontrol" />
<None Remove="Views\FeatureSamples\PostBack\RecursiveTextRepeater2.dotcontrol" />
<None Remove="Views\FeatureSamples\PostBack\UniqueIdGenerationOnPostbackUpdate.dothtml" />
<None Remove="Views\FeatureSamples\Redirect\Redirect_StaticCommand.dothtml" />
<None Remove="Views\FeatureSamples\Resources\LocationFallback.dothtml" />
<None Remove="Views\FeatureSamples\Resources\RequiredOnPostback.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\DeserializationVirtualElements.dothtml" />
<None Remove="Views\FeatureSamples\CustomResponseProperties\SimpleExceptionFilter.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\Dictionary.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\CustomAwaitable.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_ArrayAssigment.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_LoadComplexDataFromService.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_NullAssignment.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_TaskSequence.dothtml" />
<None Remove="Views\FeatureSamples\UsageValidation\OverrideValidation.dothtml" />
<None Remove="Views\FeatureSamples\Validation\EnforceClientSideValidationDisabled.dothtml" />
<None Remove="Views\FeatureSamples\Validation\InvalidCssClassNotDuplicated.dothtml" />
<None Remove="Views\FeatureSamples\Validation\ValidationPropertyPathResolving.dothtml" />
<None Remove="Views\FeatureSamples\ViewModelCache\ViewModelCache_Miss.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\OuterModuleControl.dotcontrol" />
<None Remove="**/*.dotmaster;**/*.dotcontrol;**/*.dothtml" />
</ItemGroup>
<ItemGroup>
<Content Include="sampleConfig.json">
Expand Down
3 changes: 3 additions & 0 deletions src/Samples/Common/DotvvmStartup.cs
Expand Up @@ -31,6 +31,7 @@
using DotVVM.Samples.Common.ViewModels.FeatureSamples.BindingVariables;
using DotVVM.Samples.Common.Views.ControlSamples.TemplateHost;
using DotVVM.Framework.ResourceManagement;
using DotVVM.Samples.Common.Presenters;
using DotVVM.Samples.Common.ViewModels.FeatureSamples.CustomPrimitiveTypes;

namespace DotVVM.Samples.BasicSamples
Expand Down Expand Up @@ -251,6 +252,8 @@ private static void AddRoutes(DotvvmConfiguration config)
config.RouteTable.Add("FeatureSamples_PostBack_PostBackHandlers_Localized", "FeatureSamples/PostBack/PostBackHandlers_Localized", "Views/FeatureSamples/PostBack/ConfirmPostBackHandler.dothtml", presenterFactory: LocalizablePresenter.BasedOnQuery("lang"));

config.RouteTable.Add("Errors_UndefinedRouteLinkParameters-PageDetail", "Erros/UndefinedRouteLinkParameters/{Id}", "Views/Errors/UndefinedRouteLinkParameters.dothtml", new { Id = 0 });

config.RouteTable.Add("DumpExtensionsMethods", "dump-extension-methods", _ => new DumpExtensionMethodsPresenter());
}

private static void AddControls(DotvvmConfiguration config)
Expand Down
45 changes: 45 additions & 0 deletions src/Samples/Common/Presenters/DumpExtensionMethodsPresenter.cs
@@ -0,0 +1,45 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.Compilation;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Utils;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

namespace DotVVM.Samples.Common.Presenters
{
public class DumpExtensionMethodsPresenter : IDotvvmPresenter
{
public async Task ProcessRequest(IDotvvmRequestContext context)
{
var cache = context.Configuration.ServiceProvider.GetService<ExtensionMethodsCache>();

var contents = typeof(ExtensionMethodsCache)
.GetField("methodsCache", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(cache) as ConcurrentDictionary<string, ImmutableArray<MethodInfo>>;

var dump = contents.SelectMany(p => p.Value.Select(m => new {
Namespace = p.Key,
m.Name,
m.DeclaringType!.FullName,
Params = m.GetParameters().Select(p => new {
p.Name,
Type = p.ParameterType!.FullName
}),
m.IsGenericMethodDefinition,
GenericParameters = m.IsGenericMethodDefinition ? m.GetGenericArguments().Select(a => new {
a.Name
}) : null
}))
.OrderBy(m => m.Namespace).ThenBy(m => m.Name);

await context.HttpContext.Response.WriteAsync("ExtensionMethodsCache dump: " + JsonConvert.SerializeObject(dump, Formatting.Indented));
}
}
}
29 changes: 27 additions & 2 deletions src/Samples/Tests/Tests/Feature/StaticCommandTests.cs
@@ -1,6 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using DotVVM.Samples.Tests.Base;
using DotVVM.Testing.Abstractions;
using OpenQA.Selenium;
Expand Down Expand Up @@ -814,7 +818,7 @@ public void Feature_List_Translation_Remove_Range()
Assert.Equal(new List<string> { "1", "2", "8", "9", "10" }, column);
});
}

[Fact]
public void Feature_List_Translation_Remove_Reverse()
{
Expand All @@ -828,6 +832,27 @@ public void Feature_List_Translation_Remove_Reverse()
});
}

[Fact]
public async Task Feature_ExtensionMethodsNotResolvedOnStartup()
{
var client = new HttpClient();

// try to visit the page
var pageResponse = await client.GetAsync(TestSuiteRunner.Configuration.BaseUrls[0].TrimEnd('/') + "/" + SamplesRouteUrls.FeatureSamples_JavascriptTranslation_ListMethodTranslations);
TestOutput.WriteLine($"Page response: {(int)pageResponse.StatusCode}");
var wasError = pageResponse.StatusCode != HttpStatusCode.OK;

// dump extension methods on the output
var json = await client.GetStringAsync(TestSuiteRunner.Configuration.BaseUrls[0].TrimEnd('/') + "/dump-extension-methods");
TestOutput.WriteLine(json);

if (wasError)
{
// fail the test on error
throw new Exception("Extension methods were not resolved on application startup.");
}
}

protected IElementWrapperCollection<IElementWrapper, IBrowserWrapper> GetSortedRow(IBrowserWrapper browser, string btn)
{
var orderByBtn = browser.First($"//input[@value='{btn}']", By.XPath);
Expand Down