<commit_before>'''
Tests for ansibleKeeper
'''

__author__     = "Jan Kogut"
__copyright__  = "Jan Kogut"
__license__    = "MIT"
__version__    = "0.0.1"
__maintainer__ = "Jan Kogut"
__status__     = "Beta"

import pytest
import socket
from ansibleKeeper import *
from kazoo.client import KazooClient
from kazoo.handlers.threading import *
from kazoo.exceptions import *

## START of TestVars: global vars for tests
##################################################

class TestVars(object):
    ''' Test vars section '''
    pass

tst = TestVars()

tst.testDict  = {"testgroupname1":
                 {
                  "testhostname1":{"var1":"val1", "var2":"val2", "var3":"val3"},
                  "testhostname2":{"var1":"val11", "var2":"val22", "var3":"val33"},
                  "testhostname3":{"var1":"val111", "var2":"val222", "var3":"val333"}
                 }
}

tst.updateDict  = {"testgroupname1":
                 {
                  "testhostname1":{"var1":"valUpdated1", "var2":"valUpdated2", "var3":"valUpdated3"},
                  "testhostname2":{"var1":"valUpdated11", "var2":"valUpdated22", "var3":"valUpdated33"},
                  "testhostname3":{"var1":"valUpdated111", "var2":"valUpdated222", "var3":"valUpdated333"}
                 }
}

tst.groupName     = tst.testDict.keys()[0]                     ## ==> 'testgroupname1'
tst.hostName      = tst.testDict[tst.groupName].keys()[0]      ## ==> 'testhostname1'

tst.varDict       = tst.testDict[tst.groupName][tst.hostName]  ## ==> {'var1': 'val1', 'var3': 'val3', 'var2': 'val2'}
tst.oneDict       = {tst.groupName:{tst.hostName:tst.varDict}} ## ==> {'testgroupname1': {'testhostname1': {'var1': 'val1', 'var3': 'val3', 'var2': 'val2'}}}

tst.hostPath      = "{0}/hosts/{1}".format(cfg.aPath, tst.hostName)
tst.groupPath     = "{0}/groups/{1}".format(cfg.aPath, tst.groupName)
tst.hostGroupPath = "{0}/groups/{1}/{2}".format(cfg.aPath, tst.groupName, tst.hostName)

tst.groupHostStr  = "{0}:{1}".format(tst.groupName, tst.hostName) ## ==> 'testgroupname1:testhostname1'
tst.hostHostStr   = "hosts:{0}".format(tst.hostName)              ## ==> 'hosts:testhostname1'

#################################################
## END of TestVars: global vars for tests

class TestConfig(object):
    '''
    Suite of config tests with read-only zookeeper client connection.
    '''

    def test_zkClusterUp(self):
        '''
        Test if the zookeeper cluster is UP.
        We expect all servers are UP and port for zookeeper: 2181 is open.
        '''

        zkSrvList = cfg.zkServers.replace(':2181','').split(',')

        for srv in zkSrvList:
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                assert sock.connect_ex((srv,2181)) == 0

            finally:
                sock.close()

    @pytest.fixture
    def ro_zk(self):
        '''
        Fixture for zookeeper client connection in read-only mode.
        '''

        ## example server list string 'zoo1.dmz:2181,zoo2.dmz:2181,zoo3.dmz:2181'
        zk = KazooClient(hosts=cfg.zkServers, read_only = True)
        zk.start()

        return zk

    def test_configZkClusterConnection(self, ro_zk):
        '''
        Test if we can establish zookeeper client connection to zookeeper cluster servers.
        We expect at least one server runnig zookeeper.
        '''

        try:
            assert type(ro_zk).__name__ == 'KazooClient'

        finally:
            ro_zk.stop()

    def test_configZkServerConnection(self, ro_zk):
        '''
        Test if we can establish zookeeper client connection to each zookeeper server.
        We expect all of the servers are running zookeeper.
        '''

        ## example server list string 'zoo1.dmz:2181,zoo2.dmz:2181,zoo3.dmz:2181'
        zkSrvList = cfg.zkServers.split(',')

        for srv in zkSrvList:
            try:
                assert type(ro_zk).__name__ == 'KazooClient'

            except KazooTimeoutError as error:
                print("{0} check your connection with zookeeper server: {1} ").format(error, srv)

            finally:
                ro_zk.stop()

    def test_configBasePrefixZnode(self, ro_zk):
        '''
        Test if base prefix znode from config exists.
        '''

        try:
            assert ro_zk.exists(cfg.aPath) is not None

        finally:
            ro_zk.stop()

class TestReadWrite(object):
    '''
    Suite of tests where read-write zookeeper client connection is required.
    '''

    @pytest.fixture
    def rw_zk(self):
        '''
        Fixture for zookeeper client connection in read-write mode.
        '''

        ## example server list string 'zoo1.dmz:2181,zoo2.dmz:2181,zoo3.dmz:2181'
        zk = KazooClient(hosts=cfg.zkServers)
        zk.start()

        return zk

    def test_addHostWithHostvars(self, rw_zk):
        '''
        Test if hostname-znode added with addHostWithHostvars(var) exists.
        '''

        ## 1. check if Znode provided with test config exists
        ## 2. run addHostWithHostvars(var) function
        ## 3. check hostname value against tested values (from tst.testDict)
        ## 4. run twice deleteZnodeRecur(var) to remove hostname from groupname and hosts group

        if rw_zk.exists(tst.hostPath) is not None:
            rw_zk.delete(tst.hostPath, recursive=True)
            rw_zk.stop()

        addHostWithHostvars(tst.oneDict)

        try:
            assert rw_zk.exists(tst.hostPath) ## is not None

        finally:
            rw_zk.stop()

        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_addHostToGroup(self, rw_zk):
        '''
        Test if hostname-znode added with addHostToGroup(var) exists.
        '''

        ## 1. check if Znode provided with test config exists
        ## 2. run addHostWithHostvars(var) and addHostToGroup(var) functions
        ## 3. check if hostname added with addHostToGroup exists
        ## 4. run twice deleteZnodeRecur(var) to remove hostname from groupname and hosts group

        if rw_zk.exists(tst.groupPath) is not None:
            rw_zk.delete(tst.groupPath, recursive=True)
            rw_zk.stop()

        addHostWithHostvars(tst.oneDict)
        addHostToGroup(splitZnodeString(tst.groupHostStr))

        try:
            assert rw_zk.exists(tst.hostGroupPath) ## is not None

        finally:
            rw_zk.stop()

        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_deleteZnodeRecur(self, rw_zk):
        '''
        Test that znode deleted with deleteZnodeRecur(var) does not exist.
        '''

        ## 1. run addHostWithHostvars(var) function to add example Znode provided in test config
        ## 2. run twice deleteZnodeRecur(var) function to delete given Znode provided in test config
        ## 3. check Znode path against that string

        addHostWithHostvars(tst.oneDict)
        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

        try:
            assert rw_zk.exists(tst.hostPath) is None
            assert rw_zk.exists(tst.hostGroupPath) is None

        finally:
            rw_zk.stop()

    def test_deleteZnodeHostExistance(self):
        '''
        Test that deleteZnodeRecur() will inform us that we want to delete nonexistent Znode from hosts group.
        '''

        errStringHost  = 'ERROR  ==> could not delete host: {0} that does not exist !!!'.format(tst.hostName)

        assert deleteZnodeRecur(splitZnodeString(tst.hostHostStr)) == errStringHost

    def test_deleteZnodeHostInGroupExistance(self):
        '''
        Test that deleteZnodeRecur() will inform us that we want to delete nonexistent Znode from groups/groupname group.
        '''

        errStringGroup  = 'ERROR  ==> could not delete host: {0} that does not exist in group: {1} !!!'.format(tst.hostName, tst.groupName)

        addHostWithHostvars(tst.oneDict)
        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))

        assert deleteZnodeRecur(splitZnodeString(tst.groupHostStr)) == errStringGroup

        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_deleteZnodeRecurGroup(self, rw_zk):
        '''
        Test that znode deleted with deleteZnodeRecur(var) for groupname does not exist.
        '''

        ## 1. run addHostWithHostvars(var) function to create given Znode provided in tst.oneDict
        ## 2. run deleteZnodeRecur(var) function to delete given Znode provided in tst.groupName
        ## 3. check Znode path against that string
        ## 4. delete hostname Znode in hosts group with deleteZnodeRecur(var)

        addHostWithHostvars(tst.oneDict)
        deleteZnodeRecur(splitZnodeString(tst.groupName))

        try:
            assert rw_zk.exists(tst.groupPath) is None

        finally:
            rw_zk.stop()

        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_hostVarsShowOneHost(self):
        '''
        Test hostVarsShow() function for group with one host.
        '''

        ## 1. run addHostWithHostvars(var) function to create given Znode with vars provided in tst.oneDict
        ## 2. test showHostVars(var) against vars and values provided in tst.oneDict
        ## 3. run deleteZnodeRecur(var) function to delete given Znode provided in tst.hostHostStr

        addHostWithHostvars(tst.oneDict)

        testList = [(tst.hostHostStr,{tst.hostName:tst.varDict}),(tst.groupName, tst.oneDict[tst.groupName])]

        for val in testList:
            assert showHostVars(splitZnodeString(val[0])) == val[1]

        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    # def test_hostVarsShowMultipleHosts(self):
    #     '''
    #     Test hostVarsShow() function for group with multiple hosts.
    #     '''

    #     ## 1. run addHostWithHostvars(var) function to create given Znode with vars provided in tst.oneDict
    #     ## 2. test showHostVars(var) against vars and values provided in tst.testDict
    #     ## 3. run deleteGroupZnode(var) function to delete given Znode provided in tst.hostHostStr

    #     for hostname in tst.testDict[tst.groupName].keys():
    #         tmpDict = {tst.groupName : { hostname : tst.testDict[tst.groupName][hostname] }}
    #         addHostWithHostvars(tmpDict)

    #     testList = [(tst.hostHostStr, {tst.hostName:tst.varDict}),(tst.groupName, tst.testDict[tst.groupName])]

    #     for val in testList:
    #         assert showHostVars(splitZnodeString(val[0])) == val[1]

    #     delete all hosts in group created with addHostWithHostvars(var)
    #     deleteZnodeRecur(splitZnodeString(tst.groupName))
    #     for hostname in  tst.testDict[tst.groupName].keys():
    #         tmpHostStr = "hosts:{}".format(hostname)
    #         deleteZnodeRecur(splitZnodeString(tmpHostStr))

    # # def test_updateZnode():
    # #     '''
    # #     Test updated Znode with updateZnode(var).
    # #     '''

    # #     ## 1. run addHostWithHostvars(var) function to create given Znode provided in tst.testDict
    # #     ## 2. run updateZnode(var) function to update given Znode provided in tst.updateDict
    # #     ## 3. check upated results against tst.updateDict
    # #     ## 4. run deleteZnodeRecur(var) function to delete given Znode provided in tst.hostHostStr

    # #     addHostWithHostvars(tst.testDict)
    # #     updateZnode(tst.updateDict)

    # #     zk = KazooClient(hosts=cfg.zkServers)
    # #     zk.start()

    # #     for key in tst.updateDict[tst.groupName][tst.hostName].keys():
    # #         zkGet     = zk.get('{0}/{1}'.format(tst.hostGroupPath, key))[0]
    # #         updateValue = tst.updateDict[tst.groupName][tst.hostName][key]
    # #         assert zkGet == testValue

    # #         zk.stop()

    # #     deleteZnodeRecur(splitZnodeString(tst.groupName))

