unitary testing in doGet(request) - Google Apps Script - unit-testing

I'm developing a simple google Script and publishing it as a web app.
The starting of my method is as follows:
function doGet(request) {
var start = request.parameters.start;
var end = request.parameters.end;
if (isNaN(Number(start)))
return generateError (3, start);
if (isNaN(Number(end)))
return generateError (4, end);
/*
* ...
* lot of irrelevant stuff for current question
* ...
*/
}
I want to add some basic unitary testing. I have it ready for secondary functions, but I'm not sure how to do it with the doGet (request) function.
At the present moment I'm using the following method:
function testDoGet(){
var queryString = "?start=1&end=5";
var url = ScriptApp.getService().getUrl() + queryString;
var options =
{
"method" : "GET",
"followRedirects" : true,
"muteHttpExceptions": true
};
Logger.log(url);
var result = UrlFetchApp.fetch(url, options);
Logger.log(result);
But this does not allow me to debug, and also it requires that the code has been published (but is not executing the latest code), I would be interested in validate parameters received (for example)
Is there any way so we can simulate this?

I guess you can just call it directly and provide the parameters as an actual HTTP call would do, e.g.
function testDoGet() {
var requestMock = {
parameters: {
start: 1,
end: 5
}
};
Logger.log(requestMock);
var result = doGet(requestMock);
Logger.log(result);
}

Related

.net core 6 jwt token mocking

I am looking for a tutorial on how to mock authentication tokens for .net core 6 web services. Some years ago, at a previous job, I looked up how to do this with .net 3 and got it to work. But 6 removed the startup.cs file and seems to have shifted things around quite a bit. There are very few examples of doing this for 6.
I am in the process of creating a series of unit tests for the endpoints in a new web application. I am starting over from bare bones. Here is the code example. I know that it is possible to recreate the Startup.cs file, but for the time being I would prefer to do it without that. Are there any examples of this for a .net 6 specific architecture?
internal class DssiApiTest : WebApplicationFactory<Program>
{
private readonly string _environment;
public DssiApiTest(string environment = "Development")
{
_environment = environment;
}
protected override IHost CreateHost(IHostBuilder builder)
{
builder.UseEnvironment(_environment);
var settings = new ApiSettings();
// Add mock/test services to the builder here
builder.ConfigureServices(services =>
{
services.AddScoped(sp =>
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase("Tests")
.UseApplicationServiceProvider(sp)
.Options;
using (var context = new ApplicationDbContext(options,
MakeMockTenantService(),
(Microsoft.Extensions.Options.IOptions<ApiSettings>)settings))
{
context.PartCustomers.Add(CreatePartCustomer(1, 1));
context.PartCustomers.Add(CreatePartCustomer(2, 1));
context.SaveChanges();
}
// Replace SQLite with in-memory database for tests
return options;
});
});
return base.CreateHost(builder);
}
}
I think I found the answer to what I needed to do. I have not been able to fully test it yet, however, because I am running into another issue that is throwing an error. Will have to ask another question for that one. Here is what I have so far. If anyone can elaborate or correct this please feel free to do so. Like I said, I have not fully tested it and don't want to lead others astray. Will update once I have it worked out.
I added a new TestAuthHandler to the virtual client that returns a mock auth result like so :
using var application = new TestWebApplicationFactory();
var client = application.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"Test", options => { });
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
Here is the code for the TestAuthHandler
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[] { new Claim(ClaimTypes.Name, "Test user") };
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}

When launching icCube report how can I get the user name

