-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.cfm
224 lines (168 loc) · 7.29 KB
/
index.cfm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<!---Built using CommandBox: http://cmdbox.cayton.local:40011/CFIDE/administrator/index.cfm--->
<cfset setLocale("English (UK)") />
<head>
<link rel="stylesheet" type="text/css" href="/assets/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/assets/css/jquery-ui-1.8.7.custom.css" />
</head>
<body>
<div class="container-fluid">
<div class="row-fluid margintop5">
<h2>Cf & JS Test questions answered...</h2>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid margintop5">
<cfoutput>
<input type="button" id="testProduct" value="3 Products" >
<h4>Cf Q1 answer</h4><p>#Cf_q1([{tokenUuid=createUUID(),RequestTime=DateAdd("h",-4,Now()),errorCode=1}
,{tokenUuid=createUUID(),RequestTime=DateAdd("h",-2,Now()),errorCode=1}])# </p>
<h4>Cf Q2 answer</h4><p>#Cf_q2("01/01/2000")#</p>
<h4>Cf Q3 answer</h4><p>#Cf_q3()#</p>
<h4>SQL Q1 answer</h4><p>#SQL_q1(5)#</p>
<h4>SQL Q2 answer</h4><p>#SQL_q2(3)#</p>
</cfoutput>
</div>
</div>
</body>
<footer>
<script type="text/javascript" src="/assets/javascript/bootstrap/jquery.js"></script>
<script type="text/javascript" src="/assets/javascript/bootstrap/bootstrap-modal.js"></script>
<script type="text/javascript" src="/assets/javascript/bootstrap/bootstrap.min.js"></script>
<script type="text/javascript" src="/assets/javascript/seniorJSQ.js"></script>
</footer>
<cfscript>
/*
Error retries and Back off Algorithm.
External API calls sometimes fail intermittently due to network connection errors and although we will
want to retry the call, we don’t want to overload the service.
Your task is to write a function that accepts a single argument of the number of attempts previously made
and returns the next date and time to retry.
The function should implement an exponential back off algorithm of your choosing, and we should never retry
calls more than 24 hours after the initial failure. Think about edge cases.
*/
private any function Cf_q1(required array failures){
// Assume failures is an array of previous attempts from which we could derive the time in ms since the first call
variables.exponentialBackoff = CreateObject("component", "exponentialBackoff");
if (failures.len()){
var retryInterval = variables.exponentialBackoff.calcTimeRetry(failures.len());
var msSinceFirstApiCall = dateDiff('s',failures[1].RequestTime, Now())*1000;
if ( retryInterval LTE (86400000 - msSinceFirstApiCall)){
// perform operation again
var arr = variables.exponentialBackoff.doOperationAndWaitForResult(1);
for (i in arr) {
failures.append(i);
}
// failures.append(variables.exponentialBackoff.doOperationAndWaitForResult(1) );
}else{
// 24 hrs have lapsed since last tried
writeOutPut("Too long to wait for retry");
}
}
// deliberately left this so there is something to see - obvioulsy would not leave in Production-ready code...
writeDump(var=failures, label="Failures", expand=false);
// have a get function getFailuress() in the cfc for unit testing before and after attempts array will tell us what happened.
return retryInterval;
}
/*
Find the next palindromatic date.
i. Increments the date string one day at a time, until it finds the next legitimate palindrome date string (i.e. 21/02/2012).
ii. Prints the palindrome Date String, and the number of increments to the screen.
*/
private void function Cf_q2(source, limit){
var cnt = 0;
var thisDate = arguments.source;
var formattedDate = arguments.source;
if (isValid("date", thisDate)){
thisDate = LSParseDateTime(arguments.source, getLocale(), "dd/mm/yyyy");
cnt += 1;
// arbitrary number to limit loop; could easily be sent as a parameter OR restricted via a 'maximum' date
while (cnt LT 30000) {
newDate = thisDate.add("d", 1);
formattedDate = LSDateFormat(newDate, "dd/mm/yyyy", getLocale());
if ( isPalindrome(formattedDate) ){
foundPalindrome = true;
attempt = formattedDate;
writeOutPut("After " & cnt & " tries I got #attempt#</br>");
}
thisDate = newDate;
cnt += 1;
}
}
}
private boolean function isPalindrome(thisDate){
var reverseDate = replace(reverse(arguments.thisDate),"/","","ALL");
var thisdate2 = replace(arguments.thisDate,"/","","ALL");
return (Compare(thisdate2,reverseDate) EQ 0);
}
/*
Explain using examples if necessary, how you would write a Unit Test for the function in question 1.
*/
private void function Cf_q3(){
writeOutPut("<p>I would mock the backoff component such that the control constants could be modified to much smaller values - we don't really want to be unit testing with large back-off values.");
writeOutPut("To that end I would create getters and setters for all properties and move the variables.constants.Results values to component properties.");
writeOutPut("I would mock varying failures arrays of differring lengths and check my algorithm yields exponential back-off times as the length increses.");
writeOutPut("I would test this independently of the actual call to doOperationAndWaitForResult().");
writeOutPut("I would override the sleep function too (or allow in to be ignored by passing in an argument) in order to rapidly unit test the doOperationAndWaitForResult() method.");
writeOutPut("Clearly we would also want to mock any actual asynchronous/http calls - either using mock api responses OR by overidding methods in our Unit testing framework (e.g. MXUnit or TestBox).");
writeOutPut("Edge cases to consider are a) the failures array is empty b) extremely large values for back-off time are generated by a large array of failures c) whether the time delay would exceed the 24hr rule.</p>");
}
/*
Find the Nth row based on a column value.
*/
private string function SQL_q1(target){
var result = readSQL_q1();
var arr = [];
for (row in result){
if (row.rank EQ arguments.target){
ArrayAppend(arr, row.student_id);
}
}
return Arraylen(arr) ? "Student ID's ranking 5th:" & ArrayToList(arr) : "None found";
}
/*
Find a value that shows at least [N] times consecutively in a table.
*/
private void function SQL_q2(target){
var x = -1;
var cnt =0;
var result = readSQL_q2();
for (row in result){
if (x EQ row.rank){
cnt +=1;
}else{
cnt = 1;
}
if (cnt GTE arguments.target){
writeOutPut("First Num counted #target# consecutive times is: #row.num#");
break;
}
x = row.rank;
}
}
</cfscript>
<cfabort>
<!--- DAO --->
<cffunction name="readSQL_Q1" access="public" returntype="query" output="false" >
<cfquery name="local.sql" datasource="#getDatasource()#">
SELECT *
,RANK() OVER
(ORDER BY MathScore.score ASC) AS Rank
FROM dbo.MathScore
ORDER BY Score;
</cfquery>
<cfreturn local.sql />
</cffunction>
<cffunction name="readSQL_q2" access="public" returntype="query" output="false">
<cfargument name="something" type="any" required="false" />
<cfquery name="local.sql" datasource="#getDatasource()#">
SELECT id,num
,RANK() OVER
(ORDER BY t.num ASC) AS Rank
FROM dbo.t
ORDER BY t.id
</cfquery>
<cfreturn local.sql />
</cffunction>
<cffunction name="getDatasource" returntype="String" output="false">
<cfreturn "test" />
</cffunction>