def test_splitZnodeString():
    '''
    Test for splitZnodeString() parser.
    '''

    testTup = ({"string": tst.groupHostStr,
                "output": [(tst.groupName, tst.groupPath), (tst.hostName, tst.hostPath, tst.hostGroupPath)]},
               {"string": tst.hostHostStr,
                "output": [(tst.hostName, tst.hostPath, None)]},
               {"string": tst.groupName,
                "output": [(tst.groupName, tst.groupPath)]}
    )

    for znodeStringDict in testTup:
        assert splitZnodeString(znodeStringDict['string']) == znodeStringDict['output']

def test_splitZnodeVarString():
    '''
    Test for splitZnodeVarString() parser.
    '''

    testTup = ({"string":"groupname1:hostname1,var1:val1,var2:val2,var3:val3",
                "output":{"groupname1":{"hostname1":{"var1":"val1", "var2":"val2", "var3":"val3"}}}},
               {"string":"kafka:kafka01,fqdn:kafka01.fqdn.com,ipv4:1.2.3.4,kafka-id:1",
                "output":{"kafka":{"kafka01":{"fqdn":"kafka01.fqdn.com","ipv4":"1.2.3.4","kafka-id":"1"}}}},
               {"string":"zoo:zoo-srv01,fqdn:zoo-srv01.fqdn.com,ipv4:2.3.4.5,zoo-id:1",
                "output":{"zoo":{"zoo-srv01":{"fqdn":"zoo-srv01.fqdn.com","ipv4":"2.3.4.5","zoo-id":"1"}}}}
    )

    for varDict in testTup:
        assert splitZnodeVarString(varDict['string']) == varDict['output']
<commit_msg>TESTS: moved splitter tests to TestSplitter class<commit_after>'''
Tests for ansibleKeeper
'''

__author__     = "Jan Kogut"
__copyright__  = "Jan Kogut"
__license__    = "MIT"
__version__    = "0.0.1"
__maintainer__ = "Jan Kogut"
__status__     = "Beta"

import pytest
import socket
from ansibleKeeper import *
from kazoo.client import KazooClient
from kazoo.handlers.threading import *
from kazoo.exceptions import *

## START of TestVars: global vars for tests
##################################################

class TestVars(object):
    ''' Test vars section '''
    pass

tst = TestVars()

tst.testDict  = {"testgroupname1":
                 {
                  "testhostname1":{"var1":"val1", "var2":"val2", "var3":"val3"},
                  "testhostname2":{"var1":"val11", "var2":"val22", "var3":"val33"},
                  "testhostname3":{"var1":"val111", "var2":"val222", "var3":"val333"}
                 }
}

tst.updateDict  = {"testgroupname1":
                 {
                  "testhostname1":{"var1":"valUpdated1", "var2":"valUpdated2", "var3":"valUpdated3"},
                  "testhostname2":{"var1":"valUpdated11", "var2":"valUpdated22", "var3":"valUpdated33"},
                  "testhostname3":{"var1":"valUpdated111", "var2":"valUpdated222", "var3":"valUpdated333"}
                 }
}

tst.groupName     = tst.testDict.keys()[0]                     ## ==> 'testgroupname1'
tst.hostName      = tst.testDict[tst.groupName].keys()[0]      ## ==> 'testhostname1'

tst.varDict       = tst.testDict[tst.groupName][tst.hostName]  ## ==> {'var1': 'val1', 'var3': 'val3', 'var2': 'val2'}
tst.oneDict       = {tst.groupName:{tst.hostName:tst.varDict}} ## ==> {'testgroupname1': {'testhostname1': {'var1': 'val1', 'var3': 'val3', 'var2': 'val2'}}}

tst.hostPath      = "{0}/hosts/{1}".format(cfg.aPath, tst.hostName)
tst.groupPath     = "{0}/groups/{1}".format(cfg.aPath, tst.groupName)
tst.hostGroupPath = "{0}/groups/{1}/{2}".format(cfg.aPath, tst.groupName, tst.hostName)

tst.groupHostStr  = "{0}:{1}".format(tst.groupName, tst.hostName) ## ==> 'testgroupname1:testhostname1'
tst.hostHostStr   = "hosts:{0}".format(tst.hostName)              ## ==> 'hosts:testhostname1'

#################################################
## END of TestVars: global vars for tests

class TestConfig(object):
    '''
    Suite of config tests with read-only zookeeper client connection.
    '''

    def test_zkClusterUp(self):
        '''
        Test if the zookeeper cluster is UP.
        We expect all servers are UP and port for zookeeper: 2181 is open.
        '''

        zkSrvList = cfg.zkServers.replace(':2181','').split(',')

        for srv in zkSrvList:
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                assert sock.connect_ex((srv,2181)) == 0

            finally:
                sock.close()

    @pytest.fixture
    def ro_zk(self):
        '''
        Fixture for zookeeper client connection in read-only mode.
        '''

        ## example server list string 'zoo1.dmz:2181,zoo2.dmz:2181,zoo3.dmz:2181'
        zk = KazooClient(hosts=cfg.zkServers, read_only = True)
        zk.start()

        return zk

    def test_configZkClusterConnection(self, ro_zk):
        '''
        Test if we can establish zookeeper client connection to zookeeper cluster servers.
        We expect at least one server runnig zookeeper.
        '''

        try:
            assert type(ro_zk).__name__ == 'KazooClient'

        finally:
            ro_zk.stop()

    def test_configZkServerConnection(self, ro_zk):
        '''
        Test if we can establish zookeeper client connection to each zookeeper server.
        We expect all of the servers are running zookeeper.
        '''

        ## example server list string 'zoo1.dmz:2181,zoo2.dmz:2181,zoo3.dmz:2181'
        zkSrvList = cfg.zkServers.split(',')

        for srv in zkSrvList:
            try:
                assert type(ro_zk).__name__ == 'KazooClient'

            except KazooTimeoutError as error:
                print("{0} check your connection with zookeeper server: {1} ").format(error, srv)

            finally:
                ro_zk.stop()

    def test_configBasePrefixZnode(self, ro_zk):
        '''
        Test if base prefix znode from config exists.
        '''

        try:
            assert ro_zk.exists(cfg.aPath) is not None

        finally:
            ro_zk.stop()

