LSP for VS Code - client/server, need some tips - c#

I struggle with understanding how does LSP client-side works. I mean I think I understand the theory of communication (JSON-RPC/LSP Protocol basics) but I struggle with existing libraries that are used for this for VS Code and I think trying to rewrite it is kinda pointless, especially client-side where I do not feel proficient at all
All examples I see provide a path to the server, so the LSP client can start it
it makes sense, but I'd rather avoid it during development, I'd want to have the server aopen in debugging mode and just start VS Code
I tried to start with basic of basic server implementation (C#)
public class Server
{
private JsonRpc RPC { get; set; }
public async Task Start()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
var pipeName = "LSP_Pipe";
var writerPipe = new NamedPipeClientStream(pipeName);
var readerPipe = new NamedPipeClientStream(pipeName);
await writerPipe.ConnectAsync(10_000);
await readerPipe.ConnectAsync(10_000);
Log.Information("RPC Listening");
RPC = new JsonRpc(writerPipe, readerPipe, this);
RPC.StartListening();
this.RPC.Disconnected += RPC_Disconnected;
await Task.Delay(-1);
}
private void RPC_Disconnected(object sender, JsonRpcDisconnectedEventArgs e)
{
Log.Information("Disconnected");
}
[JsonRpcMethod(RPCMethods.InitializeName)]
public object Initialize(JToken arg)
{
Log.Information("Initialization");
var serializer = new JsonSerializer()
{
ContractResolver = new ResourceOperationKindContractResolver()
};
var param = arg.ToObject<InitializeParams>();
var clientCapabilities = param?.Capabilities;
var capabilities = new ServerCapabilities
{
TextDocumentSync = new TextDocumentSyncOptions(),
CompletionProvider = new CompletionOptions(),
SignatureHelpProvider = new SignatureHelpOptions(),
ExecuteCommandProvider = new ExecuteCommandOptions(),
DocumentRangeFormattingProvider = false,
};
capabilities.TextDocumentSync.Change = TextDocumentSyncKind.Incremental;
capabilities.TextDocumentSync.OpenClose = true;
capabilities.TextDocumentSync.Save = new SaveOptions { IncludeText = true };
capabilities.CodeActionProvider = clientCapabilities?.Workspace?.ApplyEdit ?? true;
capabilities.DefinitionProvider = true;
capabilities.ReferencesProvider = true;
capabilities.DocumentSymbolProvider = true;
capabilities.WorkspaceSymbolProvider = false;
capabilities.RenameProvider = true;
capabilities.HoverProvider = true;
capabilities.DocumentHighlightProvider = true;
return new InitializeResult { Capabilities = capabilities };
}
}
but I'm unable to setup client with those vscode-languageclient/node libraries even to get Log.Information("Initialization"); part
How can I provide the way they communicate - e.g name of named pipe? or just HTTP posts?
I'm not proficent in js / node development at all, so sorry for every foolish question
I've seen mature/production grade C# Language Server implementations but I'm overwhelmed just by their builders, there's sooo much stuff happening, sop that's why I'd want to write server from scratch, but for client use existing libs
var server = await LanguageServer.From(
options =>
options
.WithInput(Console.OpenStandardInput())
.WithOutput(Console.OpenStandardOutput())
.ConfigureLogging(
x => x
.AddSerilog(Log.Logger)
.AddLanguageProtocolLogging()
.SetMinimumLevel(LogLevel.Debug)
)
.WithHandler<TextDocumentHandler>()
.WithHandler<DidChangeWatchedFilesHandler>()
.WithHandler<FoldingRangeHandler>()
.WithHandler<MyWorkspaceSymbolsHandler>()
.WithHandler<MyDocumentSymbolHandler>()
.WithHandler<SemanticTokensHandler>()
.WithServices(x => x.AddLogging(b => b.SetMinimumLevel(LogLevel.Trace)))
.WithServices(
services => {
services.AddSingleton(
provider => {
var loggerFactory = provider.GetService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Foo>();
logger.LogInformation("Configuring");
return new Foo(logger);
}
);
services.AddSingleton(
new ConfigurationItem {
Section = "typescript",
}
).AddSingleton(
new ConfigurationItem {
Section = "terminal",
}
);
}
)
.OnInitialize(
async (server, request, token) => {
var manager = server.WorkDoneManager.For(
request, new WorkDoneProgressBegin {
Title = "Server is starting...",
Percentage = 10,
}
);
workDone = manager;
await Task.Delay(2000);
manager.OnNext(
new WorkDoneProgressReport {
Percentage = 20,
Message = "loading in progress"
}
);
}
)
.OnInitialized(
async (server, request, response, token) => {
workDone.OnNext(
new WorkDoneProgressReport {
Percentage = 40,
Message = "loading almost done",
}
);
await Task.Delay(2000);
workDone.OnNext(
new WorkDoneProgressReport {
Message = "loading done",
Percentage = 100,
}
);
workDone.OnCompleted();
}
)
.OnStarted(
async (languageServer, token) => {
using var manager = await languageServer.WorkDoneManager.Create(new WorkDoneProgressBegin { Title = "Doing some work..." });
manager.OnNext(new WorkDoneProgressReport { Message = "doing things..." });
await Task.Delay(10000);
manager.OnNext(new WorkDoneProgressReport { Message = "doing things... 1234" });
await Task.Delay(10000);
manager.OnNext(new WorkDoneProgressReport { Message = "doing things... 56789" });
var logger = languageServer.Services.GetService<ILogger<Foo>>();
var configuration = await languageServer.Configuration.GetConfiguration(
new ConfigurationItem {
Section = "typescript",
}, new ConfigurationItem {
Section = "terminal",
}
);
var baseConfig = new JObject();
foreach (var config in languageServer.Configuration.AsEnumerable())
{
baseConfig.Add(config.Key, config.Value);
}
logger.LogInformation("Base Config: {Config}", baseConfig);
var scopedConfig = new JObject();
foreach (var config in configuration.AsEnumerable())
{
scopedConfig.Add(config.Key, config.Value);
}
logger.LogInformation("Scoped Config: {Config}", scopedConfig);
}
)
);
Thanks in advance

Related

How to dynamically Configure different "SubscriptionProperties" for Azure ServiceSub Subscription in C#

I'm trying to configure Azure ServiceBus Topic Subscription dynamically(using C#) with all of its properties which we can set up using Azure Portal.
I have tried the below code, but it's giving me an "object reference error" for SubscriptionProperties while setting up its values.
static SubscriptionProperties subscriptionProperties;
static async Task Main(string[] args)
{
adminClient = new ServiceBusAdministrationClient(connectionString);
client = new ServiceBusClient(connectionString);
subscriptionProperties.AutoDeleteOnIdle = TimeSpan.FromDays(14);
subscriptionProperties.DefaultMessageTimeToLive = TimeSpan.FromDays(14);
subscriptionProperties.TopicName = topicName;
subscriptionProperties.SubscriptionName = subscriptionName;
subscriptionProperties.MaxDeliveryCount = 3;
subscriptionProperties.LockDuration = TimeSpan.FromSeconds(5.00);
subscriptionProperties.DeadLetteringOnMessageExpiration = true;
subscriptionProperties.EnableDeadLetteringOnFilterEvaluationExceptions = true;
Console.WriteLine($"Creating the subscription {subscriptionName} with a correlation filter");
if (!await adminClient.SubscriptionExistsAsync(topicName, subscriptionName))
{
await adminClient.CreateSubscriptionAsync(
new CreateSubscriptionOptions(subscriptionProperties),
new CreateRuleOptions(subscriptionFilterName, new CorrelationRuleFilter() { Subject = correlationFilterValue }));
}
}
Let me know if this is the correct way of setting the property values for "SubscriptionProperties" class or how can I do so?
I was able to fix this issue by following this link https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/servicebus/Azure.Messaging.ServiceBus/samples/Sample07_CrudOperations.md#create-a-topic-and-subscription
var client = new ServiceBusAdministrationClient(connectionString);
string subscriptionName = "<subscription_name>";
var subscriptionOptions = new CreateSubscriptionOptions(topicName, subscriptionName)
{
AutoDeleteOnIdle = TimeSpan.FromDays(7),
DefaultMessageTimeToLive = TimeSpan.FromDays(2),
EnableBatchedOperations = true,
UserMetadata = "some metadata"
};
SubscriptionProperties createdSubscription = await client.CreateSubscriptionAsync(subscriptionOptions);
This might be helpful for other readers as well as having similar doubuts.

How to write unit test for a MediatR handler C#

I'm trying to write unit test using Moq framework for one of my MediatR handler. I have the following code. Briefly, what this handler does is that it queries for the given key and returns a response that contains key and its value using EF Core. Also there is a basic cache mechanism. If the key found in cache it is pulled from cache and returned.
Handler
public GetConfigByKeyRequestHandler(MyContext context, ICacheProvider cacheProvider, IOptions<CacheConfigs> cacheConfigs)
{
this.context = context;
this.cacheProvider = cacheProvider;
this.cacheConfigs = cacheConfigs?.Value;
}
public async Task<ConfigResponse> Handle(GetConfigByKeyRequest request, CancellationToken cancellationToken)
{
ConfigResponse config;
if (!await cacheProvider.ExistsAsync(request.Key))
{
config = await context.Configs
.Where(x.ConfigKey.Equals(request.Key))
.Select(x =>
new ConfigResponse {
ConfigKey = x.ConfigKey,
ConfigValue = x.ConfigValue
})
.FirstOrDefaultAsync(cancellationToken);
if (config is not null)
{
await cacheProvider.PutAsync(new CacheItem<ConfigResponse>(request.Key, config), new CacheOptions
{
ExpireAfter = TimeSpan.FromMinutes(cacheConfigs.ExpireAfterInMinutes).TotalMilliseconds,
ExpireInactive = TimeSpan.FromMinutes(cacheConfigs.ExpireInActiveInMinutes).TotalMilliseconds
});
}
return config;
}
config = await cacheProvider.PullAsync<ConfigResponse>(request.Key);
return config;
}
I have thought that I should cover 2 different scenarios:
When the key found in the cache
When the key is not found in cache and it's returned from DbContext.
Unit tests
private Mock<ICacheProvider> cacheProviderMock;
private IOptions<CacheConfigs> cacheConfigs;
public GetConfigByKeyRequestHandlerTests()
{
cacheProviderMock = new Mock<ICacheProvider>();
cacheConfigs = Options.Create(
new CacheConfigs
{
ExpireAfterInMinutes = 3,
ExpireInActiveInMinutes = 3
});
}
[Fact]
public async Task GetConfigByKeyHandler_WhenKeyIsCached_ShouldReturnConfigByKey()
{
// arrange
var options = new DbContextOptionsBuilder<MyContext>().UseInMemoryDatabase("MyInMemoryDatabase").Options;
var configItems = Enumerable.Range(0, 5).Select(x => new Config
{
ConfigKey = $"key{x}",
ConfigValue = $"value{x}"
});
using (var context = new MyContext(options))
{
await context.Configs.AddRangeAsync(configItems);
await context.SaveChangesAsync();
}
using (var context = new MyContext(options))
{
cacheProviderMock.Setup(x => x.ExistsAsync(It.IsAny<string>())).Returns(Task.FromResult(true));
cacheProviderMock.Setup(x => x.PullAsync<ConfigResponse>("key2"))
.Returns(Task.FromResult(new ConfigResponse
{
ConfigKey = "key2",
ConfigValue = "value2"
}));
var getConfigByKeyHandler = new GetConfigByKeyRequestHandler(context, cacheProviderMock.Object, cacheConfigs);
var getConfigByKeyRequest = new GetConfigByKeyRequest("key2");
// act
var result = await getConfigByKeyHandler.Handle(getConfigByKeyRequest, CancellationToken.None);
// assert
Assert.NotNull(result);
Assert.Equal("key2", result.ConfigKey);
}
}
...
...
With the same logic, I have one more test for the other scenario that when key is not cached
...
...
[Fact]
public async Task GetConfigByKeyHandler_WhenKeyIsNotCached_ShouldReturnConfigByKey()
{
// arrange
var options = new DbContextOptionsBuilder<MyContext>().UseInMemoryDatabase("MyInMemoryDatabase").Options;
var configItems = Enumerable.Range(0, 5).Select(x => new Config
{
ConfigKey = $"key{x}",
ConfigValue = $"value{x}"
});
using (var context = new MyContext(options))
{
await context.Configs.AddRangeAsync(configItems);
await context.SaveChangesAsync();
}
using (var context = new MyContext(options))
{
cacheProviderMock.Setup(x => x.ExistsAsync(It.IsAny<string>())).Returns(Task.FromResult(false));
var getConfigByKeyHandler = new GetConfigByKeyRequestHandler(context, cacheProviderMock.Object, cacheConfigs);
var getConfigByKeyRequest = new GetConfigByKeyRequest("key2");
// act
var result = await getConfigByKeyHandler.Handle(getConfigByKeyRequest, CancellationToken.None);
// assert
Assert.NotNull(result);
Assert.Equal("key2", result.ConfigKey);
}
}
I have written 2 unit tests that covers the scenarios that I have mentioned above, but I'm not sure that they are reasonable ones and I'm not sure it should be tested like this way. Do you have any suggestions what/how should I write tests for the handler I shared above?

