Compare commits

...

6 Commits
v0.6 ... master

Author SHA1 Message Date
Andreas Schneider 4742af20fe Fixed list in README 2015-10-22 11:01:58 +02:00
Andreas Schneider 282ae6fa28 Added template support to BasicAuth command 2015-10-18 21:44:25 +02:00
Andreas Schneider 7cc7705b29 Added status expectation 2015-10-08 11:59:41 +02:00
Andreas Schneider 8e820eb2f3 * Set default method (GET or POST)
* Allow setting variables on the commandline
2015-10-08 11:33:07 +02:00
Andreas Schneider e576805e84 * Added generator
* Added request output
2015-10-07 16:22:44 +02:00
Andreas Schneider b260f184f8 Fixed Indy to correctly assign request headers 2015-10-06 22:01:27 +02:00
4 changed files with 147 additions and 20 deletions

View File

@ -113,6 +113,22 @@ Once the first none-empty line is unrecognized (no command found), the parser wi
: Sets authentication for the HTTP proxy.
Same syntax as `BasicAuth`.
`Generate <variablename> <generator>`
: Sets a variable with a generated value.
Possible generators:
* `UUID`
* `unixtime` (a unix timestamp)
* `localtime` (a formatted time)
* `isodatetime` (Date and Time according to ISO8601)
* `isodate` (Date according to ISO8601)
* `isotime` (Time according to ISO8601)
`Expect <expectation type>=<expecation>`
: Checks expectations after the request.
* `Status=<statuscode>`: checks, if the status code matches
If an expectation fails, the application exists with code 5.
`Call <URL>`
: This prepares the actual call by providing the URL to be called.
Variables in the form of `@<variablename>` are replaced accordingly.

View File