class TestReadWrite(object):
    '''
    Suite of tests where read-write zookeeper client connection is required.
    '''

    @pytest.fixture
    def rw_zk(self):
        '''
        Fixture for zookeeper client connection in read-write mode.
        '''

        ## example server list string 'zoo1.dmz:2181,zoo2.dmz:2181,zoo3.dmz:2181'
        zk = KazooClient(hosts=cfg.zkServers)
        zk.start()

        return zk

    def test_addHostWithHostvars(self, rw_zk):
        '''
        Test if hostname-znode added with addHostWithHostvars(var) exists.
        '''

        ## 1. check if Znode provided with test config exists
        ## 2. run addHostWithHostvars(var) function
        ## 3. check hostname value against tested values (from tst.testDict)
        ## 4. run twice deleteZnodeRecur(var) to remove hostname from groupname and hosts group

        if rw_zk.exists(tst.hostPath) is not None:
            rw_zk.delete(tst.hostPath, recursive=True)
            rw_zk.stop()

        addHostWithHostvars(tst.oneDict)

        try:
            assert rw_zk.exists(tst.hostPath) ## is not None

        finally:
            rw_zk.stop()

        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_addHostToGroup(self, rw_zk):
        '''
        Test if hostname-znode added with addHostToGroup(var) exists.
        '''

        ## 1. check if Znode provided with test config exists
        ## 2. run addHostWithHostvars(var) and addHostToGroup(var) functions
        ## 3. check if hostname added with addHostToGroup exists
        ## 4. run twice deleteZnodeRecur(var) to remove hostname from groupname and hosts group

        if rw_zk.exists(tst.groupPath) is not None:
            rw_zk.delete(tst.groupPath, recursive=True)
            rw_zk.stop()

        addHostWithHostvars(tst.oneDict)
        addHostToGroup(splitZnodeString(tst.groupHostStr))

        try:
            assert rw_zk.exists(tst.hostGroupPath) ## is not None

        finally:
            rw_zk.stop()

        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_deleteZnodeRecur(self, rw_zk):
        '''
        Test that znode deleted with deleteZnodeRecur(var) does not exist.
        '''

        ## 1. run addHostWithHostvars(var) function to add example Znode provided in test config
        ## 2. run twice deleteZnodeRecur(var) function to delete given Znode provided in test config
        ## 3. check Znode path against that string

        addHostWithHostvars(tst.oneDict)
        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

        try:
            assert rw_zk.exists(tst.hostPath) is None
            assert rw_zk.exists(tst.hostGroupPath) is None

        finally:
            rw_zk.stop()

    def test_deleteZnodeHostExistance(self):
        '''
        Test that deleteZnodeRecur() will inform us that we want to delete nonexistent Znode from hosts group.
        '''

        errStringHost  = 'ERROR  ==> could not delete host: {0} that does not exist !!!'.format(tst.hostName)

        assert deleteZnodeRecur(splitZnodeString(tst.hostHostStr)) == errStringHost

    def test_deleteZnodeHostInGroupExistance(self):
        '''
        Test that deleteZnodeRecur() will inform us that we want to delete nonexistent Znode from groups/groupname group.
        '''

        errStringGroup  = 'ERROR  ==> could not delete host: {0} that does not exist in group: {1} !!!'.format(tst.hostName, tst.groupName)

        addHostWithHostvars(tst.oneDict)
        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))

        assert deleteZnodeRecur(splitZnodeString(tst.groupHostStr)) == errStringGroup

        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_deleteZnodeRecurGroup(self, rw_zk):
        '''
        Test that znode deleted with deleteZnodeRecur(var) for groupname does not exist.
        '''

        ## 1. run addHostWithHostvars(var) function to create given Znode provided in tst.oneDict
        ## 2. run deleteZnodeRecur(var) function to delete given Znode provided in tst.groupName
        ## 3. check Znode path against that string
        ## 4. delete hostname Znode in hosts group with deleteZnodeRecur(var)

        addHostWithHostvars(tst.oneDict)
        deleteZnodeRecur(splitZnodeString(tst.groupName))

        try:
            assert rw_zk.exists(tst.groupPath) is None

        finally:
            rw_zk.stop()

        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    def test_hostVarsShowOneHost(self):
        '''
        Test hostVarsShow() function for group with one host.
        '''

        ## 1. run addHostWithHostvars(var) function to create given Znode with vars provided in tst.oneDict
        ## 2. test showHostVars(var) against vars and values provided in tst.oneDict
        ## 3. run deleteZnodeRecur(var) function to delete given Znode provided in tst.hostHostStr

        addHostWithHostvars(tst.oneDict)

        testList = [(tst.hostHostStr,{tst.hostName:tst.varDict}),(tst.groupName, tst.oneDict[tst.groupName])]

        for val in testList:
            assert showHostVars(splitZnodeString(val[0])) == val[1]

        deleteZnodeRecur(splitZnodeString(tst.groupHostStr))
        deleteZnodeRecur(splitZnodeString(tst.hostHostStr))

    # def test_hostVarsShowMultipleHosts(self):
    #     '''
    #     Test hostVarsShow() function for group with multiple hosts.
    #     '''

    #     ## 1. run addHostWithHostvars(var) function to create given Znode with vars provided in tst.oneDict
    #     ## 2. test showHostVars(var) against vars and values provided in tst.testDict
    #     ## 3. run deleteGroupZnode(var) function to delete given Znode provided in tst.hostHostStr

    #     for hostname in tst.testDict[tst.groupName].keys():
    #         tmpDict = {tst.groupName : { hostname : tst.testDict[tst.groupName][hostname] }}
    #         addHostWithHostvars(tmpDict)

    #     testList = [(tst.hostHostStr, {tst.hostName:tst.varDict}),(tst.groupName, tst.testDict[tst.groupName])]

    #     for val in testList:
    #         assert showHostVars(splitZnodeString(val[0])) == val[1]

    #     delete all hosts in group created with addHostWithHostvars(var)
    #     deleteZnodeRecur(splitZnodeString(tst.groupName))
    #     for hostname in  tst.testDict[tst.groupName].keys():
    #         tmpHostStr = "hosts:{}".format(hostname)
    #         deleteZnodeRecur(splitZnodeString(tmpHostStr))

    # # def test_updateZnode():
    # #     '''
    # #     Test updated Znode with updateZnode(var).
    # #     '''

    # #     ## 1. run addHostWithHostvars(var) function to create given Znode provided in tst.testDict
    # #     ## 2. run updateZnode(var) function to update given Znode provided in tst.updateDict
    # #     ## 3. check upated results against tst.updateDict
    # #     ## 4. run deleteZnodeRecur(var) function to delete given Znode provided in tst.hostHostStr

    # #     addHostWithHostvars(tst.testDict)
    # #     updateZnode(tst.updateDict)

    # #     zk = KazooClient(hosts=cfg.zkServers)
    # #     zk.start()

    # #     for key in tst.updateDict[tst.groupName][tst.hostName].keys():
    # #         zkGet     = zk.get('{0}/{1}'.format(tst.hostGroupPath, key))[0]
    # #         updateValue = tst.updateDict[tst.groupName][tst.hostName][key]
    # #         assert zkGet == testValue

    # #         zk.stop()

    # #     deleteZnodeRecur(splitZnodeString(tst.groupName))

class TestSplitters(object):
    '''
    Suite of tests splitter functions
    '''

    def test_splitZnodeString(self):
        '''
        Test for splitZnodeString() parser.
        '''

        testTup = ({"string": tst.groupHostStr,
                    "output": [(tst.groupName, tst.groupPath), (tst.hostName, tst.hostPath, tst.hostGroupPath)]},
                   {"string": tst.hostHostStr,
                    "output": [(tst.hostName, tst.hostPath, None)]},
                   {"string": tst.groupName,
                    "output": [(tst.groupName, tst.groupPath)]}
        )

        for znodeStringDict in testTup:
            assert splitZnodeString(znodeStringDict['string']) == znodeStringDict['output']

    def test_splitZnodeVarString(self):
        '''
        Test for splitZnodeVarString() parser.
        '''

        testTup = ({"string":"groupname1:hostname1,var1:val1,var2:val2,var3:val3",
                    "output":{"groupname1":{"hostname1":{"var1":"val1", "var2":"val2", "var3":"val3"}}}},
                   {"string":"kafka:kafka01,fqdn:kafka01.fqdn.com,ipv4:1.2.3.4,kafka-id:1",
                    "output":{"kafka":{"kafka01":{"fqdn":"kafka01.fqdn.com","ipv4":"1.2.3.4","kafka-id":"1"}}}},
                   {"string":"zoo:zoo-srv01,fqdn:zoo-srv01.fqdn.com,ipv4:2.3.4.5,zoo-id:1",
                    "output":{"zoo":{"zoo-srv01":{"fqdn":"zoo-srv01.fqdn.com","ipv4":"2.3.4.5","zoo-id":"1"}}}}
        )

        for varDict in testTup:
            assert splitZnodeVarString(varDict['string']) == varDict['output']
<|endoftext|>


<commit_before>from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import Config
from selenium.webdriver.common.action_chains import ActionChains

class Scraper(object):

    def __init__(self):
        options = webdriver.ChromeOptions()
        options.add_argument('headless')
        self.browser = webdriver.Chrome(chrome_options=options)
        self.browser.implicitly_wait(10)
        self.login()

    def login(self):
        self.browser.get('https://leetcode.com/accounts/github/login/')

        emailField = self.browser.find_element_by_id('login_field')
        passField = self.browser.find_element_by_id('password')

        emailField.send_keys(Config.user)
        passField.send_keys(Config.password)

        submitButton = self.browser.find_element_by_css_selector('.btn.btn-primary.btn-block')
        submitButton.click()
        self.browser.get('https://leetcode.com/jspsun/')

    def getQuestionsSolved(self):
        return list(map(lambda n: int(n), self.browser.find_elements_by_css_selector('.progress-bar-success')[3].text.split('/')))

    def getStars(self):
        stars = self.browser.find_element_by_css_selector('.ranking')
        ActionChains(self.browser).move_to_element(stars)

    # incomplete
    def getRanking(self):
        return 1

    def cleanup(self):
        self.browser.close()
<commit_msg>added files<commit_after>from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import Config
from selenium.webdriver.common.action_chains import ActionChains

class Scraper(object):

    def __init__(self):
        options = webdriver.ChromeOptions()
        # options.add_argument('headless')
        self.browser = webdriver.Chrome(chrome_options=options)
        self.browser.implicitly_wait(10)
        self.login()

    def login(self):
        self.browser.get('https://leetcode.com/accounts/github/login/')

        emailField = self.browser.find_element_by_id('login_field')
        passField = self.browser.find_element_by_id('password')

        emailField.send_keys(Config.user)
        passField.send_keys(Config.password)

        submitButton = self.browser.find_element_by_css_selector('.btn.btn-primary.btn-block')
        submitButton.click()
        self.browser.get('https://leetcode.com/jspsun/')

    def getQuestionsSolved(self):
        return list(map(lambda n: int(n), self.browser.find_elements_by_css_selector('.progress-bar-success')[3].text.split('/')))

    def getStars(self):
        stars = self.browser.find_element_by_css_selector('.ranking')
        ActionChains(self.browser).move_to_element(stars)

    # incomplete
    def getRanking(self):
        return 1

    def cleanup(self):
        self.browser.close()
<|endoftext|>


<commit_before>#!/usr/bin/env python3

from passwd_change import passwd_change, shadow_change, mails_delete

from unittest import TestCase, TestLoader, TextTestRunner
import os
import subprocess

class PasswdChange_Test(TestCase):
    def setUp(self):
        """
        Preconditions
        """
        subprocess.call(['mkdir', 'test'])
        subprocess.call(['touch', 'test/rvv', 'test/max',
                         'test/bdv' ,'test/mail'])
        #TODO create passwd test file
        #TODO create shadow test file
        #TODO create keys.txt file

    def tearDown(self):
        try:
            if os.path.exists('test/rvv'):
                raise Exception('test/rvv must not exist')
            if not (os.path.exists('test/max') and
                    os.path.exists('test/bdv') and
                    os.path.exists('test/mail')):
                raise Exception('File max, bdv or mail must exist!')
        except:
            raise
        else:
            subprocess.call(['rm', '-r', 'test/'])

    def test_passwd_change(self):
        shadow_change(*passwd_change())
        mails_delete(maildir_path='test')

    def test_passwd_change_2(self):
        shadow_change(*passwd_change())
        mails_delete(maildir_path='test/')

suite = TestLoader().loadTestsFromTestCase(PasswdChange_Test)
TextTestRunner(verbosity=2).run(suite)
<commit_msg>Add passwd, shadow, keys test files. Change exception behaviour - add finally.<commit_after>#!/usr/bin/env python3

from passwd_change import passwd_change, shadow_change, mails_delete

from unittest import TestCase, TestLoader, TextTestRunner
import os
import subprocess

