Skip to content

Commit

Permalink
Merge pull request #2285 from zspitzer/LDEV-4670
Browse files Browse the repository at this point in the history
LDEV-4670 test case for database session expiry (WIP)
  • Loading branch information
michaeloffner authored Feb 16, 2024
2 parents 67c899a + d9b42c8 commit 22cba0b
Show file tree
Hide file tree
Showing 4 changed files with 306 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public void clean(Config config, DatasourceConnection dc, int type, StorageScope
String strType = VariableInterpreter.scopeInt2String(type);
// select
SQL sqlSelect = new SQLImpl("SELECT cfid, name FROM " + PREFIX + "_" + strType + "_data WHERE expires <= ?",
new SQLItem[] { new SQLItemImpl(System.currentTimeMillis(), Types.VARCHAR) });
new SQLItem[] { new SQLItemImpl(now(config), Types.VARCHAR) });
Query query;
try {
query = new QueryImpl(ThreadLocalPageContext.get(), dc, sqlSelect, -1, -1, null, strType + "_storage");
Expand Down
207 changes: 207 additions & 0 deletions test/tickets/LDEV4670.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
component extends="org.lucee.cfml.test.LuceeTestCase" labels="session" {

function isMySqlNotSupported() {
var mySql = server.getDatasource("mysql");
return isEmpty( mysql );
}

function run( testResults , testBox ) {
describe( title="Test suite for LDEV-4670", body=function() {
it( title='Checking datasource session expiry, timezone UTC',skip=isMySqlNotSupported(),body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "UTC", "datasource" );
dumpResult( remainingSessions, "UTC" );
expect( remainingSessions.recordcount ).toBe( 0 );
});

it( title='Checking datasource session expiry, timezone PDT -7',skip=isMySqlNotSupported(),body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "PDT", "datasource" );
dumpResult( remainingSessions, "PDT" );
expect( remainingSessions.recordcount ).toBe( 0 );
});

it( title='Checking datasource session expiry, timezone AEST +10',skip=isMySqlNotSupported(),body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "AEST", "datasource" );
dumpResult( remainingSessions, "AEST" );

expect( remainingSessions.recordcount ).toBe( 0 );
});

it( title='Checking memory session expiry, timezone UTC', body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "UTC", "memory" );
dumpResult( remainingSessions, "UTC" );
expect( remainingSessions.recordcount ).toBe( 0 );
});

it( title='Checking memory session expiry, timezone PDT -7', body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "PDT", "memory" );
dumpResult( remainingSessions, "PDT" );
expect( remainingSessions.recordcount ).toBe( 0 );
});

it( title='Checking memory session expiry, timezone Europe/Berlin +1', body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "Europe/Berlin", "memory" );
dumpResult( remainingSessions, "Europe/Berlin" );

expect( remainingSessions.recordcount ).toBe( 0 );
});

it( title='Checking memory session expiry, timezone AEST +10', body=function( currentSpec ) {
var remainingSessions = testSessionTimezone( "AEST", "memory" );
dumpResult( remainingSessions, "AEST" );

expect( remainingSessions.recordcount ).toBe( 0 );
});

});
}

private query function testSessionTimezone( required string timezone, required string sessionStorageType ){
systemOutput( " ", true );

systemOutput(">>>>> testSessionTimezone #arguments.timezone# / #arguments.sessionStorageType# ----- ", true);
if ( arguments.sessionStorageType == "datasource" ) {
var result = testSession("first cleanout sessions table",{
action: "purge",
sessionEnable: false,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
});
}
systemoutput("purgeExpiredSessions", true);
admin
action="purgeExpiredSessions"
type="server"
password="#request.SERVERADMINPASSWORD#";

if ( arguments.sessionStorageType == "datasource" ) {
result = testSession("dump sessions table",{
action: "dumpDatabaseSessions",
sessionEnable: false,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
});
expect( deserializeJson( result.filecontent, false ).recordcount ).toBe( 0 );
}

result = testSession("create a session", {
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType,
action: "createSession"
});

var currentSession = duplicate( result.session );
if ( arguments.sessionStorageType == "datasource" ) {
result = testSession("dump sessions table, should have 1 session", {
action: "dumpDatabaseSessions",
sessionEnable: false,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
});
expect( deserializeJson( result.filecontent, false ).recordcount ).toBe( 1 );
}

result = testSession("check that the current session is still active", {
action: "checkSession",
sessionEnable: true,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
},
currentSession // pass in previous session
);
expect( result.session.cfid ).toBe( currentSession.cfid );
expect( result.session.requestCount ).toBe( 2 );

// now let the session expire, session expiry is 1s
sleep( 1001 );

systemoutput("purgeExpiredSessions", true);
admin
action="purgeExpiredSessions"
type="server"
password="#request.SERVERADMINPASSWORD#";

result = testSession("dump sessions from memory, should have 0 sessions", {
action: "dumpMemorySessions",
sessionEnable: false,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
});

var remainingSessionCount = deserializeJson( result.filecontent, false );

expect ( remainingSessionCount.recordcount ).toBe( 0 );

result = testSession("check that the current session was recreated, requestcount 1", {
action: "checkSession",
sessionEnable: true,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
},
currentSession // pass in previous session
);

// expect( result.session.cfid ).notToBe( currentSession.cfid ); // doesn't work session gets recreated with the same cfid?
expect( result.session.requestCount ).toBe( 1 );

if ( arguments.sessionStorageType == "datasource" ) {
result = testSession("dump sessions table, should have 0 sessions", {
action: "dumpDatabaseSessions",
sessionEnable: false,
timezone: arguments.timezone,
sessionStorageType: arguments.sessionStorageType
});
remainingSessionCount = deserializeJson( result.filecontent, false );
}

return remainingSessionCount;
}

