Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
StackExchange.Redis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
StackExchange.Redis
Commits
6718f8a9
Commit
6718f8a9
authored
Apr 24, 2014
by
Marc Gravell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue 25: improved handling of configuration strings
parent
59e54f53
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
208 additions
and
119 deletions
+208
-119
AsyncTests.cs
StackExchange.Redis.Tests/AsyncTests.cs
+1
-1
BasicOps.cs
StackExchange.Redis.Tests/BasicOps.cs
+2
-2
Commands.cs
StackExchange.Redis.Tests/Commands.cs
+1
-0
Issue25.cs
StackExchange.Redis.Tests/Issues/Issue25.cs
+37
-0
StackExchange.Redis.Tests.csproj
StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
+1
-0
ConfigurationOptions.cs
...xchange.Redis/StackExchange/Redis/ConfigurationOptions.cs
+166
-116
No files found.
StackExchange.Redis.Tests/AsyncTests.cs
View file @
6718f8a9
...
...
@@ -42,7 +42,7 @@ public void AsyncTasksReportFailureIfServerUnavailable()
Assert
.
IsTrue
(
c
.
IsFaulted
,
"faulted"
);
var
ex
=
c
.
Exception
.
InnerExceptions
.
Single
();
Assert
.
IsInstanceOf
<
RedisConnectionException
>(
ex
);
Assert
.
AreEqual
(
"No connection is available to service this operation: SADD"
,
ex
.
Message
);
Assert
.
AreEqual
(
"No connection is available to service this operation: SADD
AsyncTasksReportFailureIfServerUnavailable
"
,
ex
.
Message
);
}
}
#endif
...
...
StackExchange.Redis.Tests/BasicOps.cs
View file @
6718f8a9
...
...
@@ -293,7 +293,7 @@ public void GetWithExpiry(bool exists, bool hasExpiry)
}
}
[
Test
]
[
ExpectedException
(
typeof
(
RedisServerException
),
ExpectedMessage
=
"
ERR
Operation against a key holding the wrong kind of value"
)]
[
ExpectedException
(
typeof
(
RedisServerException
),
ExpectedMessage
=
"
WRONGTYPE
Operation against a key holding the wrong kind of value"
)]
public
void
GetWithExpiryWrongTypeAsync
()
{
using
(
var
conn
=
Create
())
...
...
@@ -315,7 +315,7 @@ public void GetWithExpiryWrongTypeAsync()
}
[
Test
]
[
ExpectedException
(
typeof
(
RedisServerException
),
ExpectedMessage
=
"
ERR
Operation against a key holding the wrong kind of value"
)]
[
ExpectedException
(
typeof
(
RedisServerException
),
ExpectedMessage
=
"
WRONGTYPE
Operation against a key holding the wrong kind of value"
)]
public
void
GetWithExpiryWrongTypeSync
()
{
using
(
var
conn
=
Create
())
...
...
StackExchange.Redis.Tests/Commands.cs
View file @
6718f8a9
...
...
@@ -11,6 +11,7 @@ public void Basic()
{
var
config
=
ConfigurationOptions
.
Parse
(
".,$PING=p"
);
Assert
.
AreEqual
(
1
,
config
.
EndPoints
.
Count
);
config
.
SetDefaultPorts
();
Assert
.
Contains
(
new
DnsEndPoint
(
"."
,
6379
),
config
.
EndPoints
);
var
map
=
config
.
CommandMap
;
Assert
.
AreEqual
(
"$PING=p"
,
map
.
ToString
());
...
...
StackExchange.Redis.Tests/Issues/Issue25.cs
0 → 100644
View file @
6718f8a9
using
NUnit.Framework
;
using
System
;
namespace
StackExchange.Redis.Tests.Issues
{
[
TestFixture
]
public
class
Issue25
:
TestBase
{
[
Test
]
public
void
CaseInsensitive
()
{
var
options
=
ConfigurationOptions
.
Parse
(
"ssl=true"
);
Assert
.
IsTrue
(
options
.
Ssl
);
Assert
.
AreEqual
(
"ssl=True"
,
options
.
ToString
());
options
=
ConfigurationOptions
.
Parse
(
"SSL=TRUE"
);
Assert
.
IsTrue
(
options
.
Ssl
);
Assert
.
AreEqual
(
"ssl=True"
,
options
.
ToString
());
}
[
Test
]
public
void
UnkonwnKeywordHandling_Ignore
()
{
var
options
=
ConfigurationOptions
.
Parse
(
"ssl2=true"
,
true
);
}
[
Test
,
ExpectedException
(
typeof
(
ArgumentException
),
ExpectedMessage
=
"Keyword 'ssl2' is not supported"
)]
public
void
UnkonwnKeywordHandling_ExplicitFail
()
{
var
options
=
ConfigurationOptions
.
Parse
(
"ssl2=true"
,
false
);
}
[
Test
,
ExpectedException
(
typeof
(
ArgumentException
),
ExpectedMessage
=
"Keyword 'ssl2' is not supported"
)]
public
void
UnkonwnKeywordHandling_ImplicitFail
()
{
var
options
=
ConfigurationOptions
.
Parse
(
"ssl2=true"
);
}
}
}
StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
View file @
6718f8a9
...
...
@@ -72,6 +72,7 @@
<Compile
Include=
"Config.cs"
/>
<Compile
Include=
"FloatingPoint.cs"
/>
<Compile
Include=
"Issues\BGSAVEResponse.cs"
/>
<Compile
Include=
"Issues\Issue25.cs"
/>
<Compile
Include=
"Issues\Issue6.cs"
/>
<Compile
Include=
"Issues\SO22786599.cs"
/>
<Compile
Include=
"Keys.cs"
/>
...
...
StackExchange.Redis/StackExchange/Redis/ConfigurationOptions.cs
View file @
6718f8a9
...
...
@@ -6,7 +6,7 @@
using
System.Net.Security
;
using
System.Text
;
using
System.Threading.Tasks
;
using
System.Linq
;
namespace
StackExchange.Redis
{
...
...
@@ -32,12 +32,68 @@ public sealed class ConfigurationOptions : ICloneable
{
internal
const
string
DefaultTieBreaker
=
"__Booksleeve_TieBreak"
,
DefaultConfigurationChannel
=
"__Booksleeve_MasterChanged"
;
private
const
string
AllowAdminPrefix
=
"allowAdmin="
,
SyncTimeoutPrefix
=
"syncTimeout="
,
ServiceNamePrefix
=
"serviceName="
,
ClientNamePrefix
=
"name="
,
KeepAlivePrefix
=
"keepAlive="
,
VersionPrefix
=
"version="
,
ConnectTimeoutPrefix
=
"connectTimeout="
,
PasswordPrefix
=
"password="
,
TieBreakerPrefix
=
"tiebreaker="
,
WriteBufferPrefix
=
"writeBuffer="
,
sslPrefix
=
"ssl="
,
SslHostPrefix
=
"sslHost="
,
ConfigChannelPrefix
=
"configChannel="
,
AbortOnConnectFailPrefix
=
"abortConnect="
,
ResolveDnsPrefix
=
"resolveDns="
,
ChannelPrefixPrefix
=
"channelPrefix="
,
ProxyPrefix
=
"proxy="
;
private
static
class
OptionKeys
{
public
static
int
ParseInt32
(
string
key
,
string
value
,
int
minValue
=
int
.
MinValue
,
int
maxValue
=
int
.
MaxValue
)
{
int
tmp
;
if
(!
Format
.
TryParseInt32
(
value
,
out
tmp
))
throw
new
ArgumentOutOfRangeException
(
"Keyword '"
+
key
+
"' requires an integer value"
);
if
(
tmp
<
minValue
)
throw
new
ArgumentOutOfRangeException
(
"Keyword '"
+
key
+
"' has a minimum value of "
+
minValue
);
if
(
tmp
>
maxValue
)
throw
new
ArgumentOutOfRangeException
(
"Keyword '"
+
key
+
"' has a maximum value of "
+
maxValue
);
return
tmp
;
}
internal
static
bool
ParseBoolean
(
string
key
,
string
value
)
{
bool
tmp
;
if
(!
Format
.
TryParseBoolean
(
value
,
out
tmp
))
throw
new
ArgumentOutOfRangeException
(
"Keyword '"
+
key
+
"' requires a boolean value"
);
return
tmp
;
}
internal
static
Version
ParseVersion
(
string
key
,
string
value
)
{
Version
tmp
;
if
(!
System
.
Version
.
TryParse
(
value
,
out
tmp
))
throw
new
ArgumentOutOfRangeException
(
"Keyword '"
+
key
+
"' requires a version value"
);
return
tmp
;
}
internal
static
Proxy
ParseProxy
(
string
key
,
string
value
)
{
Proxy
tmp
;
if
(!
Enum
.
TryParse
(
value
,
true
,
out
tmp
))
throw
new
ArgumentOutOfRangeException
(
"Keyword '"
+
key
+
"' requires a proxy value"
);
return
tmp
;
}
internal
static
void
Unknown
(
string
key
)
{
throw
new
ArgumentException
(
"Keyword '"
+
key
+
"' is not supported"
);
}
internal
const
string
AllowAdmin
=
"allowAdmin"
,
SyncTimeout
=
"syncTimeout"
,
ServiceName
=
"serviceName"
,
ClientName
=
"name"
,
KeepAlive
=
"keepAlive"
,
Version
=
"version"
,
ConnectTimeout
=
"connectTimeout"
,
Password
=
"password"
,
TieBreaker
=
"tiebreaker"
,
WriteBuffer
=
"writeBuffer"
,
Ssl
=
"ssl"
,
SslHost
=
"sslHost"
,
ConfigChannel
=
"configChannel"
,
AbortOnConnectFail
=
"abortConnect"
,
ResolveDns
=
"resolveDns"
,
ChannelPrefix
=
"channelPrefix"
,
Proxy
=
"proxy"
;
private
static
readonly
Dictionary
<
string
,
string
>
normalizedOptions
=
new
[]
{
AllowAdmin
,
SyncTimeout
,
ServiceName
,
ClientName
,
KeepAlive
,
Version
,
ConnectTimeout
,
Password
,
TieBreaker
,
WriteBuffer
,
Ssl
,
SslHost
,
ConfigChannel
,
AbortOnConnectFail
,
ResolveDns
,
ChannelPrefix
,
Proxy
}.
ToDictionary
(
x
=>
x
,
StringComparer
.
InvariantCultureIgnoreCase
);
public
static
string
TryNormalize
(
string
value
)
{
string
tmp
;
if
(
value
!=
null
&&
normalizedOptions
.
TryGetValue
(
value
,
out
tmp
))
{
return
tmp
??
""
;
}
return
value
??
""
;
}
}
private
readonly
EndPointCollection
endpoints
=
new
EndPointCollection
();
...
...
@@ -199,7 +255,16 @@ public CommandMap CommandMap
public
static
ConfigurationOptions
Parse
(
string
configuration
)
{
var
options
=
new
ConfigurationOptions
();
options
.
DoParse
(
configuration
);
options
.
DoParse
(
configuration
,
false
);
return
options
;
}
/// <summary>
/// Parse the configuration from a comma-delimited configuration string
/// </summary>
public
static
ConfigurationOptions
Parse
(
string
configuration
,
bool
ignoreUnknown
)
{
var
options
=
new
ConfigurationOptions
();
options
.
DoParse
(
configuration
,
ignoreUnknown
);
return
options
;
}
...
...
@@ -256,23 +321,23 @@ public override string ToString()
{
Append
(
sb
,
Format
.
ToString
(
endpoint
));
}
Append
(
sb
,
ClientNamePrefix
,
clientName
);
Append
(
sb
,
ServiceNamePrefix
,
serviceName
);
Append
(
sb
,
KeepAlivePrefix
,
keepAlive
);
Append
(
sb
,
SyncTimeoutPrefix
,
syncTimeout
);
Append
(
sb
,
AllowAdminPrefix
,
allowAdmin
);
Append
(
sb
,
VersionPrefix
,
defaultVersion
);
Append
(
sb
,
ConnectTimeoutPrefix
,
connectTimeout
);
Append
(
sb
,
PasswordPrefix
,
password
);
Append
(
sb
,
TieBreakerPrefix
,
tieBreaker
);
Append
(
sb
,
WriteBufferPrefix
,
writeBuffer
);
Append
(
sb
,
sslPrefix
,
ssl
);
Append
(
sb
,
SslHostPrefix
,
sslHost
);
Append
(
sb
,
ConfigChannelPrefix
,
configChannel
);
Append
(
sb
,
AbortOnConnectFailPrefix
,
abortOnConnectFail
);
Append
(
sb
,
ResolveDnsPrefix
,
resolveDns
);
Append
(
sb
,
ChannelPrefix
Prefix
,
(
string
)
ChannelPrefix
);
Append
(
sb
,
ProxyPrefix
,
proxy
);
Append
(
sb
,
OptionKeys
.
ClientName
,
clientName
);
Append
(
sb
,
OptionKeys
.
ServiceName
,
serviceName
);
Append
(
sb
,
OptionKeys
.
KeepAlive
,
keepAlive
);
Append
(
sb
,
OptionKeys
.
SyncTimeout
,
syncTimeout
);
Append
(
sb
,
OptionKeys
.
AllowAdmin
,
allowAdmin
);
Append
(
sb
,
OptionKeys
.
Version
,
defaultVersion
);
Append
(
sb
,
OptionKeys
.
ConnectTimeout
,
connectTimeout
);
Append
(
sb
,
OptionKeys
.
Password
,
password
);
Append
(
sb
,
OptionKeys
.
TieBreaker
,
tieBreaker
);
Append
(
sb
,
OptionKeys
.
WriteBuffer
,
writeBuffer
);
Append
(
sb
,
OptionKeys
.
Ssl
,
ssl
);
Append
(
sb
,
OptionKeys
.
SslHost
,
sslHost
);
Append
(
sb
,
OptionKeys
.
ConfigChannel
,
configChannel
);
Append
(
sb
,
OptionKeys
.
AbortOnConnectFail
,
abortOnConnectFail
);
Append
(
sb
,
OptionKeys
.
ResolveDns
,
resolveDns
);
Append
(
sb
,
OptionKeys
.
Channel
Prefix
,
(
string
)
ChannelPrefix
);
Append
(
sb
,
OptionKeys
.
Proxy
,
proxy
);
if
(
commandMap
!=
null
)
commandMap
.
AppendDeltas
(
sb
);
return
sb
.
ToString
();
}
...
...
@@ -347,7 +412,11 @@ static void Append(StringBuilder sb, string prefix, object value)
if
(!
string
.
IsNullOrWhiteSpace
(
s
))
{
if
(
sb
.
Length
!=
0
)
sb
.
Append
(
','
);
sb
.
Append
(
prefix
).
Append
(
s
);
if
(!
string
.
IsNullOrEmpty
(
prefix
))
{
sb
.
Append
(
prefix
).
Append
(
'='
);
}
sb
.
Append
(
s
);
}
}
...
...
@@ -372,7 +441,7 @@ void Clear()
object
ICloneable
.
Clone
()
{
return
Clone
();
}
private
void
DoParse
(
string
configuration
)
private
void
DoParse
(
string
configuration
,
bool
ignoreUnknown
)
{
Clear
();
if
(!
string
.
IsNullOrWhiteSpace
(
configuration
))
...
...
@@ -390,97 +459,78 @@ private void DoParse(string configuration)
int
idx
=
option
.
IndexOf
(
'='
);
if
(
idx
>
0
)
{
var
key
=
option
.
Substring
(
0
,
idx
).
Trim
();
var
value
=
option
.
Substring
(
idx
+
1
).
Trim
();
if
(
IsOption
(
option
,
SyncTimeoutPrefix
))
{
int
tmp
;
if
(
Format
.
TryParseInt32
(
value
.
Trim
(),
out
tmp
)
&&
tmp
>
0
)
SyncTimeout
=
tmp
;
}
else
if
(
IsOption
(
option
,
AllowAdminPrefix
))
{
bool
tmp
;
if
(
Format
.
TryParseBoolean
(
value
.
Trim
(),
out
tmp
))
AllowAdmin
=
tmp
;
}
else
if
(
IsOption
(
option
,
AbortOnConnectFailPrefix
))
{
bool
tmp
;
if
(
Format
.
TryParseBoolean
(
value
.
Trim
(),
out
tmp
))
AbortOnConnectFail
=
tmp
;
}
else
if
(
IsOption
(
option
,
ResolveDnsPrefix
))
{
bool
tmp
;
if
(
Format
.
TryParseBoolean
(
value
.
Trim
(),
out
tmp
))
ResolveDns
=
tmp
;
}
else
if
(
IsOption
(
option
,
ServiceNamePrefix
))
{
ServiceName
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
ClientNamePrefix
))
{
ClientName
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
ChannelPrefixPrefix
))
{
ChannelPrefix
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
ConfigChannelPrefix
))
{
ConfigurationChannel
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
KeepAlivePrefix
))
{
int
tmp
;
if
(
Format
.
TryParseInt32
(
value
.
Trim
(),
out
tmp
))
KeepAlive
=
tmp
;
}
else
if
(
IsOption
(
option
,
ConnectTimeoutPrefix
))
{
int
tmp
;
if
(
Format
.
TryParseInt32
(
value
.
Trim
(),
out
tmp
))
ConnectTimeout
=
tmp
;
}
else
if
(
IsOption
(
option
,
VersionPrefix
))
{
Version
tmp
;
if
(
Version
.
TryParse
(
value
.
Trim
(),
out
tmp
))
DefaultVersion
=
tmp
;
}
else
if
(
IsOption
(
option
,
PasswordPrefix
))
{
Password
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
TieBreakerPrefix
))
{
TieBreaker
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
sslPrefix
))
{
bool
tmp
;
if
(
Format
.
TryParseBoolean
(
value
.
Trim
(),
out
tmp
))
Ssl
=
tmp
;
}
else
if
(
IsOption
(
option
,
SslHostPrefix
))
{
SslHost
=
value
.
Trim
();
}
else
if
(
IsOption
(
option
,
WriteBufferPrefix
))
{
int
tmp
;
if
(
Format
.
TryParseInt32
(
value
.
Trim
(),
out
tmp
))
WriteBuffer
=
tmp
;
}
else
if
(
IsOption
(
option
,
ProxyPrefix
))
{
Proxy
tmp
;
if
(
Enum
.
TryParse
(
option
,
true
,
out
tmp
))
Proxy
=
tmp
;
}
else
if
(
option
[
0
]==
'$'
)
switch
(
OptionKeys
.
TryNormalize
(
key
))
{
case
OptionKeys
.
SyncTimeout
:
SyncTimeout
=
OptionKeys
.
ParseInt32
(
key
,
value
,
minValue
:
1
);
break
;
case
OptionKeys
.
AllowAdmin
:
AllowAdmin
=
OptionKeys
.
ParseBoolean
(
key
,
value
);
break
;
case
OptionKeys
.
AbortOnConnectFail
:
AbortOnConnectFail
=
OptionKeys
.
ParseBoolean
(
key
,
value
);
break
;
case
OptionKeys
.
ResolveDns
:
ResolveDns
=
OptionKeys
.
ParseBoolean
(
key
,
value
);
break
;
case
OptionKeys
.
ServiceName
:
ServiceName
=
value
;
break
;
case
OptionKeys
.
ClientName
:
ClientName
=
value
;
break
;
case
OptionKeys
.
ChannelPrefix
:
ChannelPrefix
=
value
;
break
;
case
OptionKeys
.
ConfigChannel
:
ConfigurationChannel
=
value
;
break
;
case
OptionKeys
.
KeepAlive
:
KeepAlive
=
OptionKeys
.
ParseInt32
(
key
,
value
);
break
;
case
OptionKeys
.
ConnectTimeout
:
ConnectTimeout
=
OptionKeys
.
ParseInt32
(
key
,
value
);
break
;
case
OptionKeys
.
Version
:
DefaultVersion
=
OptionKeys
.
ParseVersion
(
key
,
value
);
break
;
case
OptionKeys
.
Password
:
Password
=
value
;
break
;
case
OptionKeys
.
TieBreaker
:
TieBreaker
=
value
;
break
;
case
OptionKeys
.
Ssl
:
Ssl
=
OptionKeys
.
ParseBoolean
(
key
,
value
);
break
;
case
OptionKeys
.
SslHost
:
SslHost
=
value
;
break
;
case
OptionKeys
.
WriteBuffer
:
WriteBuffer
=
OptionKeys
.
ParseInt32
(
key
,
value
);
break
;
case
OptionKeys
.
Proxy
:
Proxy
=
OptionKeys
.
ParseProxy
(
key
,
value
);
break
;
default
:
if
(!
string
.
IsNullOrEmpty
(
key
)
&&
key
[
0
]
==
'$'
)
{
RedisCommand
cmd
;
option
=
option
.
Substring
(
1
,
idx
-
1
);
if
(
Enum
.
TryParse
(
option
,
true
,
out
cmd
))
var
cmdName
=
option
.
Substring
(
1
,
idx
-
1
);
if
(
Enum
.
TryParse
(
cmdName
,
true
,
out
cmd
))
{
if
(
map
==
null
)
map
=
new
Dictionary
<
string
,
string
>(
StringComparer
.
InvariantCultureIgnoreCase
);
map
[
option
]
=
value
;
map
[
cmdName
]
=
value
;
}
}
else
{
ConnectionMultiplexer
.
TraceWithoutContext
(
"Unknown configuration option:"
+
option
);
if
(!
ignoreUnknown
)
OptionKeys
.
Unknown
(
key
);
}
break
;
}
}
else
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment