testconsole.py
1 """ 2 Console module tests 3 """ 4 5 import contextlib 6 import io 7 import os 8 import tempfile 9 import unittest 10 11 from txtai.console import Console 12 from txtai.embeddings import Embeddings 13 14 APPLICATION = """ 15 path: %s 16 17 workflow: 18 test: 19 tasks: 20 - task: console 21 """ 22 23 24 class TestConsole(unittest.TestCase): 25 """ 26 Console tests. 27 """ 28 29 @classmethod 30 def setUpClass(cls): 31 """ 32 Initialize test data. 33 """ 34 35 cls.data = [ 36 "US tops 5 million confirmed virus cases", 37 "Canada's last fully intact ice shelf has suddenly collapsed, forming a Manhattan-sized iceberg", 38 "Beijing mobilises invasion craft along coast as Taiwan tensions escalate", 39 "The National Park Service warns against sacrificing slower friends in a bear attack", 40 "Maine man wins $1M from $25 lottery ticket", 41 "Make huge profits without work, earn up to $100,000 a day", 42 ] 43 44 # Create embeddings model, backed by sentence-transformers & transformers 45 cls.embeddings = Embeddings({"path": "sentence-transformers/nli-mpnet-base-v2", "content": True}) 46 47 # Create an index for the list of text 48 cls.embeddings.index([(uid, text, None) for uid, text in enumerate(cls.data)]) 49 50 # Create app paths 51 cls.apppath = os.path.join(tempfile.gettempdir(), "console.yml") 52 cls.embedpath = os.path.join(tempfile.gettempdir(), "embeddings.console") 53 54 # Create app.yml 55 with open(cls.apppath, "w", encoding="utf-8") as out: 56 out.write(APPLICATION % cls.embedpath) 57 58 # Save index as uncompressed and compressed 59 cls.embeddings.save(cls.embedpath) 60 cls.embeddings.save(f"{cls.embedpath}.tar.gz") 61 62 # Create console 63 cls.console = Console(cls.embedpath) 64 65 def testApplication(self): 66 """ 67 Test application 68 """ 69 70 self.assertNotIn("Traceback", self.command(f".load {self.apppath}")) 71 self.assertIn("1", self.command(".limit 1")) 72 self.assertIn("Maine man wins", self.command("feel good story")) 73 74 def testConfig(self): 75 """ 76 Test .config command 77 """ 78 79 self.assertIn("tasks", self.command(".config")) 80 81 def testEmbeddings(self): 82 """ 83 Test embeddings index 84 """ 85 86 self.assertNotIn("Traceback", self.command(f".load {self.embedpath}.tar.gz")) 87 self.assertNotIn("Traceback", self.command(f".load {self.embedpath}")) 88 self.assertIn("1", self.command(".limit 1")) 89 self.assertIn("Maine man wins", self.command("feel good story")) 90 91 def testEmbeddingsNoDatabase(self): 92 """ 93 Test embeddings with no database/content 94 """ 95 96 console = Console() 97 98 # Create embeddings model, backed by sentence-transformers & transformers 99 embeddings = Embeddings({"path": "sentence-transformers/nli-mpnet-base-v2"}) 100 101 # Create an index for the list of text 102 embeddings.index([(uid, text, None) for uid, text in enumerate(self.data)]) 103 104 # Set embeddings on console 105 console.app = embeddings 106 self.assertIn("4", self.command("feel good story", console)) 107 108 def testEmpty(self): 109 """ 110 Test empty console instance 111 """ 112 113 console = Console() 114 self.assertIn("AttributeError", self.command("search", console)) 115 116 def testHighlight(self): 117 """ 118 Test .highlight command 119 """ 120 121 self.assertIn("highlight", self.command(".highlight")) 122 self.assertIn("wins", self.command("feel good story")) 123 self.assertIn("Taiwan", self.command("asia")) 124 125 def testPreloop(self): 126 """ 127 Test preloop 128 """ 129 130 self.assertIn("txtai console", self.preloop()) 131 132 def testWorkflow(self): 133 """ 134 Test .workflow command 135 """ 136 137 self.command(f".load {self.apppath}") 138 self.assertIn("echo", self.command(".workflow test echo")) 139 140 def command(self, command, console=None): 141 """ 142 Runs a console command. 143 144 Args: 145 command: command to run 146 console: console instance, defaults to self.console 147 148 Returns: 149 command output 150 """ 151 152 # Run info 153 output = io.StringIO() 154 with contextlib.redirect_stdout(output): 155 if not console: 156 console = self.console 157 158 console.onecmd(command) 159 160 return output.getvalue() 161 162 def preloop(self): 163 """ 164 Runs console.preloop and redirects stdout. 165 166 Returns: 167 preloop output 168 """ 169 170 # Run info 171 output = io.StringIO() 172 with contextlib.redirect_stdout(output): 173 self.console.preloop() 174 175 return output.getvalue()