Example #1
0
 def test_constructor(self):
     """
     SimpleHintFactory.__init__() Test plan:
         - make sure DISCOUNT_FACTOR, GOAL_REWARD, STD_REWARD
         - make sure self.db is a graphdatabase service
     """
     test_subject = SimpleHintFactory()
     isinstance(test_subject.db,neo4j.GraphDatabaseService).should.equal(True)
     test_subject.DISCOUNT_FACTOR.should.equal(.5)
     test_subject.GOAL_REWARD.should.equal(100)
     test_subject.STD_REWARD.should.equal(0)
Example #2
0
 def setUp(self):
     self.test_subject = SimpleHintFactory()
     self.test_subject.db = neo4j.GraphDatabaseService("http://localhost:7474/db/data/")
     for node in self.test_subject.db.find("_unit_test_only"):
         node.delete_related()
Example #3
0
class TestSimpleHintFactory(unittest.TestCase):
    def setUp(self):
        self.test_subject = SimpleHintFactory()
        self.test_subject.db = neo4j.GraphDatabaseService("http://localhost:7474/db/data/")
        for node in self.test_subject.db.find("_unit_test_only"):
            node.delete_related()
            
    def tearDown(self):
        for node in self.test_subject.db.find("_unit_test_only"):
            node.delete_related()
        self.test_subject = None
        
    def test_constructor(self):
        """
        SimpleHintFactory.__init__() Test plan:
            - make sure DISCOUNT_FACTOR, GOAL_REWARD, STD_REWARD
            - make sure self.db is a graphdatabase service
        """
        test_subject = SimpleHintFactory()
        isinstance(test_subject.db,neo4j.GraphDatabaseService).should.equal(True)
        test_subject.DISCOUNT_FACTOR.should.equal(.5)
        test_subject.GOAL_REWARD.should.equal(100)
        test_subject.STD_REWARD.should.equal(0)
      
    
    def test_push_node(self):
        """
        SimpleHintFactory.push_node() Test plan:
            - if not problem_node, issue statedoesnotexistexception
            - if from node doesnt exist, either problem or state, should raise statedoesnotexistexception
            - it to state does not exist, new node should exist
            - if state exists and edge, taken count should be incremented
            - update action probabilities should be called
            - bellman update should be called
        """
        self.test_subject.update_action_probabilities = MagicMock()
        self.test_subject.bellman_update = MagicMock()
        self.test_subject.push_node.when.called_with("problem","2+4","add","4+4").should.throw(StateDoesNotExistException)
        
        problem_node, = self.test_subject.db.create({"start_string":"problem","goal_string":"goal","discount_factor":0.5})
        problem_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problems_index")
        problem_index.add("start_string","problem",problem_node)
        problem_node.add_labels("_unit_test_only")
        
        self.test_subject.push_node.when.called_with("problem","2+4","add","4+4").should.throw(StateDoesNotExistException)
        
        self.test_subject.push_node("problem","problem","add","4+5")
        self.test_subject.update_action_probabilities.call_count.should_not.equal(0)
        self.test_subject.update_action_probabilities.reset_mock()
        
        state_hash = hashlib.sha256(bytes("problem-4+5".encode('utf-8'))).hexdigest()
        new_node = self.test_subject.db.get_indexed_node("problem_states_index","state_hash",state_hash)
        new_node.should_not.equal(None)
        
        self.test_subject.push_node("problem","problem","add","4+5")
        self.test_subject.update_action_probabilities.call_count.should_not.equal(0)
        self.test_subject.update_action_probabilities.reset_mock()
        
        edge = next(problem_node.match_outgoing("action",new_node))
        edge.should_not.equal(None)
        edge["taken_count"].should.equal(2)
        
        self.test_subject.bellman_update.call_count.should.equal(2)
        
        problem_node.delete_related()
    
    def test_delete_node(self):
        """
        SimpleHintFactory.delete_problem() Test plan:
            - add a node, then delete it
        """
        self.test_subject.delete_node.when.called_with("problem","state").should.throw(StateDoesNotExistException)
        
        problem_node, = self.test_subject.db.create({"start_string":"state","goal_string":"goal","discount_factor":"0.5"})
        problem_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problems_index")
        problem_index.add("start_string","state",problem_node)
        problem_node.add_labels("_unit_test_only")
        
        state_string = "state_2"
        state_hash = hashlib.sha256(bytes('-'.join(['problem', state_string]).encode('utf-8'))).hexdigest()
        new_node, new_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":"0.5"},(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,new_node)
        
        self.test_subject.delete_node("problem","state_2").should.equal(True)
        
        child_edges = problem_node.match_outgoing("action")
        len(list(child_edges)).should.equal(0)
        
        problem_node.delete_related()
    
    def test_delete_problem(self):
        """
        SimpleHintFactory.delete_problem() Test plan:
            - add a problem, then delete it
        """
        self.test_subject.delete_problem("problem","state").should.equal(False)
        
        problem_node, = self.test_subject.db.create({"start_string":"state","goal_string":"goal","discount_factor":"0.5"})
        problem_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problems_index")
        problem_index.add("start_string","state",problem_node)
        problem_node.add_labels("_unit_test_only")
        
        state_string = "state_2"
        state_hash = hashlib.sha256(bytes('-'.join(['problem', state_string]).encode('utf-8'))).hexdigest()
        new_node, new_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":"0.5"},(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,new_node)
        
        self.test_subject.delete_problem("problem","state2").should.equal(False)
        self.test_subject.delete_problem("problem","state").should.equal(True)
    
    def test_hash_string(self):
        """
        SimpleHintFactory.hash_string() Test plan:
            - test with string and number, should return expected results
        """
        self.test_subject.hash_string("hello").should.equal(hashlib.sha256(bytes("hello".encode('utf-8'))).hexdigest())
        self.test_subject.hash_string(4).should.equal(hashlib.sha256(bytes("4".encode('utf-8'))).hexdigest())
    
    def test_update_action_probabilities(self):
        """
        SimpleHintFactory.update_action_probabilities() Test plan:
            - populate database with a parent with 3 children, one with transition not action
                - relationships should have counts
                - afterwards, edges should have predicted values
            - remove entry from database
        """
        
        root_node = self.test_subject.db.create({"name":"start"})[0]
        root_node.add_labels("_unit_test_only")

        node_1, rel_1 = self.test_subject.db.create({"name":"node_1"},(root_node,"action",0))
        rel_1["taken_count"] = 1
        rel_1["probability"] = 0
        
        node_2, rel_2 = self.test_subject.db.create({"name":"node_2"},(root_node,"action",0))
        rel_2["taken_count"] = 3
        rel_2["probability"] = 0
        
        node_3, rel_3 = self.test_subject.db.create({"name":"node_3"},(root_node,"bogus",0))
        rel_3["taken_count"] = 5
        rel_3["probability"] = 0
        
        self.test_subject.update_action_probabilities(rel_2)
        
        rel_1["probability"].should.equal(.25)
        rel_2["probability"].should.equal(.75)
        rel_3["probability"].should.equal(0)
        
        root_node.delete_related()
    
    def test_bellman_update(self):
        """
        SimpleHintFactory._do_bellman() Test plan:
            - add some states
            - make sure bellman values are what is expected
        """
        
        problem_node, = self.test_subject.db.create({"start_string":"state","goal_string":"state_4","discount_factor":0.5})
        problem_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problems_index")
        problem_index.add("start_string","state",problem_node)
        problem_node.add_labels("_unit_test_only")
        
        state_string = "state_2"
        state_hash = hashlib.sha256(bytes('-'.join(['state', state_string]).encode('utf-8'))).hexdigest()
        new_node, new_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":0.5},(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,new_node)
        new_rel["probability"] = .75
        
        state_string = "state_3"
        state_hash = hashlib.sha256(bytes('-'.join(['state', state_string]).encode('utf-8'))).hexdigest()
        another_node, another_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":0.5},(new_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,another_node)
        another_rel["probability"] = .25
        
        state_string = "state_4"
        state_hash = hashlib.sha256(bytes('-'.join(['state', state_string]).encode('utf-8'))).hexdigest()
        goal_node, goal_rel1, goal_rel2 = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":0.5},(new_node,"action",0),(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,goal_node)
        goal_rel1["probability"] = 1
        goal_rel2["probability"] = 1
        
        self.test_subject.bellman_update("state","state_4")
        goal_node["bellman_value"].should.equal(100)
        another_rel["bellman_value"] = 50
        new_rel["bellman_value"] = 50
        problem_node["bellman_value"] = 18.75
        
        problem_node.delete_related()
        
    
    def test_create_or_get_problem_node(self):
        """
        SimpleHintFactory.create_or_get_problem_node() Test plan:
            - mock get_indexed_node, if returns true, method should return true
            - if it returns false, a node should be returned
            - cleanup
        """
        self.test_subject.db.get_indexed_node = MagicMock(return_value = True)
        self.test_subject.create_or_get_problem_node("start_string","goal_string").should.equal(True)
        
        self.test_subject.db.get_indexed_node = MagicMock(return_value = None)
        cur = self.test_subject.create_or_get_problem_node("start_string","goal_string")
        isinstance(cur,neo4j.Node).should.equal(True)
        cur.get_properties()["start_string"].should.equal("start_string")
        cur.get_properties()["goal_string"].should.equal("goal_string")
        cur.get_labels().should.contain("Problem")
        
        cur.delete_related()
        
    def test_hint_exists(self):
        """
        SimpleHintFactory.hint_exists() Test plan:
            - with no states, should return false
            - with a problem_states_index
                -with an edge, should return True
                -without an edge, should return False
            - with a problems_index
                -with an edge, should return True
                -without an edge, should return False
        """
        self.test_subject.hint_exists.when.called_with("problem","state").should.throw(StateDoesNotExistException)
        
        problem_node, = self.test_subject.db.create({"start_string":"state","goal_string":"goal","discount_factor":"0.5"})
        problem_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problems_index")
        problem_index.add("start_string","state",problem_node)
        problem_node.add_labels("_unit_test_only")
        
        self.test_subject.hint_exists("problem","state").should.equal(False)
        
        state_string = "state_2"
        state_hash = hashlib.sha256(bytes('-'.join(['problem', state_string]).encode('utf-8'))).hexdigest()
        new_node, new_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":"0.5"},(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,new_node)
        
        self.test_subject.hint_exists("problem","state").should.equal(True)
        
        self.test_subject.hint_exists("problem","state_2").should.equal(False)
        
        state_string = "state_3"
        state_hash = hashlib.sha256(bytes('-'.join(['problem', state_string]).encode('utf-8'))).hexdigest()
        another_node, another_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":"0.5"},(new_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,another_node)
        
        self.test_subject.hint_exists("problem","state_3").should.equal(False)
        
        problem_node.delete_related()
           
    def test_get_hint(self):
        """
        SimpleHintFactory.get_hint() Test plan:
            - mock hint_exists, if false, should return None
            - if a problem node
                - if no relationships, should return none
                - with 2 relationships, should return string from largest bellman value
            - if a state node
                - if no relationships, should return none
                - with 2 relationships, should return string from largest bellman value
        """
        self.test_subject.hint_exists = MagicMock(return_value = False)
        self.test_subject.get_hint.when.called_with("problem","state").should.throw(HintDoesNotExistException)
        
        self.test_subject.hint_exists = MagicMock(return_value = True)
        
        #create a problem node, nothing else
        problem_node, = self.test_subject.db.create({"start_string":"state","goal_string":"goal","discount_factor":"0.5"})
        problem_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problems_index")
        problem_index.add("start_string","state",problem_node)
        problem_node.add_labels("_unit_test_only")
        
        #should return nothing
        self.test_subject.get_hint.when.called_with("problem","state").should.throw(HintDoesNotExistException)
        
        #add a state to the problem node, state_2, bellman value 0
        state_string = "state_2"
        state_hash = hashlib.sha256(bytes(("problem-"+state_string).encode('utf-8'))).hexdigest()
        new_node, new_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":"0.5"},(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,new_node)
        new_rel["action_string"] = "bad hint"
        
        #add a state, state 3  to problem node, bellman value 1
        state_string = "state_3"
        state_hash = hashlib.sha256(bytes(("problem-"+state_string).encode('utf-8'))).hexdigest()
        another_node, another_rel = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":1,"discount_factor":"0.5"},(problem_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,another_node)
        another_rel["action_string"] = "good hint"
        
        #should pick higher bellman value (state_3)
        self.test_subject.get_hint("problem","state").should.equal({"hint_text":"good hint","hint_result":"state_3"})
        
        #should return nothing for hint from state_2
        self.test_subject.get_hint.when.called_with("problem","state_2").should.throw(HintDoesNotExistException)
        
        #add state_3 branching from state_2, bellman value 0 
        state_string = "state_3"
        state_hash = hashlib.sha256(bytes(("problem-"+state_string).encode('utf-8'))).hexdigest()
        new_node2, new_rel2 = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":0,"discount_factor":"0.5"},(new_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,new_node2)
        new_rel2["action_string"] = "bad hint"
        
        #add state_5 branching from state 2, bellman value 1
        state_string = "state_5"
        state_hash = hashlib.sha256(bytes(("problem-"+state_string).encode('utf-8'))).hexdigest()
        another_node2, another_rel2 = self.test_subject.db.create({"state_string":state_string,"state_hash":state_hash,"bellman_value":1,"discount_factor":"0.5"},(new_node,"action",0))
        problem_states_index = self.test_subject.db.get_or_create_index(neo4j.Node,"problem_states_index")
        problem_states_index.add("state_hash",state_hash,another_node2)
        another_rel2["action_string"] = "good hint"
        
        #should return hint_5, higher bellman value
        self.test_subject.get_hint("problem","state_2").should.equal({"hint_text":"good hint","hint_result":"state_5"})
        
        problem_node.delete_related()