class PasswdChange_Test(TestCase):
    def setUp(self):
        """
        Preconditions
        """
        subprocess.call(['mkdir', 'test'])
        subprocess.call(['touch', 'test/test', 'test/max',
                         'test/root', 'test/mail', 'test/test_alive'])
        # Create passwd test file
        with open('passwd_test', 'w') as pt:
            pt.write('root:x:0:0:root:/dir:/shell\n')
            pt.write('max:x:1234:777:Account Max:/home/max:/bin/bash\n')
            pt.write('mail:x:8:12:mail:/var/spool/mail:/sbin/nologin\n')
            pt.write('test:x:9:12:test for deleting:/maildir:/shell\n')
            pt.write('test_alive:x:9:12:test NOT deleting:/maildir:/shell\n')
        # Create shadow test file
        with open('shadow_test', 'w') as st:
            st.write('root:testhash:12345:6:7777:8:::\n')
            st.write('max:testhash:12345:6:7777:8:::\n')
            st.write('mail:testhash:12345:6:7777:8:::\n')
            st.write('test:testhash:12345:6:7777:8:::\n')
            st.write('test_alive:testhash:12345:6:7777:8:::\n')
        # Create keys.txt file
        with open('keys_test.txt', 'w') as kt:
            kt.write('test_alive\n')
            kt.write('mail\n')
            kt.write('missing_name\n')

    def tearDown(self):
        try:
            if os.path.exists('test/test'):
                raise Exception('test/test must not exist')
            if not (os.path.exists('test/max') and
                    os.path.exists('test/root') and
                    os.path.exists('test/mail') and
                    os.path.exists('test/test_alive')):
                raise Exception('File test_alive, max, root, mail must exist!')
        except Exception:
            raise
        finally:
            subprocess.call(['rm', '-r', 'test/'])

    def test_passwd_change(self):
        shadow_change(*passwd_change(keys_file='keys_test.txt',
                      passwd_orig='passwd_test', passwd_new='passwd_test_new',
                      passwd_log='passwd_test.log',
                      missing_log='missing_test.log'),
                      shadow_orig='shadow_test', shadow_new='shadow_test_new',
                      shadow_log='shadow_test.log')
        mails_delete(passwd_log='passwd_test.log', maildir_path='test')

    def test_passwd_change_2(self):
        shadow_change(*passwd_change(keys_file='keys_test.txt',
                       passwd_orig='passwd_test', passwd_new='passwd_test_new',
                       passwd_log='passwd_test.log',
                       missing_log='missing_test.log'),
                       shadow_orig='shadow_test', shadow_new='shadow_test_new',
                       shadow_log='shadow_test.log')
        mails_delete(passwd_log='passwd_test.log', maildir_path='test/')

suite = TestLoader().loadTestsFromTestCase(PasswdChange_Test)
TextTestRunner(verbosity=2).run(suite)
<|endoftext|>


<commit_before>from ._utils import *

from .. import utils

class get_configured_item_model(TestCase):
    def test_returns_configured_model(self):
        m = "%s.FooBar" % self.__class__.__module__
        with override_settings(ARMSTRONG_SECTION_ITEM_MODEL=m):
            module, model = utils.get_module_and_model_names()
            self.assertEqual(self.__class__.__module__, module)
            self.assertEqual("FooBar", model)

    def test_provides_default_value(self):
        with override_settings(ARMSTRONG_SECTION_ITEM_MODEL=False):
            module, model = utils.get_module_and_model_names()
            self.assertEqual("armstrong.apps.content.models", module)
            self.assertEqual("Content", model)
<commit_msg>Add TestCase suffix<commit_after>from ._utils import *

from .. import utils

class get_configured_item_modelTestCase(TestCase):
    def test_returns_configured_model(self):
        m = "%s.FooBar" % self.__class__.__module__
        with override_settings(ARMSTRONG_SECTION_ITEM_MODEL=m):
            module, model = utils.get_module_and_model_names()
            self.assertEqual(self.__class__.__module__, module)
            self.assertEqual("FooBar", model)

    def test_provides_default_value(self):
        with override_settings(ARMSTRONG_SECTION_ITEM_MODEL=False):
            module, model = utils.get_module_and_model_names()
            self.assertEqual("armstrong.apps.content.models", module)
            self.assertEqual("Content", model)
<|endoftext|>


<commit_before>###############################################################################
##
##  Copyright (C) 2012-2013 Tavendo GmbH
##
##  Licensed under the Apache License, Version 2.0 (the "License");
##  you may not use this file except in compliance with the License.
##  You may obtain a copy of the License at
##
##      http://www.apache.org/licenses/LICENSE-2.0
##
##  Unless required by applicable law or agreed to in writing, software
##  distributed under the License is distributed on an "AS IS" BASIS,
##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
##  See the License for the specific language governing permissions and
##  limitations under the License.
##
###############################################################################

import six

## use Cython implementation of XorMasker validator if available
##
try:
   from wsaccel.xormask import XorMaskerNull, createXorMasker

except ImportError:
   ## fallback to pure Python implementation

   ## http://stackoverflow.com/questions/15014310/python3-xrange-lack-hurts
   try:
      xrange
   except NameError:
      ## Python 3
      # noinspection PyShadowingBuiltins
      xrange = range

   from array import array

   class XorMaskerNull:

      # noinspection PyUnusedLocal
      def __init__(self, mask = None):
         self.ptr = 0

      def pointer(self):
         return self.ptr

      def reset(self):
         self.ptr = 0

      def process(self, data):
         self.ptr += len(data)
         return data

   class XorMaskerSimple:

      def __init__(self, mask):
         assert len(mask) == 4
         self.ptr = 0
         self.msk = array('B', mask)

      def pointer(self):
         return self.ptr

      def reset(self):
         self.ptr = 0

      def process(self, data):
         dlen = len(data)
         payload = array('B', data)
         for k in xrange(dlen):
            payload[k] ^= self.msk[self.ptr & 3]
            self.ptr += 1
         return payload.tostring()

   class XorMaskerShifted1:

      def __init__(self, mask):
         assert len(mask) == 4
         self.ptr = 0
         self.mskarray = [array('B'), array('B'), array('B'), array('B')]
         if six.PY3:
            for j in xrange(4):
               self.mskarray[0].append(mask[ j & 3])
               self.mskarray[1].append(mask[(j + 1) & 3])
               self.mskarray[2].append(mask[(j + 2) & 3])
               self.mskarray[3].append(mask[(j + 3) & 3])
         else:
            for j in xrange(4):
               self.mskarray[0].append(ord(mask[ j & 3]))
               self.mskarray[1].append(ord(mask[(j + 1) & 3]))
               self.mskarray[2].append(ord(mask[(j + 2) & 3]))
               self.mskarray[3].append(ord(mask[(j + 3) & 3]))

      def pointer(self):
         return self.ptr

      def reset(self):
         self.ptr = 0

      def process(self, data):
         dlen = len(data)
         payload = array('B', data)
         msk = self.mskarray[self.ptr & 3]
         for k in xrange(dlen):
            payload[k] ^= msk[k & 3]
         self.ptr += dlen
         return payload.tostring()

   def createXorMasker(mask, length = None):
      if length is None or length < 128:
         return XorMaskerSimple(mask)
      else:
         return XorMaskerShifted1(mask)