in ic3Report.html file, is it possible to get the user name in the callback function ?
var options = {
root: "ic3-report/app/",
rootLocal: "ic3-report/app-local/",
rootVersion: "_IC3_ROOT_VERSION_",
callback: function () {
$('#intro').remove();
window.ic3application = ic3.startReport(
{
<!-- ic3-start-report-options (DO NOT REMOVE - USED TO GENERATE FILES) -->
});
// get user name here !
}
};
in order to gather current user information you should setup GVI configuration. It could be done with appropriate method:
var options = {
root: "ic3-report/app/",
rootLocal: "ic3-report/app-local/",
rootVersion: "_IC3_ROOT_VERSION_",
callback: function () {
$('#intro').remove();
var ic3reporting = new ic3.Reporting(
{
noticesLevel: ic3.NoticeLevel.INFO,
dsSettings: {
url: GVI_URL
}
});
ic3reporting.setupGVIConfiguration(function () {
var userName = ic3reporting.userName();
})
}
};
After that user information will be available inside context. See code above for details.
Update
A more robust solution is adding the code to the local files that are not overwritten with a new version of the reporting. You can use ic3bootstrapLocal function in Admin > Common JS configuration.
function ic3bootstrapLocal(options) {
var ic3reporting = new ic3.Reporting({
noticesLevel: ic3.NoticeLevel.INFO,
});
ic3reporting.setupGVIConfiguration(function(){
ic3reporting.userName()
options.callback && options.callback();
});
}

Unit Test NService.Send from an API Controller

I have an API Controller which publishes a command using NServiceBus. I am using NUnit and NSubstitute for testing. I want to test that certain properties from the model are populated on the command
Here is my controller with a route.
[RoutePrefix("api/fileService")]
public class FileServiceController : ApiController
{
[HttpPost]
[Route("releasefile")]
public async Task<IHttpActionResult> ReleaseFile(FileReleaseAPIModels.ReleaseFileModel model)
{
var currentUser = RequestContext.Principal?.Identity as ClaimsIdentity;
if (model.FileType.Equals("ProductFile"))
{
_logger.Info($"Releasing Product files for date: {model.FileDate.ToShortDateString()} ");
_bus.Send<IReleaseProductFiles>("FileManager.Service", t =>
{
t.FileId = Guid.NewGuid();
t.RequestedDataDate = model.FileDate;
t.RequestingUser = currentUser?.Name;
t.RequestDateTime = DateTime.Now;
});
}
return Ok();
}
}
In my test, I substitute(mock) Ibus and try to validate the call received. Here is the test method:
[Test]
public async Task TestReleaseProductsFile()
{
var bus = Substitute.For<IBus>();
var dbContent = _container.Resolve<IFileManagerDbContext>();
var apiContext = new FileServiceController(bus, dbContent);
//Create a snapshot
var releaseDate = DateTime.Now.Date;
var result = await apiContext.ReleaseFile(new ReleaseFileModel
{
FileDate = releaseDate,
FileType = "ProductFile"
});
Assert.That(result, Is.Not.Null, "Result is null");
Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok");
bus.Received(1)
.Send<IReleaseProductFiles>(Arg.Is<string>("FileManager.Service"), Arg.Is<Action<IReleaseProductFiles>>(
action =>
{
action.FileId = Guid.NewGuid();
action.RequestedDataDate = releaseDate;
action.RequestingUser = String.Empty;
action.RequestDateTime = DateTime.Now;
}));
}
This results in error - even though the message is actually sent. Here is the error message:
NSubstitute.Exceptions.ReceivedCallsException : Expected to receive exactly 1 call matching:
Send<IReleaseProductFiles>("Capelogic.Service", Action<IReleaseProductFiles>)
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Send<IReleaseProductFiles>("Capelogic.Service", *Action<IReleaseProductFiles>*)
I am obviously missing something obvious here.
The problem here is with the Action<IReleaseProductFiles> argument to Send -- we can't automatically tell if two different actions are the same. Instead, NSubstitute relies on the references being equivalent. Because both the test and the production code create their own Action instance, these will always be different and NSubstitute will say the calls don't match.
There are a few different options for testing this. These examples relate to Expression<Func<>>, but the same ideas apply to Action<>s.
In this case I'd be tempted to test this indirectly:
[Test]
public async Task TestReleaseProductsFile()
{
var bus = Substitute.For<IBus>();
var returnedProductFiles = Substitute.For<IReleaseProductFiles>();
// Whenever bus.Send is called with "FileManager.Service" arg, invoke
// the given callback with the `returnedProductFiles` object.
// We can then make sure the action updates that object as expected.
bus.Send<IReleaseProductFiles>(
"FileManager.Service",
Arg.Invoke<IReleaseProductFiles>(returnedProductFiles));
// ... remainder of test ...
Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok");
Assert.That(returnedProductFiles.FileId, Is.Not.EqualTo(Guid.Empty));
Assert.That(returnedProductFiles.RequestedDataDate, Is.EqualTo(releaseDate));
Assert.That(returnedProductFiles.RequestingUser, Is.EqualTo(String.Empty));
}
I'd recommend having a look through the previously mentioned answer though to see if there is a better fit for your situation.

