#
#
# To test:	multiple stripes (yonge)
#	 	multiple devices in one stripe (??, I think we have it)
#
import unittest
import metaparse

test0 = """
d5: Concat/Stripe
    Size: 119691270 blocks
    Stripe 0:
        Device     Start Block  Dbase
        c0t0d0s5          0     No
    Stripe 1:
        Device     Start Block  Dbase
        c0t1d0s5          0     No
"""

test1 = """
d0: Mirror
    Submirror 0: d10
      State: Okay
    Submirror 1: d20
      State: Okay
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 2097414 blocks

d10: Submirror of d0
    State: Okay
    Size: 2097414 blocks
    Stripe 0:
        Device     Start Block  Dbase State        Hot Spare
        c0t0d0s0          0     No    Okay


d20: Submirror of d0
    State: Okay
    Size: 2097414 blocks
    Stripe 0:
        Device     Start Block  Dbase State        Hot Spare
        c0t1d0s0          0     No    Okay
"""

testfs1 = """
fs7/d221: Mirror
    Submirror 0: fs7/d806
      State: Okay
    Submirror 1: fs7/d807
      State: Okay
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 70320128 blocks
"""

test_one_submirror = """
fs5/d5: Mirror
    Submirror 1: fs5/d764
      State: Okay
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 70909952 blocks

fs5/d764: Submirror of fs5/d5
    State: Okay
    Size: 70909952 blocks
    Stripe 0:
        Device      Start Block  Dbase State        Hot Spare
        c2t3d12s0          0     No    Okay
"""

# A degraded example.
test_degraded = """
fs7/d151: Mirror
    Submirror 0: fs7/d645
      State: Okay
    Submirror 1: fs7/d624
      State: Needs maintenance
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 70909952 blocks

fs7/d645: Submirror of fs7/d151
    State: Okay
    Size: 70909952 blocks
    Stripe 0:
        Device      Start Block  Dbase State        Hot Spare
        c2t0d19s0          0     No    Okay


fs7/d624: Submirror of fs7/d151
    State: Needs maintenance
    Invoke: metaonline fs7/d151 fs7/d624
    Size: 70909952 blocks
    Stripe 0:
        Device      Start Block  Dbase State        Hot Spare
        c2t0d16s0          0     No    Okay


"""

class parseSimple(unittest.TestCase):
	def verify_mirror(self, mirror, type, dev, subnum):
		self.assertEqual(mirror.type, type)
		self.assertEqual(mirror.dev, dev)
		self.assertEqual(len(mirror.submirrors), subnum)
	def verify_submirror(self, mirror, state, dev, realdev):
		self.assertEqual(mirror.dev, dev)
		self.assertEqual(mirror.realdev, [realdev])
		self.assertEqual(mirror.state, state)
	def parse_verify_one(self, txt, dev, subnum):
		res = metaparse.parse(txt)
		self.assertEqual(len(res), 1)
		dev0 = res[0]
		self.verify_mirror(dev0, "mirror", dev, subnum)
		return dev0

	def testParseStripe(self):
		"""Test to see that we correctly parse, ie ignore, a stripe"""
		res = metaparse.parse(test0)
		self.assertEqual(len(res), 0)
		
	def testParseMirror(self):
		"""Test basic parsing of a known metastat for a single top-level device."""
		dev0 = self.parse_verify_one(test1, "d0", 2)
		self.verify_submirror(dev0.submirrors[0], "okay", "d10",
				      "c0t0d0s0")
		self.verify_submirror(dev0.submirrors[1], "okay", "d20",
				      "c0t1d0s0")
		self.assertEqual(dev0.all_okay(), True)
		self.assertEqual(dev0.is_consistent(), True)

	#def testParseFsMirror(self):
	#	"""Parse a fsN mirror example (without submirrors)."""
	#	dev0 = self.parse_verify_one(testfs1, "d221", 2)
	#	self.assertEqual(dev0.is_consistent(), False)

	def testParseOneSubmirror(self):
		"""Parse a fsN mirror device with only one submirror."""
		dev0 = self.parse_verify_one(test_one_submirror, "fs5/d5", 1)
		self.verify_submirror(dev0.submirrors[0], "okay", "fs5/d764",
				      "c2t3d12s0")
		self.assertEqual(dev0.all_okay(), True)
		self.assertEqual(dev0.is_consistent(), True)

	def testParseDegraded(self):
		"""Parse a mirror in degraded mode."""
		dev0 = self.parse_verify_one(test_degraded, "fs7/d151", 2)
		self.verify_submirror(dev0.submirrors[0], "okay", "fs7/d645",
				      "c2t0d19s0")
		self.verify_submirror(dev0.submirrors[1], "needsmaint",
				      "fs7/d624", "c2t0d16s0")
		self.assertEqual(dev0.all_okay(), False)
		self.assertEqual(dev0.is_consistent(), True)

