aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/cpp/qps
diff options
context:
space:
mode:
authorGravatar Siddharth Rakesh <sidrakesh@google.com>2015-06-15 17:02:51 -0700
committerGravatar Siddharth Rakesh <sidrakesh@google.com>2015-06-15 17:02:51 -0700
commitd0010ae439406e4118a1ca1788276d2c1f6fe9e5 (patch)
tree1902007f8d59b28bc1007c348a39c86a91da249a /test/cpp/qps
parent668f33c6f3a5554c20b84780c4a4ed297ee00f1a (diff)
added comments
Diffstat (limited to 'test/cpp/qps')
-rw-r--r--test/cpp/qps/data_script.sh7
-rw-r--r--test/cpp/qps/report.cc2
-rwxr-xr-xtest/cpp/qps/run_auth_test.py138
-rw-r--r--test/cpp/qps/user_data_client.cc16
-rw-r--r--test/cpp/qps/user_data_client.h7
5 files changed, 146 insertions, 24 deletions
diff --git a/test/cpp/qps/data_script.sh b/test/cpp/qps/data_script.sh
new file mode 100644
index 0000000000..51d840f8d8
--- /dev/null
+++ b/test/cpp/qps/data_script.sh
@@ -0,0 +1,7 @@
+while [ true ]
+do
+ python run_auth_test.py ../../../bins/opt/async_streaming_ping_pong_test sidrakesh@google.com
+ python run_auth_test.py ../../../bins/opt/async_unary_ping_pong_test sidrakesh@google.com
+ python run_auth_test.py ../../../bins/opt/sync_streaming_ping_pong_test sidrakesh@google.com
+ python run_auth_test.py ../../../bins/opt/sync_unary_ping_pong_test sidrakesh@google.com
+done \ No newline at end of file
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index 83860ab9ce..91fe9524cb 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -176,8 +176,10 @@ void UserDatabaseReporter::ReportTimes(const ScenarioResult& result) const {
}
void UserDatabaseReporter::SendData() const {
+ //send data to performance database
int userDataState = userDataClient.sendData(access_token_, test_name_, sys_info_);
+ //check state of data sending
switch(userDataState) {
case 1:
gpr_log(GPR_INFO, "Data sent to user database successfully");
diff --git a/test/cpp/qps/run_auth_test.py b/test/cpp/qps/run_auth_test.py
index 06b064cad0..c327a505b6 100755
--- a/test/cpp/qps/run_auth_test.py
+++ b/test/cpp/qps/run_auth_test.py
@@ -1,3 +1,33 @@
+#
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
#!/usr/bin/python
import os
@@ -8,6 +38,7 @@ import urllib
import json
import time
import subprocess
+import fnmatch
CLIENT_ID = '1018396037782-tv81fshn76nemr24uuhuginceb9hni2m.apps.googleusercontent.com'
CLIENT_SECRET = '_HGHXg4DAA59r4w4x8p6ARzD'
@@ -17,6 +48,7 @@ AUTH_TOKEN_LINK = 'https://www.googleapis.com/oauth2/v3/token'
GOOGLE_ACCOUNTS_LINK = 'https://accounts.google.com/o/oauth2/device/code'
USER_INFO_LINK = 'https://www.googleapis.com/oauth2/v1/userinfo'
+# Fetches JSON reply object, given a url and parameters
def fetchJSON(url, paramDict):
if len(paramDict) == 0:
req = urllib2.Request(url)
@@ -33,6 +65,7 @@ def fetchJSON(url, paramDict):
return result
+# Fetch user info; used to check if access token is valid
def getUserInfo(accessToken):
url = USER_INFO_LINK + '?access_token=' + accessToken
paramDict = {}
@@ -41,6 +74,7 @@ def getUserInfo(accessToken):
return data
+# Returns true if stored access token is valid
def isAccessTokenValid(accessToken):
data = getUserInfo(accessToken);
@@ -49,32 +83,47 @@ def isAccessTokenValid(accessToken):
else:
return False
+# Returns user id given a working access token
def getUserId(accessToken):
data = getUserInfo(accessToken)
email = data['email']
- email = email.split('@')[0].lower()
- userId = re.sub('[.]', '', email)
+ userId = getUserIdFromEmail(email)
return userId
+# Extracts a unique user id from an email address
+def getUserIdFromEmail(email):
+ email = email.split('@')[0].lower() # take username and convert to lower case
+ userId = re.sub('[.]', '', email) # remove periods
+
+ return userId
+
+# Use an existing access token
def useAccessToken(userTokFile):
with open(userTokFile, "r") as data_file:
- data = json.load(data_file)
+ data = json.load(data_file) # load JSON data from file
accessToken = data["access_token"]
+ # If access token has gone stale, refresh it
if not isAccessTokenValid(accessToken):
return refreshAccessToken(data["refresh_token"], userTokFile)
return accessToken
+# refresh stale access token
def refreshAccessToken(refreshToken, userTokFile):
+ # Parameters for request
paramDict = {'refresh_token':refreshToken, 'client_id':CLIENT_ID, 'client_secret':CLIENT_SECRET, 'grant_type':'refresh_token'}
+ # Fetch reply to request
JSONBody = fetchJSON(AUTH_TOKEN_LINK, paramDict)
data = json.loads(JSONBody)
+
if not 'access_token' in data:
+ # Refresh token has gone stale, re-authentication required
return reauthenticate()
else:
+ # write fresh access token to tokens file
tokenData = {}
with open(userTokFile, "r") as data_file:
@@ -83,61 +132,108 @@ def refreshAccessToken(refreshToken, userTokFile):
with open(userTokFile, "w") as data_file:
tokenData['access_token'] = data['access_token']
json.dump(tokenData, data_file)
-
+
+ # return fresh access token
return data['access_token']
def reauthenticate():
+ # Request parameters
paramDict = {'client_id':CLIENT_ID, 'scope':'email profile'}
JSONBody = fetchJSON(GOOGLE_ACCOUNTS_LINK, paramDict)
data = json.loads(JSONBody)
print 'User authorization required\n'
- print 'Please use the following code in you browser: ', data['user_code']
- print 'Verification URL: ', data['verification_url']
+ print 'Please use the following code in you browser: ', data['user_code'] # Code to be entered by user in browser
+ print 'Verification URL: ', data['verification_url'] # Authentication link
print '\nAwaiting user authorization. May take a few more seconds after authorizing...\n'
authData = {}
while not 'access_token' in authData:
+ # Request parameters
authDict = {'client_id':CLIENT_ID, 'client_secret':CLIENT_SECRET, 'code':data['device_code'], 'grant_type':GRANT_TYPE}
JSONBody = fetchJSON(AUTH_TOKEN_LINK, authDict)
authData = json.loads(JSONBody)
+ # If server pinged too quickly, will get slowdown message; need to wait for specified interval
time.sleep(data['interval'])
+ # File to write tokens
newUserTokFile = ACCESS_TOKENS_DIR + '/' + getUserId(authData['access_token'])
+ # Write tokens to file
with open(newUserTokFile, "w") as data_file:
json.dump(authData, data_file)
+ # return working access token
return authData['access_token']
-def main():
- if not os.path.exists(ACCESS_TOKENS_DIR):
- os.makedirs(ACCESS_TOKENS_DIR)
-
- if len(sys.argv) > 2:
- email = sys.argv[2]
- else:
- email = raw_input('Enter your e-mail id: ')
-
- email = email.split('@')[0].lower()
- userId = re.sub('[.]', '', email)
+# Fetch a working access token given user entered email id; authntication may be required
+def getAccessToken(email):
+ # Get unique user id from email address
+ userId = getUserIdFromEmail(email)
+ # Token file
userTokFile = ACCESS_TOKENS_DIR + '/' + userId
accessToken = ''
if os.path.exists(userTokFile):
+ # File containing access token exists; unless refresh token has expired, user authentication will not be required
accessToken = useAccessToken(userTokFile)
else:
+ # User authentication required
accessToken = reauthenticate()
- testName = sys.argv[1].split('/')[-1]
- sysInfo = os.popen('lscpu').readlines()
+ return accessToken
+
+# If user has not entered full path to test, recursively searches for given test in parent folders
+def findTestPath(test):
+ # If user entered full path to test, return it
+ if(os.path.isfile(test)):
+ return test
+
+ testName = test.split('/')[-1] # Extract just test name
+ testPath = ''
+
+ # Search for test
+ for root, dirnames, filenames in os.walk('../../../'):
+ for fileName in fnmatch.filter(filenames, '*'+testName):
+ testPath = os.path.join(root, fileName)
+
+ return testPath
+
+def main():
+ # If tokens directory does not exist, creates it
+ if not os.path.exists(ACCESS_TOKENS_DIR):
+ os.makedirs(ACCESS_TOKENS_DIR)
+
+ if len(sys.argv) > 1:
+ test = sys.argv[1]
+ else:
+ test = raw_input('Enter the test path/name: ')
+
+ if len(sys.argv) > 2:
+ email = sys.argv[2]
+ else:
+ email = raw_input('Enter your e-mail id: ')
+
+ try:
+ # Fetch working access token
+ accessToken = getAccessToken(email)
+ except Exception, e:
+ print 'Error in authentication'
try:
- subprocess.call([sys.argv[1], '--access_token='+accessToken, '--test_name='+testName, '--sys_info='+str(sysInfo).strip('[]')])
+ testPath = findTestPath(test) # Get path to test
+ testName = testPath.split('/')[-1] # Get test name
+
+ # Fetch system information
+ sysInfo = os.popen('lscpu').readlines()
+
+ # Run the test
+ subprocess.call([testPath, '--access_token='+accessToken, '--test_name='+testName, '--sys_info='+str(sysInfo).strip('[]')])
except OSError:
- print 'Could not execute the test, please check test path'
+ print 'Could not execute the test, please check test name'
+
if __name__ == "__main__":
main() \ No newline at end of file
diff --git a/test/cpp/qps/user_data_client.cc b/test/cpp/qps/user_data_client.cc
index f56b79ee4a..a8ced7559d 100644
--- a/test/cpp/qps/user_data_client.cc
+++ b/test/cpp/qps/user_data_client.cc
@@ -36,19 +36,23 @@
namespace grpc {
namespace testing {
+//sets the client and server config information
void UserDataClient::setConfigs(const ClientConfig& clientConfig, const ServerConfig& serverConfig) {
clientConfig_ = clientConfig;
serverConfig_ = serverConfig;
}
+//sets the QPS
void UserDataClient::setQPS(double QPS) {
QPS_ = QPS;
}
+//sets the QPS per core
void UserDataClient::setQPSPerCore(double QPSPerCore) {
QPSPerCore_ = QPSPerCore;
}
+//sets the 50th, 90th, 95th, 99th and 99.9th percentile latency
void UserDataClient::setLatencies(double percentileLatency50, double percentileLatency90,
double percentileLatency95, double percentileLatency99, double percentileLatency99Point9) {
percentileLatency50_ = percentileLatency50;
@@ -58,6 +62,7 @@ void UserDataClient::setLatencies(double percentileLatency50, double percentileL
percentileLatency99Point9_ = percentileLatency99Point9;
}
+//sets the server and client, user and system times
void UserDataClient::setTimes(double serverSystemTime, double serverUserTime,
double clientSystemTime, double clientUserTime) {
serverSystemTime_ = serverSystemTime;
@@ -66,18 +71,23 @@ void UserDataClient::setTimes(double serverSystemTime, double serverUserTime,
clientUserTime_ = clientUserTime;
}
+//sends the data to the performancew database server
int UserDataClient::sendData(std::string access_token, std::string test_name, std::string sys_info) {
-
+ //Data record request object
SingleUserRecordRequest singleUserRecordRequest;
+
+ //setting access token, name of the test and the system information
singleUserRecordRequest.set_access_token(access_token);
singleUserRecordRequest.set_test_name(test_name);
singleUserRecordRequest.set_sys_info(sys_info);
+ //setting configs
*(singleUserRecordRequest.mutable_client_config()) = clientConfig_;
*(singleUserRecordRequest.mutable_server_config()) = serverConfig_;
Metrics* metrics = singleUserRecordRequest.mutable_metrics();
+ //setting metrcs in data record request
if(QPS_ != DBL_MIN) metrics->set_qps(QPS_);
if(QPSPerCore_ != DBL_MIN) metrics->set_qps_per_core(QPSPerCore_);
if(percentileLatency50_ != DBL_MIN) metrics->set_perc_lat_50(percentileLatency50_);
@@ -95,9 +105,9 @@ int UserDataClient::sendData(std::string access_token, std::string test_name, st
Status status = stub_->RecordSingleClientData(&context, singleUserRecordRequest, &singleUserRecordReply);
if (status.IsOk()) {
- return 1;
+ return 1; //data sent to database successfully
} else {
- return -1;
+ return -1; //error in data sending
}
}
} //testing
diff --git a/test/cpp/qps/user_data_client.h b/test/cpp/qps/user_data_client.h
index c99b7e9b3a..c2e07ef5cd 100644
--- a/test/cpp/qps/user_data_client.h
+++ b/test/cpp/qps/user_data_client.h
@@ -49,6 +49,7 @@
namespace grpc{
namespace testing {
+//Manages data sending to performance database server
class UserDataClient {
public:
UserDataClient(std::shared_ptr<ChannelInterface> channel)
@@ -56,18 +57,24 @@ public:
~UserDataClient() {}
+ //sets the client and server config information
void setConfigs(const ClientConfig& clientConfig, const ServerConfig& serverConfig);
+ //sets the QPS
void setQPS(double QPS);
+ //sets the QPS per core
void setQPSPerCore(double QPSPerCore);
+ //sets the 50th, 90th, 95th, 99th and 99.9th percentile latency
void setLatencies(double percentileLatency50, double percentileLatency90,
double percentileLatency95, double percentileLatency99, double percentileLatency99Point9);
+ //sets the server and client, user and system times
void setTimes(double serverSystemTime, double serverUserTime,
double clientSystemTime, double clientUserTime);
+ //sends the data to the performancew database server
int sendData(std::string access_token, std::string test_name, std::string sys_info);
private: