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