<commit_msg>xrange produces warning on Python 3 (fixes #319)<commit_after>###############################################################################
##
##  Copyright (C) 2012-2015 Tavendo GmbH
##
##  Licensed under the Apache License, Version 2.0 (the "License");
##  you may not use this file except in compliance with the License.
##  You may obtain a copy of the License at
##
##      http://www.apache.org/licenses/LICENSE-2.0
##
##  Unless required by applicable law or agreed to in writing, software
##  distributed under the License is distributed on an "AS IS" BASIS,
##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
##  See the License for the specific language governing permissions and
##  limitations under the License.
##
###############################################################################

import six

## use Cython implementation of XorMasker validator if available
##
try:
   from wsaccel.xormask import XorMaskerNull, createXorMasker

except ImportError:
   ## fallback to pure Python implementation

   ## http://stackoverflow.com/questions/15014310/python3-xrange-lack-hurts
   try:
      xrange
   except NameError:
      ## Python 3
      # noinspection PyShadowingBuiltins
      xrange = range

   from array import array

   class XorMaskerNull:

      # noinspection PyUnusedLocal
      def __init__(self, mask = None):
         self.ptr = 0

      def pointer(self):
         return self.ptr

      def reset(self):
         self.ptr = 0

      def process(self, data):
         self.ptr += len(data)
         return data

   class XorMaskerSimple:

      def __init__(self, mask):
         assert len(mask) == 4
         self.ptr = 0
         self.msk = array('B', mask)

      def pointer(self):
         return self.ptr

      def reset(self):
         self.ptr = 0

      def process(self, data):
         dlen = len(data)
         payload = array('B', data)
         for k in xrange(dlen):
            payload[k] ^= self.msk[self.ptr & 3]
            self.ptr += 1
         if six.PY3:
            return payload.tobytes()
         else:
            return payload.tostring()

   class XorMaskerShifted1:

      def __init__(self, mask):
         assert len(mask) == 4
         self.ptr = 0
         self.mskarray = [array('B'), array('B'), array('B'), array('B')]
         if six.PY3:
            for j in xrange(4):
               self.mskarray[0].append(mask[ j & 3])
               self.mskarray[1].append(mask[(j + 1) & 3])
               self.mskarray[2].append(mask[(j + 2) & 3])
               self.mskarray[3].append(mask[(j + 3) & 3])
         else:
            for j in xrange(4):
               self.mskarray[0].append(ord(mask[ j & 3]))
               self.mskarray[1].append(ord(mask[(j + 1) & 3]))
               self.mskarray[2].append(ord(mask[(j + 2) & 3]))
               self.mskarray[3].append(ord(mask[(j + 3) & 3]))

      def pointer(self):
         return self.ptr

      def reset(self):
         self.ptr = 0

      def process(self, data):
         dlen = len(data)
         payload = array('B', data)
         msk = self.mskarray[self.ptr & 3]
         for k in xrange(dlen):
            payload[k] ^= msk[k & 3]
         self.ptr += dlen
         if six.PY3:
            return payload.tobytes()
         else:
            return payload.tostring()

   def createXorMasker(mask, length = None):
      if length is None or length < 128:
         return XorMaskerSimple(mask)
      else:
         return XorMaskerShifted1(mask)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#  Copyright (c) 2008, Martin W. Kirst 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.
#
#  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
#  HOLDER 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.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
  ASCII art movie Telnet player.
  Version         : 0.1

  Can stream an ~20 minutes ASCII movie via Telnet emulation
  as stand alone server or via xinetd daemon.
  Tested with Python 2.3, Python 2.5, Python 2.7

  Original art work : Simon Jansen ( http://www.asciimation.co.nz/ )
  Telnetification
  & Player coding   : Martin W. Kirst ( https://github.com/nitram509/ascii-telnet-server )
"""

from __future__ import division, print_function

import os
import sys
import time
from io import BytesIO
from optparse import OptionParser

try:
    # noinspection PyCompatibility
    from socketserver import StreamRequestHandler, ThreadingTCPServer
except ImportError:  # Py2
    # noinspection PyCompatibility,PyUnresolvedReferences
    from SocketServer import StreamRequestHandler, ThreadingTCPServer

MAXDIM = (80, 24)  # maximum dimension of the VT100 terminal

class VT100Codes(object):
    """
        Some escape codes used within VT100 Streams
        @see: http://ascii-table.com/ansi-escape-sequences-vt-100.php
    """
    ESC = chr(27)  # VT100 escape character constant
    JMPHOME = ESC + "[H"  # Move cursor to upper left corner
    CLEARSCRN = ESC + "[2J"  # Clear entire screen
    CLEARDOWN = ESC + "[J"  # Clear screen from cursor down

    def JMPXY(self, x, y):
        """
        Send VT100 commands: goto position X,Y

        Args:
            x (int): x coordinate (starting at 1)
            y (int): y coordinate (starting at 1)

        Returns:
            str: the VT100 code as a string

        """
        if 0 >= x > MAXDIM[0] or 0 >= y > MAXDIM[1]:
            sys.stderr.write("Warning, coordinates out of range. ({}, {})\n".format(x, y))
            return
        else:
            return (self.ESC + "[{0};{1}H".format(y, x)).encode()

class Frame(object):
    """
        One frame is 67 columns and 13 rows in effective size on screen.
        Use 'displayTime' to get the frame cycles this specific frame should
        be displayed.
        Use 'data' to get the 13 lines.
    """

    def __init__(self):
        self.displayTime = 1  # number of frame cycles to display this frame, default 1
        self.data = []  # 13 lines

class Movie(object):
    """
        A movie consists of frames and is empty by default.
        Movies are loaded from text files.
        Use 'dimension' to get the dimension of the movie.
        A movie only can be loaded once. A second try will fail.
    """

    def __init__(self):
        self._frames = []
        self._loaded = False
        self.dimension = (67, 13)
        f = Frame()
        f.data.append("No movie yet loaded.")
        self._frames.append(f)

    def loadMovie(self, filepath):
        """
            Loads the ASCII movie from given text file.
            Using an encoded format, described on
            http://www.asciimation.co.nz/asciimation/ascii_faq.html
            In short:
            67x14 chars,
            lines separated with 0x0a,
            first line is a number telling delay in number of frames,
            13 lines effective movie size,
            15 frames per second,
        """
        if self._loaded:
            # we don't want to be loaded twice.
            return False
        self._frames = []
        current_frame = None
        max_lines_per_frame = self.dimension[1] + 1  # incl. meta data (time information)
        max_width = self.dimension[0]

        with open(filepath) as f:
            for counter, line in enumerate(f):
                i = -1
                if (counter % max_lines_per_frame) == 0:
                    i = int(line[0:3])
                if len(line.strip()) <= 3 and 0 < i <= 999:
                    current_frame = Frame()
                    current_frame.data = []
                    current_frame.displayTime = i
                    self._frames.append(current_frame)
                else:
                    if current_frame:
                        # first strip every white character from the right
                        line = line.rstrip()
                        # second fill them with blanks, that they later
                        # automatically clear old lines from screen
                        line = line.ljust(max_width)
                        # to center the frame on the screen, we also add some
                        # BLANKs on the left side
                        line = line.rjust(max_width + (MAXDIM[0] - max_width) // 2)
                        current_frame.data.append(line)
        self._loaded = True
        return True

    def getEncFrames(self):
        """
            return a list with frames.
            Each frame carries its own display time, thats why it's 'encoded'.
        """
        return self._frames

class TelnetRequestHandler(StreamRequestHandler):
    """
        Request handler used for multi threaded TCP server
        @see: SocketServer.StreamRequestHandler
    """

    filename = None  # filename is set once, so it's immutable and safe for multi threading

    def handle(self):
        movie = Movie()
        movie.loadMovie(TelnetRequestHandler.filename)
        player = VT100Player(movie)
        player.onNextFrame = self.onNextFrame
        player.play()

    def onNextFrame(self, screen_buffer):
        """
            Gets the current screen buffer and writes it to the socket.
        """
        self.wfile.write(screen_buffer.read())

class VT100Player(object):
    """
        Player class plays a movie. Offers higher methods for play, stop,
        fast forward and rewind on the movie. It also stores the current
        position.
        It exposes the all frame numbers in real values. Therefore not encoded.
    """
    _TIMEBAR = " <" + " " * (MAXDIM[0] - 4) + ">"

    def __init__(self, movie):
        self._movie = movie
        self._movCursor = 0  # virtual cursor pointing to the current frame
        self._maxFrames = 0
        for f in self._movie.getEncFrames():
            self._maxFrames += f.displayTime

    def getDuration(self):
        """
            return the number of seconds this movie is playing
        """
        return self._maxFrames // 15  # 15 frames per second

    def play(self):
        """
            plays the movie
        """
        for frame in self._movie.getEncFrames():
            self._movCursor += frame.displayTime
            self._onNextFrameInternal(frame, self._movCursor)
            time.sleep(frame.displayTime // 15.0)

    def _onNextFrameInternal(self, frame, frame_pos):
        """
            internal event, happen when next frame should be drawn
        """
        screenbuf = BytesIO()
        if frame_pos <= 1:
            screenbuf.write(VT100Codes.CLEARSCRN)
        # center vertical, with respect to the time bar
        y = (MAXDIM[1] - 1 - self._movie.dimension[1]) // 2

        screenbuf.write(VT100Codes().JMPXY(1, y))
        for line in frame.data:
            screenbuf.write((line + "\r\n").encode())
        self._updateTimeBar(screenbuf, frame_pos, self._maxFrames)
        # now rewind the internal buffer and fire the public event
        screenbuf.seek(0)
        self.onNextFrame(screenbuf)

    def onNextFrame(self, screen_buffer):
        """
        Public event method, which can be used to get new Screens.

        Args:
            screen_buffer:  its a file like object containing the VT100 screen buffer

        Returns:

        """
        pass

    def _updateTimeBar(self, screen_buffer, current_value, max_size=10):
        """
            Writes at the bottom of the screen a line like this
            <.......o.....................>
            Left and right are one blank spaces from the max screen dimensions
            It should visualize a timeline with 'o' is the current position.

        Args:
            screen_buffer: file like object, where the data is written to
            current_value: current value
            max_size: maximum value

        Returns:

        """
        screen_buffer.write(VT100Codes().JMPXY(1, MAXDIM[1]))
        screen_buffer.write(self._TIMEBAR.encode())  #
        # now some weird calculations incl. some tricks to avoid rounding errors.
        x = min(((current_value * (MAXDIM[0] - 4)) // (max_size - 1)), (MAXDIM[0] - 4 - 1))
        screen_buffer.write(VT100Codes().JMPXY(x + 3, MAXDIM[1]))
        screen_buffer.write(b"o")

def runTcpServer(interface, port, filename):
    """
    Args:
        interface:  bind to this interface
        port: bind to this port
        filename: file name of the ASCII movie

    Returns:

    """
    TelnetRequestHandler.filename = filename
    server = ThreadingTCPServer((interface, port), TelnetRequestHandler)
    server.serve_forever()

def onNextFrameStdOut(screen_buffer):
    sys.stdout.write(screen_buffer.read().decode('iso-8859-15'))

def runStdOut(filename):
    """
    Args:
        filename: file name of the ASCII movie

    Returns:

    """

    sys.stdout.write(VT100Codes.CLEARSCRN)
    movie = Movie()
    movie.loadMovie(filename)
    player = VT100Player(movie)
    player.onNextFrame = onNextFrameStdOut
    player.play()

########
# MAIN #
########

if __name__ == "__main__":
    usage = "Usage: %prog [options]"
    parser = OptionParser(usage=usage)
    parser.add_option("", "--standalone", dest="tcpserv", action="store_true",
                      help="Run as stand alone multi threaded TCP server (default)")
    parser.add_option("", "--stdout", dest="tcpserv", action="store_false",
                      help="Run with STDIN and STDOUT, for example in XINETD " +
                           "instead of stand alone TCP server. " +
                           "Use with python option '-u' for unbuffered " +
                           "STDIN STDOUT communication")
    parser.add_option("-f", "--file", dest="filename", metavar="FILE",
                      help="Text file containing the ASCII movie")
    parser.add_option("-i", "--interface", dest="interface",
                      help="Bind to this interface (default '0.0.0.0', all interfaces)",
                      default="0.0.0.0")
    parser.add_option("-p", "--port", dest="port", metavar="PORT",
                      help="Bind to this port (default 23, Telnet)",
                      default=23, type="int")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
                      help="Verbose (default for TCP server)")
    parser.add_option("-q", "--quiet", action="store_false", dest="verbose",
                      help="Quiet! (default for STDIN STDOUT server)")
    parser.set_defaults(interface="0.0.0.0",
                        port=23,
                        tcpserv=True,
                        verbose=True, )
    (options, args) = parser.parse_args()

    if not (options.filename and os.path.exists(options.filename)):
        parser.exit(1, "Error, file not found! See --help for details.\n")

    if options.tcpserv:
        if options.verbose:
            print("Running TCP server on {0}:{1}".format(options.interface, options.port))
            print("Playing movie {0}".format(options.filename))
        runTcpServer(options.interface, options.port, options.filename)
    else:
        runStdOut(options.filename)

    sys.exit(0)
<commit_msg>Fix time bug with new division changes<commit_after>#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#  Copyright (c) 2008, Martin W. Kirst 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.
#
#  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
#  HOLDER 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.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
  ASCII art movie Telnet player.
  Version         : 0.1

  Can stream an ~20 minutes ASCII movie via Telnet emulation
  as stand alone server or via xinetd daemon.
  Tested with Python 2.3, Python 2.5, Python 2.7

  Original art work : Simon Jansen ( http://www.asciimation.co.nz/ )
  Telnetification
  & Player coding   : Martin W. Kirst ( https://github.com/nitram509/ascii-telnet-server )
"""

from __future__ import division, print_function

import os
import sys
import time
from io import BytesIO
from optparse import OptionParser

try:
    # noinspection PyCompatibility
    from socketserver import StreamRequestHandler, ThreadingTCPServer
except ImportError:  # Py2
    # noinspection PyCompatibility,PyUnresolvedReferences
    from SocketServer import StreamRequestHandler, ThreadingTCPServer

MAXDIM = (80, 24)  # maximum dimension of the VT100 terminal

class VT100Codes(object):
    """
        Some escape codes used within VT100 Streams
        @see: http://ascii-table.com/ansi-escape-sequences-vt-100.php
    """
    ESC = chr(27)  # VT100 escape character constant
    JMPHOME = ESC + "[H"  # Move cursor to upper left corner
    CLEARSCRN = ESC + "[2J"  # Clear entire screen
    CLEARDOWN = ESC + "[J"  # Clear screen from cursor down

    def JMPXY(self, x, y):
        """
        Send VT100 commands: goto position X,Y

        Args:
            x (int): x coordinate (starting at 1)
            y (int): y coordinate (starting at 1)

        Returns:
            str: the VT100 code as a string

        """
        if 0 >= x > MAXDIM[0] or 0 >= y > MAXDIM[1]:
            sys.stderr.write("Warning, coordinates out of range. ({}, {})\n".format(x, y))
            return
        else:
            return (self.ESC + "[{0};{1}H".format(y, x)).encode()

class Frame(object):
    """
        One frame is 67 columns and 13 rows in effective size on screen.
        Use 'displayTime' to get the frame cycles this specific frame should
        be displayed.
        Use 'data' to get the 13 lines.
    """

    def __init__(self):
        self.displayTime = 1  # number of frame cycles to display this frame, default 1
        self.data = []  # 13 lines

class Movie(object):
    """
        A movie consists of frames and is empty by default.
        Movies are loaded from text files.
        Use 'dimension' to get the dimension of the movie.
        A movie only can be loaded once. A second try will fail.
    """

    def __init__(self):
        self._frames = []
        self._loaded = False
        self.dimension = (67, 13)
        f = Frame()
        f.data.append("No movie yet loaded.")
        self._frames.append(f)

    def loadMovie(self, filepath):
        """
            Loads the ASCII movie from given text file.
            Using an encoded format, described on
            http://www.asciimation.co.nz/asciimation/ascii_faq.html
            In short:
            67x14 chars,
            lines separated with 0x0a,
            first line is a number telling delay in number of frames,
            13 lines effective movie size,
            15 frames per second,
        """
        if self._loaded:
            # we don't want to be loaded twice.
            return False
        self._frames = []
        current_frame = None
        max_lines_per_frame = self.dimension[1] + 1  # incl. meta data (time information)
        max_width = self.dimension[0]

        with open(filepath) as f:
            for counter, line in enumerate(f):
                time_metadata = -1
                if (counter % max_lines_per_frame) == 0:
                    time_metadata = int(line[0:3])
                if 0 < time_metadata <= 999:
                    current_frame = Frame()
                    current_frame.displayTime = time_metadata
                    self._frames.append(current_frame)
                else:
                    if current_frame:
                        # first strip every white character from the right
                        line = line.rstrip()
                        # second fill them with blanks, that they later
                        # automatically clear old lines from screen
                        line = line.ljust(max_width)
                        # to center the frame on the screen, we also add some
                        # BLANKs on the left side
                        line = line.rjust(max_width + (MAXDIM[0] - max_width) // 2)
                        current_frame.data.append(line)
        self._loaded = True
        return True

    def getEncFrames(self):
        """
            return a list with frames.
            Each frame carries its own display time, thats why it's 'encoded'.
        """
        return self._frames

class TelnetRequestHandler(StreamRequestHandler):
    """
        Request handler used for multi threaded TCP server
        @see: SocketServer.StreamRequestHandler
    """

    filename = None  # filename is set once, so it's immutable and safe for multi threading

    def handle(self):
        movie = Movie()
        movie.loadMovie(TelnetRequestHandler.filename)
        player = VT100Player(movie)
        player.onNextFrame = self.onNextFrame
        player.play()

    def onNextFrame(self, screen_buffer):
        """
            Gets the current screen buffer and writes it to the socket.
        """
        self.wfile.write(screen_buffer.read())

class VT100Player(object):
    """
        Player class plays a movie. Offers higher methods for play, stop,
        fast forward and rewind on the movie. It also stores the current
        position.
        It exposes the all frame numbers in real values. Therefore not encoded.
    """
    _TIMEBAR = " <" + " " * (MAXDIM[0] - 4) + ">"

    def __init__(self, movie):
        self._movie = movie
        self._movCursor = 0  # virtual cursor pointing to the current frame
        self._maxFrames = 0
        for f in self._movie.getEncFrames():
            self._maxFrames += f.displayTime

    def getDuration(self):
        """
            return the number of seconds this movie is playing
        """
        return self._maxFrames // 15  # 15 frames per second

    def play(self):
        """
            plays the movie
        """
        for frame in self._movie.getEncFrames():
            self._movCursor += frame.displayTime
            self._onNextFrameInternal(frame, self._movCursor)
            time.sleep(frame.displayTime / 15)

    def _onNextFrameInternal(self, frame, frame_pos):
        """
            internal event, happen when next frame should be drawn
        """
        screenbuf = BytesIO()
        if frame_pos <= 1:
            screenbuf.write(VT100Codes.CLEARSCRN)
        # center vertical, with respect to the time bar
        y = (MAXDIM[1] - 1 - self._movie.dimension[1]) // 2

        screenbuf.write(VT100Codes().JMPXY(1, y))
        for line in frame.data:
            screenbuf.write((line + "\r\n").encode())
        self._updateTimeBar(screenbuf, frame_pos, self._maxFrames)
        # now rewind the internal buffer and fire the public event
        screenbuf.seek(0)
        self.onNextFrame(screenbuf)

    def onNextFrame(self, screen_buffer):
        """
        Public event method, which can be used to get new Screens.

        Args:
            screen_buffer:  its a file like object containing the VT100 screen buffer

        Returns:

        """
        pass

    def _updateTimeBar(self, screen_buffer, current_value, max_size=10):
        """
            Writes at the bottom of the screen a line like this
            <.......o.....................>
            Left and right are one blank spaces from the max screen dimensions
            It should visualize a timeline with 'o' is the current position.

        Args:
            screen_buffer: file like object, where the data is written to
            current_value: current value
            max_size: maximum value

        Returns:

        """
        screen_buffer.write(VT100Codes().JMPXY(1, MAXDIM[1]))
        screen_buffer.write(self._TIMEBAR.encode())  #
        # now some weird calculations incl. some tricks to avoid rounding errors.
        x = min(((current_value * (MAXDIM[0] - 4)) // (max_size - 1)), (MAXDIM[0] - 4 - 1))
        screen_buffer.write(VT100Codes().JMPXY(x + 3, MAXDIM[1]))
        screen_buffer.write(b"o")

def runTcpServer(interface, port, filename):
    """
    Args:
        interface:  bind to this interface
        port: bind to this port
        filename: file name of the ASCII movie

    Returns:

    """
    TelnetRequestHandler.filename = filename
    server = ThreadingTCPServer((interface, port), TelnetRequestHandler)
    server.serve_forever()

def onNextFrameStdOut(screen_buffer):
    sys.stdout.write(screen_buffer.read().decode('iso-8859-15'))

def runStdOut(filename):
    """
    Args:
        filename: file name of the ASCII movie

    Returns:

    """

    sys.stdout.write(VT100Codes.CLEARSCRN)

    movie = Movie()
    movie.loadMovie(filename)
    player = VT100Player(movie)
    player.onNextFrame = onNextFrameStdOut
    player.play()

########
# MAIN #
########

if __name__ == "__main__":
    usage = "Usage: %prog [options]"
    parser = OptionParser(usage=usage)
    parser.add_option("", "--standalone", dest="tcpserv", action="store_true",
                      help="Run as stand alone multi threaded TCP server (default)")
    parser.add_option("", "--stdout", dest="tcpserv", action="store_false",
                      help="Run with STDIN and STDOUT, for example in XINETD " +
                           "instead of stand alone TCP server. " +
                           "Use with python option '-u' for unbuffered " +
                           "STDIN STDOUT communication")
    parser.add_option("-f", "--file", dest="filename", metavar="FILE",
                      help="Text file containing the ASCII movie")
    parser.add_option("-i", "--interface", dest="interface",
                      help="Bind to this interface (default '0.0.0.0', all interfaces)",
                      default="0.0.0.0")
    parser.add_option("-p", "--port", dest="port", metavar="PORT",
                      help="Bind to this port (default 23, Telnet)",
                      default=23, type="int")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
                      help="Verbose (default for TCP server)")
    parser.add_option("-q", "--quiet", action="store_false", dest="verbose",
                      help="Quiet! (default for STDIN STDOUT server)")
    parser.set_defaults(interface="0.0.0.0",
                        port=23,
                        tcpserv=True,
                        verbose=True, )
    (options, args) = parser.parse_args()

    if not (options.filename and os.path.exists(options.filename)):
        parser.exit(1, "Error, file not found! See --help for details.\n")

    if options.tcpserv:
        if options.verbose:
            print("Running TCP server on {0}:{1}".format(options.interface, options.port))
            print("Playing movie {0}".format(options.filename))
        runTcpServer(options.interface, options.port, options.filename)
    else:
        runStdOut(options.filename)

    sys.exit(0)
<|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2009 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Survey (Model) query functions.
"""

__authors__ = [
  '"Daniel Diniz" <ajaksu@gmail.com>',
  '"James Levy" <jamesalexanderlevy@gmail.com>',
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

import logging

from google.appengine.ext import db

from soc.cache import sidebar
from soc.logic.models import linkable as linkable_logic
from soc.logic.models import survey_record as survey_record_logic
from soc.logic.models.user import logic as user_logic
from soc.logic.models import work
from soc.models.program import Program
from soc.models import student_project
from soc.models.survey import Survey
from soc.models.grading_project_survey import GradingProjectSurvey
from soc.models.grading_record import GradingRecord
from soc.models.project_survey import ProjectSurvey
from soc.models.survey import SurveyContent
from soc.models.survey_record import SurveyRecord
from soc.models.work import Work

#TODO(James): Ensure this facilitates variable # of surveys
GRADES = {'pass': True, 'fail': False}
PROJECT_STATUSES = {
'accepted': {True: 'mid_term_passed', False: 'mid_term_failed'},
'mid_term_passed': {True: 'passed', False: 'final_failed'}
}

class Logic(work.Logic):
  """Logic methods for the Survey model.
  """

  def __init__(self, model=Survey, base_model=Work,
               scope_logic=linkable_logic,
               record_logic=survey_record_logic.logic):
    """Defines the name, key_name and model for this entity.

    params:
      record_logic: SurveyRecordLogic (or subclass) instance for this Survey
    """

    self.record_logic = record_logic

    super(Logic, self).__init__(model=model, base_model=base_model,
                                scope_logic=scope_logic)

  def createSurvey(self, survey_fields, schema, survey_content=False):
    """Create a new survey from prototype.

    params:
      survey_fields = dict of survey field items (see SurveyContent model)
      schema = metadata about survey fields (SurveyContent.schema)
      survey_content = existing SurveyContent entity
    """

    if not survey_content:
      survey_content = SurveyContent()
    else:
      # wipe clean existing dynamic properties if they exist
      for prop in survey_content.dynamic_properties():
        delattr(survey_content, prop)

    for name, value in survey_fields.items():
      setattr(survey_content, name, value)

    survey_content.schema = str(schema)

    db.put(survey_content)

    return survey_content

  def getSurveyForContent(self, survey_content):
    """Returns the Survey belonging to the given SurveyContent.

    params:
      survey_content: the SurveyContent to retrieve the Survey for.

    returns:
      Survey or subclass if possible else None.
    """

    fields = {'survey_content': survey_content}

    return self.getForFields(fields, unique=True)

  def getRecordLogic(self):
    """Returns SurveyRecordLogic that belongs to this SurveyLogic.
    """

    return self.record_logic

  def getUserRole(self, user, survey, project):
    """Gets the role of a user for a project, used for SurveyRecordGroup.

    params:
      user: user taking survey
      survey: survey entity
      project: student project for this user
    """

    if survey.taking_access == 'mentor evaluation':
      mentors = self.getMentorforProject(user, project)

      if len(mentors) < 1 or len(mentors) > 1:
        logging.warning('Unable to determine mentor for \
        user %s. Results returned: %s ' % (
        user.key().name(), str(mentors)) )
        return False

      this_mentor = mentors[0]

    if survey.taking_access == 'student evaluation':
      students = self.getStudentforProject(user, project)

      if len(students) < 1 or len(students) > 1:
        logging.warning('Unable to determine student for \
        user %s. Results returned: %s ' % (
        user.key().name(), str(students)) )
        return False

  def getStudentforProject(self, user, project):
    """Get student projects for a given User.

    params:
      user = survey taking user
      project = survey taker's student project
    """
    from soc.logic.models.student import logic as student_logic
    import soc.models.student

    # TODO this should be done per Student or Program
    # TODO filter for accepted, midterm_passed, etc?
    user_students = student_logic.getForFields({'user': user})
    if not user_students: return []
    return set([project.student for project in sum(
    (list(s.student_projects.run())
    for s in user_students), []) if project.key() == project.key()])

  def getMentorforProject(self, user, project):
    """Get Student Projects that are being mentored by the given User.

    params:
      user = survey taking user
      project = survey taker's student project
    """

    from soc.logic.models.mentor import logic as mentor_logic
    import soc.models.mentor

    # TODO filter for accepted, midterm_passed, etc?
    # TODO this should be done a program basis not user

    user_mentors = mentor_logic.getForFields({'user': user})

    if not user_mentors:
      return []

    return set([project.mentor for project in sum(
            (list(mentor.student_projects.run())
             for mentor in user_mentors), [])
        if project.key() == project.key()])

  def activateGrades(self, survey):
    """Activates the grades on a Grading Survey.

    TODO(James) Fix this Docstring

    params:
      survey = survey entity
    """
    if survey.taking_access != "mentor evaluation":
      logging.error("Cannot grade survey %s with taking access %s"
      % (survey.key().name(), survey.taking_access))
      return False

    program = survey.scope or Program.get_by_key_name(survey.scope_path)

    for project in program.student_projects.fetch(1000):
      this_record_group = GradingRecord.all().filter(
      "project = ", project).filter(
      "initial_status = ", project.status).get()

      if not this_record_group:
         logging.warning('neither mentor nor student has \
         taken the survey for project %s' % project.key().name() )
         continue

      if not this_record_group.mentor_record:
        # student has taken survey, but not mentor
        logging.warning('not continuing without mentor record...')
        continue

      status_options = PROJECT_STATUSES.get(project.status)

      if not status_options:
        logging.warning('unable to find status options for project \
        status %s' % project.status)
        continue

      new_project_grade = this_record_group.mentor_record.grade
      new_project_status = status_options.get(new_project_grade)

      if getattr(this_record_group, 'final_status'):
         logging.warning('project %s record group should not \
         yet have a final status %s' % (
         project.key().name(), this_record_group.final_status ) )
         continue

      # assign the new status to the project and surveyrecordgroup
      project.status = new_project_status
      this_record_group.final_status = new_project_status

  def getKeyNameFromPath(self, path):
    """Gets survey key name from a request path.

    params:
      path = path of the current request
    """

    # TODO determine if kwargs in the request contains this information
    return '/'.join(path.split('/')[-4:]).split('?')[0]

  def getProjects(self, survey, user):
    """Get projects linking user to a program.

    Serves as access handler (since no projects == no access).
    And retrieves projects to choose from (if mentors have >1 projects).

    params:
      survey = survey entity
      user = survey taking user
    """

    this_program = survey.scope or Program.get_by_key_name(survey.scope_path)

    if 'mentor' in survey.taking_access:
      these_projects = self.getMentorProjects(user, this_program)

    elif 'student' in survey.taking_access:
      these_projects = self.getStudentProjects(user, this_program)

    logging.info(these_projects)

    if len(these_projects) == 0:
      return False

    return these_projects

  def getDebugUser(self, survey, this_program):
    """Debugging method impersonates other roles.

    Tests taking survey, saving response, and grading.

    params:
      survey = survey entity
      this_program = program scope of survey
    """

    if 'mentor' in survey.taking_access:
      from soc.models.mentor import Mentor
      role = Mentor.get_by_key_name(
      this_program.key().name() + "/org_1/test")

    if 'student' in survey.taking_access:
      from soc.models.student import Student
      role = Student.get_by_key_name(
      this_program.key().name() + "/test")

    if role: return role.user

  def getKeyValuesFromEntity(self, entity):
    """See base.Logic.getKeyNameValues.
    """

    return [entity.prefix, entity.scope_path, entity.link_id]

  def getKeyValuesFromFields(self, fields):
    """See base.Logic.getKeyValuesFromFields.
    """

    return [fields['prefix'], fields['scope_path'], fields['link_id']]

  def getKeyFieldNames(self):
    """See base.Logic.getKeyFieldNames.
    """

    return ['prefix', 'scope_path', 'link_id']

  def getScope(self, entity):
    """Gets Scope for entity.

    params:
      entity = Survey entity
    """

    if getattr(entity, 'scope', None):
      return entity.scope

    import soc.models.program
    import soc.models.organization
    import soc.models.user
    import soc.models.site

    # use prefix to generate dict key
    scope_types = {"program": soc.models.program.Program,
    "org": soc.models.organization.Organization,
    "user": soc.models.user.User,
    "site": soc.models.site.Site}

    # determine the type of the scope
    scope_type = scope_types.get(entity.prefix)

    if not scope_type:
      # no matching scope type found
      raise AttributeError('No Matching Scope type found for %s' % entity.prefix)

    # set the scope and update the entity
    entity.scope = scope_type.get_by_key_name(entity.scope_path)
    entity.put()

    # return the scope
    return entity.scope

  def _onCreate(self, entity):
    """Set the scope of the survey.
    """

    self.getScope(entity)
    super(Logic, self)._onCreate(entity)

class ProjectLogic(Logic):
  """Logic class for ProjectSurvey.
  """

  def __init__(self, model=ProjectSurvey,
               base_model=Survey, scope_logic=linkable_logic,
               record_logic=survey_record_logic.project_logic):
    """Defines the name, key_name and model for this entity.
    """

    super(ProjectLogic, self).__init__(model=model, base_model=base_model,
                                       scope_logic=scope_logic,
                                       record_logic=record_logic)

class GradingProjectLogic(ProjectLogic):
  """Logic class for GradingProjectSurvey.
  """

  def __init__(self, model=GradingProjectSurvey,
               base_model=ProjectSurvey, scope_logic=linkable_logic,
               record_logic=survey_record_logic.grading_logic):
    """Defines the name, key_name and model for this entity.
    """

    super(GradingProjectLogic, self).__init__(model=model,
                                              base_model=base_model,
                                              scope_logic=scope_logic,
                                              record_logic=record_logic)

logic = Logic()
project_logic = ProjectLogic()
grading_logic = GradingProjectLogic()
<commit_msg>Added hasAtLeastOneRecord method to Survey Logic.<commit_after>#!/usr/bin/python2.5
#
# Copyright 2009 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Survey (Model) query functions.
"""

__authors__ = [
  '"Daniel Diniz" <ajaksu@gmail.com>',
  '"James Levy" <jamesalexanderlevy@gmail.com>',
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

import logging

from google.appengine.ext import db

from soc.cache import sidebar
from soc.logic.models import linkable as linkable_logic
from soc.logic.models import survey_record as survey_record_logic
from soc.logic.models.user import logic as user_logic
from soc.logic.models import work
from soc.models.program import Program
from soc.models import student_project
from soc.models.survey import Survey
from soc.models.grading_project_survey import GradingProjectSurvey
from soc.models.grading_record import GradingRecord
from soc.models.project_survey import ProjectSurvey
from soc.models.survey import SurveyContent
from soc.models.survey_record import SurveyRecord
from soc.models.work import Work

#TODO(James): Ensure this facilitates variable # of surveys
GRADES = {'pass': True, 'fail': False}
PROJECT_STATUSES = {
'accepted': {True: 'mid_term_passed', False: 'mid_term_failed'},
'mid_term_passed': {True: 'passed', False: 'final_failed'}
}

class Logic(work.Logic):
  """Logic methods for the Survey model.
  """

  def __init__(self, model=Survey, base_model=Work,
               scope_logic=linkable_logic,
               record_logic=survey_record_logic.logic):
    """Defines the name, key_name and model for this entity.

    params:
      record_logic: SurveyRecordLogic (or subclass) instance for this Survey
    """

    self.record_logic = record_logic

    super(Logic, self).__init__(model=model, base_model=base_model,
                                scope_logic=scope_logic)

  def createSurvey(self, survey_fields, schema, survey_content=False):
    """Create a new survey from prototype.

    params:
      survey_fields = dict of survey field items (see SurveyContent model)
      schema = metadata about survey fields (SurveyContent.schema)
      survey_content = existing SurveyContent entity
    """

    if not survey_content:
      survey_content = SurveyContent()
    else:
      # wipe clean existing dynamic properties if they exist
      for prop in survey_content.dynamic_properties():
        delattr(survey_content, prop)

    for name, value in survey_fields.items():
      setattr(survey_content, name, value)

    survey_content.schema = str(schema)

    db.put(survey_content)

    return survey_content

  def getSurveyForContent(self, survey_content):
    """Returns the Survey belonging to the given SurveyContent.

    params:
      survey_content: the SurveyContent to retrieve the Survey for.

    returns:
      Survey or subclass if possible else None.
    """

    fields = {'survey_content': survey_content}

    return self.getForFields(fields, unique=True)

  def getRecordLogic(self):
    """Returns SurveyRecordLogic that belongs to this SurveyLogic.
    """

    return self.record_logic

  def getUserRole(self, user, survey, project):
    """Gets the role of a user for a project, used for SurveyRecordGroup.

    params:
      user: user taking survey
      survey: survey entity
      project: student project for this user
    """

    if survey.taking_access == 'mentor evaluation':
      mentors = self.getMentorforProject(user, project)

      if len(mentors) < 1 or len(mentors) > 1:
        logging.warning('Unable to determine mentor for \
        user %s. Results returned: %s ' % (
        user.key().name(), str(mentors)) )
        return False

      this_mentor = mentors[0]

    if survey.taking_access == 'student evaluation':
      students = self.getStudentforProject(user, project)

      if len(students) < 1 or len(students) > 1:
        logging.warning('Unable to determine student for \
        user %s. Results returned: %s ' % (
        user.key().name(), str(students)) )
        return False

  def getStudentforProject(self, user, project):
    """Get student projects for a given User.

    params:
      user = survey taking user
      project = survey taker's student project
    """
    from soc.logic.models.student import logic as student_logic
    import soc.models.student

    # TODO this should be done per Student or Program
    # TODO filter for accepted, midterm_passed, etc?
    user_students = student_logic.getForFields({'user': user})
    if not user_students: return []
    return set([project.student for project in sum(
    (list(s.student_projects.run())
    for s in user_students), []) if project.key() == project.key()])

  def getMentorforProject(self, user, project):
    """Get Student Projects that are being mentored by the given User.

    params:
      user = survey taking user
      project = survey taker's student project
    """

    from soc.logic.models.mentor import logic as mentor_logic
    import soc.models.mentor

    # TODO filter for accepted, midterm_passed, etc?
    # TODO this should be done a program basis not user

    user_mentors = mentor_logic.getForFields({'user': user})

    if not user_mentors:
      return []

    return set([project.mentor for project in sum(
            (list(mentor.student_projects.run())
             for mentor in user_mentors), [])
        if project.key() == project.key()])

  def activateGrades(self, survey):
    """Activates the grades on a Grading Survey.

    TODO(James) Fix this Docstring

    params:
      survey = survey entity
    """
    if survey.taking_access != "mentor evaluation":
      logging.error("Cannot grade survey %s with taking access %s"
      % (survey.key().name(), survey.taking_access))
      return False

    program = survey.scope or Program.get_by_key_name(survey.scope_path)

    for project in program.student_projects.fetch(1000):
      this_record_group = GradingRecord.all().filter(
      "project = ", project).filter(
      "initial_status = ", project.status).get()

      if not this_record_group:
         logging.warning('neither mentor nor student has \
         taken the survey for project %s' % project.key().name() )
         continue

      if not this_record_group.mentor_record:
        # student has taken survey, but not mentor
        logging.warning('not continuing without mentor record...')
        continue

      status_options = PROJECT_STATUSES.get(project.status)

      if not status_options:
        logging.warning('unable to find status options for project \
        status %s' % project.status)
        continue

      new_project_grade = this_record_group.mentor_record.grade
      new_project_status = status_options.get(new_project_grade)

      if getattr(this_record_group, 'final_status'):
         logging.warning('project %s record group should not \
         yet have a final status %s' % (
         project.key().name(), this_record_group.final_status ) )
         continue

      # assign the new status to the project and surveyrecordgroup
      project.status = new_project_status
      this_record_group.final_status = new_project_status

  def getKeyNameFromPath(self, path):
    """Gets survey key name from a request path.

    params:
      path = path of the current request
    """

    # TODO determine if kwargs in the request contains this information
    return '/'.join(path.split('/')[-4:]).split('?')[0]

  def getProjects(self, survey, user):
    """Get projects linking user to a program.

    Serves as access handler (since no projects == no access).
    And retrieves projects to choose from (if mentors have >1 projects).

    params:
      survey = survey entity
      user = survey taking user
    """

    this_program = survey.scope or Program.get_by_key_name(survey.scope_path)

    if 'mentor' in survey.taking_access:
      these_projects = self.getMentorProjects(user, this_program)

    elif 'student' in survey.taking_access:
      these_projects = self.getStudentProjects(user, this_program)

    logging.info(these_projects)

    if len(these_projects) == 0:
      return False

    return these_projects

  def getDebugUser(self, survey, this_program):
    """Debugging method impersonates other roles.

    Tests taking survey, saving response, and grading.

    params:
      survey = survey entity
      this_program = program scope of survey
    """

    if 'mentor' in survey.taking_access:
      from soc.models.mentor import Mentor
      role = Mentor.get_by_key_name(
      this_program.key().name() + "/org_1/test")

    if 'student' in survey.taking_access:
      from soc.models.student import Student
      role = Student.get_by_key_name(
      this_program.key().name() + "/test")

    if role: return role.user

  def getKeyValuesFromEntity(self, entity):
    """See base.Logic.getKeyNameValues.
    """

    return [entity.prefix, entity.scope_path, entity.link_id]

  def getKeyValuesFromFields(self, fields):
    """See base.Logic.getKeyValuesFromFields.
    """

    return [fields['prefix'], fields['scope_path'], fields['link_id']]

  def getKeyFieldNames(self):
    """See base.Logic.getKeyFieldNames.
    """

    return ['prefix', 'scope_path', 'link_id']

  def getScope(self, entity):
    """Gets Scope for entity.

    params:
      entity = Survey entity
    """

    if getattr(entity, 'scope', None):
      return entity.scope

    import soc.models.program
    import soc.models.organization
    import soc.models.user
    import soc.models.site

    # use prefix to generate dict key
    scope_types = {"program": soc.models.program.Program,
    "org": soc.models.organization.Organization,
    "user": soc.models.user.User,
    "site": soc.models.site.Site}

    # determine the type of the scope
    scope_type = scope_types.get(entity.prefix)

    if not scope_type:
      # no matching scope type found
      raise AttributeError('No Matching Scope type found for %s' % entity.prefix)

    # set the scope and update the entity
    entity.scope = scope_type.get_by_key_name(entity.scope_path)
    entity.put()

    # return the scope
    return entity.scope

  def hasAtLeastOneRecord(self, survey_entity):
    """Returns True iff the given Survey has at least one SurveyRecord.

    Args:
      survey_entity: a Survey instance
    """

    fields = {'survey': survey_entity}

    record_logic = self.getRecordLogic()
    return record_logic.getQueryForFields(fields).count(1) > 0

  def _onCreate(self, entity):
    """Set the scope of the survey.
    """

    self.getScope(entity)
    super(Logic, self)._onCreate(entity)

class ProjectLogic(Logic):
  """Logic class for ProjectSurvey.
  """

  def __init__(self, model=ProjectSurvey,
               base_model=Survey, scope_logic=linkable_logic,
               record_logic=survey_record_logic.project_logic):
    """Defines the name, key_name and model for this entity.
    """

    super(ProjectLogic, self).__init__(model=model, base_model=base_model,
                                       scope_logic=scope_logic,
                                       record_logic=record_logic)

class GradingProjectLogic(ProjectLogic):
  """Logic class for GradingProjectSurvey.
  """

  def __init__(self, model=GradingProjectSurvey,
               base_model=ProjectSurvey, scope_logic=linkable_logic,
               record_logic=survey_record_logic.grading_logic):
    """Defines the name, key_name and model for this entity.
    """

    super(GradingProjectLogic, self).__init__(model=model,
                                              base_model=base_model,
                                              scope_logic=scope_logic,
                                              record_logic=record_logic)

logic = Logic()
project_logic = ProjectLogic()
grading_logic = GradingProjectLogic()
<|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This module contains the Organization Model.
"""

__authors__ = [
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
]

from google.appengine.ext import db

from django.utils.translation import ugettext

import soc.models.group

class Organization(soc.models.group.Group):
  """Organization details.

  A Organization entity participates in the following relationships implemented
  as a db.ReferenceProperty elsewhere in another db.Model:

   reviewers)  a many:1 relationship associating Reviewers with
     a specific Organization. This relation is implemented as the
     'reviewers' back-reference Query of the Organization model 'org'
     reference.
  """

  #: Optional development mailing list.
  dev_mailing_list = db.StringProperty(required=False,
    verbose_name=ugettext('Development Mailing List'))
  dev_mailing_list.help_text = ugettext(
    'Mailing list email address, URL to sign-up page, etc.')

  member_template = db.ReferenceProperty(
    reference_class=soc.models.document.Document, required=False,
    collection_name='org_app_member_template',
    verbose_name=ugettext('Application template'))
  member_template.help_text = ugettext(
    'This template will be presented to potential members when they'
    ' apply to the organization.')

  ideas = db.LinkProperty(required=False, verbose_name=ugettext('Idea list'))
  ideas.help_text = ugettext(
      'The URL to the ideas list of your organization.')
  ideas.example_text = ugettext('For instance a link to a Melange public '
      'document or some other URL')
<commit_msg>Deleted stale comment<commit_after>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This module contains the Organization Model.
"""

__authors__ = [
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
]

from google.appengine.ext import db

from django.utils.translation import ugettext

import soc.models.group

class Organization(soc.models.group.Group):
  """Organization details.
  """

  #: Optional development mailing list.
  dev_mailing_list = db.StringProperty(required=False,
    verbose_name=ugettext('Development Mailing List'))
  dev_mailing_list.help_text = ugettext(
    'Mailing list email address, URL to sign-up page, etc.')

  member_template = db.ReferenceProperty(
    reference_class=soc.models.document.Document, required=False,
    collection_name='org_app_member_template',
    verbose_name=ugettext('Application template'))
  member_template.help_text = ugettext(
    'This template will be presented to potential members when they'
    ' apply to the organization.')

  ideas = db.LinkProperty(required=False, verbose_name=ugettext('Idea list'))
  ideas.help_text = ugettext(
      'The URL to the ideas list of your organization.')
  ideas.example_text = ugettext('For instance a link to a Melange public '
      'document or some other URL')
<|endoftext|>


<commit_before>#!/usr/bin/env python
# encoding: utf-8
"""
helpers.py
Some modules to help with this project

Created by Karl Dubost on 2016-02-24.
Copyright (c) 2016 La Grange. All rights reserved.
MIT License
"""
def main():
    '''core program'''
    pass

if __name__ == "__main__":
    sys.exit(main())
<commit_msg>for fetching content online<commit_after>#!/usr/bin/env python
# encoding: utf-8
"""
helpers.py
Some modules to help with this project

Created by Karl Dubost on 2016-02-24.
Copyright (c) 2016 La Grange. All rights reserved.
MIT License
"""
import requests
def fetch_content(uri):
    '''Fetch the URI and returns the raw content and its encoding'''
    content = requests.get(uri)
    return content.text, content.encoding
def main():
    '''core program'''
    pass

if __name__ == "__main__":
    sys.exit(main())
<|endoftext|>