Sinon managing multiple clocks independently - sinon

Recently I updated from sinon 9 to sinon 14 which causes one of my tests to fail with the error Can't install fake timers twice on the same global object.. It looks like since version 12 it is not possible to call useFakeTimers multiple times to manage different clocks. What would be the alternative to achieve the same thing in sinon version 14?
t.test(`Skip calling the callback when the delay exceeds maxDelay`, t => {
t.plan(1);
const oneMinute = 60e3;
let rules = ['0 * * * * *']; // every minute
let timezone = null;
let maxDelay = 10;
let timerLag = 11;
let callback = spy();
let realClock = useFakeTimers({toFake: ['Date']});
let timerClock = useFakeTimers({ toFake: ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate'] });
scheduleInterval(rules, timezone, maxDelay, callback);
realClock.tick(oneMinute + timerLag);
timerClock.tick(oneMinute);
t.equal(callback.callCount, 0);
realClock.restore();
timerClock.restore();
});

Related

Update firebase database value every 5 seconds using Pub/sub OR Cloud Tasks?

I am new to Firebase and I am totally confused about what should I use. Here is my flow.
I have a collection score on firebase and it has values
- start_time
- count
- max_count
Now when start_time matches with the current time, I need to increment the count every five seconds till it matches max_count to the database. This should be in the backend. Now here I got confused. What can be suitable for this?
There are so many documents about Cloud Tasks and Pub/Sub.
If I Call the firebase function from Pub/Sub to update the count every 5 seconds then I will be paying for un-used compute time for calling a function.
I am not aware more about Cloud Tasks that is it matches my requirement? Can anyone please guide me?
Neither Cloud Tasks nor Pub/Sub would be the right solution for this and I wouldn't recommend using a cron-type service for such a menial task.
Instead consider moving the incremental logic to your client and just storing start_time and max_count in your database. Here's an example:
// Let's set a start_time 10 seconds in the future and pretend this was in the database
const start_time = Math.floor((new Date()).getTime() / 1000) + 10;
// Pretend this came from the database, we only want to iterate 10 times
const max_count = 10;
let prev_count = 0;
document.write("Waiting 10 seconds before starting<br />");
// Let's iterate once a second until we reach the start_time
let interval = setInterval(() => {
const now = Math.floor((new Date()).getTime() / 1000);
// If it's not start time, exit
if (now < start_time) return;
// Determine the count by dividing by 5 seconds
let count = Math.floor((now - start_time) / 5);
if (count > prev_count) {
document.write(`Tick: ${count}<br />`);
}
prev_count = count;
if (count >= max_count) {
clearInterval(interval);
}
}, 1000);
If you need the count stored in the database, have it update the count value in your database each time it increments.

Limit with getting info about audience from Analytics API

I'm trying to get audienc name aduience id etc we' ve created on our google analytics account. We have around 2,4k audiences list but I can just get 999 of them. I can't find any soultions. Code is below
function main() {
var spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadshe');
var sheet = spreadsheet.getSheetByName('Sh');
function listRemarketingAudiences(accountId, propertyId) {
var request = Analytics.Management.RemarketingAudience.list(
accountId,
propertyId
);
var leno = Object.keys(request).length
console.log(leno);
sheet.getRange(1,1).setValue("audianceName");
sheet.getRange(1,2).setValue("audianceId");
sheet.getRange(1,3).setValue("audianceDefinition");
sheet.getRange(1,4).setValue("audianceDescription");
for ( var i = 2; i <3000; i++) {
var audianceName = request.items[i+154].name ;
Logger.log(audianceName);
console.log(i);
sheet.getRange(i,1).setValue("elo")
var audianceId = request.items[i].id ;
sheet.getRange(i,2).setValue(audianceId);
// var audianceId = request.items[i].
var audienceDefinition = request.items[i].audienceDefinition ;
sheet.getRange(i,3).setValue(audienceDefinition);
var audienceDescription = request.items[i].description ;
sheet.getRange(i,4).setValue(audienceDescription);
};
}
listRemarketingAudiences('xxxxx', 'UA-xxxxx-1');
}
Currently you are supplying only the required parameters: accountId and webPropertyId. These are necessary to identify the Analytics property, where you are looking for the data.
Based on the documentation, optional parameters can be passed, which are actually in connection with the pagination, which you are trying to achieve.
As the developer guide is not mentioning the absolute limit of the result, you could experiment with higher limits, with a code something like this:
request = gapi.client.analytics.management.remarketingAudience.list(
{
'accountId': accountId,
'webPropertyId': propertyId,
'max-results': 5000
}
If you can't get all the data at once, you need to implement paging yourself, where an other paramerer, start-index will be necessary. You need to call the function several times, preferably from a loop, where start index is continuously increased.
request = gapi.client.analytics.management.remarketingAudience.list(
{
'accountId': accountId,
'webPropertyId': propertyId,
'start-index': 999,
'max-results': 1000
}
I wrote sth like this:
var optional = {'startIndex': 12,
'maxresults': 212};
function listRemarketingAudiences (accountId, propertyId, optional){
var request = Analytics.Management.RemarketingAudience.list(
accountId,
propertyId,
optional.maxresults
);
and an error occure:
We're sorry, a server error occurred. Please wait a bit and try again. (line 9, file "Code")

Is it possible to call 2 API's and displaying a combined answer string at the same time?

I am having trouble doing just that because of the await and async functions.
I want to have an app that analize a face in real time and is displaing the rectangle on his face and above it should say gender, age, emotion, emotion confidance.
So I want to use the Face API and Emotion API at the same time.
Thanks.
Duplicate with Calling the face and emotion API at the same time.
Please refer to that thread for more information.
Assuming you're using the C# SDKs, you can wait for both tasks to complete. The code would like something like this:
static bool SameFace(Microsoft.ProjectOxford.Face.Contract.FaceRectangle r1,
Microsoft.ProjectOxford.Common.Rectangle r2)
{
// Fuzzy match of rectangles...
return Math.Abs((r1.Top + r1.Height / 2) - (r2.Top + r2.Height / 2)) < 3 &&
Math.Abs((r1.Left + r1.Width / 2) - (r2.Left + r2.Width / 2)) < 3;
}
void Test(string imageUrl)
{
var faceClient = new FaceServiceClient(FACE_API_KEY);
var emotionClient = new EmotionServiceClient(EMOTION_API_KEY);
var faceTask = faceClient.DetectAsync(imageUrl, false, false, new FaceAttributeType[] { FaceAttributeType.Age, FaceAttributeType.Gender });
var emotionTask = emotionClient.RecognizeAsync(imageUrl);
Task.WaitAll(faceTask, emotionTask);
var people = from face in faceTask.Result
from emotion in emotionTask.Result
where SameFace(face.FaceRectangle, emotion.FaceRectangle)
select new {
face.FaceAttributes.Gender,
face.FaceAttributes.Age,
emotion.Scores
};
// Do something with 'people'
}
The tricky part is that the two APIs don't have the same rectangle type, and give slightly different values, hence a fuzzy match.

Moq SetupSet on property

i am trying to learn to use Moq (4) to test the C# code below. I was hoping that by setting
mockTimer.SetupSet(m => m.Interval = It.IsInRange(
interval - shorter, interval + longer, Range.Inclusive));
before calling the method which assigns the interval property a value (ageService.AddParticipant method), the test would throw when an incorrect value was assigned. However, even when a value well outside the specified range is assigned to the Interval property within the AddParticipant method, the test passes. I also find timer.Interval has a value of 0 after executing the AddParticipant method, even though I can see this property being assigned a non-zero value when stepping through the AddParticipant method.
[TestMethod]
public void TestAgeUpdatingStartOnAdd()
{
var mockTimer = new Mock<IDispatcherTimer>();
mockTimer.SetupProperty(m => m.Interval);
mockTimer.Setup(m => m.Start());
mockTimer.Setup(m => m.Stop());
IDispatcherTimer timer = mockTimer.Object;
var ageService = new AgeUpdatingService(timer);
TimeSpan interval = TimeSpan.FromMinutes(10);
TimeSpan tolerance = TimeSpan.FromMilliseconds(100)
mockTimer.SetupSet(m => m.Interval = It.IsInRange(
interval - tolerance, interval + tolerance, Range.Inclusive));
ageService.AddParticipant(new Participant{ DOB = DateTime.Now + interval });
What am I doing wrong? Am I missing the point of the SetupSet method all together (and therefore should just stick to examining the properties on the timer object after executing the function, which seemed to work prior to placing the SetupSet method in the code)? If so, could you please explain what SetupSet exists for. Thank you.
Since you're creating your mock with new Mock<IDispatcherTimer>(), it defaults to Loose mock behavior. This means that the mock object will not complain when it is used in a way that was not specified via a Setup method. Using the constructor overload that accepts a MockBehavior enumeration and specifying Strict will make the code behave like you'd expect. It looks like that's how you're expecting to use it judging by the Setup calls; they would be unnecessary if you were using loose mocks.
Alternatively you can keep the loose mock and change the SetupSet for the Interval to be a VerifySet after you expect it to be set. I.e.:
var ageService = new AgeUpdatingService(timer);
TimeSpan interval = TimeSpan.FromMinutes(10);
TimeSpan tolerance = TimeSpan.FromMilliseconds(100)
ageService.AddParticipant(new Participant{ DOB = DateTime.Now + interval });
mockTimer.VerifySet(m => m.Interval = It.IsInRange(
interval - tolerance, interval + tolerance, Range.Inclusive));
This is like a test assertion, meaning if a set of the Interval property never happened when this is invoked, it would throw a MoqException and fail the test.
SetupSet can be used to setup a property setter - it is fairly unusual to need this, as arguments passed to Set typically don't need to be captured, as the calls to the Setter can be verified with a VerifySet after the "Act" step.
Here's a way to achieve what you want:
var mockTimer = new Mock<ITimer>();
// Simulate the actions of the Sut with the Mock
mockTimer.Object.Interval = 6;
mockTimer.Object.Interval = 7;
mockTimer.Object.Interval = 999;
// Ensure the mock was called in-band
mockTimer.VerifySet(m => m.Interval = It.IsInRange(5, 10, Range.Inclusive),
Times.Exactly(2));
// Ensure the mock was not called out of band
mockTimer.VerifySet(m => m.Interval = It.Is<int>(i => i < 5 || i > 10),
Times.Never);
Another, less elegant approach would be to use SetupSet to detect invalid invocations directly:
mockTimer.SetupSet(m => m.Interval = It.Is<int>(i => i < 5 || i > 10))
.Throws(new ArgumentOutOfRangeException());

Simple Timer in Meteor JS

I am creating a simple countdown timer for a game. I am using CoffeeScript and Meteor. I have a Handlebars "Timer" template with a {{time}} expression.
Here is the code:
clock = 10
timeLeft = () ->
if clock > 0
clock--
else
"That's All Folks"
Meteor.clearInterval(interval)
interval = Meteor.setInterval(timeLeft, 1000)
if Meteor.isClient
Template.timer.time = interval
The above code just gives me a static display of 8 or 6 instead of the countdown timer.
If I add a few console.log statements I can see it work as designed in the terminal.
clock = 10
timeLeft = () ->
if clock > 0
clock--
console.log clock
else
console.log "That's All Folks"
Meteor.clearInterval(interval)
interval = Meteor.setInterval(timeLeft, 1000)
if Meteor.isClient
Template.timer.time = interval
If you want to update a value in handlebars you need to use Session so that its reactive, otherwise the Templating system won't be aware of when to update it in the ui. Also you passed the template a handler thats the handle instead of the timer value.
Using the below, I've used Session to pass this data through to handlebars.
clock = 10
timeLeft = ->
if clock > 0
clock--
Session.set "time", clock
console.log clock
else
console.log "That's All Folks"
Meteor.clearInterval interval
interval = Meteor.setInterval(timeLeft, 1000)
if Meteor.isClient
Template.timer.time = ->
Session.get "time"
Also in javascript in case anyone else wants this:
var clock = 10;
var timeLeft = function() {
if (clock > 0) {
clock--;
Session.set("time", clock);
return console.log(clock);
} else {
console.log("That's All Folks");
return Meteor.clearInterval(interval);
}
};
var interval = Meteor.setInterval(timeLeft, 1000);
if (Meteor.isClient) {
Template.registerHelper("time", function() {
return Session.get("time");
});
}
In essence you tell Session the time value, and when its updated it tells the templating system to redraw with the updated time value.

Resources