Example #1
0
class UsersController:
    """This is a controller for the main /users requests"""

    # The JSON schema expected for requests
    docRequest_login = """
    <ul>
        <li> The request must be a POST to /user/login with Content-Type "application/json"
        <li> The data in the request will be a JSON dictionary of the form given below
        <li> The two fields in the request are ASCII strings
    </ul>
    """
    schemaRequest_loginOrAdd = Schema({
        'user': '******',
        'password': '******'
    })

    # The JSON schema ensured for responses
    docResponse_login = """
    <ul>
       <li> The request must be a POST to /user/login or /user/add with Content-Type "application/json"
       <li> The response will be a JSON dictionary of the form given below
       <li> The errCode field is an integer with the same values as for the login/add method of UsersModel class
       <li> The count is present only if errCode is SUCCESS, and is the count of logins for the current user
       <li> The response will use HTTP status code 200 unless there is a catastrophic error outside
            the ones captured by the error codes (e.g., an unhandled exception).
            In that case a status code of 500 should be used.
    </ul>
    """
    schemaResp_loginOrAdd = Schema({
        'errCode': 1
    }).when(errCode__eq=UsersModel.SUCCESS,
            doc='Additional fields on SUCCESS',
            update={'count': 15})

    def do_POST(self, request):
        if request.path == "/users/login" or request.path == "/users/add":
            # Most of the code for "login" and "add" is the same
            rdata = request.getRequestData(
                requestName=request.path,
                requestSchema=UsersController.schemaRequest_loginOrAdd)
            if not rdata: return

            username = rdata["user"]
            password = rdata["password"]
            if request.path == "/users/login":
                rval = g_users.login(username, password)
            else:
                rval = g_users.add(username, password)

            if rval < 0:
                resp = {"errCode": rval}
            else:
                resp = {"errCode": UsersModel.SUCCESS, "count": rval}
            request.sendResponse(data=Utils.jsonDumps(
                resp,
                objName='resp:' + request.path,
                schema=UsersController.schemaResp_loginOrAdd))
        else:
            return request.send_error(404, "Unrecognized request")
Example #2
0
 def jsonDumps(data, objName="", schema=None):
     """
     Serialize data with JSON, optionally checking the schema
     @param data:
     @param objName:
     @param schema:
     @return:
     """
     if schema == None:
         msg = "No schema given for JSON serialization of "+objName
         Utils.log(msg, err=True)
         raise Exception(msg)  # Make sure we fail the request
     else:
         Schema.validate(schema, data, objName=objName)
     return json.dumps(data)
Example #3
0
 def jsonDumps(data, objName="", schema=None):
     """
     Serialize data with JSON, optionally checking the schema
     @param data:
     @param objName:
     @param schema:
     @return:
     """
     if schema == None:
         msg = "No schema given for JSON serialization of " + objName
         Utils.log(msg, err=True)
         raise Exception(msg)  # Make sure we fail the request
     else:
         Schema.validate(schema, data, objName=objName)
     return json.dumps(data)
Example #4
0
    def jsonLoads(dataStr, objName="", schema=None):
        """
        Deserialize data with JSON, optionally checking the schema
        @param dataStr:
        @param objName:
        @param schema:
        @return:
        """
        data = json.loads(dataStr)

        if schema == None:
            msg = 'No schema given for JSON deserialization of '+objName
            Utils.log(msg, err=True)
            raise Exception(msg) # Make sure we fail the request
        else:
            Schema.validate(schema, data, objName=objName)
        return data
Example #5
0
    def jsonLoads(dataStr, objName="", schema=None):
        """
        Deserialize data with JSON, optionally checking the schema
        @param dataStr:
        @param objName:
        @param schema:
        @return:
        """
        data = json.loads(dataStr)

        if schema == None:
            msg = 'No schema given for JSON deserialization of ' + objName
            Utils.log(msg, err=True)
            raise Exception(msg)  # Make sure we fail the request
        else:
            Schema.validate(schema, data, objName=objName)
        return data
Example #6
0
 def generateSchema(outf,
                    header="h2",
                    anchor="",
                    title="",
                    descr="",
                    schema=None):
     generateSection(outf, header=header, anchor=anchor, title=title)
     outf.write(descr + "\n")
     html = Schema.htmlDoc(schema)
     outf.write(html + "\n")
Example #7
0
 def generateSchema(outf, header="h2", anchor="", title="", descr="", schema=None):
     generateSection(outf, header=header, anchor=anchor, title=title)
     outf.write(descr+"\n")
     html = Schema.htmlDoc(schema)
     outf.write(html+"\n")
Example #8
0
        outf.write(TESTAPI_Controller.docReq_resetFixture)
        outf.write(TESTAPI_Controller.docResp_resetFixture)
        generateSchema(outf,
                       schema=TESTAPI_Controller.schemaResp_resetFixture)

        generateSection(outf, header="h2", title='/TESTAPI/unitTests request',
                        anchor='unitTests')

        outf.write(TESTAPI_Controller.docReq_unitTests)
        outf.write(TESTAPI_Controller.docResp_unitTests)
        generateSchema(outf,
                       schema=TESTAPI_Controller.schemaResp_unitTests)


Schema.registerErrorReporter(Utils.schemaErrorReporter)

###
### Main entry point
###
def run():
    """
    Main entry point
    """
    port = int(os.environ.get("PORT", 5000))
    # We use port 5000 to please Heroku 
    sys.stderr.write('http server is starting on 0.0.0.0:'+str(port)+'...\n')

    #ip and port of servr
    #by default http server port is 80
    server_address = ('0.0.0.0', port)