Loopback strange behaviour

I am talking about loopback push component. I am trying to intercept the "create" method of "Installation" model. My code looks like this -
server/boot/installationex.js
module.exports = function (app) {
var Installation = app.models.Installation;
var create = Installation.create;
Installation.create = function (data, cb) {
//reinitializing old implementation
this.create = create;
console.log("Received data: "+JSON.stringify(data));
if (!data || !data.imei) {
console.log("No data or imei was provided, creating new");
this.create(data, cb);
return;
}
//saving 'this' reference
var that = this;
//search by imei filter
var filter = {where: {imei: data.imei}};
this.findOne(filter, function (err, result) {
if (err) {
console.log("Error occurred while looking for installation by IMEI");
cb(err);
return;
}
if (!result) {
console.log("No installation found by IMEI, will create a new installation");
that.create(data, cb);
return;
}
console.log("Found existing installation with id: " + JSON.stringify(result));
result.deviceToken = result.gpsLocation = result.osVersion = result.vendor = result.phoneNumbers = null;
if (data.deviceToken) {
result.deviceToken = data.deviceToken;
}
if (data.gpsLocation) {
result.gpsLocation = data.gpsLocation;
}
if (data.osVersion) {
result.osVersion = data.osVersion;
}
if (data.vendor) {
//result.vendor=data.vendor;
result.vendor = 'jahid';
}
if (data.phoneNumbers) {
result.phoneNumbers = data.phoneNumbers;
}
that.upsert(result, cb);
});
}
}
Unfortunately this code is invoked only once, I mean the first time. After that this code is never invoked. I became sure by looking at the log. It only prints the log first time. After that it does not print any log.
Any idea why this glue code is only invoked once? My intention is to intercept all create method invocation for Installation model. And check if there is already an entry for supplied "IMEI", if so then reuse that. Otherwise create new.
Thanks in advance.
Best regards,
Jahid
What I would start here with is:
instead of implementing your own intercepting mechanism use Model Hooks
check out findOrCreate() method
boot scripts are only run once during application startup. if you want a function that triggers every time a function is called, use a remote hook or model hook. probably something along the lines of:
...
Installation.beforeRemote('create', ...
...
see http://docs.strongloop.com/display/LB/Adding+logic+to+models for more info

How to embed latest tweets in Sitecore 6.5

I have to embed latest tweets in a Sitecore 6.5 project as given below image
How can I implement this functionality.
Thanks
Hello You can do this See below code. I am pasting code here for a single sublayout. Please update some tokens as per your requirement. This code will return you a Json you can get that json in JQuery.
Code - ----------------
public partial class LatestTweets : BaseSublayout
{
SiteItem objSiteItem = SiteItem.GetSiteRoot();
protected void Page_Load(object sender, EventArgs e)
{
if (objSiteItem != null)
{
hdJsonData.Value = GetTweets();
frLatestTweets.Item = objSiteItem;
frLatestTweets.Item = objSiteItem;
frFollowUsLink.Item = objSiteItem;
ltFollowUs.Text = Sitecore.Globalization.Translate.Text(Constants.FOLLOW_US);
ltTweetUs.Text = Sitecore.Globalization.Translate.Text(Constants.TWEET_US);
}
}
public string GetTweets()
{
// oauth application keys
var oauth_token = objSiteItem.AccessToken.Rendered;
var oauth_token_secret = objSiteItem.AccessTokenSecret.Rendered;
var oauth_consumer_key = objSiteItem.ConsumerKey.Rendered;
var oauth_consumer_secret = objSiteItem.ConsumerSecret.Rendered;
var screen_name = objSiteItem.TwitterUser.Rendered;
// oauth implementation details
var oauth_version = "1.0";
var oauth_signature_method = "HMAC-SHA1";
// unique request details
var oauth_nonce = Convert.ToBase64String(
new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
var timeSpan = DateTime.UtcNow
- new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
// message api details
var status = "Updating status via REST API if this works";
var resource_url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
// create oauth signature
var baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" +
"&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&screen_name={6}";
var baseString = string.Format(baseFormat,
oauth_consumer_key,
oauth_nonce,
oauth_signature_method,
oauth_timestamp,
oauth_token,
oauth_version,
Uri.EscapeDataString(screen_name)
);
baseString = string.Concat("GET&", Uri.EscapeDataString(resource_url), "&", Uri.EscapeDataString(baseString));
var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
"&", Uri.EscapeDataString(oauth_token_secret));
string oauth_signature;
using (HMACSHA1 hasher = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey)))
{
oauth_signature = Convert.ToBase64String(hasher.ComputeHash(ASCIIEncoding.ASCII.GetBytes(baseString)));
}
// create the request header
var headerFormat = "OAuth oauth_nonce=\"{0}\", oauth_signature_method=\"{1}\", " +
"oauth_timestamp=\"{2}\", oauth_consumer_key=\"{3}\", " +
"oauth_token=\"{4}\", oauth_signature=\"{5}\", " +
"oauth_version=\"{6}\"";
var authHeader = string.Format(headerFormat,
Uri.EscapeDataString(oauth_nonce),
Uri.EscapeDataString(oauth_signature_method),
Uri.EscapeDataString(oauth_timestamp),
Uri.EscapeDataString(oauth_consumer_key),
Uri.EscapeDataString(oauth_token),
Uri.EscapeDataString(oauth_signature),
Uri.EscapeDataString(oauth_version)
);
// make the request
ServicePointManager.Expect100Continue = false;
var postBody = "screen_name=" + Uri.EscapeDataString(screen_name);//
resource_url += "?" + postBody;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);
request.Headers.Add("Authorization", authHeader);
request.Method = "GET";
request.ContentType = "application/x-www-form-urlencoded";
WebResponse response = request.GetResponse();
string responseData = new StreamReader(response.GetResponseStream()).ReadToEnd();
return responseData;
}
}
Just as you would add it into any website... create a component for it and use the twitter API like this for example: http://jsfiddle.net/abenlumley/xRwam/4/
/*********************************************************************
#### Twitter Post Fetcher! ####
Coded by Jason Mayes 2013.
www.jasonmayes.com
Please keep this disclaimer with my code if you use it. Thanks. :-)
Got feedback or questions, ask here: http://goo.gl/JinwJ
Ammended by Ben Lumley and djb31st 2013
www.dijitul.com
Ammended to display latest tweet only with links
********************************************************************/
var twitterFetcher=function(){var d=null;return{fetch:function(a,b){d=b;var c=document.createElement("script");c.type="text/javascript";c.src="http://cdn.syndication.twimg.com/widgets/timelines/"+a+"?&lang=en&callback=twitterFetcher.callback&suppress_response_codes=true&rnd="+Math.random();document.getElementsByTagName("head")[0].appendChild(c)},callback:function(a){var b=document.createElement("div");b.innerHTML=a.body;a=b.getElementsByClassName("e-entry-title");d(a)}}}();
/*
* ### HOW TO USE: ###
* Create an ID:
* Go to www.twitter.com and sign in as normal, go to your settings page.
* Go to "Widgets" on the left hand side.
* Create a new widget for "user timeline". Feel free to check "exclude replies"
* if you dont want replies in results.
* Now go back to settings page, and then go back to widgets page, you should
* see the widget you just created. Click edit.
* Now look at the URL in your web browser, you will see a long number like this:
* 345735908357048478
* Use this as your ID below instead!
*/
twitterFetcher.fetch('345190342812909568', function(tweets){
// Do what you want with your tweets here! For example:
var x = tweets.length;
var n = 0;
var element = document.getElementById('tweets');
var html = '<ul>';
if (tweets[n].innerHTML) {
html += '<li>' + tweets[n].innerHTML + '</li>';
} else {
html += '<li>' + tweets[n].textContent + '</li>';
}
n++;
html += '</ul>';
element.innerHTML = html;
});
As #IvanL said, you will simply want to create a sublayout and add the markup/JS/etc as you normally would. Below, I describe an easy-to-use library that will help you to get your Tweets via Twitter's API and also a jQuery plugin that will help simplify the way you render them. All you would need to do is wire up the library, make the necessary C# call, and then use the jQuery plugin to help you render the Tweets, using the markup style that you specify.
As mentioned below, note that I originally wrote both the library and the jQuery plugin for integration with a Sitecore 6.5 environment, and made them flexible enough to use with any solution.
Getting and Rendering Tweets
I created a C# library for the Twitter API about a year ago, named TweetNET. It has MSDN style documentation, and I built it in such a way as it could be integrated into .NET applications, and the first production site that I used it on was a Sitecore 6.5 site. The documentation and examples are pretty comprehensive, but if you have any questions, feel free to let me know.
As for the actual displaying of the Tweets after getting them from Twitter, I also have another repo, Twitter Feed, which is a jQuery plugin designed to simplify rendering Tweets. Both projects include examples of the TweetNET's use, and the Twitter Feed project also includes examples of its call, so this would be a one-stop-shop for you.
TweetNET - Latest Tweets Call
TweetNET reduces the code that you need in order to get the latest Tweets for a given handle to the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TweetNET.OAuth;
using TweetNET.Requests.Timelines.Statuses;
using System.Net;
using System.IO;
public partial class _Default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
var consumerKey = "your consumerKey";
var consumerSecret = "your consumerSecret";
var oAuthToken = "your oAuthToken";
var oAuthTokenSecret = "your oAuthTokenSecret";
var twitterHandle = "your twitter handle";
var tokens = new SecurityTokens(consumerKey, consumerSecret, oAuthToken, oAuthTokenSecret);
var utGETRequest = new UserTimelineRequest(tokens);
utGETRequest.Screen_Name = twitterHandle;
var request = utGETRequest.BuildRequest();
WebResponse response = utGETRequest.SendRequest(request);
string responseData = new StreamReader(response.GetResponseStream()).ReadToEnd();
}
}
Twitter Feed - Rendering Tweets
$(document).ready(function () {
$("#feedTarget").twitterFeed({
count: 4,
rawData: yourRawJSONData,
prepend: "<div class='tweetWrapper'>",
append: "</div>",
tweetBodyClass: "tweetBody tweetText",
date: { prepend: "<div>", append: " - ", order: 3, cssClass: "tweetDate" },
retweet: { show: false },
favorite: { prepend: " - ", order: 0, append: "</div>" },
callbackOnEach: true,
callback: function() {
$(this).find(".tweetBody").myCallbackOnEachTweet();
}
});
});
});
To get latest tweet read following url
https://umerpasha.wordpress.com/2013/06/13/c-code-to-get-latest-tweets-using-twitter-api-1-1/