def testTempView(self):
		"""Make a temp view."""
		be1 = CouchStub()
		be1.expect_POST("/funstuff0/_temp_view").reply(200, dict(
			total_rows=2,
			offset=0,
			rows=[
				{"id":"a", "key":"a", "value": "b"},
				{"id":"c", "key":"c", "value": "d"}
			]))
		be1.listen("localhost", 23456)

		be2 = CouchStub()
		be2.expect_POST("/funstuff1/_temp_view").reply(200, dict(
			total_rows=2,
			offset=0,
			rows=[
				{"id":"x", "key":"b", "value": "c"},
				{"id":"y", "key":"d", "value": "e"}
			]))
		be2.listen("localhost", 34567)

		resp = post("http://localhost:22008/funstuff/_temp_view", body={"language":"javascript", "map": "function(doc) { emit(doc.x, doc.y); }"})

		be1.verify()
		be2.verify()

		self.assertEqual(resp.body["total_rows"], 4)
		self.assertEqual(resp.body["offset"], 0)
		self.assertEqual(len(resp.body["rows"]), 4)
		self.assertEqual(resp.body["rows"][0]["key"], "a")
		self.assertEqual(resp.body["rows"][1]["key"], "b")
		self.assertEqual(resp.body["rows"][2]["key"], "c")
		self.assertEqual(resp.body["rows"][3]["key"], "d")
	def testMultikeyGet(self):
		"""Make a temp view."""
		be1 = CouchStub()
		be1_request = be1.expect_POST("/funstuff0/_all_docs?include_docs=true")
		be1_request.reply(200, dict(
			total_rows=2,
			offset=0,
			rows=[
				{"id":"a", "key":"a", "value": {"rev":"2"},"doc":"b"},
				{"id":"c", "key":"c", "value": {"rev":"3"},"doc":"d"}
			]))
		be1.listen("localhost", 23456)

		be2 = CouchStub()
		be2_request = be2.expect_POST("/funstuff1/_all_docs?include_docs=true")
		be2_request.reply(200, dict(
			total_rows=2,
			offset=0,
			rows=[
				{"id":"b", "key":"b", "value": {"rev":"7"},"doc":"z"},
				{"id":"y", "key":"y", "value": {"rev":"9"},"doc":"w"}
			]))
		be2.listen("localhost", 34567)

		resp = post("http://localhost:22008/funstuff/_all_docs?include_docs=true", body={"keys":["a","c","x","y"]})

		be1.verify()
		be2.verify()
		
		be1_post = cjson.decode(be1_request.input_body)
		be2_post = cjson.decode(be2_request.input_body)

		def lounge_hash(x):
			crc = zlib.crc32(x,0)
			return (crc >> 16)&0x7fff

		keys1 = be1_post['keys']
		keys2 = be2_post['keys']
		keys = {0:keys1, 1:keys2}
		num_shards = 2
		for v, k in keys.items():
			for key in k:
				self.assertEqual(lounge_hash(key) % num_shards, int(v))

		self.assertEqual(resp.body["total_rows"], 4)
		self.assertEqual(resp.body["offset"], 0)
		self.assertEqual(len(resp.body["rows"]), 4)
		rows = [x["key"] for x in resp.body["rows"]]
		rows.sort()
		self.assertEqual(rows, ["a","b","c","y"])
	def testBulkDocsWrongContentType(self):
		"""Make a bulk_docs req with the wrong content-type.

		We should handle this the same way a single node does (treat
		the body as JSON)
		"""
		be1 = CouchStub()
		be1_request = be1.expect_POST("/funstuff0/_bulk_docs")
		be1_request.reply(201, [
			{"id":"b","rev":"1-23456"},
			{"id":"e","error":"conflict","reason":"Document update conflict."}
		])
		be1.listen("localhost", 23456)

		be2 = CouchStub()
		be2_request = be2.expect_POST("/funstuff1/_bulk_docs")
		be2_request.reply(201, [
			{"id":"a","rev":"1-23456"},
			{"id":"c","rev":"2-34567"}
		])
		be2.listen("localhost", 34567)

		resp = post("http://localhost:22008/funstuff/_bulk_docs", {"docs":[
			{"_id":"a","how":"low"},
			{"_id":"b","can":"a"},
			{"_id":"c","punk":"get"},
			{"_id":"e","bannedin":"dc"}
		]}, {"Content-Type": "application/x-www-form-urlencoded"})

		be1.verify()
		be2.verify()

		be1_post = cjson.decode(be1_request.input_body)
		be2_post = cjson.decode(be2_request.input_body)

		self.assertEqual(len(resp.body), 4)
		for row in resp.body:
			if row['id']=='e':
				self.assertEqual(row['error'],'conflict')
			else:
				assert "rev" in row

		be1_post = cjson.decode(be1_request.input_body)
		self.assertEqual(len(be1_post['docs']), 2)
		self.assertEqual(sorted([row['_id'] for row in be1_post['docs']]), ['b', 'e'])

		be2_post = cjson.decode(be2_request.input_body)
		self.assertEqual(len(be2_post['docs']), 2)
		self.assertEqual(sorted([row['_id'] for row in be2_post['docs']]), ['a', 'c'])
	def testBulkDocs(self):
		be1 = CouchStub()
		be1_request = be1.expect_POST("/funstuff0/_bulk_docs")
		be1_request.reply(201, [
			{"id":"b","rev":"1-23456"},
			{"id":"e","error":"conflict","reason":"Document update conflict."}
		])
		be1.listen("localhost", 23456)

		be2 = CouchStub()
		be2_request = be2.expect_POST("/funstuff1/_bulk_docs")
		be2_request.reply(201, [
			{"id":"a","rev":"1-23456"},
			{"id":"c","rev":"2-34567"}
		])
		be2.listen("localhost", 34567)

		resp = post("http://localhost:22008/funstuff/_bulk_docs", {"docs":[
			{"_id":"a","how":"low"},
			{"_id":"b","can":"a"},
			{"_id":"c","punk":"get"},
			{"_id":"e","bannedin":"dc"}
		]})

		be1.verify()
		be2.verify()

		be1_post = cjson.decode(be1_request.input_body)
		be2_post = cjson.decode(be2_request.input_body)

		self.assertEqual(len(resp.body), 4)
		for row in resp.body:
			if row['id']=='e':
				self.assertEqual(row['error'],'conflict')
			else:
				assert "rev" in row

		be1_post = cjson.decode(be1_request.input_body)
		self.assertEqual(len(be1_post['docs']), 2)
		self.assertEqual(sorted([row['_id'] for row in be1_post['docs']]), ['b', 'e'])

		be2_post = cjson.decode(be2_request.input_body)
		self.assertEqual(len(be2_post['docs']), 2)
		self.assertEqual(sorted([row['_id'] for row in be2_post['docs']]), ['a', 'c'])