Add latency checking and sorting of inserted rows to find session.
This commit is contained in:
parent
04d059368a
commit
f4afd9bcb1
|
|
@ -0,0 +1,21 @@
|
|||
(function(context,$) {
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.FakeJamClient = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
logger.info("*** Fake JamClient instance initialized. ***");
|
||||
|
||||
function testLatency(client, callback) {
|
||||
var response = {
|
||||
id: client.id,
|
||||
latency: 50
|
||||
};
|
||||
callback(response);
|
||||
}
|
||||
|
||||
// Javascript Bridge seems to camel-case
|
||||
this.TestLatency = testLatency;
|
||||
|
||||
};
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -4,32 +4,73 @@
|
|||
context.JK.FindSessionScreen = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var sessionLatency;
|
||||
var sessions = {};
|
||||
var selectors = {
|
||||
TABLE_BODY: '#findSession-tableBody'
|
||||
};
|
||||
|
||||
function loadSessions() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/api/sessions",
|
||||
// TODO: Change to buildLatencyMap
|
||||
success: renderSessions
|
||||
success: startSessionLatencyChecks
|
||||
});
|
||||
}
|
||||
|
||||
function renderSessions(response) {
|
||||
$tb = $('#findSession-tableBody');
|
||||
$tb.empty();
|
||||
var rowTemplate = $('#template-findSession-row').html();
|
||||
$.each(response, function() {
|
||||
var vals = {
|
||||
id: this.id,
|
||||
participants: this.participants.length,
|
||||
description: this.description || "(No description)"
|
||||
};
|
||||
var row = JK.fillTemplate(rowTemplate, vals);
|
||||
$tb.append(row);
|
||||
function startSessionLatencyChecks(response) {
|
||||
sessionLatency.subscribe(latencyResponse);
|
||||
$.each(response, function(index, session) {
|
||||
sessions[session.id] = session;
|
||||
sessionLatency.sessionPings(session);
|
||||
});
|
||||
}
|
||||
|
||||
function latencyResponse(sessionId) {
|
||||
renderSession(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not used normally. Allows modular unit testing
|
||||
* of the renderSession method without having to do
|
||||
* as much heavy setup.
|
||||
*/
|
||||
function setSession(session) { sessions[session.id] = session; }
|
||||
|
||||
/**
|
||||
* Render a single session line into the table.
|
||||
* It will be inserted at the appropriate place according to the
|
||||
* sortScore in sessionLatency.
|
||||
*/
|
||||
function renderSession(sessionId) {
|
||||
$tb = $(selectors.TABLE_BODY);
|
||||
var rowTemplate = $('#template-findSession-row').html();
|
||||
var session = sessions[sessionId];
|
||||
var latencyInfo = sessionLatency.sessionInfo(sessionId);
|
||||
var vals = {
|
||||
id: session.id,
|
||||
genres: session.genres.join (','),
|
||||
sortScore: latencyInfo.sortScore,
|
||||
participants: session.participants.length,
|
||||
description: session.description || "(No description)"
|
||||
};
|
||||
var row = JK.fillTemplate(rowTemplate, vals);
|
||||
var insertedEarly = false;
|
||||
$.each($('tr', $tb), function() {
|
||||
$this = $(this);
|
||||
var rowSortScore = parseInt($this.attr('data-sortScore'), 10);
|
||||
if (vals.sortScore > rowSortScore) {
|
||||
$this.before(row);
|
||||
insertedEarly = true;
|
||||
}
|
||||
});
|
||||
if (!(insertedEarly)) {
|
||||
return $tb.append(row);
|
||||
}
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
$tb = $(selectors.TABLE_BODY);
|
||||
$tb.empty();
|
||||
loadSessions();
|
||||
}
|
||||
|
||||
|
|
@ -47,20 +88,30 @@
|
|||
$('#findSession-tableBody').on("click", '[action="delete"]', deleteSession);
|
||||
}
|
||||
|
||||
this.afterShow = afterShow;
|
||||
|
||||
this.initialize = function() {
|
||||
if ("jamClient" in context) {
|
||||
sessionLatency = new context.JK.SessionLatency(jamClient);
|
||||
/**
|
||||
* Initialize, providing an instance of the SessionLatency class.
|
||||
*/
|
||||
function initialize(_sessionLatency) {
|
||||
if (_sessionLatency) {
|
||||
sessionLatency = _sessionLatency;
|
||||
} else {
|
||||
logger.warn("No jamClient available. Session pings will not be performed.");
|
||||
logger.warn("No sessionLatency provided.");
|
||||
}
|
||||
screenBindings = {
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('findSession', screenBindings);
|
||||
events();
|
||||
};
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.afterShow = afterShow;
|
||||
this.renderSession = renderSession;
|
||||
|
||||
// Following exposed for easier testing.
|
||||
this.setSession = setSession;
|
||||
this.selectors = selectors;
|
||||
|
||||
};
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
var sessionPingsOut = {};
|
||||
var clientsToSessions = {};
|
||||
var sessionLatency = {};
|
||||
var subscribers = [];
|
||||
|
||||
function getSortScore(sessionId) {
|
||||
return sessionLatency[sessionId].sortScore;
|
||||
|
|
@ -51,7 +52,7 @@
|
|||
sessionPingsOut[session.id] = 0;
|
||||
}
|
||||
sessionPingsOut[session.id]++;
|
||||
jamClient.testLatency(client, clientPingResponse);
|
||||
jamClient.TestLatency(client, clientPingResponse);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +60,9 @@
|
|||
var sessionId = clientsToSessions[response.id];
|
||||
sessionPingsOut[sessionId]--;
|
||||
updateSessionLatency(sessionId, response);
|
||||
$.each(subscribers, function() {
|
||||
this(sessionId);
|
||||
});
|
||||
}
|
||||
|
||||
function updateSessionLatency(sessionId, latencyResponse) {
|
||||
|
|
@ -96,9 +100,14 @@
|
|||
return sessionLatency[sessionId];
|
||||
}
|
||||
|
||||
function subscribe(cb) {
|
||||
subscribers.push(cb);
|
||||
}
|
||||
|
||||
this.sessionPings = sessionPings;
|
||||
this.sessionInfo = sessionInfo;
|
||||
this.getSortScore = getSortScore;
|
||||
this.subscribe = subscribe;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,13 @@
|
|||
<p layout-link="home">Home</p>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Members</th>
|
||||
<th>Name</th>
|
||||
<th>Delete</th>
|
||||
<th>Genre</th>
|
||||
<th>Description</th>
|
||||
<th>Musicians</th>
|
||||
<th>Audience</th>
|
||||
<th>Latency</th>
|
||||
<th>Listen</th>
|
||||
<th>Join</th>
|
||||
</tr>
|
||||
<tbody id="findSession-tableBody">
|
||||
</tbody>
|
||||
|
|
@ -14,9 +18,13 @@
|
|||
</div>
|
||||
|
||||
<script type="text/template" id="template-findSession-row">
|
||||
<tr>
|
||||
<tr data-sortScore="{sortScore}">
|
||||
<td>{genres}</td>
|
||||
<td>{description}</td>
|
||||
<td>{participants}</td>
|
||||
<td><a href="#/session/{id}">{description}</a></td>
|
||||
<td><a action="delete" action-id="{id}">X</a></td>
|
||||
<td>TODO Audience</td>
|
||||
<td>TODO Latency</td>
|
||||
<td>TODO Listen</td>
|
||||
<td><a href="#/session/{id}">Join</a></td>
|
||||
</tr>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
|
||||
JK = JK || {};
|
||||
|
||||
|
||||
// The following allows testing of native (jamClient) functionality
|
||||
// with a fake. Uncomment when developing without the native client.
|
||||
window.jamClient = new JK.FakeJamClient();
|
||||
|
||||
<% if current_user %>
|
||||
JK.currentUserId = '<%= current_user.id %>';
|
||||
<% else %>
|
||||
|
|
@ -40,7 +45,11 @@
|
|||
createSessionScreen.initialize();
|
||||
|
||||
var findSessionScreen = new JK.FindSessionScreen(jk);
|
||||
findSessionScreen.initialize();
|
||||
var sessionLatency = null;
|
||||
if ("jamClient" in window) {
|
||||
sessionLatency = new JK.SessionLatency(window.jamClient);
|
||||
}
|
||||
findSessionScreen.initialize(sessionLatency);
|
||||
|
||||
var sessionScreen = new JK.SessionScreen(jk);
|
||||
sessionScreen.initialize();
|
||||
|
|
|
|||
|
|
@ -3,11 +3,6 @@
|
|||
describe("FindSession", function() {
|
||||
|
||||
var fss;
|
||||
var ajaxSpy;
|
||||
|
||||
var selectors = {
|
||||
sessions: '#findSession-tableBody'
|
||||
};
|
||||
|
||||
var appFake = {
|
||||
clientId: '12345',
|
||||
|
|
@ -16,34 +11,130 @@
|
|||
ajaxError: function() { console.debug("ajaxError"); }
|
||||
};
|
||||
|
||||
var jamClientFake = {
|
||||
TestLatency: function(client, cb) {
|
||||
cb({id: client.id, latency: 50});
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
fss = null;
|
||||
// Use the actual screen markup
|
||||
jasmine.getFixtures().fixturesPath = '/app/views/clients';
|
||||
loadFixtures('_findSession.html.erb');
|
||||
spyOn(appFake, 'notify');
|
||||
fss = new context.JK.FindSessionScreen(appFake);
|
||||
fss.initialize();
|
||||
});
|
||||
|
||||
describe("loadSessions", function() {
|
||||
beforeEach(function() {
|
||||
spyOn($, "ajax");
|
||||
});
|
||||
it("should query ajax for sessions", function() {
|
||||
fss.afterShow({});
|
||||
expect($.ajax).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
var sessionLatencyReal;
|
||||
|
||||
describe("renderSessions", function() {
|
||||
describe("RealSessionLatency", function() {
|
||||
beforeEach(function() {
|
||||
spyOn($, "ajax").andCallFake(function(opts) {
|
||||
opts.success(TestResponses.getSessions);
|
||||
sessionLatencyReal = new JK.SessionLatency(jamClientFake);
|
||||
spyOn(sessionLatencyReal, 'sessionPings').andCallThrough();
|
||||
fss = new context.JK.FindSessionScreen(appFake);
|
||||
fss.initialize(sessionLatencyReal);
|
||||
$(fss.selectors.TABLE_BODY).empty();
|
||||
});
|
||||
|
||||
describe("loadSessions", function() {
|
||||
beforeEach(function() {
|
||||
spyOn($, "ajax");
|
||||
});
|
||||
it("should query ajax for sessions", function() {
|
||||
fss.afterShow({});
|
||||
expect($.ajax).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
it("should output table rows for sessions", function() {
|
||||
fss.afterShow({});
|
||||
expect($(selectors.sessions + ' tr').length).toEqual(1);
|
||||
|
||||
describe("afterShow flow", function() {
|
||||
beforeEach(function() {
|
||||
spyOn($, "ajax").andCallFake(function(opts) {
|
||||
opts.success(TestGetSessionResponses.oneOfEach);
|
||||
});
|
||||
});
|
||||
|
||||
it("should output table rows for sessions", function() {
|
||||
fss.afterShow({});
|
||||
expect($(fss.selectors.TABLE_BODY + ' tr').length).toEqual(5);
|
||||
});
|
||||
|
||||
it("should call sessionPings", function() {
|
||||
fss.afterShow({});
|
||||
expect(sessionLatencyReal.sessionPings).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe("FakeSessionLatency", function() {
|
||||
|
||||
beforeEach(function() {
|
||||
sessionInfoResponses = {
|
||||
"1": {id:"1", sortScore: 3},
|
||||
"2": {id:"2", sortScore: 2}
|
||||
};
|
||||
sessionLatencyFake = {
|
||||
sessionInfo: null
|
||||
};
|
||||
spyOn(sessionLatencyFake, 'sessionInfo').andCallFake(function(id) {
|
||||
return sessionInfoResponses[id];
|
||||
});
|
||||
fss = new context.JK.FindSessionScreen(appFake);
|
||||
fss.initialize(sessionLatencyFake);
|
||||
$(fss.selectors.TABLE_BODY).empty();
|
||||
});
|
||||
|
||||
describe("renderSession", function() {
|
||||
|
||||
describe("layout", function() {
|
||||
var tbody;
|
||||
|
||||
beforeEach(function() {
|
||||
var session = TestGetSessionResponses.oneOfEach[0];
|
||||
fss.setSession(session);
|
||||
fss.renderSession(session.id);
|
||||
tbody = $(fss.selectors.TABLE_BODY);
|
||||
});
|
||||
|
||||
it("single session should render", function() {
|
||||
expect($('tr', tbody).length).toEqual(1);
|
||||
});
|
||||
|
||||
it("Should render genre", function() {
|
||||
expect($('tr td', tbody).first().text()).toEqual('classical');
|
||||
});
|
||||
|
||||
it("Should render description", function() {
|
||||
expect($('tr td', tbody).first().next().text()).toEqual('Invited');
|
||||
});
|
||||
|
||||
it("Should render musician count", function() {
|
||||
expect($('tr td', tbody).first().next().next().text()).toEqual('1');
|
||||
});
|
||||
|
||||
// TODO - test audience
|
||||
// TODO - test latency
|
||||
// TODO - test Listen
|
||||
|
||||
it("Should render join link", function() {
|
||||
expect($('tr td', tbody).last().text()).toEqual('Join');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("higher sortScore inserted before lower sortScore", function() {
|
||||
var sessionLow = TestGetSessionResponses.oneOfEach[1];
|
||||
var sessionHigh = TestGetSessionResponses.oneOfEach[0];
|
||||
fss.setSession(sessionLow);
|
||||
fss.setSession(sessionHigh);
|
||||
fss.renderSession(sessionLow.id);
|
||||
fss.renderSession(sessionHigh.id);
|
||||
|
||||
var tbody = $(fss.selectors.TABLE_BODY);
|
||||
expect($('tr', tbody).length).toEqual(2);
|
||||
expect($('tr', tbody).first().attr('data-sortScore')).toEqual('3');
|
||||
expect($('tr', tbody).first().next().attr('data-sortScore')).toEqual('2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
window.TestGetSessionResponses = {
|
||||
oneOfEach: [
|
||||
|
||||
// Session 1 - you're invited to this.
|
||||
{
|
||||
"id": "1",
|
||||
"description": "Invited",
|
||||
"musician_access": true,
|
||||
"genres" : [ "classical" ],
|
||||
"participants": [
|
||||
{
|
||||
"client_id": "0f8f7987-29a0-4e5d-a60c-6b23103e3533",
|
||||
"ip_address":"1.1.1.1",
|
||||
"user_id" : "02303020402042040",
|
||||
"tracks" : [
|
||||
{
|
||||
"id" : "xxxx",
|
||||
"instrument_id" : "electric guitar",
|
||||
"sound" : "mono"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"invitations" : [
|
||||
{
|
||||
"id" : "3948797598275987",
|
||||
"sender_id" : "02303020402042040"
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Session 2 - no invite, but friend #1 (good latency)
|
||||
{
|
||||
"id": "2",
|
||||
"description": "Friends 1",
|
||||
"musician_access": true,
|
||||
"genres" : [ "blues" ],
|
||||
"participants": [
|
||||
{
|
||||
"client_id": "0f8f7987-29a0-4e5d-a60c-6b23103e3533",
|
||||
"ip_address":"1.1.1.1",
|
||||
"user_id" : "02303020402042040",
|
||||
"tracks" : [
|
||||
{
|
||||
"id" : "xxxx",
|
||||
"instrument_id" : "electric guitar",
|
||||
"sound" : "mono"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Session 3 - no invite, but friend #2 (med latency)
|
||||
{
|
||||
"id": "3",
|
||||
"description": "Friends 2",
|
||||
"musician_access": true,
|
||||
"genres" : [ "blues" ],
|
||||
"participants": [
|
||||
{
|
||||
"client_id": "0f8f7987-29a0-4e5d-a60c-6b23103e3533",
|
||||
"ip_address":"1.1.1.1",
|
||||
"user_id" : "02303020402042040",
|
||||
"tracks" : [
|
||||
{
|
||||
"id" : "xxxx",
|
||||
"instrument_id" : "electric guitar",
|
||||
"sound" : "mono"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Session 4 - no invite, no friends 1
|
||||
{
|
||||
"id": "4",
|
||||
"description": "Anonymous 1",
|
||||
"musician_access": true,
|
||||
"genres" : [ "blues" ],
|
||||
"participants": [
|
||||
{
|
||||
"client_id": "0f8f7987-29a0-4e5d-a60c-6b23103e3533",
|
||||
"ip_address":"1.1.1.1",
|
||||
"tracks" : [
|
||||
{
|
||||
"id" : "xxxx",
|
||||
"instrument_id" : "electric guitar",
|
||||
"sound" : "mono"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Session 5 - no invite, no friends 2
|
||||
{
|
||||
"id": "5",
|
||||
"description": "Anonymous 2",
|
||||
"musician_access": true,
|
||||
"genres" : [ "blues" ],
|
||||
"participants": [
|
||||
{
|
||||
"client_id": "0f8f7987-29a0-4e5d-a60c-6b23103e3533",
|
||||
"ip_address":"1.1.1.1",
|
||||
"tracks" : [
|
||||
{
|
||||
"id" : "xxxx",
|
||||
"instrument_id" : "electric guitar",
|
||||
"sound" : "mono"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
};
|
||||
|
|
@ -1,34 +1,4 @@
|
|||
window.TestResponses = {
|
||||
getSessions: [
|
||||
{
|
||||
"id": "1234",
|
||||
"description": "Hello",
|
||||
"musician_access": true,
|
||||
"genres" : [ "classical" ],
|
||||
"participants": [
|
||||
{
|
||||
"client_id": "0f8f7987-29a0-4e5d-a60c-6b23103e3533",
|
||||
"ip_address":"1.1.1.1",
|
||||
"user_id" : "02303020402042040", // NOTE THIS WILL BE UNDEFINED (ABSENT) IF THIS CLIENT IS NOT YOUR FRIEND
|
||||
"tracks" : [
|
||||
{
|
||||
"id" : "xxxx",
|
||||
"instrument_id" : "electric guitar",
|
||||
"sound" : "mono"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"invitations" : [
|
||||
{
|
||||
"id" : "3948797598275987",
|
||||
"sender_id" : "02303020402042040"
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
sessionPost: {
|
||||
"id": "1234",
|
||||
"description": "Hello",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
var sessionLatency; // Instance of SessionLatency class for test
|
||||
|
||||
fakeJamClient = {
|
||||
testLatency: function() {} // Will be overridden by test cases
|
||||
TestLatency: function() {} // Will be overridden by test cases
|
||||
};
|
||||
|
||||
var sessions = [
|
||||
|
|
@ -33,16 +33,16 @@
|
|||
beforeEach(function() {
|
||||
callCount = 0;
|
||||
sessionLatency = new context.JK.SessionLatency(fakeJamClient);
|
||||
spyOn(fakeJamClient, "testLatency").andCallFake(function(client, callback) {
|
||||
spyOn(fakeJamClient, "TestLatency").andCallFake(function(client, callback) {
|
||||
callback(testLatencyResponses[client.id]);
|
||||
callCount++;
|
||||
});
|
||||
});
|
||||
|
||||
describe("SessionPings", function() {
|
||||
it("should call jamClient.testLatency and compute new average", function() {
|
||||
it("should call jamClient.TestLatency and compute new average", function() {
|
||||
sessionLatency.sessionPings(sessions[0]);
|
||||
expect(fakeJamClient.testLatency).toHaveBeenCalled();
|
||||
expect(fakeJamClient.TestLatency).toHaveBeenCalled();
|
||||
var info = sessionLatency.sessionInfo(sessions[0].id);
|
||||
expect(info.averageLatency).toEqual(35);
|
||||
});
|
||||
|
|
@ -87,6 +87,21 @@
|
|||
});
|
||||
});
|
||||
|
||||
describe("Register for Events", function() {
|
||||
it("should register successfully", function() {
|
||||
var cb = jasmine.createSpy();
|
||||
sessionLatency.subscribe(cb);
|
||||
});
|
||||
it("should invoke callback on latency result", function() {
|
||||
var cb = jasmine.createSpy("Latency Subscription Callback");
|
||||
sessionLatency.subscribe(cb);
|
||||
$.each(sessions, function(index, session) {
|
||||
sessionLatency.sessionPings(session);
|
||||
});
|
||||
expect(cb).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue