github.com/jbking/gohan@v0.0.0-20151217002006-b41ccf1c2a96/server/resources/resource_management_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 resources_test
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"github.com/cloudwan/gohan/extension"
    22  	"github.com/cloudwan/gohan/extension/otto"
    23  	"github.com/cloudwan/gohan/schema"
    24  	"github.com/cloudwan/gohan/server/middleware"
    25  	"github.com/cloudwan/gohan/server/resources"
    26  	"github.com/cloudwan/gohan/util"
    27  	. "github.com/onsi/ginkgo"
    28  	. "github.com/onsi/gomega"
    29  )
    30  
    31  var _ = Describe("Resource manager", func() {
    32  	const (
    33  		resourceID1 = "6660fbf8-ca60-4cb0-a42e-9a913beafbaf"
    34  		resourceID2 = "6660fbf8-ca60-4cb0-a42e-9a913beafbae"
    35  	)
    36  
    37  	var (
    38  		manager       *schema.Manager
    39  		adminAuth     schema.Authorization
    40  		memberAuth    schema.Authorization
    41  		auth          schema.Authorization
    42  		context       middleware.Context
    43  		schemaID      string
    44  		path          string
    45  		action        string
    46  		currentSchema *schema.Schema
    47  		extensions    []*schema.Extension
    48  		env           extension.Environment
    49  		events        map[string]string
    50  
    51  		defaultState map[string]interface{}
    52  	)
    53  
    54  	BeforeEach(func() {
    55  		manager = schema.GetManager()
    56  
    57  		adminAuth = schema.NewAuthorization(adminTenantID, "admin", adminTokenID, []string{"admin"}, nil)
    58  		memberAuth = schema.NewAuthorization(memberTenantID, "demo", memberTokenID, []string{"_member_"}, nil)
    59  		auth = adminAuth
    60  
    61  		context = middleware.Context{}
    62  
    63  		events = map[string]string{}
    64  
    65  		defaultState = map[string]interface{}{
    66  			"config_version":   1,
    67  			"state_version":    0,
    68  			"error":            "",
    69  			"state":            "",
    70  			"state_monitoring": "",
    71  		}
    72  	})
    73  
    74  	environmentManager := extension.GetManager()
    75  
    76  	JustBeforeEach(func() {
    77  		var ok bool
    78  		currentSchema, ok = manager.Schema(schemaID)
    79  		Expect(ok).To(BeTrue())
    80  
    81  		path = currentSchema.GetPluralURL()
    82  
    83  		policy, role := manager.PolicyValidate(action, path, auth)
    84  		Expect(policy).NotTo(BeNil())
    85  		context["policy"] = policy
    86  		context["role"] = role
    87  		context["tenant_id"] = auth.TenantID()
    88  		context["tenant_name"] = auth.TenantName()
    89  		context["auth_token"] = auth.AuthToken()
    90  		context["catalog"] = auth.Catalog()
    91  		context["auth"] = auth
    92  
    93  		env = otto.NewEnvironment(testDB, &middleware.FakeIdentity{})
    94  		extensions = []*schema.Extension{}
    95  		for event, javascript := range events {
    96  			extension, err := schema.NewExtension(map[string]interface{}{
    97  				"id":   event + "_extension",
    98  				"code": `gohan_register_handler("` + event + `", function(context) {` + javascript + `});`,
    99  				"path": path,
   100  			})
   101  			Expect(err).ToNot(HaveOccurred())
   102  			extensions = append(extensions, extension)
   103  		}
   104  		Expect(env.LoadExtensionsForPath(extensions, path)).To(Succeed())
   105  		environmentManager.RegisterEnvironment(schemaID, env)
   106  	})
   107  
   108  	AfterEach(func() {
   109  		tx, err := testDB.Begin()
   110  		Expect(err).ToNot(HaveOccurred(), "Failed to create transaction.")
   111  		environmentManager.UnRegisterEnvironment(schemaID)
   112  		defer tx.Close()
   113  		for _, schema := range schema.GetManager().Schemas() {
   114  			if whitelist[schema.ID] {
   115  				continue
   116  			}
   117  			err = clearTable(tx, schema)
   118  			Expect(err).ToNot(HaveOccurred(), "Failed to clear table.")
   119  		}
   120  		err = tx.Commit()
   121  		Expect(err).ToNot(HaveOccurred(), "Failed to commite transaction.")
   122  	})
   123  
   124  	Describe("Getting a schema", func() {
   125  		BeforeEach(func() {
   126  			schemaID = "schema"
   127  			action = "read"
   128  		})
   129  
   130  		Context("As an admin", func() {
   131  			It("Should always return the full schema", func() {
   132  				for _, currentSchema := range manager.OrderedSchemas() {
   133  					trimmedSchema, err := schema.GetSchema(currentSchema, auth)
   134  					Expect(err).NotTo(HaveOccurred())
   135  					rawSchema, ok := currentSchema.RawData.(map[string]interface{})
   136  					Expect(ok).To(BeTrue())
   137  					fullSchema, err := schema.NewResource(currentSchema, rawSchema)
   138  					Expect(err).ToNot(HaveOccurred())
   139  					Expect(trimmedSchema).To(util.MatchAsJSON(fullSchema))
   140  				}
   141  			})
   142  		})
   143  
   144  		Context("As a member", func() {
   145  			BeforeEach(func() {
   146  				auth = memberAuth
   147  			})
   148  
   149  			It("Should return full schema when appropriate", func() {
   150  				By("Fetching the schema")
   151  				schemaSchema, ok := manager.Schema("schema")
   152  				Expect(ok).To(BeTrue())
   153  				By("The schema being equal to the full schema")
   154  				trimmedSchema, err := schema.GetSchema(currentSchema, auth)
   155  				Expect(err).NotTo(HaveOccurred())
   156  				Expect(trimmedSchema).NotTo(BeNil())
   157  				rawSchema, ok := schemaSchema.RawData.(map[string]interface{})
   158  				Expect(ok).To(BeTrue())
   159  				fullSchema, err := schema.NewResource(currentSchema, rawSchema)
   160  				Expect(err).ToNot(HaveOccurred())
   161  				Expect(trimmedSchema).To(util.MatchAsJSON(fullSchema))
   162  			})
   163  
   164  			It("Should return trimmed schema when appropriate", func() {
   165  				By("Fetching the schema")
   166  				networkSchema, ok := manager.Schema("network")
   167  				Expect(ok).To(BeTrue())
   168  				trimmedSchema, err := schema.GetSchema(networkSchema, auth)
   169  				Expect(err).NotTo(HaveOccurred())
   170  				Expect(trimmedSchema).NotTo(BeNil())
   171  				theSchema, ok := trimmedSchema.Get("schema").(map[string]interface{})
   172  				Expect(ok).To(BeTrue())
   173  				properties, ok := theSchema["properties"].(map[string]interface{})
   174  				Expect(ok).To(BeTrue())
   175  
   176  				By("Leaving allowed properties")
   177  				_, ok = properties["id"]
   178  				Expect(ok).To(BeTrue())
   179  				_, ok = properties["name"]
   180  				Expect(ok).To(BeTrue())
   181  				_, ok = properties["description"]
   182  				Expect(ok).To(BeTrue())
   183  				_, ok = properties["tenant_id"]
   184  				Expect(ok).To(BeTrue())
   185  
   186  				By("Removing other properties")
   187  				_, ok = properties["providor_networks"]
   188  				Expect(ok).To(BeFalse())
   189  				_, ok = properties["route_targets"]
   190  				Expect(ok).To(BeFalse())
   191  				_, ok = properties["shared"]
   192  				Expect(ok).To(BeFalse())
   193  			})
   194  
   195  			It("Should return no schema when appropriate", func() {
   196  				By("Not fetching the schema")
   197  				testSchema, ok := manager.Schema("admin_only")
   198  				Expect(ok).To(BeTrue())
   199  				trimmedSchema, err := schema.GetSchema(testSchema, auth)
   200  				Expect(err).NotTo(HaveOccurred())
   201  				Expect(trimmedSchema).To(BeNil())
   202  			})
   203  		})
   204  	})
   205  
   206  	Describe("Listing resources", func() {
   207  		BeforeEach(func() {
   208  			schemaID = "test"
   209  			action = "read"
   210  		})
   211  
   212  		Describe("When there are no resources in the database", func() {
   213  			It("Should return an empty list", func() {
   214  				err := resources.GetMultipleResources(
   215  					context, testDB, currentSchema, map[string][]string{})
   216  				result, _ := context["response"].(map[string]interface{})
   217  				number := context["total"].(uint64)
   218  				Expect(err).NotTo(HaveOccurred())
   219  				Expect(err).NotTo(HaveOccurred())
   220  				Expect(number).To(Equal(uint64(0)))
   221  				Expect(result).To(HaveKeyWithValue("tests", BeEmpty()))
   222  			})
   223  
   224  			Describe("With extensions", func() {
   225  				Context("Only pre_list", func() {
   226  					BeforeEach(func() {
   227  						events["pre_list"] = `context["response"] = {"respondo": "bona"};`
   228  					})
   229  
   230  					It("Should run the extension", func() {
   231  						err := resources.GetMultipleResources(
   232  							context, testDB, currentSchema, map[string][]string{})
   233  						result, _ := context["response"].(map[string]interface{})
   234  						number, _ := context["total"].(uint64)
   235  
   236  						Expect(err).NotTo(HaveOccurred())
   237  						Expect(number).To(Equal(uint64(0)))
   238  						Expect(result).To(HaveKeyWithValue("respondo", "bona"))
   239  					})
   240  				})
   241  
   242  				Context("Only pre_list_in_transaction", func() {
   243  					BeforeEach(func() {
   244  						events["pre_list_in_transaction"] = `throw new CustomException("malbona", 390);`
   245  					})
   246  
   247  					It("Should run the extension", func() {
   248  						err := resources.GetMultipleResources(
   249  							context, testDB, currentSchema, map[string][]string{})
   250  						Expect(err).To(HaveOccurred())
   251  						extErr, ok := err.(extension.Error)
   252  						Expect(ok).To(BeTrue())
   253  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   254  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   255  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   256  					})
   257  				})
   258  
   259  				Context("Only post_list_in_transaction", func() {
   260  					BeforeEach(func() {
   261  						events["post_list_in_transaction"] = `throw new CustomException("tre malbona", 390);`
   262  					})
   263  
   264  					It("Should run the extension", func() {
   265  						err := resources.GetMultipleResources(
   266  							context, testDB, currentSchema, map[string][]string{})
   267  						Expect(err).To(HaveOccurred())
   268  						extErr, ok := err.(extension.Error)
   269  						Expect(ok).To(BeTrue())
   270  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   271  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
   272  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   273  					})
   274  				})
   275  
   276  				Context("Only post_list", func() {
   277  					BeforeEach(func() {
   278  						events["post_list"] = `context["response"] = {"respondo": "tre bona"};`
   279  					})
   280  
   281  					It("Should run the extension", func() {
   282  						err := resources.GetMultipleResources(
   283  							context, testDB, currentSchema, map[string][]string{})
   284  						result := context["response"].(map[string]interface{})
   285  						number := context["total"].(uint64)
   286  						Expect(err).NotTo(HaveOccurred())
   287  						Expect(number).To(Equal(uint64(0)))
   288  						Expect(result).To(HaveKeyWithValue("respondo", "tre bona"))
   289  					})
   290  				})
   291  
   292  				Context("With pre_list throwing exception", func() {
   293  					BeforeEach(func() {
   294  						events["pre_list"] = `throw new CustomException("malbona", 390);`
   295  					})
   296  
   297  					It("Should run the extension", func() {
   298  						err := resources.GetMultipleResources(
   299  							context, testDB, currentSchema, map[string][]string{})
   300  						Expect(err).To(HaveOccurred())
   301  						extErr, ok := err.(extension.Error)
   302  						Expect(ok).To(BeTrue())
   303  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   304  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   305  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   306  					})
   307  				})
   308  
   309  				Context("With post_list throwing exception", func() {
   310  					BeforeEach(func() {
   311  						events["post_list"] = `throw new CustomException("tre malbona", 390);`
   312  					})
   313  
   314  					It("Should run the extension", func() {
   315  						err := resources.GetMultipleResources(
   316  							context, testDB, currentSchema, map[string][]string{})
   317  						Expect(err).To(HaveOccurred())
   318  						extErr, ok := err.(extension.Error)
   319  						Expect(ok).To(BeTrue())
   320  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   321  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
   322  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   323  					})
   324  				})
   325  
   326  				Context("With pre_list returning invalid JSON", func() {
   327  					BeforeEach(func() {
   328  						events["pre_list"] = `context["response"] = "erara";`
   329  					})
   330  
   331  					It("Should run the extension", func() {
   332  						err := resources.GetMultipleResources(
   333  							context, testDB, currentSchema, map[string][]string{})
   334  						Expect(err).To(MatchError(HavePrefix("extension returned invalid JSON:")))
   335  					})
   336  				})
   337  
   338  				Context("With post_list returning invalid JSON", func() {
   339  					BeforeEach(func() {
   340  						events["post_list"] = `context["response"] = "erara";`
   341  					})
   342  
   343  					It("Should run the extension", func() {
   344  						err := resources.GetMultipleResources(
   345  							context, testDB, currentSchema, map[string][]string{})
   346  						Expect(err).To(MatchError(HavePrefix("extension returned invalid JSON:")))
   347  					})
   348  				})
   349  
   350  				Context("With post_list returning no response", func() {
   351  					BeforeEach(func() {
   352  						events["post_list"] = `delete context["response"];`
   353  					})
   354  
   355  					It("Should run the extension", func() {
   356  						err := resources.GetMultipleResources(
   357  							context, testDB, currentSchema, map[string][]string{})
   358  						Expect(err).To(MatchError("No response"))
   359  					})
   360  				})
   361  			})
   362  		})
   363  
   364  		Describe("When there are resources in the database", func() {
   365  			var (
   366  				adminResourceData, memberResourceData map[string]interface{}
   367  			)
   368  
   369  			BeforeEach(func() {
   370  				adminResourceData = map[string]interface{}{
   371  					"id":          resourceID1,
   372  					"tenant_id":   adminTenantID,
   373  					"test_string": "Steloj estas en ordo.",
   374  				}
   375  				memberResourceData = map[string]interface{}{
   376  					"id":          resourceID2,
   377  					"tenant_id":   powerUserTenantID,
   378  					"test_string": "Mi estas la pordo, mi estas la sxlosilo.",
   379  				}
   380  			})
   381  
   382  			JustBeforeEach(func() {
   383  				adminResource, err := manager.LoadResource(currentSchema.ID, adminResourceData)
   384  				Expect(err).NotTo(HaveOccurred())
   385  				memberResource, err := manager.LoadResource(currentSchema.ID, memberResourceData)
   386  				Expect(err).NotTo(HaveOccurred())
   387  				transaction, err := testDB.Begin()
   388  				Expect(err).NotTo(HaveOccurred())
   389  				defer transaction.Close()
   390  				Expect(transaction.Create(adminResource)).To(Succeed())
   391  				Expect(transaction.Create(memberResource)).To(Succeed())
   392  				Expect(transaction.Commit()).To(Succeed())
   393  			})
   394  
   395  			Context("As an admin", func() {
   396  				It("Should return a filled list", func() {
   397  					err := resources.GetMultipleResources(
   398  						context, testDB, currentSchema, map[string][]string{})
   399  					result := context["response"].(map[string]interface{})
   400  					number := context["total"].(uint64)
   401  					Expect(err).NotTo(HaveOccurred())
   402  					Expect(number).To(Equal(uint64(2)))
   403  					Expect(result).To(HaveKeyWithValue("tests", ConsistOf(adminResourceData, memberResourceData)))
   404  				})
   405  			})
   406  
   407  			Context("As a member", func() {
   408  				BeforeEach(func() {
   409  					auth = memberAuth
   410  				})
   411  
   412  				It("Should return a only owned resources", func() {
   413  					err := resources.GetMultipleResources(
   414  						context, testDB, currentSchema, map[string][]string{})
   415  
   416  					result := context["response"].(map[string]interface{})
   417  					number := context["total"].(uint64)
   418  					Expect(err).NotTo(HaveOccurred())
   419  					Expect(number).To(Equal(uint64(1)))
   420  					Expect(result).To(HaveKeyWithValue("tests", ConsistOf(adminResourceData)))
   421  				})
   422  			})
   423  		})
   424  	})
   425  
   426  	Describe("Showing a resource", func() {
   427  		BeforeEach(func() {
   428  			schemaID = "test"
   429  			action = "read"
   430  		})
   431  
   432  		Describe("When there are no resources in the database", func() {
   433  			It("Should return an informative error", func() {
   434  				err := resources.GetSingleResource(
   435  					context, testDB, currentSchema, resourceID1)
   436  				Expect(err).To(HaveOccurred())
   437  				_, ok := err.(resources.ResourceError)
   438  				Expect(ok).To(BeTrue())
   439  			})
   440  
   441  			Describe("With extensions", func() {
   442  				Context("Only pre_show", func() {
   443  					BeforeEach(func() {
   444  						events["pre_show"] = `context["response"] = {"respondo": "bona"};`
   445  					})
   446  
   447  					It("Should run the extension", func() {
   448  						err := resources.GetSingleResource(
   449  							context, testDB, currentSchema, resourceID1)
   450  						result := context["response"].(map[string]interface{})
   451  						Expect(err).NotTo(HaveOccurred())
   452  						Expect(result).To(HaveKeyWithValue("respondo", "bona"))
   453  					})
   454  				})
   455  
   456  				Context("Only pre_show_in_transaction", func() {
   457  					BeforeEach(func() {
   458  						events["pre_show_in_transaction"] = `throw new CustomException("malbona", 390);`
   459  					})
   460  
   461  					It("Should run the extension", func() {
   462  						err := resources.GetSingleResource(
   463  							context, testDB, currentSchema, resourceID1)
   464  						Expect(err).To(HaveOccurred())
   465  						extErr, ok := err.(extension.Error)
   466  						Expect(ok).To(BeTrue())
   467  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   468  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   469  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   470  					})
   471  				})
   472  
   473  				Context("Only post_show_in_transaction", func() {
   474  					BeforeEach(func() {
   475  						events["post_show_in_transaction"] = `throw new CustomException("tre malbona", 390);`
   476  					})
   477  
   478  					It("Should not run the extension", func() {
   479  						err := resources.GetSingleResource(
   480  							context, testDB, currentSchema, resourceID1)
   481  						Expect(err).To(HaveOccurred())
   482  						_, ok := err.(resources.ResourceError)
   483  						Expect(ok).To(BeTrue())
   484  					})
   485  				})
   486  
   487  				Context("Only post_show", func() {
   488  					BeforeEach(func() {
   489  						events["post_show"] = `context["response"] = {"respondo": "tre bona"};`
   490  					})
   491  
   492  					It("Should not run the extension", func() {
   493  						err := resources.GetSingleResource(
   494  							context, testDB, currentSchema, resourceID1)
   495  						Expect(err).To(HaveOccurred())
   496  						_, ok := err.(resources.ResourceError)
   497  						Expect(ok).To(BeTrue())
   498  					})
   499  				})
   500  
   501  				Context("With pre_show throwing exception", func() {
   502  					BeforeEach(func() {
   503  						events["pre_show"] = `throw new CustomException("malbona", 390);`
   504  					})
   505  
   506  					It("Should run the extension", func() {
   507  						err := resources.GetSingleResource(
   508  							context, testDB, currentSchema, resourceID1)
   509  						Expect(err).To(HaveOccurred())
   510  						extErr, ok := err.(extension.Error)
   511  						Expect(ok).To(BeTrue())
   512  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   513  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   514  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   515  					})
   516  				})
   517  
   518  			})
   519  		})
   520  
   521  		Describe("When there are resources in the database", func() {
   522  			var (
   523  				adminResourceData, memberResourceData map[string]interface{}
   524  			)
   525  
   526  			BeforeEach(func() {
   527  				adminResourceData = map[string]interface{}{
   528  					"id":          resourceID1,
   529  					"tenant_id":   adminTenantID,
   530  					"test_string": "Steloj estas en ordo.",
   531  				}
   532  				memberResourceData = map[string]interface{}{
   533  					"id":          resourceID2,
   534  					"tenant_id":   powerUserTenantID,
   535  					"test_string": "Mi estas la pordo, mi estas la sxlosilo.",
   536  				}
   537  			})
   538  
   539  			JustBeforeEach(func() {
   540  				adminResource, err := manager.LoadResource(currentSchema.ID, adminResourceData)
   541  				Expect(err).NotTo(HaveOccurred())
   542  				memberResource, err := manager.LoadResource(currentSchema.ID, memberResourceData)
   543  				Expect(err).NotTo(HaveOccurred())
   544  				transaction, err := testDB.Begin()
   545  				Expect(err).NotTo(HaveOccurred())
   546  				defer transaction.Close()
   547  				Expect(transaction.Create(adminResource)).To(Succeed())
   548  				Expect(transaction.Create(memberResource)).To(Succeed())
   549  				Expect(transaction.Commit()).To(Succeed())
   550  			})
   551  
   552  			Context("As an admin", func() {
   553  				It("Should return owned resource", func() {
   554  					err := resources.GetSingleResource(
   555  						context, testDB, currentSchema, resourceID1)
   556  					result := context["response"].(map[string]interface{})
   557  					Expect(err).NotTo(HaveOccurred())
   558  					Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(adminResourceData)))
   559  				})
   560  
   561  				It("Should return not owned resource", func() {
   562  					err := resources.GetSingleResource(
   563  						context, testDB, currentSchema, resourceID2)
   564  					result := context["response"].(map[string]interface{})
   565  					Expect(err).NotTo(HaveOccurred())
   566  					Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(memberResourceData)))
   567  				})
   568  			})
   569  
   570  			Context("As a member", func() {
   571  				BeforeEach(func() {
   572  					auth = memberAuth
   573  				})
   574  
   575  				It("Should return owned resource", func() {
   576  					err := resources.GetSingleResource(
   577  						context, testDB, currentSchema, resourceID1)
   578  					result := context["response"].(map[string]interface{})
   579  					Expect(err).NotTo(HaveOccurred())
   580  					Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(adminResourceData)))
   581  				})
   582  
   583  				It("Should not return not owned resource", func() {
   584  					err := resources.GetSingleResource(
   585  						context, testDB, currentSchema, resourceID2)
   586  					Expect(err).To(HaveOccurred())
   587  					_, ok := err.(resources.ResourceError)
   588  					Expect(ok).To(BeTrue())
   589  				})
   590  			})
   591  
   592  			Describe("With extensions", func() {
   593  				Context("Only pre_show", func() {
   594  					BeforeEach(func() {
   595  						events["pre_show"] = `context["response"] = {"respondo": "bona"};`
   596  					})
   597  
   598  					It("Should run the extension", func() {
   599  						err := resources.GetSingleResource(
   600  							context, testDB, currentSchema, resourceID1)
   601  						result := context["response"].(map[string]interface{})
   602  						Expect(err).NotTo(HaveOccurred())
   603  						Expect(result).To(HaveKeyWithValue("respondo", "bona"))
   604  					})
   605  				})
   606  
   607  				Context("Only pre_show_in_transaction", func() {
   608  					BeforeEach(func() {
   609  						events["pre_show_in_transaction"] = `throw new CustomException("malbona", 390);`
   610  					})
   611  
   612  					It("Should run the extension", func() {
   613  						err := resources.GetSingleResource(
   614  							context, testDB, currentSchema, resourceID1)
   615  						Expect(err).To(HaveOccurred())
   616  						extErr, ok := err.(extension.Error)
   617  						Expect(ok).To(BeTrue())
   618  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   619  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   620  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   621  					})
   622  				})
   623  
   624  				Context("Only post_show_in_transaction", func() {
   625  					BeforeEach(func() {
   626  						events["post_show_in_transaction"] = `throw new CustomException("tre malbona", 390);`
   627  					})
   628  
   629  					It("Should run the extension", func() {
   630  						err := resources.GetSingleResource(
   631  							context, testDB, currentSchema, resourceID1)
   632  						Expect(err).To(HaveOccurred())
   633  						extErr, ok := err.(extension.Error)
   634  						Expect(ok).To(BeTrue())
   635  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   636  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
   637  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   638  					})
   639  				})
   640  
   641  				Context("Only post_show", func() {
   642  					BeforeEach(func() {
   643  						events["post_show"] = `context["response"] = {"respondo": "tre bona"};`
   644  					})
   645  
   646  					It("Should run the extension", func() {
   647  						err := resources.GetSingleResource(
   648  							context, testDB, currentSchema, resourceID1)
   649  						result := context["response"].(map[string]interface{})
   650  						Expect(err).NotTo(HaveOccurred())
   651  						Expect(result).To(HaveKeyWithValue("respondo", "tre bona"))
   652  					})
   653  				})
   654  
   655  				Context("With pre_show throwing exception", func() {
   656  					BeforeEach(func() {
   657  						events["pre_show"] = `throw new CustomException("malbona", 390);`
   658  					})
   659  
   660  					It("Should run the extension", func() {
   661  						err := resources.GetSingleResource(
   662  							context, testDB, currentSchema, resourceID1)
   663  						Expect(err).To(HaveOccurred())
   664  						extErr, ok := err.(extension.Error)
   665  						Expect(ok).To(BeTrue())
   666  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   667  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   668  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   669  					})
   670  				})
   671  
   672  				Context("With post_show throwing exception", func() {
   673  					BeforeEach(func() {
   674  						events["post_show"] = `throw new CustomException("tre malbona", 390);`
   675  					})
   676  
   677  					It("Should run the extension", func() {
   678  						err := resources.GetSingleResource(
   679  							context, testDB, currentSchema, resourceID1)
   680  						Expect(err).To(HaveOccurred())
   681  						extErr, ok := err.(extension.Error)
   682  						Expect(ok).To(BeTrue())
   683  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   684  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
   685  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   686  					})
   687  				})
   688  
   689  			})
   690  		})
   691  	})
   692  
   693  	Describe("Deleting a resource", func() {
   694  		BeforeEach(func() {
   695  			schemaID = "test"
   696  			action = "delete"
   697  		})
   698  
   699  		Describe("When there are no resources in the database", func() {
   700  			It("Should return an informative error", func() {
   701  				err := resources.DeleteResource(
   702  					context, testDB, currentSchema, resourceID1)
   703  				Expect(err).To(HaveOccurred())
   704  				_, ok := err.(resources.ResourceError)
   705  				Expect(ok).To(BeTrue())
   706  			})
   707  
   708  			Describe("With extensions", func() {
   709  				Context("Only pre_delete", func() {
   710  					BeforeEach(func() {
   711  						events["pre_delete"] = `throw new CustomException("bona", 390);`
   712  					})
   713  
   714  					It("Should run the extension", func() {
   715  						err := resources.DeleteResource(
   716  							context, testDB, currentSchema, resourceID1)
   717  						Expect(err).To(HaveOccurred())
   718  						extErr, ok := err.(extension.Error)
   719  						Expect(ok).To(BeTrue())
   720  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   721  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "bona"))
   722  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   723  					})
   724  				})
   725  
   726  				Context("Only pre_delete_in_transaction", func() {
   727  					BeforeEach(func() {
   728  						events["pre_delete_in_transaction"] = `throw new CustomException("malbona", 390);`
   729  					})
   730  
   731  					It("Should not run the extension", func() {
   732  						err := resources.DeleteResource(
   733  							context, testDB, currentSchema, resourceID1)
   734  						Expect(err).To(HaveOccurred())
   735  						_, ok := err.(resources.ResourceError)
   736  						Expect(ok).To(BeTrue())
   737  					})
   738  				})
   739  
   740  				Context("Only post_delete_in_transaction", func() {
   741  					BeforeEach(func() {
   742  						events["post_delete_in_transaction"] = `throw new CustomException("tre malbona", 390);`
   743  					})
   744  
   745  					It("Should not run the extension", func() {
   746  						err := resources.DeleteResource(
   747  							context, testDB, currentSchema, resourceID1)
   748  						Expect(err).To(HaveOccurred())
   749  						_, ok := err.(resources.ResourceError)
   750  						Expect(ok).To(BeTrue())
   751  					})
   752  				})
   753  
   754  				Context("Only post_delete", func() {
   755  					BeforeEach(func() {
   756  						events["post_delete"] = `throw new CustomException("tre bona", 390);`
   757  					})
   758  
   759  					It("Should not run the extension", func() {
   760  						err := resources.DeleteResource(
   761  							context, testDB, currentSchema, resourceID1)
   762  						Expect(err).To(HaveOccurred())
   763  						_, ok := err.(resources.ResourceError)
   764  						Expect(ok).To(BeTrue())
   765  					})
   766  				})
   767  			})
   768  		})
   769  
   770  		Describe("When there are resources in the database", func() {
   771  			var (
   772  				adminResourceData, memberResourceData map[string]interface{}
   773  			)
   774  
   775  			BeforeEach(func() {
   776  				adminResourceData = map[string]interface{}{
   777  					"id":          resourceID1,
   778  					"tenant_id":   adminTenantID,
   779  					"test_string": "Steloj estas en ordo.",
   780  				}
   781  				memberResourceData = map[string]interface{}{
   782  					"id":          resourceID2,
   783  					"tenant_id":   powerUserTenantID,
   784  					"test_string": "Mi estas la pordo, mi estas la sxlosilo.",
   785  				}
   786  			})
   787  
   788  			JustBeforeEach(func() {
   789  				adminResource, err := manager.LoadResource(currentSchema.ID, adminResourceData)
   790  				Expect(err).NotTo(HaveOccurred())
   791  				memberResource, err := manager.LoadResource(currentSchema.ID, memberResourceData)
   792  				Expect(err).NotTo(HaveOccurred())
   793  				transaction, err := testDB.Begin()
   794  				Expect(err).NotTo(HaveOccurred())
   795  				defer transaction.Close()
   796  				Expect(transaction.Create(adminResource)).To(Succeed())
   797  				Expect(transaction.Create(memberResource)).To(Succeed())
   798  				Expect(transaction.Commit()).To(Succeed())
   799  			})
   800  
   801  			Context("As an admin", func() {
   802  				It("Should delete owned resource", func() {
   803  					Expect(resources.DeleteResource(
   804  						context, testDB, currentSchema, resourceID1)).To(Succeed())
   805  				})
   806  
   807  				It("Should delete not owned resource", func() {
   808  					Expect(resources.DeleteResource(
   809  						context, testDB, currentSchema, resourceID1)).To(Succeed())
   810  				})
   811  			})
   812  
   813  			Context("As a member", func() {
   814  				BeforeEach(func() {
   815  					auth = memberAuth
   816  				})
   817  
   818  				It("Should delete owned resource", func() {
   819  					Expect(resources.DeleteResource(
   820  						context, testDB, currentSchema, resourceID1)).To(Succeed())
   821  				})
   822  
   823  				It("Should not delete not owned resource", func() {
   824  					err := resources.DeleteResource(
   825  						context, testDB, currentSchema, resourceID2)
   826  					Expect(err).To(HaveOccurred())
   827  					_, ok := err.(resources.ResourceError)
   828  					Expect(ok).To(BeTrue())
   829  				})
   830  			})
   831  
   832  			Describe("With extensions", func() {
   833  				Context("Only pre_delete", func() {
   834  					BeforeEach(func() {
   835  						events["pre_delete"] = `throw new CustomException("bona", 390);`
   836  					})
   837  
   838  					It("Should run the extension", func() {
   839  						err := resources.DeleteResource(
   840  							context, testDB, currentSchema, resourceID1)
   841  						Expect(err).To(HaveOccurred())
   842  						extErr, ok := err.(extension.Error)
   843  						Expect(ok).To(BeTrue())
   844  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   845  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "bona"))
   846  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   847  					})
   848  				})
   849  
   850  				Context("Only pre_delete_in_transaction", func() {
   851  					BeforeEach(func() {
   852  						events["pre_delete_in_transaction"] = `throw new CustomException("malbona", 390);`
   853  					})
   854  
   855  					It("Should run the extension", func() {
   856  						err := resources.DeleteResource(
   857  							context, testDB, currentSchema, resourceID1)
   858  						Expect(err).To(HaveOccurred())
   859  						extErr, ok := err.(extension.Error)
   860  						Expect(ok).To(BeTrue())
   861  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   862  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
   863  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   864  					})
   865  				})
   866  
   867  				Context("Only post_delete_in_transaction", func() {
   868  					BeforeEach(func() {
   869  						events["post_delete_in_transaction"] = `throw new CustomException("tre malbona", 390);`
   870  					})
   871  
   872  					It("Should run the extension", func() {
   873  						err := resources.DeleteResource(
   874  							context, testDB, currentSchema, resourceID1)
   875  						Expect(err).To(HaveOccurred())
   876  						extErr, ok := err.(extension.Error)
   877  						Expect(ok).To(BeTrue())
   878  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   879  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
   880  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   881  					})
   882  				})
   883  
   884  				Context("Only post_delete", func() {
   885  					BeforeEach(func() {
   886  						events["post_delete"] = `throw new CustomException("tre bona", 390);`
   887  					})
   888  
   889  					It("Should run the extension", func() {
   890  						err := resources.DeleteResource(
   891  							context, testDB, currentSchema, resourceID1)
   892  						Expect(err).To(HaveOccurred())
   893  						extErr, ok := err.(extension.Error)
   894  						Expect(ok).To(BeTrue())
   895  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
   896  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre bona"))
   897  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
   898  					})
   899  				})
   900  			})
   901  		})
   902  	})
   903  
   904  	Describe("Creating a resource", func() {
   905  		var (
   906  			adminResourceData, memberResourceData map[string]interface{}
   907  			fakeIdentity                          middleware.IdentityService
   908  		)
   909  
   910  		BeforeEach(func() {
   911  			schemaID = "test"
   912  			action = "create"
   913  			adminResourceData = map[string]interface{}{
   914  				"id":          resourceID1,
   915  				"tenant_id":   adminTenantID,
   916  				"test_string": "Steloj estas en ordo.",
   917  			}
   918  			memberResourceData = map[string]interface{}{
   919  				"id":          resourceID2,
   920  				"tenant_id":   powerUserTenantID,
   921  				"test_string": "Mi estas la pordo, mi estas la sxlosilo.",
   922  			}
   923  			fakeIdentity = &middleware.FakeIdentity{}
   924  		})
   925  
   926  		Describe("When there are no resources in the database", func() {
   927  			Context("As an admin", func() {
   928  				It("Should create own resource", func() {
   929  					err := resources.CreateResource(
   930  						context, testDB, fakeIdentity, currentSchema, adminResourceData)
   931  
   932  					result := context["response"].(map[string]interface{})
   933  					Expect(err).NotTo(HaveOccurred())
   934  					Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(adminResourceData)))
   935  				})
   936  
   937  				It("Should create not own resource", func() {
   938  					err := resources.CreateResource(
   939  						context, testDB, fakeIdentity, currentSchema, memberResourceData)
   940  					result := context["response"].(map[string]interface{})
   941  					Expect(err).NotTo(HaveOccurred())
   942  					Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(memberResourceData)))
   943  				})
   944  
   945  				It("Should fill in an id", func() {
   946  					err := resources.CreateResource(
   947  						context, testDB, fakeIdentity, currentSchema, map[string]interface{}{"tenant_id": adminTenantID})
   948  					Expect(err).NotTo(HaveOccurred())
   949  					result := context["response"].(map[string]interface{})
   950  					theResource, ok := result[schemaID]
   951  					Expect(ok).To(BeTrue())
   952  					Expect(theResource).To(HaveKeyWithValue("tenant_id", adminTenantID))
   953  					Expect(theResource).To(HaveKey("id"))
   954  				})
   955  
   956  				It("Should fill in the tenant_id", func() {
   957  					err := resources.CreateResource(
   958  						context, testDB, fakeIdentity, currentSchema, map[string]interface{}{"id": resourceID1})
   959  					result := context["response"].(map[string]interface{})
   960  					Expect(err).NotTo(HaveOccurred())
   961  					theResource, ok := result[schemaID]
   962  					Expect(ok).To(BeTrue())
   963  					Expect(theResource).To(HaveKeyWithValue("tenant_id", adminTenantID))
   964  					Expect(theResource).To(HaveKeyWithValue("id", resourceID1))
   965  				})
   966  
   967  				It("Should fill in id and tenant_id", func() {
   968  					err := resources.CreateResource(
   969  						context, testDB, fakeIdentity, currentSchema, map[string]interface{}{})
   970  					Expect(err).NotTo(HaveOccurred())
   971  					result := context["response"].(map[string]interface{})
   972  					theResource, ok := result[schemaID]
   973  					Expect(ok).To(BeTrue())
   974  					Expect(theResource).To(HaveKeyWithValue("tenant_id", adminTenantID))
   975  					Expect(theResource).To(HaveKey("id"))
   976  				})
   977  			})
   978  
   979  			Context("As a member", func() {
   980  				BeforeEach(func() {
   981  					auth = memberAuth
   982  				})
   983  
   984  				It("Should create own resource", func() {
   985  					err := resources.CreateResource(
   986  						context, testDB, fakeIdentity, currentSchema, adminResourceData)
   987  					result := context["response"].(map[string]interface{})
   988  					Expect(err).NotTo(HaveOccurred())
   989  					Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(adminResourceData)))
   990  				})
   991  
   992  				It("Should not create not own resource", func() {
   993  					err := resources.CreateResource(
   994  						context, testDB, fakeIdentity, currentSchema, memberResourceData)
   995  					Expect(err).To(HaveOccurred())
   996  					_, ok := err.(resources.ResourceError)
   997  					Expect(ok).To(BeTrue())
   998  				})
   999  			})
  1000  
  1001  			Describe("With extensions", func() {
  1002  				Context("Only pre_create", func() {
  1003  					BeforeEach(func() {
  1004  						events["pre_create"] = `throw new CustomException("bona", 390);`
  1005  					})
  1006  
  1007  					It("Should run the extension", func() {
  1008  						err := resources.CreateResource(
  1009  							context, testDB, fakeIdentity, currentSchema, adminResourceData)
  1010  						Expect(err).To(HaveOccurred())
  1011  						extErr, ok := err.(extension.Error)
  1012  						Expect(ok).To(BeTrue())
  1013  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1014  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "bona"))
  1015  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1016  					})
  1017  				})
  1018  
  1019  				Context("Only pre_create_in_transaction", func() {
  1020  					BeforeEach(func() {
  1021  						events["pre_create_in_transaction"] = `throw new CustomException("malbona", 390);`
  1022  					})
  1023  
  1024  					It("Should run the extension", func() {
  1025  						err := resources.CreateResource(
  1026  							context, testDB, fakeIdentity, currentSchema, adminResourceData)
  1027  						Expect(err).To(HaveOccurred())
  1028  						extErr, ok := err.(extension.Error)
  1029  						Expect(ok).To(BeTrue())
  1030  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1031  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
  1032  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1033  					})
  1034  				})
  1035  
  1036  				Context("Only post_create_in_transaction", func() {
  1037  					BeforeEach(func() {
  1038  						events["post_create_in_transaction"] = `throw new CustomException("tre malbona", 390);`
  1039  					})
  1040  
  1041  					It("Should run the extension", func() {
  1042  						err := resources.CreateResource(
  1043  							context, testDB, fakeIdentity, currentSchema, adminResourceData)
  1044  						Expect(err).To(HaveOccurred())
  1045  						extErr, ok := err.(extension.Error)
  1046  						Expect(ok).To(BeTrue())
  1047  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1048  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
  1049  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1050  					})
  1051  				})
  1052  
  1053  				Context("Only post_create", func() {
  1054  					BeforeEach(func() {
  1055  						events["post_create"] = `throw new CustomException("tre bona", 390);`
  1056  					})
  1057  
  1058  					It("Should run the extension", func() {
  1059  						err := resources.CreateResource(
  1060  							context, testDB, fakeIdentity, currentSchema, adminResourceData)
  1061  						Expect(err).To(HaveOccurred())
  1062  						extErr, ok := err.(extension.Error)
  1063  						Expect(ok).To(BeTrue())
  1064  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1065  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre bona"))
  1066  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1067  					})
  1068  				})
  1069  
  1070  			})
  1071  		})
  1072  
  1073  		Describe("When there are resources in the database", func() {
  1074  			JustBeforeEach(func() {
  1075  				adminResource, err := manager.LoadResource(currentSchema.ID, adminResourceData)
  1076  				Expect(err).NotTo(HaveOccurred())
  1077  				memberResource, err := manager.LoadResource(currentSchema.ID, memberResourceData)
  1078  				Expect(err).NotTo(HaveOccurred())
  1079  				transaction, err := testDB.Begin()
  1080  				Expect(err).NotTo(HaveOccurred())
  1081  				defer transaction.Close()
  1082  				Expect(transaction.Create(adminResource)).To(Succeed())
  1083  				Expect(transaction.Create(memberResource)).To(Succeed())
  1084  				Expect(transaction.Commit()).To(Succeed())
  1085  			})
  1086  
  1087  			It("Should not create duplicate resource", func() {
  1088  				err := resources.CreateResource(
  1089  					context, testDB, fakeIdentity, currentSchema, adminResourceData)
  1090  				Expect(err).To(HaveOccurred())
  1091  				_, ok := err.(resources.ResourceError)
  1092  				Expect(ok).To(BeTrue())
  1093  			})
  1094  		})
  1095  	})
  1096  
  1097  	Describe("Updating a resource", func() {
  1098  		var (
  1099  			adminResourceData, memberResourceData map[string]interface{}
  1100  			fakeIdentity                          middleware.IdentityService
  1101  		)
  1102  
  1103  		BeforeEach(func() {
  1104  			schemaID = "test"
  1105  			action = "create"
  1106  			adminResourceData = map[string]interface{}{
  1107  				"id":          resourceID1,
  1108  				"tenant_id":   adminTenantID,
  1109  				"test_string": "Steloj estas en ordo.",
  1110  			}
  1111  			memberResourceData = map[string]interface{}{
  1112  				"id":          resourceID2,
  1113  				"tenant_id":   powerUserTenantID,
  1114  				"test_string": "Mi estas la pordo, mi estas la sxlosilo.",
  1115  			}
  1116  			fakeIdentity = &middleware.FakeIdentity{}
  1117  		})
  1118  
  1119  		Describe("When there are no resources in the database", func() {
  1120  			It("Should return an informative error", func() {
  1121  				err := resources.UpdateResource(
  1122  					context, testDB, fakeIdentity, currentSchema, resourceID1, adminResourceData)
  1123  				Expect(err).To(HaveOccurred())
  1124  				_, ok := err.(resources.ResourceError)
  1125  				Expect(ok).To(BeTrue())
  1126  			})
  1127  
  1128  			Describe("With extensions", func() {
  1129  				Context("Only pre_update", func() {
  1130  					BeforeEach(func() {
  1131  						events["pre_update"] = `throw new CustomException("bona", 390);`
  1132  					})
  1133  
  1134  					It("Should run the extension", func() {
  1135  						err := resources.UpdateResource(
  1136  							context, testDB, fakeIdentity, currentSchema, resourceID1, adminResourceData)
  1137  						Expect(err).To(HaveOccurred())
  1138  						extErr, ok := err.(extension.Error)
  1139  						Expect(ok).To(BeTrue())
  1140  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1141  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "bona"))
  1142  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1143  					})
  1144  				})
  1145  
  1146  				Context("Only pre_update_in_transaction", func() {
  1147  					BeforeEach(func() {
  1148  						events["pre_update_in_transaction"] = `throw new CustomException("malbona", 390);`
  1149  					})
  1150  
  1151  					It("Should not run the extension", func() {
  1152  						err := resources.UpdateResource(
  1153  							context, testDB, fakeIdentity, currentSchema, resourceID1, adminResourceData)
  1154  						Expect(err).To(HaveOccurred())
  1155  						_, ok := err.(resources.ResourceError)
  1156  						Expect(ok).To(BeTrue())
  1157  					})
  1158  				})
  1159  
  1160  				Context("Only post_update_in_transaction", func() {
  1161  					BeforeEach(func() {
  1162  						events["post_update_in_transaction"] = `throw new CustomException("tre malbona", 390);`
  1163  					})
  1164  
  1165  					It("Should not run the extension", func() {
  1166  						err := resources.UpdateResource(
  1167  							context, testDB, fakeIdentity, currentSchema, resourceID1, adminResourceData)
  1168  						Expect(err).To(HaveOccurred())
  1169  						_, ok := err.(resources.ResourceError)
  1170  						Expect(ok).To(BeTrue())
  1171  					})
  1172  				})
  1173  
  1174  				Context("Only post_update", func() {
  1175  					BeforeEach(func() {
  1176  						events["post_update"] = `throw new CustomException("tre bona", 390);`
  1177  					})
  1178  
  1179  					It("Should not run the extension", func() {
  1180  						err := resources.UpdateResource(
  1181  							context, testDB, fakeIdentity, currentSchema, resourceID1, adminResourceData)
  1182  						Expect(err).To(HaveOccurred())
  1183  						_, ok := err.(resources.ResourceError)
  1184  						Expect(ok).To(BeTrue())
  1185  					})
  1186  				})
  1187  			})
  1188  		})
  1189  
  1190  		Describe("When there are resources in the database", func() {
  1191  			JustBeforeEach(func() {
  1192  				adminResource, err := manager.LoadResource(currentSchema.ID, adminResourceData)
  1193  				Expect(err).NotTo(HaveOccurred())
  1194  				memberResource, err := manager.LoadResource(currentSchema.ID, memberResourceData)
  1195  				Expect(err).NotTo(HaveOccurred())
  1196  				transaction, err := testDB.Begin()
  1197  				Expect(err).NotTo(HaveOccurred())
  1198  				defer transaction.Close()
  1199  				Expect(transaction.Create(adminResource)).To(Succeed())
  1200  				Expect(transaction.Create(memberResource)).To(Succeed())
  1201  				Expect(transaction.Commit()).To(Succeed())
  1202  			})
  1203  
  1204  			Context("As an admin", func() {
  1205  				It("Should update own resource", func() {
  1206  					err := resources.UpdateResource(
  1207  						context, testDB, fakeIdentity, currentSchema, resourceID1,
  1208  						map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1209  					result := context["response"].(map[string]interface{})
  1210  					Expect(err).NotTo(HaveOccurred())
  1211  					theResource, ok := result[schemaID]
  1212  					Expect(ok).To(BeTrue())
  1213  					Expect(theResource).To(HaveKeyWithValue("test_string", "Steloj ne estas en ordo."))
  1214  				})
  1215  
  1216  				It("Should update not own resource", func() {
  1217  					err := resources.UpdateResource(
  1218  						context, testDB, fakeIdentity, currentSchema, resourceID1,
  1219  						map[string]interface{}{"test_string": "Ia, ia, HJPEV fhtang!"})
  1220  					result := context["response"].(map[string]interface{})
  1221  					Expect(err).NotTo(HaveOccurred())
  1222  					theResource, ok := result[schemaID]
  1223  					Expect(ok).To(BeTrue())
  1224  					Expect(theResource).To(HaveKeyWithValue("test_string", "Ia, ia, HJPEV fhtang!"))
  1225  				})
  1226  			})
  1227  
  1228  			Context("As a member", func() {
  1229  				BeforeEach(func() {
  1230  					auth = memberAuth
  1231  				})
  1232  
  1233  				It("Should update own resource", func() {
  1234  					err := resources.UpdateResource(
  1235  						context, testDB, fakeIdentity, currentSchema, resourceID1,
  1236  						map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1237  					result := context["response"].(map[string]interface{})
  1238  					Expect(err).NotTo(HaveOccurred())
  1239  					theResource, ok := result[schemaID]
  1240  					Expect(ok).To(BeTrue())
  1241  					Expect(theResource).To(HaveKeyWithValue("test_string", "Steloj ne estas en ordo."))
  1242  				})
  1243  
  1244  				It("Should not update not own resource", func() {
  1245  					err := resources.UpdateResource(
  1246  						context, testDB, fakeIdentity, currentSchema, resourceID2,
  1247  						map[string]interface{}{"test_string": "Ia, ia, HWCBN fhtang!"})
  1248  					resource, _ := context["response"].(map[string]interface{})
  1249  					Expect(resource).To(BeNil())
  1250  					Expect(err).To(HaveOccurred())
  1251  					_, ok := err.(resources.ResourceError)
  1252  					Expect(ok).To(BeTrue())
  1253  				})
  1254  			})
  1255  
  1256  			Describe("With extensions", func() {
  1257  				Context("Only pre_update", func() {
  1258  					BeforeEach(func() {
  1259  						events["pre_update"] = `throw new CustomException("bona", 390);`
  1260  					})
  1261  
  1262  					It("Should run the extension", func() {
  1263  						err := resources.UpdateResource(
  1264  							context, testDB, fakeIdentity, currentSchema, resourceID1,
  1265  							map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1266  						Expect(err).To(HaveOccurred())
  1267  						extErr, ok := err.(extension.Error)
  1268  						Expect(ok).To(BeTrue())
  1269  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1270  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "bona"))
  1271  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1272  					})
  1273  				})
  1274  
  1275  				Context("Only pre_update_in_transaction", func() {
  1276  					BeforeEach(func() {
  1277  						events["pre_update_in_transaction"] = `throw new CustomException("malbona", 390);`
  1278  					})
  1279  
  1280  					It("Should run the extension", func() {
  1281  						err := resources.UpdateResource(
  1282  							context, testDB, fakeIdentity, currentSchema, resourceID1,
  1283  							map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1284  						Expect(err).To(HaveOccurred())
  1285  						extErr, ok := err.(extension.Error)
  1286  						Expect(ok).To(BeTrue())
  1287  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1288  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "malbona"))
  1289  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1290  					})
  1291  				})
  1292  
  1293  				Context("Only post_update_in_transaction", func() {
  1294  					BeforeEach(func() {
  1295  						events["post_update_in_transaction"] = `throw new CustomException("tre malbona", 390);`
  1296  					})
  1297  
  1298  					It("Should run the extension", func() {
  1299  						err := resources.UpdateResource(
  1300  							context, testDB, fakeIdentity, currentSchema, resourceID1,
  1301  							map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1302  						Expect(err).To(HaveOccurred())
  1303  						extErr, ok := err.(extension.Error)
  1304  						Expect(ok).To(BeTrue())
  1305  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1306  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre malbona"))
  1307  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1308  					})
  1309  				})
  1310  
  1311  				Context("Only post_update", func() {
  1312  					BeforeEach(func() {
  1313  						events["post_update"] = `throw new CustomException("tre bona", 390);`
  1314  					})
  1315  
  1316  					It("Should run the extension", func() {
  1317  						err := resources.UpdateResource(
  1318  							context, testDB, fakeIdentity, currentSchema, resourceID1,
  1319  							map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1320  						Expect(err).To(HaveOccurred())
  1321  						extErr, ok := err.(extension.Error)
  1322  						Expect(ok).To(BeTrue())
  1323  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("name", "CustomException"))
  1324  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("message", "tre bona"))
  1325  						Expect(extErr.ExceptionInfo).To(HaveKeyWithValue("code", int64(390)))
  1326  					})
  1327  				})
  1328  
  1329  			})
  1330  		})
  1331  	})
  1332  
  1333  	Describe("Executing a sequence of operations", func() {
  1334  		var (
  1335  			adminResourceData, memberResourceData                                 map[string]interface{}
  1336  			listContext, showContext, deleteContext, createContext, updateContext middleware.Context
  1337  			fakeIdentity                                                          middleware.IdentityService
  1338  		)
  1339  
  1340  		BeforeEach(func() {
  1341  			schemaID = "test"
  1342  			action = "list"
  1343  			adminResourceData = map[string]interface{}{
  1344  				"id":          resourceID1,
  1345  				"tenant_id":   adminTenantID,
  1346  				"test_string": "Steloj estas en ordo.",
  1347  			}
  1348  			memberResourceData = map[string]interface{}{
  1349  				"id":          resourceID2,
  1350  				"tenant_id":   powerUserTenantID,
  1351  				"test_string": "Mi estas la pordo, mi estas la sxlosilo.",
  1352  			}
  1353  			listContext = middleware.Context{}
  1354  			showContext = middleware.Context{}
  1355  			deleteContext = middleware.Context{}
  1356  			createContext = middleware.Context{}
  1357  			updateContext = middleware.Context{}
  1358  			fakeIdentity = &middleware.FakeIdentity{}
  1359  		})
  1360  
  1361  		JustBeforeEach(func() {
  1362  			policy, role := manager.PolicyValidate("list", path, auth)
  1363  			Expect(policy).NotTo(BeNil())
  1364  			listContext["policy"] = policy
  1365  			listContext["role"] = role
  1366  			listContext["tenant_id"] = auth.TenantID()
  1367  			listContext["tenant_name"] = auth.TenantName()
  1368  			listContext["auth_token"] = auth.AuthToken()
  1369  			listContext["catalog"] = auth.Catalog()
  1370  			listContext["auth"] = auth
  1371  			policy, role = manager.PolicyValidate("show", path, auth)
  1372  			Expect(policy).NotTo(BeNil())
  1373  			showContext["policy"] = policy
  1374  			showContext["role"] = role
  1375  			showContext["tenant_id"] = auth.TenantID()
  1376  			showContext["tenant_name"] = auth.TenantName()
  1377  			showContext["auth_token"] = auth.AuthToken()
  1378  			showContext["catalog"] = auth.Catalog()
  1379  			showContext["auth"] = auth
  1380  			policy, role = manager.PolicyValidate("delete", path, auth)
  1381  			Expect(policy).NotTo(BeNil())
  1382  			deleteContext["policy"] = policy
  1383  			deleteContext["role"] = role
  1384  			deleteContext["tenant_id"] = auth.TenantID()
  1385  			deleteContext["tenant_name"] = auth.TenantName()
  1386  			deleteContext["auth_token"] = auth.AuthToken()
  1387  			deleteContext["catalog"] = auth.Catalog()
  1388  			deleteContext["auth"] = auth
  1389  			policy, role = manager.PolicyValidate("create", path, auth)
  1390  			Expect(policy).NotTo(BeNil())
  1391  			createContext["policy"] = policy
  1392  			createContext["role"] = role
  1393  			createContext["tenant_id"] = auth.TenantID()
  1394  			createContext["tenant_name"] = auth.TenantName()
  1395  			createContext["auth_token"] = auth.AuthToken()
  1396  			createContext["catalog"] = auth.Catalog()
  1397  			createContext["auth"] = auth
  1398  			policy, role = manager.PolicyValidate("update", path, auth)
  1399  			Expect(policy).NotTo(BeNil())
  1400  			updateContext["policy"] = policy
  1401  			updateContext["role"] = role
  1402  			updateContext["tenant_id"] = auth.TenantID()
  1403  			updateContext["tenant_name"] = auth.TenantName()
  1404  			updateContext["auth_token"] = auth.AuthToken()
  1405  			updateContext["catalog"] = auth.Catalog()
  1406  			updateContext["auth"] = auth
  1407  		})
  1408  
  1409  		It("Should behave as expected", func() {
  1410  			By("Showing nothing in an empty database")
  1411  			err := resources.GetMultipleResources(
  1412  				listContext, testDB, currentSchema, map[string][]string{})
  1413  
  1414  			result, _ := listContext["response"].(map[string]interface{})
  1415  			number, _ := listContext["total"].(uint64)
  1416  			Expect(err).NotTo(HaveOccurred())
  1417  			Expect(number).To(Equal(uint64(0)))
  1418  			Expect(result).To(HaveKeyWithValue("tests", BeEmpty()))
  1419  			delete(listContext, "response")
  1420  
  1421  			By("Successfully adding a resource to the database")
  1422  			err = resources.CreateResource(
  1423  				createContext, testDB, fakeIdentity, currentSchema, adminResourceData)
  1424  			result = createContext["response"].(map[string]interface{})
  1425  			Expect(err).NotTo(HaveOccurred())
  1426  			Expect(result).To(HaveKeyWithValue(schemaID, util.MatchAsJSON(adminResourceData)))
  1427  
  1428  			By("Listing the added resource")
  1429  			err = resources.GetMultipleResources(
  1430  				listContext, testDB, currentSchema, map[string][]string{})
  1431  			result = listContext["response"].(map[string]interface{})
  1432  			number = listContext["total"].(uint64)
  1433  
  1434  			Expect(err).NotTo(HaveOccurred())
  1435  			Expect(number).To(Equal(uint64(1)))
  1436  			Expect(result).To(HaveKeyWithValue("tests", ConsistOf(util.MatchAsJSON(adminResourceData))))
  1437  
  1438  			By("Updating the resource")
  1439  			err = resources.UpdateResource(
  1440  				updateContext, testDB, fakeIdentity, currentSchema, resourceID1,
  1441  				map[string]interface{}{"test_string": "Steloj ne estas en ordo."})
  1442  			result = updateContext["response"].(map[string]interface{})
  1443  			Expect(err).NotTo(HaveOccurred())
  1444  			Expect(result).To(HaveKeyWithValue(schemaID, HaveKeyWithValue("test_string", "Steloj ne estas en ordo.")))
  1445  
  1446  			By("Showing the updated resource")
  1447  			err = resources.GetSingleResource(
  1448  				showContext, testDB, currentSchema, resourceID1)
  1449  			result = showContext["response"].(map[string]interface{})
  1450  			By(fmt.Sprintf("%s", result))
  1451  			Expect(err).NotTo(HaveOccurred())
  1452  			Expect(result).To(HaveKeyWithValue(schemaID, HaveKeyWithValue("test_string", "Steloj ne estas en ordo.")))
  1453  
  1454  			By("Deleting the resource")
  1455  			By(resourceID1)
  1456  			Expect(resources.DeleteResource(
  1457  				deleteContext, testDB, currentSchema, resourceID1)).To(Succeed())
  1458  
  1459  			By("Again showing nothing in an empty database")
  1460  			delete(listContext, "response")
  1461  			err = resources.GetMultipleResources(
  1462  				listContext, testDB, currentSchema, map[string][]string{})
  1463  			result = listContext["response"].(map[string]interface{})
  1464  			By(fmt.Sprintf("%s", result))
  1465  			number = listContext["total"].(uint64)
  1466  			Expect(err).NotTo(HaveOccurred())
  1467  			Expect(number).To(Equal(uint64(0)))
  1468  			Expect(result).To(HaveKeyWithValue("tests", BeEmpty()))
  1469  		})
  1470  	})
  1471  })