Example #9
0
class TESTAPI_Controller:
    """This is a controller for the special TESTAPI_ interface to the server."""

    docReq_resetFixture = """
    <ul>
    <li> The request must be a POST to /TESTAPI/resetFixture with Content-Type "application/json"
    <li> The data is an empty dictionary
    </ul>
    """

    docResp_resetFixture = """
    <ul>
    <li> Upon receiving this request the back-end should reset the databases to their empty state.
        For this project, this will consist of calling the UsersModel TESTAPI_resetFixture method.
    <li> The response should be a JSON dictionary with the contents described below
    <li> Note: <i>Real life projects do not contains such a public API.
         Instead the tests would be run on a special test database.
         We added this API so that we can test your backend easily even
         if do not have direct access to the database.</i>
    </ul>
    """
    schemaResp_resetFixture = Schema({
        'errCode':
        Schema(1, doc="The error code", valid=SchemaValidator.eq(1))
    })

    docReq_unitTests = """
    <ul>
    <li> The request must be a POST to /TESTAPI/unitTests with Content-Type "application/json"
    <li> The data is an empty dictionary
    </ul>
    """

    docResp_unitTests = """
    <ul>
    <li> Upon receiving this request the backend should run all of the unit tests,
        wait for them to complete, extract the number of tests, successes, failures,
        and the complete output of the tests and package that as part of the response
    <li> The response should contain a JSON dictionary with the fields described below
    <li> If there is a major error running the unit tests, then the response should at
         least contain the 'output' field with some error message.
         <p>
         One possible strategy for implementing this is to run the unit tests as separate
         shell command, redirecting the output to a file.
         Once the tests complete, you read the output and extract the necessary information.
    <li> Note: <i>Real life projects do not contains such a public API.
         Instead the tests would be run on a special test database.
         We added this API so that we can test your backend easily even if do not have
         direct access to the database.</i>
    </ul>
    """
    schemaResp_unitTests = Schema({
        'totalTests':
        Schema(5, doc='how many unit tests were executed'),
        'nrFailed':
        Schema(3, doc='how many unit tests failed'),
        'output':
        Schema(" ... ", doc='The output of running the tests')
    })

    def do_POST(self, request):
        # Note: This is added functionality to make unit testing easier
        if request.path == "/TESTAPI/resetFixture":
            g_users.TESTAPI_resetFixture()
            # To simplify the testing, make this be a JSON object
            request.sendResponse(data=Utils.jsonDumps(
                {"errCode": UsersModel.SUCCESS},
                objName="resetFixture_resp",
                schema=TESTAPI_Controller.schemaResp_resetFixture))
            return

        elif request.path == "/TESTAPI/unitTests":
            # We run the unit tests and collect the output into a temporary file
            # Conveniently, we have a Makefile target for all unit_tests
            # There are better ways of doing this in Python, but this is a more portable example

            (ofile, ofileName) = tempfile.mkstemp(prefix="userCounter")
            try:
                errMsg = ""  # We accumulate here error messages
                output = ""  # Some default values
                totalTests = 0
                nrFailed = 0
                while True:  # Give us a way to break
                    # Find the path to the server installation
                    thisDir = os.path.dirname(os.path.abspath(__file__))
                    cmd = "make -C " + thisDir + " unit_tests >" + ofileName + " 2>&1"
                    Utils.log("Executing " + cmd)
                    code = os.system(cmd)
                    if code != 0:
                        # There was some error running the tests.
                        # This happens even if we just have some failing tests
                        errMsg = "Error running command (code=" + str(
                            code) + "): " + cmd + "\n"
                        # Continue to get the output, and to parse it

                    # Now get the output
                    try:
                        ofileFile = open(ofileName, "r")
                        output = ofileFile.read()
                        ofileFile.close()
                    except:
                        errMsg += "Error reading the output " + traceback.format_exc(
                        )
                        # No point in continuing
                        break

                    Utils.log("Got " + output)
                    # Python unittest prints a line like the following line at the end
                    # Ran 4 tests in 0.001s
                    m = re.search(r'Ran (\d+) tests', output)
                    if not m:
                        errMsg += "Cannot extract the number of tests\n"
                        break
                    totalTests = int(m.group(1))
                    # If there are failures, we will see a line like the following
                    # FAILED (failures=1)
                    m = re.search('rFAILED.*\(failures=(\d+)\)', output)
                    if m:
                        nrFailures = int(m.group(1))
                    break  # Exit while

                # End while
                if errMsg:
                    Utils.log(errMsg, err=True)
                resp = {
                    'output': errMsg + output,
                    'totalTests': totalTests,
                    'nrFailed': nrFailed
                }
                request.sendResponse(data=Utils.jsonDumps(
                    resp,
                    objName="unitTests_resp",
                    schema=TESTAPI_Controller.schemaResp_unitTests))

            finally:
                os.unlink(ofileName)

        else:
            return request.send_error(404, "Unrecognized request")
Example #10
0
        outf.write(TESTAPI_Controller.docReq_resetFixture)
        outf.write(TESTAPI_Controller.docResp_resetFixture)
        generateSchema(outf, schema=TESTAPI_Controller.schemaResp_resetFixture)

        generateSection(outf,
                        header="h2",
                        title='/TESTAPI/unitTests request',
                        anchor='unitTests')

        outf.write(TESTAPI_Controller.docReq_unitTests)
        outf.write(TESTAPI_Controller.docResp_unitTests)
        generateSchema(outf, schema=TESTAPI_Controller.schemaResp_unitTests)


Schema.registerErrorReporter(Utils.schemaErrorReporter)


###
### Main entry point
###
def run():
    """
    Main entry point
    """
    port = int(os.environ.get("PORT", 5000))
    # We use port 5000 to please Heroku
    sys.stderr.write('http server is starting on 0.0.0.0:' + str(port) +
                     '...\n')

    #ip and port of servr