#
# Bad parses; cases that should throw exceptions.
test_dup_devs = """
d10: Mirror
 Submirror 0: d610
 Submirror 1: d610
"""
test_no_devs = """
d10: Mirror
  Pass: 1
"""
test_many_stripes = """
d10: Mirror
 Submirror 0: d160

d160: Submirror of d10
  State: Okay
  Stripe 0:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s0          0     No    Okay
  Stripe 1:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s1          0     No    Okay
"""
test_no_state = """
d10: Mirror
 Submirror 0: d160

d160: Submirror of d10
  Stripe 0:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s0          0     No    Okay
"""
test_no_stripes = """
d10: Mirror
 Submirror 0: d160

d160: Submirror of d10
  State: Okay
"""
test_repeated_dev = """
d10: Mirror
  Submirror 0: d160

d10: Mirror
  Submirror 0: d180
"""
test_repeated_submirror = """
d10: Mirror
  Submirror 0: d160
  
d160: Submirror of d10
  State: Okay
  Stripe 0:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s0          0     No    Okay

d160: Submirror of d10
  State: Okay
  Stripe 0:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s0          0     No    Okay
"""
# This actually gets a duplicate mirror devices error, because of how
# the parsing is done.
test_repeated_submirror2 = """
d160: Mirror
  Submirror 0: d200

d10: Mirror
  Submirror 0: d160
"""
test_no_mirror = """
d160: Submirror of d10
  State: Okay
  Stripe 0:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s0          0     No    Okay
"""
test_no_mirror2 = """
d160: Mirror
  Submirror 0: d10

d160: Submirror of d10
  State: Okay
  Stripe 0:
    Device      Start Block  Dbase State        Hot Spare
    c2t0d19s0          0     No    Okay
"""

class badParses(unittest.TestCase):
	def testDupDevices(self):
		"Duplicate devices in a mirror definition are rejected."
		self.assertRaises(metaparse.DupMirrorDevices,
				  metaparse.parse, test_dup_devs)
	def testNoDevices(self):
		"No submirrors raises an exception."
		self.assertRaises(metaparse.NoMirrorDevices,
				  metaparse.parse, test_no_devs)
	def testMultiStripes(self):
		"Multiple stripes in a submirror raises an exception"
		self.assertRaises(metaparse.MultipleStripes,
				  metaparse.parse, test_many_stripes)
	def testNoState(self):
		"No submirror state raises an exception"
		self.assertRaises(metaparse.NoSubmirrorState,
				  metaparse.parse, test_no_state)
	def testNoDevice(self):
		"No device found for a submirror raises an exception"
		self.assertRaises(metaparse.NoRealDevice,
				  metaparse.parse, test_no_stripes)
	def testRepeatedDevs(self):
		"Repeated Mirror lines for the same device raises an exception."
		self.assertRaises(metaparse.MultipleMirror,
				  metaparse.parse, test_repeated_dev)
	def testRepeatedSubmirror(self):
		"Repeated Submirror lines for the same device raises an exception"
		self.assertRaises(metaparse.DuplicateMirror,
				  metaparse.parse, test_repeated_submirror)
		self.assertRaises(metaparse.DupMirrorDevices,
				  metaparse.parse, test_repeated_submirror2)
	def testNoMirror(self):
		"A submirror without a mirror should be an error"
		self.assertRaises(metaparse.NewSubmirror,
				  metaparse.parse, test_no_mirror)
		self.assertRaises(metaparse.NoMirror,
				  metaparse.parse, test_no_mirror2)
	def testParseFsMirror(self):
		"A mirror without submirrors should fail."
		self.assertRaises(metaparse.IncompleteData,
				  metaparse.parse, testfs1)

if __name__ == "__main__":
	unittest.main()