private any function testSession ( required string name, required struct args, struct session={} ){
systemOutput( "---- #arguments.name# ----- ", true );
var uri = createURI("LDEV4670");
var cookies = {};
if ( structCount( arguments.session ) ){
//systemOutput( arguments.session, true );
cookies = {
cfid: arguments.session.cfid,
cftoken: arguments.session.cftoken
};
//systemOutput( "cookies: #cookies.toJson()#", true );
}

var result = _InternalRequest(
template:"#uri#/ldev4670.cfm",
form: arguments.args,
cookies: cookies
);

//systemOutput(result, true);
systemOutput( deserializeJson( result.filecontent ), true );
//systemOutput(deserializeJson(result.filecontent, false), true);
return result;
}

private string function epochToDate( epoch ){
return createObject("java", "java.text.SimpleDateFormat").init("yyyy-MM-dd HH:mm:ss:SSS")
.format( createObject("java", "java.util.Date").init( arguments.epoch * 1 ) );
}

private void function dumpResult( remainingSessions, timezone ){
systemOutput("", true);
if ( remainingSessions.recordcount eq 0 )
return;
systemOutput( "#timezone# has #remainingSessions.recordcount# sessions, expires: "
& epochToDate( remainingSessions.expires )
& ", now: #dateTimeFormat(now(), " yyyy-mm-dd HH:nn:ss:LLL", "UTC" )#",
true );
var epoch = dateTimeFormat( now(), 'epochms' );
if ( len( remainingSessions.expires ) )
systemOutput( "expires: " & remainingSessions.expires & ", now: #epoch#, diff: #epoch-remainingSessions.expires#", true );
}

// Private functions
private string function createURI(string calledName){
var baseURI = "/test/#listLast(getDirectoryFromPath(getCurrenttemplatepath()),"\/")#/";
return baseURI & "" & calledName;
}
}
49 changes: 49 additions & 0 deletions test/tickets/LDEV4670/Application.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
component {
param name="form.timezone";
param name="form.sessionEnable" default="true";
param name="form.sessionStorageType";

this.name = "ldev-4670-mysql-#form.timezone#";

this.sessionManagement = form.sessionEnable;
this.sessionTimeout = createTimeSpan(0,0,0,1);

switch ( form.sessionStorageType ){
case "memory":
this.sessionStorage = "memory";
break;
case "datasource":
mySQL = mySqlCredentials();
mySQL.storage = true;
datasource = "my-ldev-4670"
this.datasources[datasource] = mySQL;
this.dataSource = datasource;
this.sessionStorage = datasource;
break;
default:
throw "unsupported sessionStorageType [#form.sessionStorageType#]";
}

this.timezone = form.timezone; // Pacific Time Zone, UTC -7

public function onRequestStart() {
// systemOutput(getTimeZone(), true);
setting requesttimeout=10 showdebugOutput=false;
if ( form.sessionEnable ) {
session["running"] = true;
session["sessionStorageType"] = form.sessionStorageType;
param name="session.requestCount" default="0";
session["requestCount"]++;
session["timezone"] = form.timezone;
}
}

function onSessionEnd( SessionScope, ApplicationScope ) {
systemOutput("!!!!!!!!!!!!!!!!!!!!!!!! #now()# session ended #cgi.SCRIPT_NAME# #sessionScope.sessionid#", true);
server.LDEV4670_endedSessions[ arguments.sessionScope.sessionid ] = now();
}

private struct function mySqlCredentials() {
return server.getDatasource("mysql");
}
}
49 changes: 49 additions & 0 deletions test/tickets/LDEV4670/ldev4670.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

<cfscript>
param name="form.action";
//systemOutput("LDEV-4670 #form.action#", true);
settings = getApplicationSettings();
params = {
name: settings.name
};
//systemOutput( params, true );
switch ( form.action ){
case "purge":
query name="purge_sessions" result="deleted" params=params {
echo("DELETE FROM cf_session_data WHERE name = :name");
}
echo( deleted.toJson() );
break;
case "dumpDatabaseSessions":
query name="q_sessions" params=params {
echo("SELECT expires, name, cfid FROM cf_session_data WHERE name = :name");
}
echo( q_sessions.toJson() );
break;
case "dumpMemorySessions":
sess = getPageContext().getCFMLFactory().getScopeContext().getAllCFSessionScopes();
//systemOutput("getAllCFSessionScopes()", true);
//systemOutput(sess, true);
if ( structKeyExists( sess, settings.name ) ) {
st = sess[ settings.name ];
keys = structKeyArray( st );
echo( queryNew( structKeyList( st[ keys[ 1 ] ] ) ,"" , st ).toJson() );
} else {
echo( queryNew( "cfid,expires" ).toJson() );
}
break;
case "createSession":
echo("['sessionCreated: #session.cfid#']");
break;
case "checkSession":
echo( session.toJson() );
break;
default:
throw "unknown action [#form.action#]";
}
</cfscript>

0 comments on commit 22cba0b

Please sign in to comment.