github.com/vmware/govmomi@v0.43.0/simulator/session_manager_test.go (about) 1 /* 2 Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package simulator 18 19 import ( 20 "context" 21 "crypto/tls" 22 "log" 23 "strings" 24 "testing" 25 26 "github.com/vmware/govmomi" 27 "github.com/vmware/govmomi/object" 28 "github.com/vmware/govmomi/property" 29 "github.com/vmware/govmomi/session" 30 "github.com/vmware/govmomi/simulator/vpx" 31 "github.com/vmware/govmomi/vim25/methods" 32 "github.com/vmware/govmomi/vim25/mo" 33 "github.com/vmware/govmomi/vim25/soap" 34 "github.com/vmware/govmomi/vim25/types" 35 ) 36 37 func isNotAuthenticated(err error) bool { 38 if soap.IsSoapFault(err) { 39 switch soap.ToSoapFault(err).VimFault().(type) { 40 case types.NotAuthenticated: 41 return true 42 } 43 } 44 return false 45 } 46 47 func TestSessionManagerAuth(t *testing.T) { 48 ctx := context.Background() 49 50 m := VPX() 51 52 defer m.Remove() 53 54 err := m.Create() 55 if err != nil { 56 t.Fatal(err) 57 } 58 59 s := m.Service.NewServer() 60 defer s.Close() 61 62 u := s.URL.User 63 s.URL.User = nil // skip Login() 64 65 c, err := govmomi.NewClient(ctx, s.URL, true) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 session, err := c.SessionManager.UserSession(ctx) 71 if err != nil { 72 t.Fatal(err) 73 } 74 75 if session != nil { 76 t.Error("expected nil session") 77 } 78 79 opts := object.NewOptionManager(c.Client, *c.ServiceContent.Setting) 80 var content []types.ObjectContent 81 err = opts.Properties(ctx, opts.Reference(), []string{"setting"}, &content) 82 if err != nil { 83 t.Fatal(err) 84 } 85 86 if len(content) != 1 { 87 t.Error("expected content len=1") 88 } 89 90 if len(content[0].PropSet) != 0 { 91 t.Error("non-empty PropSet") 92 } 93 94 if len(content[0].MissingSet) != 1 { 95 t.Error("expected MissingSet len=1") 96 } 97 98 if _, ok := content[0].MissingSet[0].Fault.Fault.(*types.NotAuthenticated); !ok { 99 t.Error("expected NotAuthenticated") 100 } 101 102 _, err = methods.GetCurrentTime(ctx, c) 103 if !isNotAuthenticated(err) { 104 t.Error("expected NotAuthenticated") 105 } 106 107 err = c.SessionManager.Login(ctx, u) 108 if err != nil { 109 t.Fatal(err) 110 } 111 112 c.UserAgent = "vcsim/x.x" 113 114 session, err = c.SessionManager.UserSession(ctx) 115 if err != nil { 116 t.Fatal(err) 117 } 118 119 if session == nil { 120 t.Error("expected session") 121 } 122 123 if session.UserAgent != c.UserAgent { 124 t.Errorf("UserAgent=%s", session.UserAgent) 125 } 126 127 active, err := c.SessionManager.SessionIsActive(ctx) 128 if err != nil { 129 t.Fatal(err) 130 } 131 132 if active == false { 133 t.Error("not active") 134 } 135 136 { 137 req := types.SessionIsActive{ 138 This: c.SessionManager.Reference(), 139 SessionID: "enoent", 140 UserName: "", 141 } 142 143 active, err := methods.SessionIsActive(ctx, c, &req) 144 if err != nil { 145 t.Fatal(err) 146 } 147 148 if active.Returnval { 149 t.Error("active") 150 } 151 } 152 153 { 154 req := types.SessionIsActive{ 155 This: c.SessionManager.Reference(), 156 SessionID: session.Key, 157 UserName: "enoent", 158 } 159 160 active, err := methods.SessionIsActive(ctx, c, &req) 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 if active.Returnval { 166 t.Error("active") 167 } 168 } 169 170 content = nil 171 err = opts.Properties(ctx, opts.Reference(), []string{"setting"}, &content) 172 if err != nil { 173 t.Fatal(err) 174 } 175 176 if len(content) != 1 { 177 t.Error("expected content len=1") 178 } 179 180 if len(content[0].PropSet) != 1 { 181 t.Error("PropSet len=1") 182 } 183 184 if len(content[0].MissingSet) != 0 { 185 t.Error("expected MissingSet len=0") 186 } 187 188 last := session.LastActiveTime 189 190 _, err = methods.GetCurrentTime(ctx, c) 191 if err != nil { 192 t.Error(err) 193 } 194 195 pc, err := property.DefaultCollector(c.Client).Create(ctx) 196 if err != nil { 197 t.Fatal(err) 198 } 199 200 session, _ = c.SessionManager.UserSession(ctx) 201 202 if session.LastActiveTime.Equal(last) { 203 t.Error("LastActiveTime was not updated") 204 } 205 206 if !strings.Contains(pc.Reference().Value, session.Key) { 207 t.Errorf("invalid ref=%s", pc.Reference()) 208 } 209 210 ticket, err := c.SessionManager.AcquireCloneTicket(ctx) 211 if err != nil { 212 t.Fatal(err) 213 } 214 215 c, err = govmomi.NewClient(ctx, s.URL, true) 216 if err != nil { 217 t.Fatal(err) 218 } 219 220 err = c.SessionManager.CloneSession(ctx, ticket) 221 if err != nil { 222 t.Fatal(err) 223 } 224 225 err = c.SessionManager.CloneSession(ctx, ticket) 226 if err == nil { 227 t.Error("expected error") 228 } 229 230 _, err = methods.GetCurrentTime(ctx, c) 231 if err != nil { 232 t.Error(err) 233 } 234 } 235 236 func TestSessionManagerLoginExtension(t *testing.T) { 237 ctx := context.Background() 238 239 s := New(NewServiceInstance(SpoofContext(), vpx.ServiceContent, vpx.RootFolder)) 240 s.TLS = new(tls.Config) 241 ts := s.NewServer() 242 defer ts.Close() 243 244 if terr := ts.StartTunnel(); terr != nil { 245 t.Fatal(terr) 246 } 247 248 u := ts.URL.User 249 ts.URL.User = nil // skip Login() 250 251 c, err := govmomi.NewClient(ctx, ts.URL, true) 252 if err != nil { 253 t.Fatal(err) 254 } 255 256 err = session.NewManager(c.Client).LoginExtensionByCertificate(ctx, u.Username()) 257 if err == nil { 258 t.Error("expected error") // client cert not set 259 } 260 261 c.SetCertificate(ts.TLS.Certificates[0]) // any cert is ok with vcsim 262 err = session.NewManager(c.Client).LoginExtensionByCertificate(ctx, u.Username()) 263 if err != nil { 264 t.Fatal(err) 265 } 266 267 _, err = methods.GetCurrentTime(ctx, c) 268 if err != nil { 269 t.Error(err) 270 } 271 } 272 273 // Test WaitForUpdates against the PropertyCollector singleton. 274 // Includes test for issue 1172, where a 2nd session use of the PropertyCollector singleton followed by Logout() 275 // unregistered the 1st session's update listener as the PC singleton has the same moref regardless of session instance. 276 func TestSessionManagerPropertyCollector(t *testing.T) { 277 ctx := context.Background() 278 279 m := VPX() 280 281 defer m.Remove() 282 283 err := m.Create() 284 if err != nil { 285 t.Fatal(err) 286 } 287 288 s := m.Service.NewServer() 289 defer s.Close() 290 291 c, err := govmomi.NewClient(ctx, s.URL, true) 292 if err != nil { 293 t.Fatal(err) 294 } 295 296 pc := property.DefaultCollector(c.Client) 297 root := object.NewRootFolder(c.Client) 298 299 filter := types.CreateFilter{ 300 This: pc.Reference(), 301 Spec: types.PropertyFilterSpec{ 302 PropSet: []types.PropertySpec{ 303 { 304 Type: "Datacenter", 305 All: types.NewBool(false), 306 PathSet: []string{"name"}, 307 }, 308 }, 309 ObjectSet: []types.ObjectSpec{ 310 { 311 Obj: root.Reference(), 312 Skip: (*bool)(nil), 313 SelectSet: []types.BaseSelectionSpec{ 314 &types.TraversalSpec{ 315 SelectionSpec: types.SelectionSpec{ 316 Name: "folder2childEntity", 317 }, 318 Type: "Folder", 319 Path: "childEntity", 320 Skip: types.NewBool(false), 321 SelectSet: []types.BaseSelectionSpec{ 322 &types.SelectionSpec{ 323 Name: "folder2childEntity", 324 }, 325 }, 326 }, 327 }, 328 }, 329 }, 330 ReportMissingObjectsInResults: (*bool)(nil), 331 }, 332 PartialUpdates: true, 333 } 334 335 if _, err = pc.CreateFilter(ctx, filter); err != nil { 336 t.Fatal(err) 337 } 338 339 updates, _ := pc.WaitForUpdates(ctx, "") // disregard first result 340 // add DC and poll 341 dc, _ := root.CreateDatacenter(ctx, "DC-A") 342 updates, _ = pc.WaitForUpdates(ctx, updates.Version) 343 set := updates.FilterSet[0].ObjectSet[0] 344 if set.Obj.Type != "Datacenter" { 345 t.Errorf("obj=%s", set.Obj) 346 } 347 if set.Kind != types.ObjectUpdateKindEnter { 348 t.Errorf("kind=%s", set.Kind) 349 } 350 351 // create a new session and a call to the PropertyCollector singleton 352 c2, err := govmomi.NewClient(ctx, s.URL, true) 353 if err != nil { 354 log.Fatal(err) 355 } 356 var folder mo.Folder 357 property.DefaultCollector(c2.Client).RetrieveOne(ctx, root.Reference(), []string{"name"}, &folder) 358 _ = c2.Logout(ctx) 359 360 // remove DC and poll 361 _, _ = dc.Destroy(ctx) 362 updates, _ = pc.WaitForUpdates(ctx, updates.Version) 363 set = updates.FilterSet[0].ObjectSet[0] 364 if set.Obj.Type != "Datacenter" { 365 t.Errorf("obj=%s", set.Obj) 366 } 367 if set.Kind != types.ObjectUpdateKindLeave { 368 t.Errorf("kind=%s", set.Kind) 369 } 370 }