.net core monitor nats request with prometheus

I have a net core 3.1 web-API application that integrated with nats
and I need to capture all my application's traffic and send them to Prometheus for monitor application's activity
in this case, I've used this article but it described a way of capturing Http requests not nats
is anyone have any experience in such a problem?
I finally figure it out!
If anyone has the same question Here is my solution:
{
private readonly ITracer _tracer;
public TraceMiddleware(ITracer tracer)
{
_tracer = tracer;
}
public async Task ExecuteAsync(NatsContext context, PipelineDelegate next)
{
var operationName = $"{context.Request.Address.Service}:{context.Request.Address.Method}";
var builder = _tracer.BuildSpan(operationName);
#region [Context TraceId]
builder.WithTag("internalRequestId", context["requestId"].ToString());
context.Tracer.AddTracer(context.Request.Address.ToNatsSubject(), context["requestId"].ToString());
builder.WithTag("TraceId", context.Tracer.TraceId);
#endregion
using (var scope = builder.StartActive(false))
{
var span = scope.Span;
span.SetTag("flow", context.Tracer.ToString());
span.SetTag("request-route", context.Request.Address.ToNatsSubject());
span.Log(DateTimeOffset.UtcNow, "request-started");
#region [Prometheus]
var counter = Metrics.CreateCounter("app_request_total", "Nats Requests Total",
new CounterConfiguration
{
LabelNames = new[] {"path", "method", "statusCode"}
});
var path = context.Request.Address.Service;
var method = context.Request.Address.Method;
int statusCode;
try
{
await next();
}
catch (Exception)
{
statusCode = 500;
counter.Labels(path, method, statusCode.ToString()).Inc();
throw;
}
statusCode = (int) context.Response.Status;
counter.Labels(path, method, statusCode.ToString()).Inc();
#endregion
span.Log(DateTimeOffset.UtcNow, "request-finished");
var logData = new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("status-code", context.Response.Status),
new KeyValuePair<string, object>("has-exception", context.Response.Error != null)
};
span.Log(logData);
span.Finish();
}
}
}```

WaterfallDialog choiceprompt working in emulator but not working in directline webchannel in Bot framework v4

I have recently migrated my project from bot framework v3 to bot V4.
I have FeedbackDialog file in this i have implemented waterfallsteps, choiceprompts.
Everything and the flow is working correctly in Emulator.
But it is not working properly means the flow is not working fine in Webchannel
Please provide the solution to this problem.
Here is my code.
public FeedbackDialog() : base(nameof(FeedbackDialog))
{
AddDialog(new ChoicePrompt("ShowChoicePrompt") { Style = ListStyle.HeroCard });
AddDialog(new ChoicePrompt(nameof(ConfirmPrompt)));
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
StartAsync,
MessageReceivedAsync,
ResumeAfterPositiveFeedbackSelectionClarification
}));
InitialDialogId = nameof(WaterfallDialog);
}
public async Task<DialogTurnResult> StartAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var reply = ((Activity)stepContext.Context.Activity).CreateReply(BotConstants.feedbackRequestText);
reply.SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>()
{
new CardAction(){ Title = "👍", Type=ActionTypes.PostBack, Value=BotConstants.positiveFeedbackValue },
new CardAction(){ Title = "👎", Type=ActionTypes.PostBack, Value=BotConstants.negativeFeedbackValue }
}
};
await stepContext.Context.SendActivityAsync(reply, cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
// return await stepContext.PromptAsync(nameof(ConfirmPrompt), promptOptions, cancellationToken);
}
public async Task<DialogTurnResult> MessageReceivedAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var data=stepContext.Result;
var res = stepContext.Result;
// string res= Convert.ToString(data.GetType().GetProperty("Synonym").GetValue(data, null));
var feedbackDetails = (FeedbackData)stepContext.Options;
var userFeedback =Convert.ToString(res);
// var userFeedback = feedbackDetails.userFeedback;
string userQuestion = feedbackDetails.userQuestion;
string intent = feedbackDetails.intent;
int Id = feedbackDetails.Id;
if (userFeedback.Contains(BotConstants.positiveFeedbackValue) || userFeedback.Contains(BotConstants.negativeFeedbackValue))
{
// create telemetry client to post to Application Insights
TelemetryClient telemetry = new TelemetryClient();
telemetry.InstrumentationKey = Configuration.CDPOSConfigurationManager.GetAppSetting("InstrumentationKey");
RequestRepository requestRepository = new RequestRepository();
if (userFeedback.Contains(BotConstants.positiveFeedbackValue))
{
// post feedback to App Insights
var properties = new Dictionary<string, string>
{
{"Question", userQuestion },
{"LuisIntent", intent },
{"Vote", "Yes" }
// add properties relevant to your bot
};
telemetry.TrackEvent("Yes-Vote", properties);
var chatFeedback = true;
//requestRepository.AddChatbotEntryToDB(userQuestion, intent, chatFeedback);
requestRepository.updateChatFeedbackStatus(Id, chatFeedback);
var options = BotConstants.positiveFeedbackOption;
var descriptions = BotConstants.positiveFeedbackOptionDesc;
Activity textPrompt = stepContext.Context.Activity.CreateReply(BotConstants.positiveFeedbackResponse);
List<Microsoft.Bot.Builder.Dialogs.Choices.Choice> choices = new List<Microsoft.Bot.Builder.Dialogs.Choices.Choice>()
{
new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.YeshaveAnotherQuestionOption, Synonyms = new List<string> { "Yes" } },
new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.NothankyouOption, Synonyms = new List<string> { "No" }}
};
try
{
await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions {Prompt= MessageFactory.Text(BotConstants.positiveFeedbackResponse), Choices= choices }, cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
}
catch (Exception ex)
{
await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions { Prompt = MessageFactory.Text(BotConstants.positiveFeedbackResponse), Choices = choices }, cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
}
}
else if (userFeedback.Contains(BotConstants.negativeFeedbackValue))
{
var properties = new Dictionary<string, string>
{
{"Question", userQuestion },
{"LuisIntent", intent },
{"Vote", "Yes" }
// add properties relevant to your bot
};
telemetry.TrackEvent("No-Vote", properties);
var chatFeedback = false;
//requestRepository.AddChatbotEntryToDB(userQuestion, intent, chatFeedback);
requestRepository.updateChatFeedbackStatus(Id, chatFeedback);
await stepContext.Context.SendActivityAsync(BotConstants.negativeFeedbackResponse);
await stepContext.Context.SendActivityAsync(BotConstants.logTicketResponse);
var options = BotConstants.negativeFeedbackOption;
var descriptions = BotConstants.negativeFeedbackDesc;
List<Microsoft.Bot.Builder.Dialogs.Choices.Choice> NegativeChoices = new List<Microsoft.Bot.Builder.Dialogs.Choices.Choice>()
{
new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.logTicket, Synonyms = new List<string> { BotConstants.logTicketOption } },
new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.rephraseQuestionOption, Synonyms = new List<string> { BotConstants.rephraseQuestionOption }}
};
try
{
await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions { Prompt = MessageFactory.Text(BotConstants.positiveFeedbackResponse), Choices = NegativeChoices }, cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
}
catch (Exception ex)
{
await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions { Prompt = MessageFactory.Text(BotConstants.question), Choices = NegativeChoices }, cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
}
}
}
else
{
return await stepContext.BeginDialogAsync(nameof(RootDialog), null, cancellationToken);
// no feedback, return to main dialog
// return await stepContext.EndDialogAsync(userFeedback, cancellationToken);
//return stepContext.BeginDialogAsync(userFeedback, cancellationToken);
}
return await stepContext.EndDialogAsync(userFeedback, cancellationToken);
}
private async Task<DialogTurnResult> ResumeAfterPositiveFeedbackSelectionClarification(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var data = stepContext.Result;
if (stepContext.Result != null)
{
string selection = Convert.ToString(data.GetType().GetProperty("Synonym").GetValue(data, null));
// var selection = stepContext.Result;
if (selection == BotConstants.YeshaveAnotherQuestionOption || selection == BotConstants.haveAnotherQuestionOption || selection == BotConstants.rephraseQuestionOption)
{
await stepContext.Context.SendActivityAsync(BotConstants.askAnotherQuestion);
}
else
{
await stepContext.Context.SendActivityAsync(BotConstants.logaTicketResponse);
}
}
return await stepContext.EndDialogAsync(null, cancellationToken);
}
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<MessagesController>().InstancePerRequest();
// The ConfigurationCredentialProvider will retrieve the MicrosoftAppId and
// MicrosoftAppPassword from Web.config
builder.RegisterType<ConfigurationCredentialProvider>().As<ICredentialProvider>().SingleInstance();
// Create the Bot Framework Adapter with error handling enabled.
builder.RegisterType<AdapterWithErrorHandler>().As<IBotFrameworkHttpAdapter>().SingleInstance();
// The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, everything stored in memory will be gone.
IStorage dataStore = new MemoryStorage();
// Create Conversation State object.
// The Conversation State object is where we persist anything at the conversation-scope.
var conversationState = new ConversationState(dataStore);
builder.RegisterInstance(conversationState).As<ConversationState>().SingleInstance();
// Register the main dialog, which is injected into the DialogBot class
builder.RegisterType<RootDialog>().SingleInstance();
// Register the DialogBot with RootDialog as the IBot interface
builder.RegisterType<DialogBot<RootDialog>>().As<IBot>();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
}
When a bot only works when it's running locally, memory storage is very often the issue. When a bot is deployed to an app service, there may be multiple instances of the service running simultaneously to provide high availability, and each instance will have its own memory. Like all REST API's, your bot needs to not rely on memory for the state it accesses across multiple turns. You need external storage so that all instances of the service have access to the same data, and so the data isn't lost when the service restarts. Please refer to the documentation for more information.

c# unit test fails with moq when it goes to hit a real service

So I was put on doing unit test and i noticed different unit tests failing in nunit and in Visual Studio with Resharper i tried debugging it and I get object
[Test]
public void KeyDocumentService_ProofKeyDocument_RepoReturnsData_ServiceReturnsTheDataWithoutError()
{
//Arrange
KeyDocumentProofRequest request = new KeyDocumentProofRequest() { KeyDocumentId = 2 };
string returnedResponse = "2";
KeyDocument keyDocumentResponse = new KeyDocument() { CampaignId = "2", DesignFileId = 3,DocumentId="2", DataSourceId="3", KeyDocumentId=1 };
List<vwKeyDocumentSearch> keyListResponse = new List<vwKeyDocumentSearch>() { new vwKeyDocumentSearch { FieldName = "test", FieldValue = "testvalue" } };
var uproduceRepo = new Mock<IUProduceRepository>();
var keyDocRepo = new Mock<IKeyDocumentRepository>();
var templateRepo = new Mock<ITemplateRepository>();
keyDocRepo.Setup(p => p.GetKeyDocument(It.IsAny<KeyDocumentRequest>())).Returns(new KeyDocumentResponse() { data = keyDocumentResponse });
keyDocRepo.Setup(p => p.GetKeyDocumentItems(It.IsAny<int>())).Returns(keyListResponse);
uproduceRepo.Setup(p => p.ProduceDocument(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Customization[]>(), It.IsAny<string>(), It.IsAny<string>(), null)).Returns(returnedResponse);
// Act.
KeyDocumentService svc = new KeyDocumentService(keyDocRepo.Object, uproduceRepo.Object, templateRepo.Object);
var response = svc.ProofKeyDocument(request);
//Assert
Assert.IsNotNull(response);
Assert.IsNotNull(response.data.JobId);
Assert.IsNull(response.Error);
}
So the error is happening on this line :
var response = svc.ProofKeyDocument(request);
Are unit Tests supposed to even be going into a real service? or is that ok?
That Method ProofKeyDocument looks like this FYI
private List<Customization> GetCustomizationsFromKeyDocumentItems(List<vwKeyDocumentSearch> keyDocumentItemsList,
int templateId, int clientId)
{
try
{
List<Customization> KeyDocumentCustomizations = new List<Customization>();
var keyDocumentVariableList = keyDocumentItemsList.Where(k => k.Type.ToUpper()=="VARIABLE").ToList();
var keyDocumentSettingList = keyDocumentItemsList.Where(k => k.Type.ToUpper() == "SETTING").ToList();
var keyDocumentContentList = keyDocumentItemsList.Where(k => k.Type.ToUpper() == "CONTENT").ToList();
KeyDocumentCustomizations.AddRange(VariableCustomizations(keyDocumentVariableList, templateId));
KeyDocumentCustomizations.AddRange(SettingCustomizations(keyDocumentSettingList, templateId));
KeyDocumentCustomizations.AddRange(ContentCustomizations(keyDocumentContentList, templateId, clientId));
return KeyDocumentCustomizations;
}
catch (Exception ex)
{
logger.Error(string.Format("Error customizing key document: {0}", templateId), ex);
throw ex;
}
}
I see with Debugging it blowing up on this line
var keyDocumentVariableList = keyDocumentItemsList.Where(k => k.Type.ToUpper()=="VARIABLE").ToList();
Object Reference not set to instance... error Why ?
var keyDocumentResponse = _repo.GetKeyDocument(new KeyDocumentRequest() { KeyDocumentId = request.KeyDocumentId });
and
Customization[] customizations = GenerateCustomizationsForKeyDocument(keyDocumentDetails.KeyDocumentId, keyDocumentResponse);
Then
public KeyDocumentProofResponse ProofKeyDocument(KeyDocumentProofRequest request)
{
//return new KeyDocumentProofResponse()
//{
// data = new KeyDocumentProofResponseData() { JobId = "2984" }
//};
KeyDocumentProofResponse response = new KeyDocumentProofResponse();
var keyDocumentDetails = _repo.GetKeyDocument(new KeyDocumentRequest() { KeyDocumentId = request.KeyDocumentId }).data;
if (keyDocumentDetails != null && (!string.IsNullOrEmpty(keyDocumentDetails.CampaignId)) &&
keyDocumentDetails.DesignFileId.HasValue &&
keyDocumentDetails.DesignFileId > 0)
{
var keyDocumentResponse = _repo.GetKeyDocument(new KeyDocumentRequest() { KeyDocumentId = request.KeyDocumentId });
Customization[] customizations = GenerateCustomizationsForKeyDocument(keyDocumentDetails.KeyDocumentId, keyDocumentResponse);
var jobTicketId = _uproduceRepo.CreateJobTicket(keyDocumentDetails.DocumentId, keyDocumentDetails.DataSourceId, "PROOF");
if (!string.IsNullOrEmpty(jobTicketId))
{
List<JobDataSource> dataSources = GenerateCSVForPersonalizedAndCustomizedVariables(keyDocumentResponse, jobTicketId);
var jobId = _uproduceRepo.ProduceDocument(keyDocumentDetails.DocumentId, keyDocumentDetails.DataSourceId, customizations, "PROOF", jobTicketId, dataSources);
if (string.IsNullOrEmpty(jobId))
{
response.Error = CreateCustomError("Error while submitting job", "Error occurred while submitting proofing job");
}
else
{
response.data.JobId = jobId;
}
}
else
{
response.Error = CreateCustomError("Unable to generate job ticket for the keydocument",
"Error while creating a job ticket for proof request");
}
}
else
{
response.Error = CreateCustomError("Unable to generate proof for the keydocument",
"Requested template is missing campaignid or Designfile in Uproduce");
}
return response;
}
Published test doesn't contain mock method for "CreteJobTicket" and jobTickedId will be null.
var jobTicketId = _uproduceRepo.CreateJobTicket(keyDocumentDetails.DocumentId, keyDocumentDetails.DataSourceId, "PROOF");

Categories