github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/extension/otto/gohan_db_test.go (about)

     1  // Copyright (C) 2015 NTT Innovation Institute, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package otto_test
    17  
    18  import (
    19  	"errors"
    20  	"time"
    21  
    22  	"github.com/cloudwan/gohan/db/pagination"
    23  	"github.com/cloudwan/gohan/db/transaction"
    24  	"github.com/cloudwan/gohan/extension"
    25  	"github.com/cloudwan/gohan/extension/otto"
    26  	"github.com/cloudwan/gohan/schema"
    27  	"github.com/cloudwan/gohan/server/middleware"
    28  
    29  	"github.com/cloudwan/gohan/db"
    30  	db_mocks "github.com/cloudwan/gohan/db/mocks"
    31  	"github.com/cloudwan/gohan/db/transaction/mocks"
    32  	"github.com/golang/mock/gomock"
    33  	. "github.com/onsi/ginkgo"
    34  	. "github.com/onsi/gomega"
    35  )
    36  
    37  func newEnvironmentWithExtension(extension *schema.Extension, db db.DB) (env extension.Environment) {
    38  	timelimit := time.Duration(1) * time.Second
    39  	extensions := []*schema.Extension{extension}
    40  	env = otto.NewEnvironment("db_test",
    41  		db, &middleware.FakeIdentity{}, timelimit, testSync)
    42  	Expect(env.LoadExtensionsForPath(extensions, "test_path")).To(Succeed())
    43  	return
    44  }
    45  
    46  var _ = Describe("GohanDb", func() {
    47  	var (
    48  		manager       *schema.Manager
    49  		s             *schema.Schema
    50  		ok            bool
    51  		fakeResources []map[string]interface{}
    52  		err           error
    53  		r0, r1        *schema.Resource
    54  		mockCtrl      *gomock.Controller
    55  	)
    56  
    57  	var ()
    58  
    59  	BeforeEach(func() {
    60  		manager = schema.GetManager()
    61  		s, ok = manager.Schema("test")
    62  		Expect(ok).To(BeTrue())
    63  		mockCtrl = gomock.NewController(GinkgoT())
    64  
    65  		fakeResources = []map[string]interface{}{
    66  			map[string]interface{}{"tenant_id": "t0", "test_string": "str0", "test_bool": false},
    67  			map[string]interface{}{"tenant_id": "t1", "test_string": "str1", "test_bool": true},
    68  		}
    69  
    70  		r0, err = schema.NewResource(s, fakeResources[0])
    71  		Expect(err).ToNot(HaveOccurred())
    72  		r1, err = schema.NewResource(s, fakeResources[1])
    73  		Expect(err).ToNot(HaveOccurred())
    74  
    75  	})
    76  
    77  	AfterEach(func() {
    78  		mockCtrl.Finish()
    79  	})
    80  
    81  	Describe("gohan_db_transaction", func() {
    82  		Context("When no argument is given", func() {
    83  			It("doesn't run SetIsolationLevel method", func() {
    84  				ext, err := schema.NewExtension(map[string]interface{}{
    85  					"id": "test_extension",
    86  					"code": `
    87  					  gohan_register_handler("test_event", function(context){
    88  					    var tx = gohan_db_transaction();
    89  					    tx.Commit();
    90  					    tx.Close();
    91  					  });`,
    92  					"path": ".*",
    93  				})
    94  				Expect(err).ToNot(HaveOccurred())
    95  				var fakeTx = new(mocks.Transaction)
    96  				fakeTx.On("Commit").Return(nil)
    97  				fakeTx.On("Close").Return(nil)
    98  				mockDB := db_mocks.NewMockDB(mockCtrl)
    99  				mockDB.EXPECT().Begin().Return(fakeTx, nil)
   100  				env := newEnvironmentWithExtension(ext, mockDB)
   101  
   102  				context := map[string]interface{}{}
   103  
   104  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   105  				fakeTx.AssertExpectations(GinkgoT())
   106  			})
   107  		})
   108  
   109  		Context("When proper isolation level argument is given", func() {
   110  			It("runs SetIsolationLevel method", func() {
   111  				ext, err := schema.NewExtension(map[string]interface{}{
   112  					"id": "test_extension",
   113  					"code": `
   114  					  gohan_register_handler("test_event", function(context){
   115  					    var tx = gohan_db_transaction("Serializable");
   116  					    tx.Commit();
   117  					    tx.Close();
   118  					  });`,
   119  					"path": ".*",
   120  				})
   121  				Expect(err).ToNot(HaveOccurred())
   122  				var fakeTx = new(mocks.Transaction)
   123  				fakeTx.On("SetIsolationLevel", transaction.Serializable).Return(nil)
   124  				fakeTx.On("Commit").Return(nil)
   125  				fakeTx.On("Close").Return(nil)
   126  				mockDB := db_mocks.NewMockDB(mockCtrl)
   127  				mockDB.EXPECT().Begin().Return(fakeTx, nil)
   128  				env := newEnvironmentWithExtension(ext, mockDB)
   129  
   130  				context := map[string]interface{}{}
   131  
   132  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   133  				fakeTx.AssertExpectations(GinkgoT())
   134  			})
   135  		})
   136  
   137  	})
   138  
   139  	Describe("gohan_db_list", func() {
   140  		Context("When valid minimum parameters are given", func() {
   141  			It("returns the list ordered by id", func() {
   142  				extension, err := schema.NewExtension(map[string]interface{}{
   143  					"id": "test_extension",
   144  					"code": `
   145  					  gohan_register_handler("test_event", function(context){
   146  					    var tx = context.transaction;
   147  					    context.resp = gohan_db_list(
   148  					      tx,
   149  					      "test",
   150  					      {"tenant_id": "tenant0"}
   151  					    );
   152  					  });`,
   153  					"path": ".*",
   154  				})
   155  				Expect(err).ToNot(HaveOccurred())
   156  				env := newEnvironmentWithExtension(extension, testDB)
   157  
   158  				var pagenator *pagination.Paginator
   159  				var fakeTx = new(mocks.Transaction)
   160  				fakeTx.On(
   161  					"List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator,
   162  				).Return(
   163  					[]*schema.Resource{r0, r1},
   164  					uint64(2),
   165  					nil,
   166  				)
   167  
   168  				context := map[string]interface{}{
   169  					"transaction": fakeTx,
   170  				}
   171  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   172  
   173  				Expect(context["resp"]).To(
   174  					Equal(
   175  						fakeResources,
   176  					),
   177  				)
   178  			})
   179  		})
   180  
   181  		Context("When boolean parameter is given", func() {
   182  			It("returns the list test_bool is true", func() {
   183  				extension, err := schema.NewExtension(map[string]interface{}{
   184  					"id": "test_extension",
   185  					"code": `
   186  					  gohan_register_handler("test_event", function(context){
   187  					    var tx = context.transaction;
   188  					    context.resp = gohan_db_list(
   189  					      tx,
   190  					      "test",
   191  					      {"test_bool": true}
   192  					    );
   193  					  });`,
   194  					"path": ".*",
   195  				})
   196  				Expect(err).ToNot(HaveOccurred())
   197  				env := newEnvironmentWithExtension(extension, testDB)
   198  
   199  				var pagenator *pagination.Paginator
   200  				var fakeTx = new(mocks.Transaction)
   201  				fakeTx.On(
   202  					"List", s, transaction.Filter{"test_bool": true}, pagenator,
   203  				).Return(
   204  					[]*schema.Resource{r1},
   205  					uint64(1),
   206  					nil,
   207  				)
   208  
   209  				context := map[string]interface{}{
   210  					"transaction": fakeTx,
   211  				}
   212  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   213  
   214  				Expect(context["resp"]).To(
   215  					Equal(
   216  						[]map[string]interface{}{
   217  							map[string]interface{}{"tenant_id": "t1", "test_string": "str1", "test_bool": true},
   218  						},
   219  					),
   220  				)
   221  			})
   222  		})
   223  
   224  		Context("When 4 parameters are given", func() {
   225  			It("returns the list ordered by given clumn", func() {
   226  				extension, err := schema.NewExtension(map[string]interface{}{
   227  					"id": "test_extension",
   228  					"code": `
   229  					  gohan_register_handler("test_event", function(context){
   230  					    var tx = context.transaction;
   231  					    context.resp = gohan_db_list(
   232  					      tx,
   233  					      "test",
   234  					      {"tenant_id": "tenant0"},
   235  					      "test_string"
   236  					    );
   237  					  });`,
   238  					"path": ".*",
   239  				})
   240  				Expect(err).ToNot(HaveOccurred())
   241  				env := newEnvironmentWithExtension(extension, testDB)
   242  
   243  				pagenator := &pagination.Paginator{
   244  					Key:   "test_string",
   245  					Order: pagination.ASC,
   246  				}
   247  				var fakeTx = new(mocks.Transaction)
   248  				fakeTx.On(
   249  					"List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator,
   250  				).Return(
   251  					[]*schema.Resource{r0, r1},
   252  					uint64(2),
   253  					nil,
   254  				)
   255  
   256  				context := map[string]interface{}{
   257  					"transaction": fakeTx,
   258  				}
   259  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   260  
   261  				Expect(context["resp"]).To(
   262  					Equal(
   263  						fakeResources,
   264  					),
   265  				)
   266  			})
   267  		})
   268  
   269  		Context("When 5 parameters are given", func() {
   270  			It("returns the list ordered by given clumn and limited", func() {
   271  				extension, err := schema.NewExtension(map[string]interface{}{
   272  					"id": "test_extension",
   273  					"code": `
   274  					  gohan_register_handler("test_event", function(context){
   275  					    var tx = context.transaction;
   276  					    context.resp = gohan_db_list(
   277  					      tx,
   278  					      "test",
   279  					      {"tenant_id": "tenant0"},
   280  					      "test_string",
   281  					      100
   282  					    );
   283  					  });`,
   284  					"path": ".*",
   285  				})
   286  				Expect(err).ToNot(HaveOccurred())
   287  				env := newEnvironmentWithExtension(extension, testDB)
   288  
   289  				pagenator := &pagination.Paginator{
   290  					Key:   "test_string",
   291  					Order: pagination.ASC,
   292  					Limit: 100,
   293  				}
   294  				var fakeTx = new(mocks.Transaction)
   295  				fakeTx.On(
   296  					"List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator,
   297  				).Return(
   298  					[]*schema.Resource{r0, r1},
   299  					uint64(2),
   300  					nil,
   301  				)
   302  
   303  				context := map[string]interface{}{
   304  					"transaction": fakeTx,
   305  				}
   306  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   307  
   308  				Expect(context["resp"]).To(
   309  					Equal(
   310  						fakeResources,
   311  					),
   312  				)
   313  			})
   314  		})
   315  
   316  		Context("When 6 parameters are given", func() {
   317  			It("returns the list ordered by given clumn and limited with offset", func() {
   318  				extension, err := schema.NewExtension(map[string]interface{}{
   319  					"id": "test_extension",
   320  					"code": `
   321  					  gohan_register_handler("test_event", function(context){
   322  					    var tx = context.transaction;
   323  					    context.resp = gohan_db_list(
   324  					      tx,
   325  					      "test",
   326  					      {"tenant_id": "tenant0"},
   327  					      "test_string",
   328  					      100,
   329  					      10
   330  					    );
   331  					  });`,
   332  					"path": ".*",
   333  				})
   334  				Expect(err).ToNot(HaveOccurred())
   335  				env := newEnvironmentWithExtension(extension, testDB)
   336  
   337  				pagenator := &pagination.Paginator{
   338  					Key:    "test_string",
   339  					Order:  pagination.ASC,
   340  					Limit:  100,
   341  					Offset: 10,
   342  				}
   343  				var fakeTx = new(mocks.Transaction)
   344  				fakeTx.On(
   345  					"List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator,
   346  				).Return(
   347  					[]*schema.Resource{r0, r1},
   348  					uint64(2),
   349  					nil,
   350  				)
   351  
   352  				context := map[string]interface{}{
   353  					"transaction": fakeTx,
   354  				}
   355  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   356  
   357  				Expect(context["resp"]).To(
   358  					Equal(
   359  						fakeResources,
   360  					),
   361  				)
   362  			})
   363  		})
   364  
   365  	})
   366  
   367  	Describe("gohan_db_state_fetch", func() {
   368  		Context("When valid parameters are given", func() {
   369  			It("returns a resource state object", func() {
   370  				extension, err := schema.NewExtension(map[string]interface{}{
   371  					"id": "test_extension",
   372  					"code": `
   373  					  gohan_register_handler("test_event", function(context){
   374  					    var tx = context.transaction;
   375  					    context.resp = gohan_db_state_fetch(
   376  					      tx,
   377  					      "test",
   378  					      "resource_id",
   379  					      "tenant0"
   380  					    );
   381  					  });`,
   382  					"path": ".*",
   383  				})
   384  				Expect(err).ToNot(HaveOccurred())
   385  				env := newEnvironmentWithExtension(extension, testDB)
   386  
   387  				var fakeTx = new(mocks.Transaction)
   388  				fakeTx.On(
   389  					"StateFetch", s,
   390  					transaction.Filter{"id": "resource_id", "tenant_id": "tenant0"},
   391  				).Return(
   392  					transaction.ResourceState{
   393  						ConfigVersion: 30,
   394  						StateVersion:  29,
   395  						Error:         "e",
   396  						State:         "s",
   397  						Monitoring:    "m",
   398  					},
   399  					nil,
   400  				)
   401  
   402  				context := map[string]interface{}{
   403  					"transaction": fakeTx,
   404  				}
   405  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   406  
   407  				Expect(context["resp"]).To(
   408  					Equal(
   409  						map[string]interface{}{
   410  							"config_version": int64(30),
   411  							"state_version":  int64(29),
   412  							"error":          "e",
   413  							"state":          "s",
   414  							"monitoring":     "m",
   415  						},
   416  					),
   417  				)
   418  			})
   419  		})
   420  	})
   421  
   422  	Describe("gohan_db_sql_make_columns", func() {
   423  		Context("when a valid schema ID is given", func() {
   424  			It("returns column names in Gohan DB compatible format", func() {
   425  				extension, err := schema.NewExtension(map[string]interface{}{
   426  					"id": "test_extension",
   427  					"code": `
   428  					  gohan_register_handler("test_event", function(context){
   429  					    context.resp = gohan_db_sql_make_columns("test");
   430  					  });`,
   431  					"path": ".*",
   432  				})
   433  				Expect(err).ToNot(HaveOccurred())
   434  				env := newEnvironmentWithExtension(extension, testDB)
   435  
   436  				context := map[string]interface{}{}
   437  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   438  				Expect(context["resp"]).To(ContainElement("tests.`id` as `tests__id`"))
   439  				Expect(context["resp"]).To(ContainElement("tests.`tenant_id` as `tests__tenant_id`"))
   440  				Expect(context["resp"]).To(ContainElement("tests.`test_string` as `tests__test_string`"))
   441  			})
   442  		})
   443  
   444  		Context("when an invalid schema ID is given", func() {
   445  			It("returns an error", func() {
   446  				extension, err := schema.NewExtension(map[string]interface{}{
   447  					"id": "test_extension",
   448  					"code": `
   449  					  gohan_register_handler("test_event", function(context){
   450  					    context.resp = gohan_db_sql_make_columns("NOT EXIST");
   451  					  });`,
   452  					"path": ".*",
   453  				})
   454  				Expect(err).ToNot(HaveOccurred())
   455  				env := newEnvironmentWithExtension(extension, testDB)
   456  
   457  				context := map[string]interface{}{}
   458  				err = env.HandleEvent("test_event", context)
   459  				Expect(err).NotTo(BeNil())
   460  				Expect(err.Error()).To(MatchRegexp("test_event: Error: Unknown schema 'NOT EXIST'"))
   461  			})
   462  		})
   463  
   464  	})
   465  
   466  	Describe("gohan_db_query", func() {
   467  		Context("when valid parameters are given", func() {
   468  			It("returns resources in db", func() {
   469  				extension, err := schema.NewExtension(map[string]interface{}{
   470  					"id": "test_extension",
   471  					"code": `
   472  					  gohan_register_handler("test_event", function(context){
   473  					    var tx = context.transaction;
   474  					    context.resp = gohan_db_query(
   475  					      tx,
   476  					      "test",
   477  					      "SELECT DUMMY",
   478  					      ["tenant0", "obj1"]
   479  					    );
   480  					  });`,
   481  					"path": ".*",
   482  				})
   483  				Expect(err).ToNot(HaveOccurred())
   484  				env := newEnvironmentWithExtension(extension, testDB)
   485  
   486  				var fakeTx = new(mocks.Transaction)
   487  				fakeTx.On(
   488  					"Query", s, "SELECT DUMMY", []interface{}{"tenant0", "obj1"},
   489  				).Return(
   490  					[]*schema.Resource{r0, r1}, nil,
   491  				)
   492  
   493  				context := map[string]interface{}{
   494  					"transaction": fakeTx,
   495  				}
   496  				Expect(env.HandleEvent("test_event", context)).To(Succeed())
   497  				Expect(context["resp"]).To(Equal(fakeResources))
   498  			})
   499  		})
   500  
   501  		Context("When an invalid transaction is provided", func() {
   502  			It("fails and return an error", func() {
   503  				extension, err := schema.NewExtension(map[string]interface{}{
   504  					"id": "test_extension",
   505  					"code": `
   506  					  gohan_register_handler("test_event", function(context){
   507  					    var tx = context.transaction;
   508  					    context.resp = gohan_db_query(
   509  					      tx,
   510  					      "test",
   511  					      "SELECT DUMMY",
   512  					      ["tenant0", "obj1"]
   513  					    );
   514  					  });`,
   515  					"path": ".*",
   516  				})
   517  				Expect(err).ToNot(HaveOccurred())
   518  				env := newEnvironmentWithExtension(extension, testDB)
   519  
   520  				context := map[string]interface{}{
   521  					"transaction": "not_a_transaction",
   522  				}
   523  
   524  				err = env.HandleEvent("test_event", context)
   525  				Expect(err).NotTo(BeNil())
   526  				Expect(err.Error()).To(MatchRegexp("test_event: Error: Argument 'not_a_transaction' should be of type 'Transaction'"))
   527  			})
   528  		})
   529  
   530  		Context("When an invalid schema ID is provided", func() {
   531  			It("fails and return an error", func() {
   532  				extension, err := schema.NewExtension(map[string]interface{}{
   533  					"id": "test_extension",
   534  					"code": `
   535  					  gohan_register_handler("test_event", function(context){
   536  					    var tx = context.transaction;
   537  					    context.resp = gohan_db_query(
   538  					      tx,
   539  					      "INVALID_SCHEMA_ID",
   540  					      "SELECT DUMMY",
   541  					      ["tenant0", "obj1"]
   542  					    );
   543  					  });`,
   544  					"path": ".*",
   545  				})
   546  				Expect(err).ToNot(HaveOccurred())
   547  				env := newEnvironmentWithExtension(extension, testDB)
   548  
   549  				context := map[string]interface{}{
   550  					"transaction": new(mocks.Transaction),
   551  				}
   552  				err = env.HandleEvent("test_event", context)
   553  				Expect(err).NotTo(BeNil())
   554  				Expect(err.Error()).To(MatchRegexp("test_event: Error: Unknown schema 'INVALID_SCHEMA_ID'"))
   555  			})
   556  		})
   557  
   558  		Context("When an invalid array is provided to arguments", func() {
   559  			It("fails and return an error", func() {
   560  				extension, err := schema.NewExtension(map[string]interface{}{
   561  					"id": "test_extension",
   562  					"code": `
   563  					  gohan_register_handler("test_event", function(context){
   564  					    var tx = context.transaction;
   565  					    context.resp = gohan_db_query(
   566  					      tx,
   567  					      "test",
   568  					      "SELECT DUMMY",
   569  					      "THIS IS NOT AN ARRAY"
   570  					    );
   571  					  });`,
   572  					"path": ".*",
   573  				})
   574  				Expect(err).ToNot(HaveOccurred())
   575  				env := newEnvironmentWithExtension(extension, testDB)
   576  
   577  				context := map[string]interface{}{
   578  					"transaction": new(mocks.Transaction),
   579  				}
   580  				err = env.HandleEvent("test_event", context)
   581  				Expect(err).NotTo(BeNil())
   582  				Expect(err.Error()).To(MatchRegexp("test_event: Error: Argument 'THIS IS NOT AN ARRAY' should be of type 'array'"))
   583  			})
   584  		})
   585  
   586  		Context("When an error occurred while processing the query", func() {
   587  			It("fails and return an error", func() {
   588  				extension, err := schema.NewExtension(map[string]interface{}{
   589  					"id": "test_extension",
   590  					"code": `
   591  					  gohan_register_handler("test_event", function(context){
   592  					    var tx = context.transaction;
   593  					    context.resp = gohan_db_query(
   594  					      tx,
   595  					      "test",
   596  					      "SELECT DUMMY",
   597  					      []
   598  					    );
   599  					  });`,
   600  					"path": ".*",
   601  				})
   602  				Expect(err).ToNot(HaveOccurred())
   603  				env := newEnvironmentWithExtension(extension, testDB)
   604  
   605  				var fakeTx = new(mocks.Transaction)
   606  				fakeTx.On(
   607  					"Query", s, "SELECT DUMMY", []interface{}{},
   608  				).Return(
   609  					nil, errors.New("SOMETHING HAPPENED"),
   610  				)
   611  
   612  				context := map[string]interface{}{
   613  					"transaction": fakeTx,
   614  				}
   615  				err = env.HandleEvent("test_event", context)
   616  				Expect(err).NotTo(BeNil())
   617  				Expect(err.Error()).To(MatchRegexp("test_event: Error: Error during gohan_db_query: SOMETHING HAPPEN"))
   618  			})
   619  		})
   620  
   621  	})
   622  })