Best Python code snippet using avocado_python
extrainfo_descriptor.py
Source:extrainfo_descriptor.py
1"""2Unit tests for stem.descriptor.extrainfo_descriptor.3"""4import datetime5import functools6import unittest7import stem.descriptor8import test.require9from stem.descriptor.extrainfo_descriptor import (10 RelayExtraInfoDescriptor,11 BridgeExtraInfoDescriptor,12 DirResponse,13 DirStat,14)15from test.unit.descriptor import (16 get_resource,17 base_expect_invalid_attr,18 base_expect_invalid_attr_for_text,19)20expect_invalid_attr = functools.partial(base_expect_invalid_attr, RelayExtraInfoDescriptor, 'nickname', 'Unnamed')21expect_invalid_attr_for_text = functools.partial(base_expect_invalid_attr_for_text, RelayExtraInfoDescriptor, 'nickname', 'Unnamed')22class TestExtraInfoDescriptor(unittest.TestCase):23 def test_metrics_relay_descriptor(self):24 """25 Parses and checks our results against an extrainfo descriptor from metrics.26 """27 descriptor_file = open(get_resource('extrainfo_relay_descriptor'), 'rb')28 expected_signature = """-----BEGIN SIGNATURE-----29K5FSywk7qvw/boA4DQcqkls6Ize5vcBYfhQ8JnOeRQC9+uDxbnpm3qaYN9jZ8myj30k0d2aofcVbHr4fPQOSST0LXDrhFl5Fqo5um296zpJGvRUeO6S44U/EfJAGShtqWw317LZqklu+gVvhMKREpchVqlAwXkWR44VENm24Hs+mT3M=32-----END SIGNATURE-----"""33 desc = next(stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0'))34 self.assertEqual('NINJA', desc.nickname)35 self.assertEqual('B2289C3EAB83ECD6EB916A2F481A02E6B76A0A48', desc.fingerprint)36 self.assertEqual(datetime.datetime(2012, 5, 5, 17, 3, 50), desc.published)37 self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.read_history_end)38 self.assertEqual(900, desc.read_history_interval)39 self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.write_history_end)40 self.assertEqual(900, desc.write_history_interval)41 self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.dir_read_history_end)42 self.assertEqual(900, desc.dir_read_history_interval)43 self.assertEqual(datetime.datetime(2012, 5, 5, 17, 2, 45), desc.dir_write_history_end)44 self.assertEqual(900, desc.dir_write_history_interval)45 self.assertEqual(expected_signature, desc.signature)46 self.assertEqual('00A57A9AAB5EA113898E2DD02A755E31AFC27227', desc.digest())47 self.assertEqual([], desc.get_unrecognized_lines())48 # The read-history, write-history, dirreq-read-history, and49 # dirreq-write-history lines are pretty long so just checking50 # the initial contents for the line and parsed values.51 read_values_start = [3309568, 9216, 41984, 27648, 123904]52 self.assertEqual(read_values_start, desc.read_history_values[:5])53 write_values_start = [1082368, 19456, 50176, 272384, 485376]54 self.assertEqual(write_values_start, desc.write_history_values[:5])55 dir_read_values_start = [0, 0, 0, 0, 33792, 27648, 48128]56 self.assertEqual(dir_read_values_start, desc.dir_read_history_values[:7])57 dir_write_values_start = [0, 0, 0, 227328, 349184, 382976, 738304]58 self.assertEqual(dir_write_values_start, desc.dir_write_history_values[:7])59 def test_metrics_bridge_descriptor(self):60 """61 Parses and checks our results against an extrainfo bridge descriptor from62 metrics.63 """64 descriptor_file = open(get_resource('extrainfo_bridge_descriptor'), 'rb')65 expected_dir_v2_responses = {66 DirResponse.OK: 0,67 DirResponse.UNAVAILABLE: 0,68 DirResponse.NOT_FOUND: 0,69 DirResponse.NOT_MODIFIED: 0,70 DirResponse.BUSY: 0,71 }72 expected_dir_v3_responses = {73 DirResponse.OK: 72,74 DirResponse.NOT_ENOUGH_SIGS: 0,75 DirResponse.UNAVAILABLE: 0,76 DirResponse.NOT_FOUND: 0,77 DirResponse.NOT_MODIFIED: 0,78 DirResponse.BUSY: 0,79 }80 desc = next(stem.descriptor.parse_file(descriptor_file, 'bridge-extra-info 1.0'))81 self.assertEqual('ec2bridgereaac65a3', desc.nickname)82 self.assertEqual('1EC248422B57D9C0BD751892FE787585407479A4', desc.fingerprint)83 self.assertEqual(datetime.datetime(2012, 6, 8, 2, 21, 27), desc.published)84 self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.read_history_end)85 self.assertEqual(900, desc.read_history_interval)86 self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.write_history_end)87 self.assertEqual(900, desc.write_history_interval)88 self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.dir_read_history_end)89 self.assertEqual(900, desc.dir_read_history_interval)90 self.assertEqual(datetime.datetime(2012, 6, 8, 2, 10, 38), desc.dir_write_history_end)91 self.assertEqual(900, desc.dir_write_history_interval)92 self.assertEqual('00A2AECCEAD3FEE033CFE29893387143146728EC', desc.digest())93 self.assertEqual([], desc.get_unrecognized_lines())94 read_values_start = [337920, 437248, 3995648, 48726016]95 self.assertEqual(read_values_start, desc.read_history_values[:4])96 write_values_start = [343040, 991232, 5649408, 49548288]97 self.assertEqual(write_values_start, desc.write_history_values[:4])98 dir_read_values_start = [0, 71680, 99328, 25600]99 self.assertEqual(dir_read_values_start, desc.dir_read_history_values[:4])100 dir_write_values_start = [5120, 664576, 2419712, 578560]101 self.assertEqual(dir_write_values_start, desc.dir_write_history_values[:4])102 self.assertEqual({}, desc.dir_v2_requests)103 self.assertEqual({}, desc.dir_v3_requests)104 self.assertEqual(expected_dir_v2_responses, desc.dir_v2_responses)105 self.assertEqual(expected_dir_v3_responses, desc.dir_v3_responses)106 self.assertEqual({}, desc.dir_v2_responses_unknown)107 self.assertEqual({}, desc.dir_v2_responses_unknown)108 @test.require.cryptography109 def test_descriptor_signing(self):110 RelayExtraInfoDescriptor.create(sign = True)111 self.assertRaisesWith(NotImplementedError, 'Signing of BridgeExtraInfoDescriptor not implemented', BridgeExtraInfoDescriptor.create, sign = True)112 def test_multiple_metrics_bridge_descriptors(self):113 """114 Check that we can read bridge descriptors when there's multiple in a file.115 """116 descriptor_file = open(get_resource('extrainfo_bridge_descriptor_multiple'), 'rb')117 desc_list = list(stem.descriptor.parse_file(descriptor_file))118 self.assertEqual(6, len(desc_list))119 self.assertEqual('909B07DB17E21D263C55794AB815BF1DB195FDD9', desc_list[0].fingerprint)120 self.assertEqual('7F7798A3CBB0F643B1CFCE3FD4F2B7C553764498', desc_list[1].fingerprint)121 self.assertEqual('B4869206C1EEA4A090FE614155BD6942701F80F1', desc_list[2].fingerprint)122 self.assertEqual('C18896EB6274DC8123491FAE1DD17E1769C54C4F', desc_list[3].fingerprint)123 self.assertEqual('478B4CB438302981DE9AAF246F48DBE57F69050A', desc_list[4].fingerprint)124 self.assertEqual('25D9D52A0350B42E69C8AB7CE945DB1CA38DA0CF', desc_list[5].fingerprint)125 def test_with_ed25519(self):126 """127 Parses a descriptor with a ed25519 identity key.128 """129 with open(get_resource('extrainfo_descriptor_with_ed25519'), 'rb') as descriptor_file:130 desc = next(stem.descriptor.parse_file(descriptor_file, validate = True))131 self.assertEqual('silverfoxden', desc.nickname)132 self.assertEqual('4970B1DC3DBC8D82D7F1E43FF44B28DBF4765A4E', desc.fingerprint)133 self.assertTrue('AQQABhz0AQFcf5tGWLvPvr' in desc.ed25519_certificate)134 self.assertEqual('g6Zg7Er8K7C1etmt7p20INE1ExIvMRPvhwt6sjbLqEK+EtQq8hT+86hQ1xu7cnz6bHee+Zhhmcc4JamV4eiMAw', desc.ed25519_signature)135 self.assertEqual([], desc.get_unrecognized_lines())136 def test_bridge_with_ed25519(self):137 """138 Parses a bridge descriptor with a ed25519 identity key.139 """140 with open(get_resource('bridge_extrainfo_descriptor_with_ed25519'), 'rb') as descriptor_file:141 desc = next(stem.descriptor.parse_file(descriptor_file, validate = True))142 self.assertEqual('Unnamed', desc.nickname)143 self.assertEqual('B8AB331047F1C1637EFE07FB1B94CCC0FE0ABFFA', desc.fingerprint)144 self.assertFalse(hasattr(desc, 'ed25519_certificate'))145 self.assertEqual('VigmhxML9uw8CT1XeGqZ8KLMhKk6AOKnChQt24usBbI', desc.ed25519_certificate_hash)146 self.assertEqual('7DSOQz9eGgjDX6GT7qcrVViK8yqJD4aoEnuhdAgYtgA', desc.router_digest_sha256)147 self.assertEqual([], desc.get_unrecognized_lines())148 def test_nonascii_v3_reqs(self):149 """150 Malformed descriptor with non-ascii content for the 'dirreq-v3-reqs' line.151 """152 with open(get_resource('unparseable/extrainfo_nonascii_v3_reqs'), 'rb') as descriptor_file:153 desc_generator = stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True)154 exc_msg = "'dirreq-v3-reqs' line had non-ascii content: S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,??=4026591624,6?=4026537520,6?=4026537520,6?=4026537520,us=8"155 self.assertRaisesWith(ValueError, exc_msg, next, desc_generator)156 def test_minimal_extrainfo_descriptor(self):157 """158 Basic sanity check that we can parse an extrainfo descriptor with minimal159 attributes.160 """161 desc = RelayExtraInfoDescriptor.create()162 self.assertTrue(desc.nickname.startswith('Unnamed'))163 def test_unrecognized_line(self):164 """165 Includes unrecognized content in the descriptor.166 """167 desc = RelayExtraInfoDescriptor.create({'pepperjack': 'is oh so tasty!'})168 self.assertEqual(['pepperjack is oh so tasty!'], desc.get_unrecognized_lines())169 def test_proceeding_line(self):170 """171 Includes a line prior to the 'extra-info' entry.172 """173 expect_invalid_attr_for_text(self, b'exit-streams-opened port=80\n' + RelayExtraInfoDescriptor.content())174 def test_trailing_line(self):175 """176 Includes a line after the 'router-signature' entry.177 """178 expect_invalid_attr_for_text(self, RelayExtraInfoDescriptor.content() + b'\nexit-streams-opened port=80')179 def test_extrainfo_line_missing_fields(self):180 """181 Checks that validation catches when the extra-info line is missing fields182 and that without validation both the nickname and fingerprint are left as183 None.184 """185 test_entries = (186 'ninja',187 'ninja ',188 'B2289C3EAB83ECD6EB916A2F481A02E6B76A0A48',189 ' B2289C3EAB83ECD6EB916A2F481A02E6B76A0A48',190 )191 for entry in test_entries:192 desc = expect_invalid_attr(self, {'extra-info': entry}, 'nickname')193 self.assertEqual(None, desc.nickname)194 self.assertEqual(None, desc.fingerprint)195 def test_geoip_db_digest(self):196 """197 Parses the geoip-db-digest and geoip6-db-digest lines with valid and198 invalid data.199 """200 geoip_db_digest = '916A3CA8B7DF61473D5AE5B21711F35F301CE9E8'201 desc = RelayExtraInfoDescriptor.create({'geoip-db-digest': geoip_db_digest})202 self.assertEqual(geoip_db_digest, desc.geoip_db_digest)203 desc = RelayExtraInfoDescriptor.create({'geoip6-db-digest': geoip_db_digest})204 self.assertEqual(geoip_db_digest, desc.geoip6_db_digest)205 test_entries = (206 '',207 '916A3CA8B7DF61473D5AE5B21711F35F301CE9E',208 '916A3CA8B7DF61473D5AE5B21711F35F301CE9E88',209 '916A3CA8B7DF61473D5AE5B21711F35F301CE9EG',210 '916A3CA8B7DF61473D5AE5B21711F35F301CE9E-',211 )212 for entry in test_entries:213 expect_invalid_attr(self, {'geoip-db-digest': entry}, 'geoip_db_digest')214 expect_invalid_attr(self, {'geoip6-db-digest': entry}, 'geoip6_db_digest')215 def test_cell_circuits_per_decile(self):216 """217 Parses the cell-circuits-per-decile line with valid and invalid data.218 """219 test_entries = (220 ('0', 0),221 ('11', 11),222 )223 for entry in ('0', '11', '25'):224 desc = RelayExtraInfoDescriptor.create({'cell-circuits-per-decile': entry})225 self.assertEqual(int(entry), desc.cell_circuits_per_decile)226 test_entries = (227 '',228 ' ',229 '-5',230 'blarg',231 )232 for entry in test_entries:233 expect_invalid_attr(self, {'cell-circuits-per-decile': entry}, 'cell_circuits_per_decile')234 def test_dir_response_lines(self):235 """236 Parses the dirreq-v2-resp and dirreq-v3-resp lines with valid and invalid237 data.238 """239 for keyword in ('dirreq-v2-resp', 'dirreq-v3-resp'):240 attr = keyword.replace('-', '_').replace('dirreq', 'dir').replace('resp', 'responses')241 unknown_attr = attr + '_unknown'242 test_value = 'ok=0,unavailable=0,not-found=984,not-modified=0,something-new=7'243 desc = RelayExtraInfoDescriptor.create({keyword: test_value})244 self.assertEqual(0, getattr(desc, attr)[DirResponse.OK])245 self.assertEqual(0, getattr(desc, attr)[DirResponse.UNAVAILABLE])246 self.assertEqual(984, getattr(desc, attr)[DirResponse.NOT_FOUND])247 self.assertEqual(0, getattr(desc, attr)[DirResponse.NOT_MODIFIED])248 self.assertEqual(7, getattr(desc, unknown_attr)['something-new'])249 test_entries = (250 'ok=-4',251 'ok:4',252 'ok=4.not-found=3',253 )254 for entry in test_entries:255 desc = expect_invalid_attr(self, {keyword: entry})256 self.assertEqual(None, getattr(desc, attr))257 self.assertEqual(None, getattr(desc, unknown_attr))258 def test_dir_stat_lines(self):259 """260 Parses the dirreq-v2-direct-dl, dirreq-v3-direct-dl, dirreq-v2-tunneled-dl,261 and dirreq-v3-tunneled-dl lines with valid and invalid data.262 """263 for keyword in ('dirreq-v2-direct-dl', 'dirreq-v2-direct-dl', 'dirreq-v2-tunneled-dl', 'dirreq-v2-tunneled-dl'):264 attr = keyword.replace('-', '_').replace('dirreq', 'dir')265 unknown_attr = attr + '_unknown'266 test_value = 'complete=2712,timeout=32,running=4,min=741,d1=14507,d2=22702,q1=28881,d3=38277,d4=73729,md=111455,d6=168231,d7=257218,q3=319833,d8=390507,d9=616301,something-new=11,max=29917857'267 desc = RelayExtraInfoDescriptor.create({keyword: test_value})268 self.assertEqual(2712, getattr(desc, attr)[DirStat.COMPLETE])269 self.assertEqual(32, getattr(desc, attr)[DirStat.TIMEOUT])270 self.assertEqual(4, getattr(desc, attr)[DirStat.RUNNING])271 self.assertEqual(741, getattr(desc, attr)[DirStat.MIN])272 self.assertEqual(14507, getattr(desc, attr)[DirStat.D1])273 self.assertEqual(22702, getattr(desc, attr)[DirStat.D2])274 self.assertEqual(28881, getattr(desc, attr)[DirStat.Q1])275 self.assertEqual(38277, getattr(desc, attr)[DirStat.D3])276 self.assertEqual(73729, getattr(desc, attr)[DirStat.D4])277 self.assertEqual(111455, getattr(desc, attr)[DirStat.MD])278 self.assertEqual(168231, getattr(desc, attr)[DirStat.D6])279 self.assertEqual(257218, getattr(desc, attr)[DirStat.D7])280 self.assertEqual(319833, getattr(desc, attr)[DirStat.Q3])281 self.assertEqual(390507, getattr(desc, attr)[DirStat.D8])282 self.assertEqual(616301, getattr(desc, attr)[DirStat.D9])283 self.assertEqual(29917857, getattr(desc, attr)[DirStat.MAX])284 self.assertEqual(11, getattr(desc, unknown_attr)['something-new'])285 test_entries = (286 'complete=-4',287 'complete:4',288 'complete=4.timeout=3',289 )290 for entry in test_entries:291 desc = expect_invalid_attr(self, {keyword: entry})292 self.assertEqual(None, getattr(desc, attr))293 self.assertEqual(None, getattr(desc, unknown_attr))294 def test_conn_bi_direct(self):295 """296 Parses the conn-bi-direct line with valid and invalid data.297 """298 desc = RelayExtraInfoDescriptor.create({'conn-bi-direct': '2012-05-03 12:07:50 (500 s) 277431,12089,0,2134'})299 self.assertEqual(datetime.datetime(2012, 5, 3, 12, 7, 50), desc.conn_bi_direct_end)300 self.assertEqual(500, desc.conn_bi_direct_interval)301 self.assertEqual(277431, desc.conn_bi_direct_below)302 self.assertEqual(12089, desc.conn_bi_direct_read)303 self.assertEqual(0, desc.conn_bi_direct_write)304 self.assertEqual(2134, desc.conn_bi_direct_both)305 test_entries = (306 '',307 '2012-05-03',308 '2012-05-03 12:07:60 (500 s)',309 '2012-05-03 12:07:50 (500 s',310 '2012-05-03 12:07:50 (500s)',311 '2012-05-03 12:07:50 (500 s)11',312 '2012-05-03 12:07:50 (500 s) 277431,12089,0',313 '2012-05-03 12:07:50 (500 s) 277431,12089,0a,2134',314 '2012-05-03 12:07:50 (500 s) -277431,12089,0,2134',315 )316 for entry in test_entries:317 desc = expect_invalid_attr(self, {'conn-bi-direct': entry})318 self.assertEqual(None, desc.conn_bi_direct_end)319 self.assertEqual(None, desc.conn_bi_direct_interval)320 self.assertEqual(None, desc.conn_bi_direct_below)321 self.assertEqual(None, desc.conn_bi_direct_read)322 self.assertEqual(None, desc.conn_bi_direct_write)323 self.assertEqual(None, desc.conn_bi_direct_both)324 def test_percentage_lines(self):325 """326 Uses valid and invalid data to tests lines of the form...327 "<keyword>" num%328 """329 for keyword in ('dirreq-v2-share', 'dirreq-v3-share'):330 attr = keyword.replace('-', '_').replace('dirreq', 'dir')331 test_entries = (332 ('0.00%', 0.0),333 ('0.01%', 0.0001),334 ('50%', 0.5),335 ('100.0%', 1.0),336 )337 for test_value, expected_value in test_entries:338 desc = RelayExtraInfoDescriptor.create({keyword: test_value})339 self.assertEqual(expected_value, getattr(desc, attr))340 test_entries = (341 (''),342 (' '),343 ('100'),344 ('-5%'),345 )346 for entry in test_entries:347 expect_invalid_attr(self, {keyword: entry}, attr)348 def test_number_list_lines(self):349 """350 Uses valid and invalid data to tests lines of the form...351 "<keyword>" num,...,num352 """353 for keyword in ('cell-processed-cells', 'cell-queued-cells', 'cell-time-in-queue'):354 attr = keyword.replace('-', '_')355 test_entries = (356 ('', []),357 (' ', []),358 ('0,0,0', [0.0, 0.0, 0.0]),359 ('2.3,-4.6,8.9,16.12,32.15', [2.3, -4.6, 8.9, 16.12, 32.15]),360 )361 for test_value, expected_value in test_entries:362 desc = RelayExtraInfoDescriptor.create({keyword: test_value})363 self.assertEqual(expected_value, getattr(desc, attr))364 test_entries = (365 (',,11', [11.0]),366 ('abc,5.7,def', [5.7]),367 ('blarg', []),368 )369 for entry, expected in test_entries:370 expect_invalid_attr(self, {keyword: entry}, attr, expected)371 def test_timestamp_lines(self):372 """373 Uses valid and invalid data to tests lines of the form...374 "<keyword>" YYYY-MM-DD HH:MM:SS375 """376 for keyword in ('published', 'geoip-start-time'):377 attr = keyword.replace('-', '_')378 desc = RelayExtraInfoDescriptor.create({keyword: '2012-05-03 12:07:50'})379 self.assertEqual(datetime.datetime(2012, 5, 3, 12, 7, 50), getattr(desc, attr))380 test_entries = (381 '',382 '2012-05-03 12:07:60',383 '2012-05-03 ',384 '2012-05-03',385 )386 for entry in test_entries:387 expect_invalid_attr(self, {keyword: entry}, attr)388 def test_timestamp_and_interval_lines(self):389 """390 Uses valid and invalid data to tests lines of the form...391 "<keyword>" YYYY-MM-DD HH:MM:SS (NSEC s)392 """393 for keyword in ('cell-stats-end', 'entry-stats-end', 'exit-stats-end', 'bridge-stats-end', 'dirreq-stats-end'):394 end_attr = keyword.replace('-', '_').replace('dirreq', 'dir')395 interval_attr = end_attr[:-4] + '_interval'396 desc = RelayExtraInfoDescriptor.create({keyword: '2012-05-03 12:07:50 (500 s)'})397 self.assertEqual(datetime.datetime(2012, 5, 3, 12, 7, 50), getattr(desc, end_attr))398 self.assertEqual(500, getattr(desc, interval_attr))399 test_entries = (400 '',401 '2012-05-03 ',402 '2012-05-03',403 '2012-05-03 12:07:60 (500 s)',404 '2012-05-03 12:07:50 (500s)',405 '2012-05-03 12:07:50 (500 s',406 '2012-05-03 12:07:50 (500 )',407 )408 for entry in test_entries:409 desc = expect_invalid_attr(self, {'entry-stats-end': entry})410 self.assertEqual(None, desc.entry_stats_end)411 self.assertEqual(None, desc.entry_stats_interval)412 def test_timestamp_interval_and_value_lines(self):413 """414 Uses valid and invalid data to tests lines of the form...415 "<keyword>" YYYY-MM-DD HH:MM:SS (NSEC s) NUM,NUM,NUM,NUM,NUM...416 """417 for keyword in ('read-history', 'write-history', 'dirreq-read-history', 'dirreq-write-history'):418 base_attr = keyword.replace('-', '_').replace('dirreq', 'dir')419 end_attr = base_attr + '_end'420 interval_attr = base_attr + '_interval'421 values_attr = base_attr + '_values'422 desc = RelayExtraInfoDescriptor.create({keyword: '2012-05-03 12:07:50 (500 s) 50,11,5'})423 self.assertEqual(datetime.datetime(2012, 5, 3, 12, 7, 50), getattr(desc, end_attr))424 self.assertEqual(500, getattr(desc, interval_attr))425 self.assertEqual([50, 11, 5], getattr(desc, values_attr))426 for test_value in ('', ' '):427 desc = RelayExtraInfoDescriptor.create({'write-history': '2012-05-03 12:07:50 (500 s)%s' % test_value})428 self.assertEqual(datetime.datetime(2012, 5, 3, 12, 7, 50), desc.write_history_end)429 self.assertEqual(500, desc.write_history_interval)430 self.assertEqual([], desc.write_history_values)431 test_entries = (432 '',433 '2012-05-03',434 '2012-05-03 12:07:60 (500 s)',435 '2012-05-03 12:07:50 (500s)',436 '2012-05-03 12:07:50 (500 s',437 '2012-05-03 12:07:50 (500 s)11',438 )439 for entry in test_entries:440 desc = expect_invalid_attr(self, {'write-history': entry})441 self.assertEqual(None, desc.write_history_end)442 self.assertEqual(None, desc.write_history_interval)443 self.assertEqual(None, desc.write_history_values)444 def test_port_mapping_lines(self):445 """446 Uses valid and invalid data to tests lines of the form...447 "<keyword>" port=N,port=N,...448 """449 for keyword in ('exit-kibibytes-written', 'exit-kibibytes-read', 'exit-streams-opened'):450 attr = keyword.replace('-', '_')451 test_entries = (452 ('', {}),453 ('443=100,other=111', {443: 100, 'other': 111}),454 ('80=115533759,443=1777,995=690', {80: 115533759, 443: 1777, 995: 690}),455 )456 for test_value, expected_value in test_entries:457 desc = RelayExtraInfoDescriptor.create({keyword: test_value})458 self.assertEqual(expected_value, getattr(desc, attr))459 test_entries = (460 '8000000=115533759',461 '-80=115533759',462 '80=-115533759',463 '=115533759',464 '80=',465 '80,115533759',466 )467 for entry in test_entries:468 expect_invalid_attr(self, {keyword: entry}, attr)469 def test_hidden_service_stats_end(self):470 """471 Exercise the hidserv-stats-end, which should be a simple date.472 """473 desc = RelayExtraInfoDescriptor.create({'hidserv-stats-end': '2012-05-03 12:07:50'})474 self.assertEqual(datetime.datetime(2012, 5, 3, 12, 7, 50), desc.hs_stats_end)475 test_entries = (476 '',477 '2012',478 '2012-05',479 '2012-05-03',480 '2012-05-03 12',481 '2012-05-03 12:07',482 '2012-05-03 12:07:-50',483 )484 for entry in test_entries:485 expect_invalid_attr(self, {'hidserv-stats-end': entry}, 'hs_stats_end')486 def test_hidden_service_stats(self):487 """488 Check the 'hidserv-rend-relayed-cells' and 'hidserv-dir-onions-seen', which489 share the same format.490 """491 attributes = (492 ('hidserv-rend-relayed-cells', 'hs_rend_cells', 'hs_rend_cells_attr'),493 ('hidserv-dir-onions-seen', 'hs_dir_onions_seen', 'hs_dir_onions_seen_attr'),494 )495 test_entries = (496 '',497 'hello',498 ' key=value',499 '40 key',500 '40 key value',501 '40 key key=value',502 )503 for keyword, stat_attr, extra_attr in attributes:504 # just the numeric stat (no extra attributes)505 desc = RelayExtraInfoDescriptor.create({keyword: '345'})506 self.assertEqual(345, getattr(desc, stat_attr))507 self.assertEqual({}, getattr(desc, extra_attr))508 # values can be negative (#15276)509 desc = RelayExtraInfoDescriptor.create({keyword: '-345'})510 self.assertEqual(-345, getattr(desc, stat_attr))511 self.assertEqual({}, getattr(desc, extra_attr))512 # with extra attributes513 desc = RelayExtraInfoDescriptor.create({keyword: '345 spiffy=true snowmen=neat'})514 self.assertEqual(345, getattr(desc, stat_attr))515 self.assertEqual({'spiffy': 'true', 'snowmen': 'neat'}, getattr(desc, extra_attr))516 for entry in test_entries:517 expect_invalid_attr(self, {keyword: entry}, stat_attr)518 expect_invalid_attr(self, {keyword: entry}, extra_attr, {})519 def test_padding_counts(self):520 """521 Check the 'hidserv-dir-onions-seen' lines.522 """523 desc = RelayExtraInfoDescriptor.create({'padding-counts': '2017-05-17 11:02:58 (86400 s) bin-size=10000 write-drop=0 write-pad=10000 write-total=10000 read-drop=0 read-pad=10000 read-total=3780000 enabled-read-pad=0 enabled-read-total=0 enabled-write-pad=0 enabled-write-total=0 max-chanpad-timers=0 non-numeric=test'})524 self.assertEqual({525 'bin-size': 10000,526 'write-drop': 0,527 'write-pad': 10000,528 'write-total': 10000,529 'read-drop': 0,530 'read-pad': 10000,531 'read-total': 3780000,532 'enabled-read-pad': 0,533 'enabled-read-total': 0,534 'enabled-write-pad': 0,535 'enabled-write-total': 0,536 'max-chanpad-timers': 0,537 'non-numeric': 'test', # presently all values are ints but the spec allows for anything538 }, desc.padding_counts)539 self.assertEqual(datetime.datetime(2017, 5, 17, 11, 2, 58), desc.padding_counts_end)540 self.assertEqual(86400, desc.padding_counts_interval)541 test_entries = (542 '',543 '2012-05-03',544 '2012-05-03 12:07:60 (500 s)',545 '2012-05-03 12:07:50 (500 s',546 '2012-05-03 12:07:50 (500s)',547 '2012-05-03 12:07:50 (500 s)bin-size=10',548 '2012-05-03 12:07:50 (500 s) bin-size',549 '2012-05-03 12:07:50 (500 s) bin-size=',550 )551 for entry in test_entries:552 desc = expect_invalid_attr(self, {'padding-counts': entry})553 self.assertEqual({}, desc.padding_counts)554 self.assertEqual(None, desc.padding_counts_end)555 self.assertEqual(None, desc.padding_counts_interval)556 def test_locale_mapping_lines(self):557 """558 Uses valid and invalid data to tests lines of the form...559 "<keyword>" CC=N,CC=N,...560 """561 for keyword in ('dirreq-v2-ips', 'dirreq-v3-ips', 'dirreq-v2-reqs', 'dirreq-v3-reqs', 'geoip-client-origins', 'entry-ips', 'bridge-ips'):562 attr = keyword.replace('-', '_').replace('dirreq', 'dir').replace('reqs', 'requests')563 test_entries = (564 ('', {}),565 ('uk=5,de=3,jp=2', {'uk': 5, 'de': 3, 'jp': 2}),566 )567 for test_value, expected_value in test_entries:568 desc = RelayExtraInfoDescriptor.create({keyword: test_value})569 self.assertEqual(expected_value, getattr(desc, attr))570 test_entries = (571 'uk=-4',572 'uki=4',573 'uk:4',574 'uk=4.de=3',575 )576 for entry in test_entries:577 expect_invalid_attr(self, {keyword: entry}, attr)578 def test_minimal_bridge_descriptor(self):579 """580 Basic sanity check that we can parse a descriptor with minimal attributes.581 """582 desc = BridgeExtraInfoDescriptor.create()583 self.assertEqual('ec2bridgereaac65a3', desc.nickname)584 self.assertEqual([], desc.get_unrecognized_lines())585 # check that we don't have crypto fields586 self.assertRaises(AttributeError, getattr, desc, 'signature')587 def test_bridge_ip_versions_line(self):588 """589 Parses the 'bridge-ip-versions' line, which only appears in bridges.590 """591 desc = BridgeExtraInfoDescriptor.create({'bridge-ip-versions': 'v4=16,v6=40'})592 self.assertEqual({'v4': 16, 'v6': 40}, desc.ip_versions)593 desc = BridgeExtraInfoDescriptor.create({'bridge-ip-versions': ''})594 self.assertEqual({}, desc.ip_versions)595 desc_text = BridgeExtraInfoDescriptor.content({'bridge-ip-versions': 'v4=24.5'})596 self.assertRaises(ValueError, RelayExtraInfoDescriptor, desc_text, True)597 def test_bridge_ip_transports_line(self):598 """599 Parses the 'bridge-ip-transports' line, which only appears in bridges.600 """601 desc = BridgeExtraInfoDescriptor.create({'bridge-ip-transports': '<OR>=16,<??>=40'})602 self.assertEqual({'<OR>': 16, '<??>': 40}, desc.ip_transports)603 desc = BridgeExtraInfoDescriptor.create({'bridge-ip-transports': ''})604 self.assertEqual({}, desc.ip_transports)605 desc_text = BridgeExtraInfoDescriptor.content({'bridge-ip-transports': '<OR>=24.5'})606 self.assertRaises(ValueError, RelayExtraInfoDescriptor, desc_text, True)607 def test_transport_line(self):608 """609 Basic exercise for both a bridge and relay's transport entry.610 """611 desc = BridgeExtraInfoDescriptor.create({'transport': 'obfs3'})612 self.assertEqual({'obfs3': (None, None, None)}, desc.transport)613 self.assertEqual([], desc.get_unrecognized_lines())614 desc = RelayExtraInfoDescriptor.create({'transport': 'obfs2 83.212.96.201:33570'})615 self.assertEqual({'obfs2': ('83.212.96.201', 33570, [])}, desc.transport)616 self.assertEqual([], desc.get_unrecognized_lines())617 # multiple transport lines618 desc = BridgeExtraInfoDescriptor.create({'transport': 'obfs3\ntransport obfs4'})619 self.assertEqual({'obfs3': (None, None, None), 'obfs4': (None, None, None)}, desc.transport)...
entries_keys_values.js
Source:entries_keys_values.js
1// Copyright 2018 MaidSafe.net limited.2//3// This SAFE Network Software is licensed to you under4// the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT> or5// the Modified BSD license <LICENSE-BSD or https://opensource.org/licenses/BSD-3-Clause>,6// at your option.7//8// This file may not be copied, modified, or distributed except according to those terms.9//10// Please review the Licences for the specific language governing permissions and limitations11// relating to use of the SAFE Network Software.12const should = require('should');13const h = require('../helpers');14describe('Mutable Data Entries', () => {15 let app;16 const TYPE_TAG = 15639;17 const TEST_ENTRIES = { key1: 'value1', key2: 'value2' };18 before(async () => {19 app = await h.createAuthenticatedTestApp();20 });21 it('get entries and check length', () => app.mutableData.newRandomPublic(TYPE_TAG)22 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getEntries()))23 .then((entries) => entries.len())24 .then((len) => should(len).equal(Object.keys(TEST_ENTRIES).length))25 );26 it('get entries and get a value', () => app.mutableData.newRandomPublic(TYPE_TAG)27 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getEntries()))28 .then((entries) => entries.get('key1'))29 .then((value) => {30 should(value).not.be.undefined();31 should(value.buf.toString()).equal('value1');32 return should(value.version).equal(0);33 })34 );35 it('check numeric key is converted to string by quickSetup', () => app.mutableData.newRandomPublic(TYPE_TAG)36 .then((m) => m.quickSetup({ 3030: 'value' }).then(() => m.getEntries()))37 .then((entries) => entries.get('3030'))38 .then((value) => {39 should(value).not.be.undefined();40 should(value.buf.toString()).equal('value');41 return should(value.version).equal(0);42 })43 );44 it('insert & get a single value', () => app.mutableData.newRandomPublic(TYPE_TAG)45 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getEntries()))46 .then((entries) => entries.insert('newKey', 'newValue')47 .then(entries.get('newKey')48 .then((value) => {49 should(value).not.be.undefined();50 should(value.buf.toString()).equal('newValue');51 return should(value.version).equal(0);52 }))53 ));54 it('fail to insert entry with numeric key', () => app.mutableData.newRandomPublic(TYPE_TAG)55 .then((m) => m.quickSetup().then(() => m.getEntries()))56 .then((entries) => should(entries.insert(3030, 'numeric')).be.rejectedWith(/"value" argument must not be/)57 ));58 it('insert & get a single value from private MD', () => app.mutableData.newRandomPrivate(TYPE_TAG)59 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getEntries()))60 .then((entries) => entries.insert('newKey', 'newValue')61 .then(entries.get('newKey')62 .then((value) => {63 should(value).not.be.undefined();64 should(value.buf.toString()).equal('newValue');65 return should(value.version).equal(0);66 }))67 ));68 it('get list of entries', async () => {69 const m = await app.mutableData.newRandomPublic(TYPE_TAG);70 await m.quickSetup(TEST_ENTRIES);71 const entries = await m.getEntries();72 const entriesArray = await entries.listEntries();73 const testKeys = Object.keys(TEST_ENTRIES);74 return entriesArray.map((entry, i) => {75 should(entry.key.toString()).be.equal(testKeys[i]);76 return should(entry.value.buf.toString()).be.equal(TEST_ENTRIES[testKeys[i]]);77 });78 }).timeout(10000);79 it('list entries after deleting an entry', async () => {80 const md = await app.mutableData.newRandomPrivate(TYPE_TAG);81 await md.quickSetup({ key1: 'value1' });82 let entries = await md.getEntries();83 let listEntries = await entries.listEntries();84 let value = listEntries[0].value;85 should(value).not.be.undefined();86 should(value.buf.toString()).equal('value1');87 should(value.version).equal(0);88 const mut = await app.mutableData.newMutation();89 await mut.delete('key1', 1);90 await md.applyEntriesMutation(mut);91 entries = await md.getEntries();92 listEntries = await entries.listEntries();93 value = listEntries[0].value;94 should(value).not.be.undefined();95 should(value.buf.toString()).equal('');96 return should(value.version).equal(1);97 });98 it('get list of keys', () => app.mutableData.newRandomPublic(TYPE_TAG)99 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getKeys()))100 .then((keys) => should(keys.length).equal(Object.keys(TEST_ENTRIES).length))101 );102 it('check list of keys', () => app.mutableData.newRandomPublic(TYPE_TAG)103 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getKeys()))104 .then((keys) => Promise.all(keys.map((key) =>105 should(TEST_ENTRIES).have.ownProperty(key.toString())))));106 it('get empty list of keys', () => app.mutableData.newRandomPublic(TYPE_TAG)107 .then((m) => m.quickSetup({}).then(() => m.getKeys()))108 .then((keys) => should(keys.length).equal(0))109 );110 it('get list of values', () => app.mutableData.newRandomPublic(TYPE_TAG)111 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getValues()))112 .then((values) => should(values.length).equal(Object.keys(TEST_ENTRIES).length))113 );114 it('check list of values', () => app.mutableData.newRandomPublic(TYPE_TAG)115 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getValues()))116 .then((values) => Promise.all(values.map((value) =>117 should(TEST_ENTRIES).matchAny((v) => {118 should(v).be.eql(value.buf.toString());119 return should(value.version).be.equal(0);120 })121 ))));122 it('get empty list of values', () => app.mutableData.newRandomPublic(TYPE_TAG)123 .then((m) => m.quickSetup({}).then(() => m.getValues()))124 .then((values) => should(values.length).equal(0))125 );126 it('fail to decrypt a private MD entry using wrong encryption keys', async () => {127 const privMd = await app.mutableData.newRandomPrivate(TYPE_TAG);128 await privMd.quickSetup();129 const nameAndTag = await privMd.getNameAndTag();130 const mut = await app.mutableData.newMutation();131 const encKey = await privMd.encryptKey('encryptedKey');132 const encValue = await privMd.encryptValue('encryptedValue');133 await mut.insert(encKey, encValue);134 await privMd.applyEntriesMutation(mut);135 const notMyPrivMd = await app.mutableData.newPrivate(nameAndTag.name,136 nameAndTag.typeTag,137 h.createRandomSecKey(),138 h.createRandomNonce());139 const val = await notMyPrivMd.get(encKey);140 return should(notMyPrivMd.decrypt(val.buf)).be.rejectedWith('Core error: Symmetric decryption failed');141 });...
permissions.js
Source:permissions.js
1// Copyright 2018 MaidSafe.net limited.2//3// This SAFE Network Software is licensed to you under4// the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT> or5// the Modified BSD license <LICENSE-BSD or https://opensource.org/licenses/BSD-3-Clause>,6// at your option.7//8// This file may not be copied, modified, or distributed except according to those terms.9//10// Please review the Licences for the specific language governing permissions and limitations11// relating to use of the SAFE Network Software.12const should = require('should');13const h = require('../helpers');14const { pubConsts: CONSTANTS } = require('../../src/consts');15describe('Permissions', () => {16 let app;17 const TYPE_TAG = 15639;18 const TEST_ENTRIES = { key1: 'value1', key2: 'value2' };19 before(async () => {20 app = await h.createAuthenticatedTestApp();21 });22 it('get list of permissions', () => app.mutableData.newRandomPublic(TYPE_TAG)23 .then((m) => m.quickSetup(TEST_ENTRIES)24 .then(() => m.getPermissions()25 .then((perm) => perm.len())26 .then((length) => should(length).equal(1)27 )28 ))29 );30 it('list permission sets and remove them', () => app.mutableData.newRandomPublic(TYPE_TAG)31 .then((m) => m.quickSetup(TEST_ENTRIES).then(() => m.getPermissions())32 .then((perms) => perms.listPermissionSets()33 .then((permSets) => Promise.all(permSets.map((userPermSet) =>34 should(m.delUserPermissions(userPermSet.signKey, 1)).be.fulfilled()35 )))36 )37 ));38 it('get permissions set', () => app.mutableData.newRandomPublic(TYPE_TAG)39 .then((m) => m.quickSetup(TEST_ENTRIES)40 .then(() => m.getPermissions()41 .then((perm) => app.crypto.getAppPubSignKey()42 .then((pk) => should(perm.getPermissionSet(pk)).be.fulfilled())43 )))44 );45 it('get empty list of permissions sets', () => app.mutableData.newRandomPublic(TYPE_TAG)46 .then((m) => m.put(CONSTANTS.MD_PERMISSION_EMPTY, CONSTANTS.MD_ENTRIES_EMPTY)47 .then(() => m.getPermissions())48 )49 .then((perms) => perms.listPermissionSets())50 .then((permsSets) => should(permsSets.length).equal(0))51 );52 it('insert permissions set for `Anyone`', () => app.mutableData.newRandomPublic(TYPE_TAG)53 .then((m) => m.quickSetup(TEST_ENTRIES)54 .then(() => m.getPermissions())55 .then((perm) => should(perm.insertPermissionSet(CONSTANTS.USER_ANYONE,56 ['Delete'])).be.fulfilled()))57 );58 it('get permissions set for `Anyone`', () => app.mutableData.newRandomPublic(TYPE_TAG)59 .then((m) => m.quickSetup(TEST_ENTRIES)60 .then(() => m.getPermissions())61 .then((perm) => perm.insertPermissionSet(CONSTANTS.USER_ANYONE, ['Delete'])62 .then(() => should(perm.getPermissionSet(CONSTANTS.USER_ANYONE)).be.fulfilled())63 ))64 );65 it('insert new permissions set', () => app.mutableData.newRandomPublic(TYPE_TAG)66 .then((m) => m.quickSetup(TEST_ENTRIES)67 .then(() => app.crypto.getAppPubSignKey()68 .then((pk) => m.setUserPermissions(pk, ['Delete'], 1)69 .then(() => app.mutableData.newMutation()70 .then((mut) => mut.update('key2', 'updatedValue', 1)71 .then(() => should(m.applyEntriesMutation(mut)).be.rejected())72 )))))73 );74 it('update user\'s permissions', () => app.mutableData.newRandomPublic(TYPE_TAG)75 .then((m) => m.quickSetup(TEST_ENTRIES)76 .then(() => app.crypto.getAppPubSignKey()77 .then((pk) => m.setUserPermissions(pk, ['Insert'], 1)78 .then(() => app.mutableData.newMutation()79 .then((mut) => mut.update('key2', 'updatedValue', 1)80 .then(() => should(m.applyEntriesMutation(mut)).be.rejected())81 )))))82 );83 it('get user\'s permissions', () => app.mutableData.newRandomPublic(TYPE_TAG)84 .then((m) => m.quickSetup(TEST_ENTRIES)85 .then(() => app.crypto.getAppPubSignKey()86 .then((pk) => should(m.getUserPermissions(pk)).be.fulfilled())87 ))88 );89 it('remove user\'s permissions', () => app.mutableData.newRandomPublic(TYPE_TAG)90 .then((m) => m.quickSetup(TEST_ENTRIES)91 .then(() => app.crypto.getAppPubSignKey()92 .then((pk) => should(m.delUserPermissions(pk, 1)).be.fulfilled())93 .then(() => app.mutableData.newMutation()94 .then((mut) => mut.update('key2', 'updatedValue', 1)95 .then(() => should(m.applyEntriesMutation(mut))96 .be.rejectedWith('Core error: Routing client error -> Access denied'))97 ))))98 );99 it('set new permissions for `Anyone`', () => app.mutableData.newRandomPublic(TYPE_TAG)100 .then((m) => m.quickSetup(TEST_ENTRIES)101 .then(() => should(m.setUserPermissions(CONSTANTS.USER_ANYONE, ['Insert'], 1)).be.fulfilled())102 )103 );104 it('deny all permissions to `Anyone`', () => app.mutableData.newRandomPublic(TYPE_TAG)105 .then((m) => m.quickSetup(TEST_ENTRIES)106 .then(() => should(m.setUserPermissions(CONSTANTS.USER_ANYONE, null, 1)).be.fulfilled())107 )108 );109 it('get user permissions for `Anyone`', () => app.mutableData.newRandomPublic(TYPE_TAG)110 .then((m) => m.quickSetup(TEST_ENTRIES)111 .then(() => should(m.getUserPermissions(CONSTANTS.USER_ANYONE)).be.rejected())112 .then(() => m.setUserPermissions(CONSTANTS.USER_ANYONE, ['Insert'], 1))113 .then(() => should(m.getUserPermissions(CONSTANTS.USER_ANYONE)).be.fulfilled())114 )115 );116 it('remove user permissions for `Anyone`', () => app.mutableData.newRandomPublic(TYPE_TAG)117 .then((m) => m.quickSetup(TEST_ENTRIES)118 .then(() => m.setUserPermissions(CONSTANTS.USER_ANYONE, ['Insert'], 1))119 .then(() => should(m.delUserPermissions(CONSTANTS.USER_ANYONE, 1)).be.rejected())120 .then(() => should(m.delUserPermissions(CONSTANTS.USER_ANYONE, 2)).be.fulfilled())121 )122 );...
test_unit_seg_update_pg_hba.py
Source:test_unit_seg_update_pg_hba.py
1#!/usr/bin/env python2#3# Copyright (c) Greenplum Inc 2008. All Rights Reserved.4#5from mock import call, patch, MagicMock, Mock6import os7import seg_update_pg_hba8from gppylib.test.unit.gp_unittest import GpTestCase, run_tests9class UpdatePgHBAConfTests(GpTestCase):10 def setUp(self):11 self.apply_patches([12 patch('os.rename'),13 patch('os.path.abspath')14 ])15 def test_lineToCanonical(self):16 test_str = " \t qwerty qwerty\tqwerty\n \n"17 result_str = seg_update_pg_hba.lineToCanonical(test_str)18 expected_str = "qwerty qwerty qwerty"19 self.assertEqual(result_str, expected_str)20 def test_remove_dup_add_entries(self):21 pg_hba_entries = ['test1', 'test2']22 test_entries = 'test2\ntest3'23 result_out_entries = seg_update_pg_hba.remove_dup_add_entries(pg_hba_entries, test_entries)24 expected_out_entries = ['test1', 'test2', 'test3']25 self.assertEqual(result_out_entries, expected_out_entries)26 def test_remove_dup_add_entries_all_dup(self):27 pg_hba_entries = ['test1', 'test2']28 test_entries = 'test2'29 result_out_entries = seg_update_pg_hba.remove_dup_add_entries(pg_hba_entries, test_entries)30 expected_out_entries = ['test1', 'test2']31 self.assertEqual(result_out_entries, expected_out_entries)32 def test_remove_dup_add_entries_existing_dup(self):33 pg_hba_entries = ['test1', 'test2', 'test2']34 test_entries = 'test3'35 result_out_entries = seg_update_pg_hba.remove_dup_add_entries(pg_hba_entries, test_entries)36 expected_out_entries = ['test1', 'test2', 'test3']37 self.assertEqual(result_out_entries, expected_out_entries)38 def test_remove_dup_with_spaces_add_entries(self):39 entries_block = """host replication gpadmin samehost trust40host all gpadmin {ip_mirror2}/32 trust41host all gpadmin {ip_mirror1}/32 trust42host all gpadmin {ip_mirror2}/32 trust43host replication gpadmin {ip_mirror1}/32 trust44host replication gpadmin {ip_mirror2}/32 trust45# host replication gpadmin {ip_mirror1}/32 trust"""46 pg_hba_existing_entries = entries_block.format(ip_mirror1='10.0.0.1', ip_mirror2='10.0.0.2').split('\n')47 test_entries = 'host all gpadmin {ip_mirror1}/32 trust\nhost all gpadmin {ip_mirror3}/32 trust'\48 .format(ip_mirror1='10.0.0.1', ip_mirror3='10.0.0.3')49 result_out_entries = seg_update_pg_hba.remove_dup_add_entries(pg_hba_existing_entries, test_entries)50 expected_block = """host replication gpadmin samehost trust51host all gpadmin {ip_mirror2}/32 trust52host all gpadmin {ip_mirror1}/32 trust53host replication gpadmin {ip_mirror1}/32 trust54host replication gpadmin {ip_mirror2}/32 trust55# host replication gpadmin {ip_mirror1}/32 trust56host all gpadmin {ip_mirror3}/32 trust"""57 expected_out_entries = expected_block.\58 format(ip_mirror1='10.0.0.1', ip_mirror2='10.0.0.2', ip_mirror3='10.0.0.3').split('\n')...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!