github.com/weaviate/weaviate@v1.24.6/test/acceptance/multi_tenancy/create_and_delete_tenants_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package test 13 14 import ( 15 "testing" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 "github.com/weaviate/weaviate/client/nodes" 20 "github.com/weaviate/weaviate/entities/models" 21 "github.com/weaviate/weaviate/entities/schema" 22 "github.com/weaviate/weaviate/entities/verbosity" 23 "github.com/weaviate/weaviate/test/helper" 24 ) 25 26 var verbose = verbosity.OutputVerbose 27 28 func TestCreateTenants(t *testing.T) { 29 testClass := models.Class{ 30 Class: "MultiTenantClass", 31 MultiTenancyConfig: &models.MultiTenancyConfig{ 32 Enabled: true, 33 }, 34 Properties: []*models.Property{ 35 { 36 Name: "name", 37 DataType: schema.DataTypeText.PropString(), 38 }, 39 }, 40 } 41 42 t.Run("Create tenant", func(Z *testing.T) { 43 expectedTenants := []string{ 44 "Tenant1", "Tenant2", "Tenant3", 45 } 46 47 defer func() { 48 helper.DeleteClass(t, testClass.Class) 49 }() 50 helper.CreateClass(t, &testClass) 51 52 tenants := make([]*models.Tenant, len(expectedTenants)) 53 for i := range tenants { 54 tenants[i] = &models.Tenant{ 55 Name: expectedTenants[i], 56 ActivityStatus: models.TenantActivityStatusHOT, 57 } 58 } 59 helper.CreateTenants(t, testClass.Class, tenants) 60 61 respGet, errGet := helper.GetTenants(t, testClass.Class) 62 require.Nil(t, errGet) 63 require.NotNil(t, respGet) 64 require.ElementsMatch(t, respGet.Payload, tenants) 65 66 resp, err := helper.Client(t).Nodes.NodesGet(nodes.NewNodesGetParams().WithOutput(&verbose), nil) 67 require.Nil(t, err) 68 require.NotNil(t, resp.Payload) 69 require.NotNil(t, resp.Payload.Nodes) 70 require.Len(t, resp.Payload.Nodes, 1) 71 require.Len(t, resp.Payload.Nodes[0].Shards, 3) 72 73 var foundTenants []string 74 for _, found := range resp.Payload.Nodes[0].Shards { 75 assert.Equal(t, testClass.Class, found.Class) 76 // Creating a tenant alone should not result in a loaded shard. 77 // This check also ensures that the nods api did not cause a 78 // force load. 79 assert.False(t, found.Loaded) 80 foundTenants = append(foundTenants, found.Name) 81 } 82 assert.ElementsMatch(t, expectedTenants, foundTenants) 83 }) 84 85 t.Run("Create duplicate tenant once", func(Z *testing.T) { 86 defer func() { 87 helper.DeleteClass(t, testClass.Class) 88 }() 89 helper.CreateClass(t, &testClass) 90 err := helper.CreateTenantsReturnError(t, testClass.Class, []*models.Tenant{{Name: "DoubleTenant"}, {Name: "DoubleTenant"}}) 91 require.Nil(t, err) 92 93 // only added once 94 respGet, errGet := helper.GetTenants(t, testClass.Class) 95 require.Nil(t, errGet) 96 require.NotNil(t, respGet) 97 require.Len(t, respGet.Payload, 1) 98 }) 99 100 t.Run("Create same tenant multiple times", func(Z *testing.T) { 101 defer func() { 102 helper.DeleteClass(t, testClass.Class) 103 }() 104 helper.CreateClass(t, &testClass) 105 helper.CreateTenants(t, testClass.Class, []*models.Tenant{{Name: "AddTenantAgain"}}) 106 107 // idempotent operation 108 err := helper.CreateTenantsReturnError(t, testClass.Class, []*models.Tenant{{Name: "AddTenantAgain"}}) 109 require.Nil(t, err) 110 }) 111 } 112 113 func TestDeleteTenants(t *testing.T) { 114 testClass := models.Class{ 115 Class: "MultiTenantClassDelete", 116 MultiTenancyConfig: &models.MultiTenancyConfig{Enabled: true}, 117 } 118 119 defer func() { 120 helper.DeleteClass(t, testClass.Class) 121 }() 122 helper.CreateClass(t, &testClass) 123 124 tenants := []*models.Tenant{ 125 {Name: "tenant1"}, 126 {Name: "tenant2"}, 127 {Name: "tenant3"}, 128 {Name: "tenant4"}, 129 } 130 helper.CreateTenants(t, testClass.Class, tenants) 131 132 t.Run("Delete same tenant multiple times", func(t *testing.T) { 133 err := helper.DeleteTenants(t, testClass.Class, []string{"tenant4"}) 134 require.Nil(t, err) 135 136 // deleted once 137 resp, err := helper.Client(t).Nodes.NodesGet(nodes.NewNodesGetParams().WithOutput(&verbose), nil) 138 require.Nil(t, err) 139 require.NotNil(t, resp.Payload) 140 require.NotNil(t, resp.Payload.Nodes) 141 require.Len(t, resp.Payload.Nodes, 1) 142 for _, shard := range resp.Payload.Nodes[0].Shards { 143 // Creating a tenant alone should not result in a loaded shard. 144 // This check also ensures that the nods api did not cause a 145 // force load. 146 assert.False(t, shard.Loaded) 147 assert.NotEqual(t, "tenant4", shard.Name) 148 } 149 150 // idempotent operation 151 err = helper.DeleteTenants(t, testClass.Class, []string{"tenant4"}) 152 require.Nil(t, err) 153 }) 154 155 t.Run("Delete duplicate tenant once", func(Z *testing.T) { 156 err := helper.DeleteTenants(t, testClass.Class, []string{"tenant1", "tenant1"}) 157 // idempotent operation 158 require.Nil(t, err) 159 160 // deleted once 161 resp, err := helper.Client(t).Nodes.NodesGet(nodes.NewNodesGetParams().WithOutput(&verbose), nil) 162 require.Nil(t, err) 163 require.NotNil(t, resp.Payload) 164 require.NotNil(t, resp.Payload.Nodes) 165 require.Len(t, resp.Payload.Nodes, 1) 166 require.Len(t, resp.Payload.Nodes[0].Shards, 2) 167 }) 168 169 t.Run("Delete non-existent tenant alongside existing", func(Z *testing.T) { 170 err := helper.DeleteTenants(t, testClass.Class, []string{"tenant1", "tenant5"}) 171 require.Nil(t, err) 172 173 // idempotent - deleting multiple times works - tenant1 is removed 174 resp, err := helper.Client(t).Nodes.NodesGet(nodes.NewNodesGetParams().WithOutput(&verbose), nil) 175 require.Nil(t, err) 176 require.NotNil(t, resp.Payload) 177 require.NotNil(t, resp.Payload.Nodes) 178 require.Len(t, resp.Payload.Nodes, 1) 179 require.Len(t, resp.Payload.Nodes[0].Shards, 2) 180 }) 181 182 t.Run("Delete tenants", func(Z *testing.T) { 183 err := helper.DeleteTenants(t, testClass.Class, []string{"tenant1", "tenant3"}) 184 require.Nil(t, err) 185 186 // successfully deleted 187 resp, err := helper.Client(t).Nodes.NodesGet(nodes.NewNodesGetParams().WithOutput(&verbose), nil) 188 require.Nil(t, err) 189 require.NotNil(t, resp.Payload) 190 require.NotNil(t, resp.Payload.Nodes) 191 require.Len(t, resp.Payload.Nodes, 1) 192 require.Len(t, resp.Payload.Nodes[0].Shards, 1) 193 }) 194 } 195 196 func TestTenantsNonMultiTenant(t *testing.T) { 197 testClass := models.Class{ 198 Class: "TenantsNoMultiClass", 199 MultiTenancyConfig: &models.MultiTenancyConfig{ 200 Enabled: false, 201 }, 202 } 203 defer func() { 204 helper.DeleteClass(t, testClass.Class) 205 }() 206 helper.CreateClass(t, &testClass) 207 208 err := helper.CreateTenantsReturnError(t, testClass.Class, []*models.Tenant{{Name: "doesNotMatter"}}) 209 require.NotNil(t, err) 210 211 _, err = helper.GetTenants(t, testClass.Class) 212 require.NotNil(t, err) 213 214 err = helper.DeleteTenants(t, testClass.Class, []string{"doesNotMatter"}) 215 require.NotNil(t, err) 216 } 217 218 func TestTenantsClassDoesNotExist(t *testing.T) { 219 err := helper.CreateTenantsReturnError(t, "DoesNotExist", []*models.Tenant{{Name: "doesNotMatter"}}) 220 require.NotNil(t, err) 221 222 _, err = helper.GetTenants(t, "DoesNotExist") 223 require.NotNil(t, err) 224 225 err = helper.DeleteTenants(t, "DoesNotExist", []string{"doesNotMatter"}) 226 require.NotNil(t, err) 227 }