Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LDEV-4670 test case for database session expiry (WIP) #2285

Merged
merged 5 commits into from
Feb 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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");
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>

Loading