@@ -311,6 +311,162 @@ def test_tables_with_prefix(self):
311311 result = connection .tables ()
312312 self .assertEqual (result , [unprefixed_table_name1 ])
313313
314+ def test_create_table (self ):
315+ import operator
316+ from gcloud ._testing import _Monkey
317+ from gcloud .bigtable .happybase import connection as MUT
318+
319+ cluster = _Cluster () # Avoid implicit environ check.
320+ connection = self ._makeOne (autoconnect = False , cluster = cluster )
321+ mock_gc_rule = object ()
322+ called_options = []
323+
324+ def mock_parse_family_option (option ):
325+ called_options .append (option )
326+ return mock_gc_rule
327+
328+ name = 'table-name'
329+ col_fam1 = 'cf1'
330+ col_fam_option1 = object ()
331+ col_fam2 = u'cf2'
332+ col_fam_option2 = object ()
333+ col_fam3 = b'cf3'
334+ col_fam_option3 = object ()
335+ families = {
336+ col_fam1 : col_fam_option1 ,
337+ # A trailing colon is also allowed.
338+ col_fam2 + ':' : col_fam_option2 ,
339+ col_fam3 + b':' : col_fam_option3 ,
340+ }
341+
342+ tables_created = []
343+
344+ def make_table (* args , ** kwargs ):
345+ result = _MockLowLevelTable (* args , ** kwargs )
346+ tables_created .append (result )
347+ return result
348+
349+ with _Monkey (MUT , _LowLevelTable = make_table ,
350+ _parse_family_option = mock_parse_family_option ):
351+ connection .create_table (name , families )
352+
353+ # Just one table would have been created.
354+ table_instance , = tables_created
355+ self .assertEqual (table_instance .args , (name , cluster ))
356+ self .assertEqual (table_instance .kwargs , {})
357+ self .assertEqual (table_instance .create_calls , 1 )
358+
359+ # Check if our mock was called twice, but we don't know the order.
360+ self .assertEqual (
361+ set (called_options ),
362+ set ([col_fam_option1 , col_fam_option2 , col_fam_option3 ]))
363+
364+ # We expect three column family instances created, but don't know the
365+ # order due to non-deterministic dict.items().
366+ col_fam_created = table_instance .col_fam_created
367+ self .assertEqual (len (col_fam_created ), 3 )
368+ col_fam_created .sort (key = operator .attrgetter ('column_family_id' ))
369+ self .assertEqual (col_fam_created [0 ].column_family_id , col_fam1 )
370+ self .assertEqual (col_fam_created [0 ].gc_rule , mock_gc_rule )
371+ self .assertEqual (col_fam_created [0 ].create_calls , 1 )
372+ self .assertEqual (col_fam_created [1 ].column_family_id , col_fam2 )
373+ self .assertEqual (col_fam_created [1 ].gc_rule , mock_gc_rule )
374+ self .assertEqual (col_fam_created [1 ].create_calls , 1 )
375+ self .assertEqual (col_fam_created [2 ].column_family_id ,
376+ col_fam3 .decode ('utf-8' ))
377+ self .assertEqual (col_fam_created [2 ].gc_rule , mock_gc_rule )
378+ self .assertEqual (col_fam_created [2 ].create_calls , 1 )
379+
380+ def test_create_table_bad_type (self ):
381+ cluster = _Cluster () # Avoid implicit environ check.
382+ connection = self ._makeOne (autoconnect = False , cluster = cluster )
383+
384+ name = 'table-name'
385+ families = None
386+ with self .assertRaises (TypeError ):
387+ connection .create_table (name , families )
388+
389+ def test_create_table_bad_value (self ):
390+ cluster = _Cluster () # Avoid implicit environ check.
391+ connection = self ._makeOne (autoconnect = False , cluster = cluster )
392+
393+ name = 'table-name'
394+ families = {}
395+ with self .assertRaises (ValueError ):
396+ connection .create_table (name , families )
397+
398+
399+ class Test__parse_family_option (unittest2 .TestCase ):
400+
401+ def _callFUT (self , option ):
402+ from gcloud .bigtable .happybase .connection import _parse_family_option
403+ return _parse_family_option (option )
404+
405+ def test_dictionary_no_keys (self ):
406+ option = {}
407+ result = self ._callFUT (option )
408+ self .assertEqual (result , None )
409+
410+ def test_null (self ):
411+ option = None
412+ result = self ._callFUT (option )
413+ self .assertEqual (result , None )
414+
415+ def test_dictionary_bad_key (self ):
416+ option = {'badkey' : None }
417+ with self .assertRaises (ValueError ):
418+ self ._callFUT (option )
419+
420+ def test_dictionary_versions_key (self ):
421+ from gcloud .bigtable .column_family import MaxVersionsGCRule
422+
423+ versions = 42
424+ option = {'max_versions' : versions }
425+ result = self ._callFUT (option )
426+
427+ gc_rule = MaxVersionsGCRule (versions )
428+ self .assertEqual (result , gc_rule )
429+
430+ def test_dictionary_ttl_key (self ):
431+ import datetime
432+ from gcloud .bigtable .column_family import MaxAgeGCRule
433+
434+ time_to_live = 24 * 60 * 60
435+ max_age = datetime .timedelta (days = 1 )
436+ option = {'time_to_live' : time_to_live }
437+ result = self ._callFUT (option )
438+
439+ gc_rule = MaxAgeGCRule (max_age )
440+ self .assertEqual (result , gc_rule )
441+
442+ def test_dictionary_both_keys (self ):
443+ import datetime
444+ from gcloud .bigtable .column_family import GCRuleIntersection
445+ from gcloud .bigtable .column_family import MaxAgeGCRule
446+ from gcloud .bigtable .column_family import MaxVersionsGCRule
447+
448+ versions = 42
449+ time_to_live = 24 * 60 * 60
450+ option = {
451+ 'max_versions' : versions ,
452+ 'time_to_live' : time_to_live ,
453+ }
454+ result = self ._callFUT (option )
455+
456+ max_age = datetime .timedelta (days = 1 )
457+ # NOTE: This relies on the order of the rules in the method we are
458+ # calling matching this order here.
459+ gc_rule1 = MaxAgeGCRule (max_age )
460+ gc_rule2 = MaxVersionsGCRule (versions )
461+ gc_rule = GCRuleIntersection (rules = [gc_rule1 , gc_rule2 ])
462+ self .assertEqual (result , gc_rule )
463+
464+ def test_non_dictionary (self ):
465+ option = object ()
466+ self .assertFalse (isinstance (option , dict ))
467+ result = self ._callFUT (option )
468+ self .assertEqual (result , option )
469+
314470
315471class _Client (object ):
316472
@@ -350,5 +506,35 @@ def copy(self):
350506 else :
351507 return self
352508
509+ < << << << 33 b3bfd533e2e1eb070afe49661483b4fb460c29
353510 def list_tables (self ):
354511 return self .list_tables_result
512+ == == == =
513+
514+ class _MockLowLevelColumnFamily (object ):
515+
516+ def __init__ (self , column_family_id , gc_rule = None ):
517+ self .column_family_id = column_family_id
518+ self .gc_rule = gc_rule
519+ self .create_calls = 0
520+
521+ def create (self ):
522+ self .create_calls += 1
523+
524+
525+ class _MockLowLevelTable (object ):
526+
527+ def __init__ (self , * args , ** kwargs ):
528+ self .args = args
529+ self .kwargs = kwargs
530+ self .create_calls = 0
531+ self .col_fam_created = []
532+
533+ def create (self ):
534+ self .create_calls += 1
535+
536+ def column_family (self , column_family_id , gc_rule = None ):
537+ result = _MockLowLevelColumnFamily (column_family_id , gc_rule = gc_rule )
538+ self .col_fam_created .append (result )
539+ return result
540+ > >> >> >> Adding HappyBase Connection .create_table ().
0 commit comments