@ -56,6 +56,7 @@ type
FFormFields: TStrings;
FFilters: TFilterList;
FBeautify: Boolean;
FExpectations: TStringList;
FURL: String;
FMethod: String;
//Main
@ -69,11 +70,14 @@ type
procedure CmdFormField(AData: String);
procedure CmdProxy(AData: String);
procedure CmdProxyAuth(AData: String);
procedure CmdGenerate(AData: String);
procedure CmdExpect(AData: String);
procedure ProcessCall(AURL: String);
//Helper
procedure WriteHelp;
procedure ListTemplates;
procedure WriteContent;
procedure CheckExpectations;
public
constructor Create; overload;
destructor Destroy; override;
@ -83,7 +87,7 @@ implementation
uses
strutils, crt, UCRTHelper, fpjson, DOM, XMLRead, XMLWrite, vinfo,
IdCompressorZLib, IdHeaderList, IdGlobalProtocols;
IdCompressorZLib, IdHeaderList, IdGlobalProtocols, xmlxsdparser;
type
TContentType = (ctOther, ctJSON, ctXML);
@ -165,8 +169,8 @@ begin
if FileExists(ParamStr(ParamCount)) then
begin
AssignFile(data, ParamStr(1));
FTemplateName := ExtractFileName(ParamStr(1));
AssignFile(data, ParamStr(ParamCount));
FTemplateName := ExtractFileName(ParamStr(ParamCount));
if AnsiEndsStr('.rest', FTemplateName) then
FTemplateName := Copy(FTemplateName, 1, Length(FTemplateName) - 5);
end else
@ -267,6 +271,16 @@ begin
Result := True;
CmdProxy(Copy(ALine, 10, Length(ALine)));
end else
if AnsiStartsStr('Generate ', ALine) then
begin
Result := True;
CmdGenerate(Copy(ALine, 10, Length(ALine)));
end else
if AnsiStartsStr('Expect ', ALine) then
begin
Result := True;
CmdExpect(Copy(ALine, 8, Length(ALine)));
end else
if AnsiStartsStr('Call ', ALine) then
begin
Result := True;
@ -289,17 +303,25 @@ begin
AName := Copy(AName, 2, Length(AName));
if mode = pmNormal then
//Check if the variable has been set on the commandline; we do not
//have to ask the user then.
if HasOption('var:' + AName) then
begin
default := FSessionIni.ReadString(FTemplateName, AName, '');
value := Prompt(AName, default);
value := GetOptionValue('var:' + AName);
end else
begin
value := Prompt(AName, mode);
end;
if mode = pmNormal then
begin
default := FSessionIni.ReadString(FTemplateName, AName, '');
value := Prompt(AName, default);
end else
begin
value := Prompt(AName, mode);
end;
if value = '' then
Halt(3); //Cancelled
if value = '' then
Halt(3); //Cancelled
end;
FParser.Fields.Add(AName, value);
@ -331,6 +353,10 @@ var
separator: Char;
i: Integer;
begin
FParser.Content := AData;
FParser.Replace;
AData := FParser.Content;
separator := AData[1];
i := 2;
while (i < Length(AData)) and (AData[i] <> separator) do
@ -379,19 +405,60 @@ begin
FHttp.ProxyParams.ProxyPassword := Copy(AData, i + 1, Length(AData));
end;
procedure TRestemplateApplication.CmdGenerate(AData: String);
var
i: Integer;
varName, generator: String;
guid: TGuid;
begin
i := 1;
while (i < Length(AData)) and (AData[i] <> ' ') do
Inc(i);
varName := Copy(AData, 1, i - 1);
generator := LowerCase(Copy(AData, i + 1, Length(AData)));
case generator of
'uuid':
begin
CreateGUID(guid);
FParser.Fields.Add(varName, Copy(GUIDToString(guid), 2, 36));
end;
'unixtime': FParser.Fields.Add(varName, IntToStr(DateTimeToUnix(Now)));
'localtime': FParser.Fields.Add(varName, DateTimeToStr(Now));
'isodatetime': FParser.Fields.Add(varName, xsdFormatDateTime(Now, nil));
'isodate': FParser.Fields.Add(varName, xsdFormatDate(Now));
'isotime': FParser.Fields.Add(varName, xsdFormatTime(Now));
else
raise Exception.Create('Unknown generator: ' + generator);
end;
end;
procedure TRestemplateApplication.CmdExpect(AData: String);
begin
FExpectations.Add(AData);
end;
procedure TRestemplateApplication.ProcessCall(AURL: String);
var
s: String;
s, httpMethod: String;
request, response: TStream;
jsonParser: TJSONParser;
jsonData: TJSONData;
contentType: TContentType;
xmlDoc: TXMLDocument;
begin
httpMethod := Trim(FMethod);
if httpMethod = '' then
if (FContent.Count > 0) or (FFormFields.Count > 0) then
httpMethod := 'POST'
else
httpMethod := 'GET';
FParser.Content := AURL;
FParser.Replace;
AURL := FParser.Content;
writeln('Calling ', AURL);
writeln(httpMethod, ' ', AURL);
response := TMemoryStream.Create;
request := nil;
@ -407,18 +474,24 @@ begin
FContent.SaveToStream(request);
end;
if HasOption('showrequest') then
begin
//TODO Handle URL-Encoded FormFields here!
writeln;
writeln('Request:');
for s in FContent do
writeln(' ', s);
end;
try
FRequest.Prepare;
FHttp.Request := FRequest;
FHttp.HTTPOptions := FHttp.HTTPOptions + [hoNoProtocolErrorException];
// Workaround for CustomHeaders not being assigned :-/
FHttp.Request.CustomHeaders.AddStrings(FRequest.CustomHeaders);
if SameText('POST', FMethod) and (FFormFields.Count > 0) then
if SameText('POST', httpMethod) and (FFormFields.Count > 0) then
FHttp.Post(AURL, FFormFields, response)
else
FHttp.Perform(FMethod, AURL, request, response);
FHttp.Perform(httpMethod, AURL, request, response);
except
on E: Exception do
begin
@ -468,6 +541,18 @@ begin
response.Free;
request.Free;
try
CheckExpectations;
except
on e: Exception do
begin
writeln;
writeln('Expections failed:');
writeln(e.Message);
ExitCode := 5;
end;
end;
end;
procedure TRestemplateApplication.WriteHelp;
@ -485,6 +570,8 @@ begin
Writeln('Options:');
Writeln(' -l --list');
Writeln(' Print a list of known templates.');
Writeln(' --var:<variableName>=<value>');
Writeln(' Sets the variable <variableName> to <value>.');
Writeln(' -h --help');
Writeln(' Print this help screen.');
end;
@ -562,6 +649,26 @@ begin
highlights.Free;
end;
procedure TRestemplateApplication.CheckExpectations;
var
i: Integer;
expectType, expectation: String;
begin
for i := 0 to FExpectations.Count - 1 do
begin
expectType := LowerCase(FExpectations.Names[i]);
expectation := FExpectations.ValueFromIndex[i];
case expectType of
'status':
if FHttp.ResponseCode <> StrToInt(expectation) then
raise Exception.Create(Format('Status code unexpected! %d <> %s', [FHttp.ResponseCode, expectation]));
else
raise Exception.Create('Invalid expectation: ' + FExpectations[i]);
end;
end;
end;
constructor TRestemplateApplication.Create;
begin
inherited Create(nil);
@ -578,6 +685,7 @@ begin
FRequest.RawHeaders.AddValue('User-Agent', 'Mozilla/4.0 (compatible; restemplate ' + VersionInfo.GetProductVersionString + ')');
FFilters := TFilterList.Create;
FParser := TJTemplateParser.Create;
FExpectations := TStringList.Create;
end;
destructor TRestemplateApplication.Destroy;
@ -589,6 +697,7 @@ begin
//TODO Owned? FRequest.Free;
FFilters.Free;
FParser.Free;
FExpectations.Free;
inherited Destroy;
end;

View File

@ -336,6 +336,7 @@ begin
begin
LDest := TIdEntityHeaderInfo(Destination);
LDest.FRawHeaders.Assign(FRawHeaders);
LDest.FCustomHeaders.Assign(FCustomHeaders);
LDest.FCacheControl := FCacheControl;
LDest.FCharSet := FCharSet;
LDest.FContentDisposition := FContentDisposition;
@ -966,9 +967,9 @@ begin
// TODO: omitted intentionally?
// LDest.FHost := FHost;
// LDest.FProxyConnection := FProxyConnection;
end else begin
inherited AssignTo(Destination);
end;
inherited AssignTo(Destination);
end;
procedure TIdRequestHeaderInfo.Clear;

View File

@ -19,7 +19,8 @@
<VersionInfo>
<UseVersionInfo Value="True"/>
<MinorVersionNr Value="6"/>
<StringTable LegalCopyright="Andreas Schneider" ProductName="restemplate" ProductVersion="0.6.0"/>
<RevisionNr Value="2"/>
<StringTable LegalCopyright="Andreas Schneider" ProductName="restemplate" ProductVersion="0.6.2"/>
</VersionInfo>
<MacroValues Count="1">
<Macro1 Name="LCLWidgetType" Value="nogui"/>